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"
53 #include "lib/util/binsearch.h"
58 #define DBGC_CLASS DBGC_DRS_REPL
60 /* the RMD_VERSION for linked attributes starts from 1 */
61 #define RMD_VERSION_INITIAL 1
64 * It's 29/12/9999 at 23:59:59 UTC as specified in MS-ADTS 7.1.1.4.2
65 * Deleted Objects Container
67 static const NTTIME DELETED_OBJECT_CONTAINER_CHANGE_TIME = 2650466015990000000ULL;
69 struct replmd_private {
71 struct la_group *la_list;
73 struct nc_entry *prev, *next;
76 uint64_t mod_usn_urgent;
78 struct ldb_dn *schema_dn;
79 bool originating_updates;
82 uint32_t num_processed;
83 bool recyclebin_enabled;
84 bool recyclebin_state_known;
88 * groups link attributes together by source-object and attribute-ID,
89 * to improve processing efficiency (i.e. for 'member' attribute, which
90 * could have 100s or 1000s of links).
91 * Note this grouping is best effort - the same source object could still
92 * correspond to several la_groups (a lot depends on the order DRS sends
93 * the links in). The groups currently don't span replication chunks (which
94 * caps the size to ~1500 links by default).
97 struct la_group *next, *prev;
98 struct la_entry *la_entries;
102 struct la_entry *next, *prev;
103 struct drsuapi_DsReplicaLinkedAttribute *la;
104 uint32_t dsdb_repl_flags;
107 struct replmd_replicated_request {
108 struct ldb_module *module;
109 struct ldb_request *req;
111 const struct dsdb_schema *schema;
112 struct GUID our_invocation_id;
114 /* the controls we pass down */
115 struct ldb_control **controls;
118 * Backlinks for the replmd_add() case (we want to create
119 * backlinks after creating the user, but before the end of
122 struct la_backlink *la_backlinks;
124 /* details for the mode where we apply a bunch of inbound replication meessages */
126 uint32_t index_current;
127 struct dsdb_extended_replicated_objects *objs;
129 struct ldb_message *search_msg;
130 struct GUID local_parent_guid;
141 * the result of replmd_process_linked_attribute(): either there was no change
142 * (update was ignored), a new link was added (either inactive or active), or
143 * an existing link was modified (active/inactive status may have changed).
148 LINK_CHANGE_MODIFIED,
149 } replmd_link_changed;
151 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
152 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
153 static int replmd_check_upgrade_links(struct ldb_context *ldb,
154 struct parsed_dn *dns, uint32_t count,
155 struct ldb_message_element *el,
156 const char *ldap_oid);
157 static int replmd_verify_link_target(struct replmd_replicated_request *ar,
159 struct la_entry *la_entry,
160 struct ldb_dn *src_dn,
161 const struct dsdb_attribute *attr);
162 static int replmd_get_la_entry_source(struct ldb_module *module,
163 struct la_entry *la_entry,
165 const struct dsdb_attribute **ret_attr,
166 struct ldb_message **source_msg);
167 static int replmd_set_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
168 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
169 uint64_t usn, uint64_t local_usn, NTTIME nttime,
170 uint32_t version, bool deleted);
172 static int replmd_make_deleted_child_dn(TALLOC_CTX *tmp_ctx,
173 struct ldb_context *ldb,
175 const char *rdn_name,
176 const struct ldb_val *rdn_value,
179 enum urgent_situation {
180 REPL_URGENT_ON_CREATE = 1,
181 REPL_URGENT_ON_UPDATE = 2,
182 REPL_URGENT_ON_DELETE = 4
185 enum deletion_state {
186 OBJECT_NOT_DELETED=1,
193 static bool replmd_recyclebin_enabled(struct ldb_module *module)
195 bool enabled = false;
196 struct replmd_private *replmd_private =
197 talloc_get_type_abort(ldb_module_get_private(module),
198 struct replmd_private);
201 * only lookup the recycle-bin state once per replication, then cache
202 * the result. This can save us 1000s of DB searches
204 if (!replmd_private->recyclebin_state_known) {
205 int ret = dsdb_recyclebin_enabled(module, &enabled);
206 if (ret != LDB_SUCCESS) {
210 replmd_private->recyclebin_enabled = enabled;
211 replmd_private->recyclebin_state_known = true;
214 return replmd_private->recyclebin_enabled;
217 static void replmd_deletion_state(struct ldb_module *module,
218 const struct ldb_message *msg,
219 enum deletion_state *current_state,
220 enum deletion_state *next_state)
222 bool enabled = false;
225 *current_state = OBJECT_REMOVED;
226 if (next_state != NULL) {
227 *next_state = OBJECT_REMOVED;
232 enabled = replmd_recyclebin_enabled(module);
234 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
236 *current_state = OBJECT_TOMBSTONE;
237 if (next_state != NULL) {
238 *next_state = OBJECT_REMOVED;
243 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
244 *current_state = OBJECT_RECYCLED;
245 if (next_state != NULL) {
246 *next_state = OBJECT_REMOVED;
251 *current_state = OBJECT_DELETED;
252 if (next_state != NULL) {
253 *next_state = OBJECT_RECYCLED;
258 *current_state = OBJECT_NOT_DELETED;
259 if (next_state == NULL) {
264 *next_state = OBJECT_DELETED;
266 *next_state = OBJECT_TOMBSTONE;
270 static const struct {
271 const char *update_name;
272 enum urgent_situation repl_situation;
273 } urgent_objects[] = {
274 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
275 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
276 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
277 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
278 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
279 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
283 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
284 static const char *urgent_attrs[] = {
287 "userAccountControl",
292 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
293 enum urgent_situation situation)
296 for (i=0; urgent_objects[i].update_name; i++) {
298 if ((situation & urgent_objects[i].repl_situation) == 0) {
302 for (j=0; j<objectclass_el->num_values; j++) {
303 const struct ldb_val *v = &objectclass_el->values[j];
304 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
312 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
314 if (ldb_attr_in_list(urgent_attrs, el->name)) {
320 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
323 initialise the module
324 allocate the private structure and build the list
325 of partition DNs for use by replmd_notify()
327 static int replmd_init(struct ldb_module *module)
329 struct replmd_private *replmd_private;
330 struct ldb_context *ldb = ldb_module_get_ctx(module);
333 replmd_private = talloc_zero(module, struct replmd_private);
334 if (replmd_private == NULL) {
336 return LDB_ERR_OPERATIONS_ERROR;
339 ret = dsdb_check_samba_compatible_feature(module,
340 SAMBA_SORTED_LINKS_FEATURE,
341 &replmd_private->sorted_links);
342 if (ret != LDB_SUCCESS) {
343 talloc_free(replmd_private);
347 replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
348 ldb_module_set_private(module, replmd_private);
349 return ldb_next_init(module);
353 cleanup our per-transaction contexts
355 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
357 talloc_free(replmd_private->la_ctx);
358 replmd_private->la_list = NULL;
359 replmd_private->la_ctx = NULL;
360 replmd_private->recyclebin_state_known = false;
365 struct la_backlink *next, *prev;
366 const char *attr_name;
367 struct ldb_dn *forward_dn;
368 struct GUID target_guid;
370 bool bl_maybe_invisible;
375 a ldb_modify request operating on modules below the
378 static int linked_attr_modify(struct ldb_module *module,
379 const struct ldb_message *message,
380 struct ldb_request *parent)
382 struct ldb_request *mod_req;
384 struct ldb_context *ldb = ldb_module_get_ctx(module);
385 TALLOC_CTX *tmp_ctx = talloc_new(module);
386 struct ldb_result *res;
388 res = talloc_zero(tmp_ctx, struct ldb_result);
390 talloc_free(tmp_ctx);
391 return ldb_oom(ldb_module_get_ctx(module));
394 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
398 ldb_modify_default_callback,
400 LDB_REQ_SET_LOCATION(mod_req);
401 if (ret != LDB_SUCCESS) {
402 talloc_free(tmp_ctx);
406 ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
408 if (ret != LDB_SUCCESS) {
412 /* Run the new request */
413 ret = ldb_next_request(module, mod_req);
415 if (ret == LDB_SUCCESS) {
416 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
419 talloc_free(tmp_ctx);
423 static int replmd_backlink_invisible(struct ldb_module *module,
424 struct ldb_message *msg,
425 struct la_backlink *bl)
427 struct ldb_context *ldb = ldb_module_get_ctx(module);
428 const struct dsdb_schema *schema = NULL;
429 TALLOC_CTX *frame = NULL;
430 struct ldb_message_element *oc_element = NULL;
431 const char **allowed_attrs = NULL;
434 if (!bl->active || !bl->bl_maybe_invisible || bl->bl_invisible) {
438 schema = dsdb_get_schema(ldb, NULL);
439 if (schema == NULL) {
440 return ldb_module_operr(module);
443 oc_element = ldb_msg_find_element(msg, "objectClass");
444 if (oc_element == NULL) {
445 return ldb_module_operr(module);
448 frame = talloc_stackframe();
450 allowed_attrs = dsdb_full_attribute_list(frame,
454 if (allowed_attrs == NULL) {
456 return ldb_module_oom(module);
459 bl_allowed = str_list_check(allowed_attrs, bl->attr_name);
461 bl->bl_maybe_invisible = false;
462 bl->bl_invisible = true;
470 process a backlinks we accumulated during a transaction, adding and
471 deleting the backlinks from the target objects
473 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
475 struct ldb_dn *target_dn, *source_dn;
476 struct ldb_message *old_msg = NULL;
477 const char * const empty_attrs[] = { NULL };
478 const char * const oc_attrs[] = { "objectClass", NULL };
479 const char * const *attrs = NULL;
480 uint32_t rmd_flags = 0;
482 struct ldb_context *ldb = ldb_module_get_ctx(module);
483 struct ldb_message *msg;
484 TALLOC_CTX *frame = talloc_stackframe();
487 if (bl->active && bl->bl_maybe_invisible) {
496 - construct ldb_message
497 - either an add or a delete
499 ret = dsdb_module_obj_by_guid(module,
505 if (ret != LDB_SUCCESS) {
506 struct GUID_txt_buf guid_str;
507 DBG_WARNING("Failed to find target DN for linked attribute with GUID %s\n",
508 GUID_buf_string(&bl->target_guid, &guid_str));
509 DBG_WARNING("Please run 'samba-tool dbcheck' to resolve any missing backlinks.\n");
513 target_dn = old_msg->dn;
515 ret = replmd_backlink_invisible(module, old_msg, bl);
516 if (ret != LDB_SUCCESS) {
521 if (bl->active && bl->bl_invisible) {
522 rmd_flags |= DSDB_RMD_FLAG_HIDDEN_BL;
525 msg = ldb_msg_new(frame);
527 ldb_module_oom(module);
529 return LDB_ERR_OPERATIONS_ERROR;
532 source_dn = ldb_dn_copy(frame, bl->forward_dn);
534 ldb_module_oom(module);
536 return LDB_ERR_OPERATIONS_ERROR;
538 /* Filter down to the attributes we want in the backlink */
539 const char *accept[] = { "GUID", "SID", NULL };
540 ldb_dn_extended_filter(source_dn, accept);
543 if (rmd_flags != 0) {
544 const char *flags_string = NULL;
545 struct ldb_val flagsv;
547 flags_string = talloc_asprintf(frame, "%u", rmd_flags);
548 if (flags_string == NULL) {
550 return ldb_module_oom(module);
553 flagsv = data_blob_string_const(flags_string);
555 ret = ldb_dn_set_extended_component(source_dn, "RMD_FLAGS", &flagsv);
556 if (ret != LDB_SUCCESS) {
562 /* construct a ldb_message for adding/deleting the backlink */
564 dn_string = ldb_dn_get_extended_linearized(frame, source_dn, 1);
566 ldb_module_oom(module);
568 return LDB_ERR_OPERATIONS_ERROR;
570 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
571 if (ret != LDB_SUCCESS) {
575 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
577 /* a backlink should never be single valued. Unfortunately the
578 exchange schema has a attribute
579 msExchBridgeheadedLocalConnectorsDNBL which is single
580 valued and a backlink. We need to cope with that by
581 ignoring the single value flag */
582 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
584 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
585 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
586 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
587 cope with possible corruption where the backlink has
588 already been removed */
589 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
590 ldb_dn_get_linearized(target_dn),
591 ldb_dn_get_linearized(source_dn),
592 ldb_errstring(ldb)));
594 } else if (ret != LDB_SUCCESS) {
595 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
596 bl->active?"add":"remove",
597 ldb_dn_get_linearized(source_dn),
598 ldb_dn_get_linearized(target_dn),
608 add a backlink to the list of backlinks to add/delete in the prepare
611 forward_dn is stolen onto the defereed context
613 static int replmd_defer_add_backlink(struct ldb_module *module,
614 struct replmd_private *replmd_private,
615 const struct dsdb_schema *schema,
616 struct replmd_replicated_request *ac,
617 struct ldb_dn *forward_dn,
618 struct GUID *target_guid, bool active,
619 const struct dsdb_attribute *schema_attr,
620 struct ldb_request *parent)
622 const struct dsdb_attribute *target_attr;
623 struct la_backlink *bl;
625 bl = talloc(ac, struct la_backlink);
627 ldb_module_oom(module);
628 return LDB_ERR_OPERATIONS_ERROR;
631 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
634 * windows 2003 has a broken schema where the
635 * definition of msDS-IsDomainFor is missing (which is
636 * supposed to be the backlink of the
637 * msDS-HasDomainNCs attribute
642 bl->attr_name = target_attr->lDAPDisplayName;
643 bl->forward_dn = talloc_steal(bl, forward_dn);
644 bl->target_guid = *target_guid;
646 bl->bl_maybe_invisible = target_attr->bl_maybe_invisible;
647 bl->bl_invisible = false;
649 DLIST_ADD(ac->la_backlinks, bl);
655 add a backlink to the list of backlinks to add/delete in the prepare
658 static int replmd_add_backlink(struct ldb_module *module,
659 struct replmd_private *replmd_private,
660 const struct dsdb_schema *schema,
661 struct ldb_dn *forward_dn,
662 struct GUID *target_guid, bool active,
663 const struct dsdb_attribute *schema_attr,
664 struct ldb_request *parent)
666 const struct dsdb_attribute *target_attr;
667 struct la_backlink bl;
670 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
673 * windows 2003 has a broken schema where the
674 * definition of msDS-IsDomainFor is missing (which is
675 * supposed to be the backlink of the
676 * msDS-HasDomainNCs attribute
681 bl.attr_name = target_attr->lDAPDisplayName;
682 bl.forward_dn = forward_dn;
683 bl.target_guid = *target_guid;
685 bl.bl_maybe_invisible = target_attr->bl_maybe_invisible;
686 bl.bl_invisible = false;
688 ret = replmd_process_backlink(module, &bl, parent);
694 * Callback for most write operations in this module:
696 * notify the repl task that a object has changed. The notifies are
697 * gathered up in the replmd_private structure then written to the
698 * @REPLCHANGED object in each partition during the prepare_commit
700 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
703 struct replmd_replicated_request *ac =
704 talloc_get_type_abort(req->context, struct replmd_replicated_request);
705 struct replmd_private *replmd_private =
706 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
707 struct nc_entry *modified_partition;
708 struct ldb_control *partition_ctrl;
709 const struct dsdb_control_current_partition *partition;
711 struct ldb_control **controls;
713 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
715 controls = ares->controls;
716 if (ldb_request_get_control(ac->req,
717 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
719 * Remove the current partition control from what we pass up
720 * the chain if it hasn't been requested manually.
722 controls = ldb_controls_except_specified(ares->controls, ares,
726 if (ares->error != LDB_SUCCESS) {
727 struct GUID_txt_buf guid_txt;
728 struct ldb_message *msg = NULL;
731 if (ac->apply_mode == false) {
732 DBG_NOTICE("Originating update failure. Error is: %s\n",
733 ldb_strerror(ares->error));
734 return ldb_module_done(ac->req, controls,
735 ares->response, ares->error);
738 msg = ac->objs->objects[ac->index_current].msg;
740 * Set at DBG_NOTICE as once these start to happe, they
741 * will happen a lot until resolved, due to repeated
742 * replication. The caller will probably print the
743 * ldb error string anyway.
745 DBG_NOTICE("DRS replication apply failure for %s. Error is: %s\n",
746 ldb_dn_get_linearized(msg->dn),
747 ldb_strerror(ares->error));
749 s = ldb_ldif_message_redacted_string(ldb_module_get_ctx(ac->module),
754 DBG_INFO("Failing DRS %s replication message was %s:\n%s\n",
755 ac->search_msg == NULL ? "ADD" : "MODIFY",
756 GUID_buf_string(&ac->objs->objects[ac->index_current].object_guid,
760 return ldb_module_done(ac->req, controls,
761 ares->response, ares->error);
764 if (ares->type != LDB_REPLY_DONE) {
765 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
766 return ldb_module_done(ac->req, NULL,
767 NULL, LDB_ERR_OPERATIONS_ERROR);
770 if (ac->apply_mode == false) {
771 struct la_backlink *bl;
773 * process our backlink list after an replmd_add(),
774 * creating and deleting backlinks as necessary (this
775 * code is sync). The other cases are handled inline
778 for (bl=ac->la_backlinks; bl; bl=bl->next) {
779 ret = replmd_process_backlink(ac->module, bl, ac->req);
780 if (ret != LDB_SUCCESS) {
781 return ldb_module_done(ac->req, NULL,
787 if (!partition_ctrl) {
788 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
789 return ldb_module_done(ac->req, NULL,
790 NULL, LDB_ERR_OPERATIONS_ERROR);
793 partition = talloc_get_type_abort(partition_ctrl->data,
794 struct dsdb_control_current_partition);
796 if (ac->seq_num > 0) {
797 for (modified_partition = replmd_private->ncs; modified_partition;
798 modified_partition = modified_partition->next) {
799 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
804 if (modified_partition == NULL) {
805 modified_partition = talloc_zero(replmd_private, struct nc_entry);
806 if (!modified_partition) {
807 ldb_oom(ldb_module_get_ctx(ac->module));
808 return ldb_module_done(ac->req, NULL,
809 NULL, LDB_ERR_OPERATIONS_ERROR);
811 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
812 if (!modified_partition->dn) {
813 ldb_oom(ldb_module_get_ctx(ac->module));
814 return ldb_module_done(ac->req, NULL,
815 NULL, LDB_ERR_OPERATIONS_ERROR);
817 DLIST_ADD(replmd_private->ncs, modified_partition);
820 if (ac->seq_num > modified_partition->mod_usn) {
821 modified_partition->mod_usn = ac->seq_num;
823 modified_partition->mod_usn_urgent = ac->seq_num;
826 if (!ac->apply_mode) {
827 replmd_private->originating_updates = true;
831 if (ac->apply_mode) {
832 ret = replmd_replicated_apply_isDeleted(ac);
833 if (ret != LDB_SUCCESS) {
834 return ldb_module_done(ac->req, NULL, NULL, ret);
838 /* free the partition control container here, for the
839 * common path. Other cases will have it cleaned up
840 * eventually with the ares */
841 talloc_free(partition_ctrl);
842 return ldb_module_done(ac->req, controls,
843 ares->response, LDB_SUCCESS);
849 * update a @REPLCHANGED record in each partition if there have been
850 * any writes of replicated data in the partition
852 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
854 struct replmd_private *replmd_private =
855 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
857 while (replmd_private->ncs) {
859 struct nc_entry *modified_partition = replmd_private->ncs;
861 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
862 modified_partition->mod_usn,
863 modified_partition->mod_usn_urgent, parent);
864 if (ret != LDB_SUCCESS) {
865 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
866 ldb_dn_get_linearized(modified_partition->dn)));
870 if (ldb_dn_compare(modified_partition->dn,
871 replmd_private->schema_dn) == 0) {
872 struct ldb_result *ext_res;
873 ret = dsdb_module_extended(module,
874 replmd_private->schema_dn,
876 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
878 DSDB_FLAG_NEXT_MODULE,
880 if (ret != LDB_SUCCESS) {
883 talloc_free(ext_res);
886 DLIST_REMOVE(replmd_private->ncs, modified_partition);
887 talloc_free(modified_partition);
895 created a replmd_replicated_request context
897 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
898 struct ldb_request *req)
900 struct ldb_context *ldb;
901 struct replmd_replicated_request *ac;
902 const struct GUID *our_invocation_id;
904 ldb = ldb_module_get_ctx(module);
906 ac = talloc_zero(req, struct replmd_replicated_request);
915 ac->schema = dsdb_get_schema(ldb, ac);
917 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
918 "replmd_modify: no dsdb_schema loaded");
919 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
924 /* get our invocationId */
925 our_invocation_id = samdb_ntds_invocation_id(ldb);
926 if (!our_invocation_id) {
927 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
928 "replmd_add: unable to find invocationId\n");
932 ac->our_invocation_id = *our_invocation_id;
938 add a time element to a record
940 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
942 struct ldb_message_element *el;
946 if (ldb_msg_find_element(msg, attr) != NULL) {
950 s = ldb_timestring(msg, t);
952 return LDB_ERR_OPERATIONS_ERROR;
955 ret = ldb_msg_add_string(msg, attr, s);
956 if (ret != LDB_SUCCESS) {
960 el = ldb_msg_find_element(msg, attr);
961 /* always set as replace. This works because on add ops, the flag
963 el->flags = LDB_FLAG_MOD_REPLACE;
969 add a uint64_t element to a record
971 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
972 const char *attr, uint64_t v)
974 struct ldb_message_element *el;
977 if (ldb_msg_find_element(msg, attr) != NULL) {
981 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
982 if (ret != LDB_SUCCESS) {
986 el = ldb_msg_find_element(msg, attr);
987 /* always set as replace. This works because on add ops, the flag
989 el->flags = LDB_FLAG_MOD_REPLACE;
994 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
995 const struct replPropertyMetaData1 *m2)
998 * This assignment seems inoccous, but it is critical for the
999 * system, as we need to do the comparisons as a unsigned
1000 * quantity, not signed (enums are signed integers)
1002 uint32_t attid_1 = m1->attid;
1003 uint32_t attid_2 = m2->attid;
1005 if (attid_1 == attid_2) {
1010 * See above regarding this being an unsigned comparison.
1011 * Otherwise when the high bit is set on non-standard
1012 * attributes, they would end up first, before objectClass
1015 return attid_1 > attid_2 ? 1 : -1;
1018 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
1019 struct replPropertyMetaDataCtr1 *ctr1,
1022 if (ctr1->count == 0) {
1023 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
1024 "No elements found in replPropertyMetaData for %s!\n",
1025 ldb_dn_get_linearized(dn));
1026 return LDB_ERR_CONSTRAINT_VIOLATION;
1029 /* the objectClass attribute is value 0x00000000, so must be first */
1030 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
1031 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
1032 "No objectClass found in replPropertyMetaData for %s!\n",
1033 ldb_dn_get_linearized(dn));
1034 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1040 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
1041 struct replPropertyMetaDataCtr1 *ctr1,
1044 /* Note this is O(n^2) for the almost-sorted case, which this is */
1045 TYPESAFE_QSORT(ctr1->array, ctr1->count,
1046 replmd_replPropertyMetaData1_attid_sort);
1047 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
1050 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
1051 const struct ldb_message_element *e2,
1052 const struct dsdb_schema *schema)
1054 const struct dsdb_attribute *a1;
1055 const struct dsdb_attribute *a2;
1058 * TODO: make this faster by caching the dsdb_attribute pointer
1059 * on the ldb_messag_element
1062 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
1063 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
1066 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
1070 return strcasecmp(e1->name, e2->name);
1072 if (a1->attributeID_id == a2->attributeID_id) {
1075 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
1078 static void replmd_ldb_message_sort(struct ldb_message *msg,
1079 const struct dsdb_schema *schema)
1081 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
1084 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1085 const struct GUID *invocation_id,
1086 uint64_t local_usn, NTTIME nttime);
1088 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2);
1090 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1091 struct ldb_message_element *el, struct parsed_dn **pdn,
1092 const char *ldap_oid, struct ldb_request *parent);
1094 static int check_parsed_dn_duplicates(struct ldb_module *module,
1095 struct ldb_message_element *el,
1096 struct parsed_dn *pdn);
1099 fix up linked attributes in replmd_add.
1100 This involves setting up the right meta-data in extended DN
1101 components, and creating backlinks to the object
1103 static int replmd_add_fix_la(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1104 struct replmd_private *replmd_private,
1105 struct ldb_message_element *el,
1106 struct replmd_replicated_request *ac,
1108 struct ldb_dn *forward_dn,
1109 const struct dsdb_attribute *sa,
1110 struct ldb_request *parent)
1113 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1114 struct ldb_context *ldb = ldb_module_get_ctx(module);
1115 struct parsed_dn *pdn;
1116 /* We will take a reference to the schema in replmd_add_backlink */
1117 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
1118 struct ldb_val *new_values = NULL;
1121 if (dsdb_check_single_valued_link(sa, el) == LDB_SUCCESS) {
1122 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
1124 ldb_asprintf_errstring(ldb,
1125 "Attribute %s is single valued but "
1126 "more than one value has been supplied",
1128 talloc_free(tmp_ctx);
1129 return LDB_ERR_CONSTRAINT_VIOLATION;
1133 * At the successful end of these functions el->values is
1134 * overwritten with new_values. However get_parsed_dns()
1135 * points p->v at the supplied el and it effectively gets used
1136 * as a working area by replmd_build_la_val(). So we must
1137 * duplicate it because our caller only called
1138 * ldb_msg_copy_shallow().
1141 el->values = talloc_memdup(tmp_ctx,
1143 sizeof(el->values[0]) * el->num_values);
1144 if (el->values == NULL) {
1145 ldb_module_oom(module);
1146 talloc_free(tmp_ctx);
1147 return LDB_ERR_OPERATIONS_ERROR;
1150 ret = get_parsed_dns(module, tmp_ctx, el, &pdn,
1151 sa->syntax->ldap_oid, parent);
1152 if (ret != LDB_SUCCESS) {
1153 talloc_free(tmp_ctx);
1157 ret = check_parsed_dn_duplicates(module, el, pdn);
1158 if (ret != LDB_SUCCESS) {
1159 talloc_free(tmp_ctx);
1163 new_values = talloc_array(tmp_ctx, struct ldb_val, el->num_values);
1164 if (new_values == NULL) {
1165 ldb_module_oom(module);
1166 talloc_free(tmp_ctx);
1167 return LDB_ERR_OPERATIONS_ERROR;
1170 for (i = 0; i < el->num_values; i++) {
1171 struct parsed_dn *p = &pdn[i];
1172 ret = replmd_build_la_val(new_values, p->v, p->dsdb_dn,
1173 &ac->our_invocation_id,
1175 if (ret != LDB_SUCCESS) {
1176 talloc_free(tmp_ctx);
1180 ret = replmd_defer_add_backlink(module, replmd_private,
1182 forward_dn, &p->guid, true, sa,
1184 if (ret != LDB_SUCCESS) {
1185 talloc_free(tmp_ctx);
1189 new_values[i] = *p->v;
1191 el->values = talloc_steal(mem_ctx, new_values);
1193 talloc_free(tmp_ctx);
1197 static int replmd_add_make_extended_dn(struct ldb_request *req,
1198 const DATA_BLOB *guid_blob,
1199 struct ldb_dn **_extended_dn)
1202 const DATA_BLOB *sid_blob;
1203 /* Calculate an extended DN for any linked attributes */
1204 struct ldb_dn *extended_dn = ldb_dn_copy(req, req->op.add.message->dn);
1206 return LDB_ERR_OPERATIONS_ERROR;
1208 ret = ldb_dn_set_extended_component(extended_dn, "GUID", guid_blob);
1209 if (ret != LDB_SUCCESS) {
1213 sid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectSID");
1214 if (sid_blob != NULL) {
1215 ret = ldb_dn_set_extended_component(extended_dn, "SID", sid_blob);
1216 if (ret != LDB_SUCCESS) {
1220 *_extended_dn = extended_dn;
1225 intercept add requests
1227 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
1229 struct ldb_context *ldb;
1230 struct ldb_control *control;
1231 struct replmd_replicated_request *ac;
1232 enum ndr_err_code ndr_err;
1233 struct ldb_request *down_req;
1234 struct ldb_message *msg;
1235 const DATA_BLOB *guid_blob;
1236 DATA_BLOB guid_blob_stack;
1238 uint8_t guid_data[16];
1239 struct replPropertyMetaDataBlob nmd;
1240 struct ldb_val nmd_value;
1241 struct ldb_dn *extended_dn = NULL;
1244 * The use of a time_t here seems odd, but as the NTTIME
1245 * elements are actually declared as NTTIME_1sec in the IDL,
1246 * getting a higher resolution timestamp is not required.
1248 time_t t = time(NULL);
1253 unsigned int functional_level;
1255 bool allow_add_guid = false;
1256 bool remove_current_guid = false;
1257 bool is_urgent = false;
1258 bool is_schema_nc = false;
1259 struct ldb_message_element *objectclass_el;
1260 struct replmd_private *replmd_private =
1261 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
1263 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
1264 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
1266 allow_add_guid = true;
1269 /* do not manipulate our control entries */
1270 if (ldb_dn_is_special(req->op.add.message->dn)) {
1271 return ldb_next_request(module, req);
1274 ldb = ldb_module_get_ctx(module);
1276 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
1278 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
1279 if (guid_blob != NULL) {
1280 if (!allow_add_guid) {
1281 ldb_set_errstring(ldb,
1282 "replmd_add: it's not allowed to add an object with objectGUID!");
1283 return LDB_ERR_UNWILLING_TO_PERFORM;
1285 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
1286 if (!NT_STATUS_IS_OK(status)) {
1287 ldb_set_errstring(ldb,
1288 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1289 return LDB_ERR_UNWILLING_TO_PERFORM;
1291 /* we remove this attribute as it can be a string and
1292 * will not be treated correctly and then we will re-add
1293 * it later on in the good format */
1294 remove_current_guid = true;
1298 guid = GUID_random();
1300 guid_blob_stack = data_blob_const(guid_data, sizeof(guid_data));
1302 /* This can't fail */
1303 ndr_push_struct_into_fixed_blob(&guid_blob_stack, &guid,
1304 (ndr_push_flags_fn_t)ndr_push_GUID);
1305 guid_blob = &guid_blob_stack;
1308 ac = replmd_ctx_init(module, req);
1310 return ldb_module_oom(module);
1313 functional_level = dsdb_functional_level(ldb);
1315 /* Get a sequence number from the backend */
1316 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1317 if (ret != LDB_SUCCESS) {
1322 /* we have to copy the message as the caller might have it as a const */
1323 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1327 return LDB_ERR_OPERATIONS_ERROR;
1330 /* generated times */
1331 unix_to_nt_time(&now, t);
1332 time_str = ldb_timestring(msg, t);
1336 return LDB_ERR_OPERATIONS_ERROR;
1338 if (remove_current_guid) {
1339 ldb_msg_remove_attr(msg,"objectGUID");
1343 * remove autogenerated attributes
1345 ldb_msg_remove_attr(msg, "whenCreated");
1346 ldb_msg_remove_attr(msg, "whenChanged");
1347 ldb_msg_remove_attr(msg, "uSNCreated");
1348 ldb_msg_remove_attr(msg, "uSNChanged");
1349 ldb_msg_remove_attr(msg, "replPropertyMetaData");
1352 * readd replicated attributes
1354 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1355 if (ret != LDB_SUCCESS) {
1361 /* build the replication meta_data */
1364 nmd.ctr.ctr1.count = msg->num_elements;
1365 nmd.ctr.ctr1.array = talloc_array(msg,
1366 struct replPropertyMetaData1,
1367 nmd.ctr.ctr1.count);
1368 if (!nmd.ctr.ctr1.array) {
1371 return LDB_ERR_OPERATIONS_ERROR;
1374 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1376 for (i=0; i < msg->num_elements;) {
1377 struct ldb_message_element *e = &msg->elements[i];
1378 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1379 const struct dsdb_attribute *sa;
1381 if (e->name[0] == '@') {
1386 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1388 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1389 "replmd_add: attribute '%s' not defined in schema\n",
1392 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1395 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1396 /* if the attribute is not replicated (0x00000001)
1397 * or constructed (0x00000004) it has no metadata
1403 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1404 if (extended_dn == NULL) {
1405 ret = replmd_add_make_extended_dn(req,
1408 if (ret != LDB_SUCCESS) {
1415 * Prepare the context for the backlinks and
1416 * create metadata for the forward links. The
1417 * backlinks are created in
1418 * replmd_op_callback() after the successful
1419 * ADD of the object.
1421 ret = replmd_add_fix_la(module, msg->elements,
1426 if (ret != LDB_SUCCESS) {
1430 /* linked attributes are not stored in
1431 replPropertyMetaData in FL above w2k */
1436 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1438 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1439 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1442 if (rdn_val == NULL) {
1445 return LDB_ERR_OPERATIONS_ERROR;
1448 rdn = (const char*)rdn_val->data;
1449 if (strcmp(rdn, "Deleted Objects") == 0) {
1451 * Set the originating_change_time to 29/12/9999 at 23:59:59
1452 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1454 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1456 m->originating_change_time = now;
1459 m->originating_change_time = now;
1461 m->originating_invocation_id = ac->our_invocation_id;
1462 m->originating_usn = ac->seq_num;
1463 m->local_usn = ac->seq_num;
1466 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1471 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1473 if (e->num_values != 0) {
1478 ldb_msg_remove_element(msg, e);
1481 /* fix meta data count */
1482 nmd.ctr.ctr1.count = ni;
1485 * sort meta data array
1487 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1488 if (ret != LDB_SUCCESS) {
1489 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1494 /* generated NDR encoded values */
1495 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1497 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1498 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1501 return LDB_ERR_OPERATIONS_ERROR;
1505 * add the autogenerated values
1507 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1508 if (ret != LDB_SUCCESS) {
1513 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1514 if (ret != LDB_SUCCESS) {
1519 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1520 if (ret != LDB_SUCCESS) {
1525 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1526 if (ret != LDB_SUCCESS) {
1531 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1532 if (ret != LDB_SUCCESS) {
1539 * sort the attributes by attid before storing the object
1541 replmd_ldb_message_sort(msg, ac->schema);
1544 * Assert that we do have an objectClass
1546 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1547 if (objectclass_el == NULL) {
1548 ldb_asprintf_errstring(ldb, __location__
1549 ": objectClass missing on %s\n",
1550 ldb_dn_get_linearized(msg->dn));
1552 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1554 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1555 REPL_URGENT_ON_CREATE);
1557 ac->is_urgent = is_urgent;
1558 ret = ldb_build_add_req(&down_req, ldb, ac,
1561 ac, replmd_op_callback,
1564 LDB_REQ_SET_LOCATION(down_req);
1565 if (ret != LDB_SUCCESS) {
1570 /* current partition control is needed by "replmd_op_callback" */
1571 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1572 ret = ldb_request_add_control(down_req,
1573 DSDB_CONTROL_CURRENT_PARTITION_OID,
1575 if (ret != LDB_SUCCESS) {
1581 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1582 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1583 if (ret != LDB_SUCCESS) {
1589 /* mark the relax control done */
1591 control->critical = 0;
1593 /* go on with the call chain */
1594 return ldb_next_request(module, down_req);
1599 * update the replPropertyMetaData for one element
1601 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1602 struct ldb_message *msg,
1603 struct ldb_message_element *el,
1604 struct ldb_message_element *old_el,
1605 struct replPropertyMetaDataBlob *omd,
1606 const struct dsdb_schema *schema,
1608 const struct GUID *our_invocation_id,
1611 bool is_forced_rodc,
1612 struct ldb_request *req)
1615 const struct dsdb_attribute *a;
1616 struct replPropertyMetaData1 *md1;
1617 bool may_skip = false;
1620 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1622 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1623 /* allow this to make it possible for dbcheck
1624 to remove bad attributes */
1628 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1630 return LDB_ERR_OPERATIONS_ERROR;
1633 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1635 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1640 * if the attribute's value haven't changed, and this isn't
1641 * just a delete of everything then return LDB_SUCCESS Unless
1642 * we have the provision control or if the attribute is
1643 * interSiteTopologyGenerator as this page explain:
1644 * http://support.microsoft.com/kb/224815 this attribute is
1645 * periodically written by the DC responsible for the intersite
1646 * generation in a given site
1648 * Unchanged could be deleting or replacing an already-gone
1649 * thing with an unconstrained delete/empty replace or a
1650 * replace with the same value, but not an add with the same
1651 * value because that could be about adding a duplicate (which
1652 * is for someone else to error out on).
1654 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1655 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1658 } else if (old_el == NULL && el->num_values == 0) {
1659 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1661 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1664 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1665 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1667 * We intentionally skip the version bump when attempting to
1670 * The control is set by dbcheck and expunge-tombstones which
1671 * both attempt to be non-replicating. Otherwise, making an
1672 * alteration to the replication state would trigger a
1673 * broadcast of all expunged objects.
1678 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1680 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1684 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1685 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1687 * allow this to make it possible for dbcheck
1688 * to rebuild broken metadata
1694 for (i=0; i<omd->ctr.ctr1.count; i++) {
1696 * First check if we find it under the msDS-IntID,
1697 * then check if we find it under the OID and
1700 * This allows the administrator to simply re-write
1701 * the attributes and so restore replication, which is
1702 * likely what they will try to do.
1704 if (attid == omd->ctr.ctr1.array[i].attid) {
1708 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1713 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1714 /* linked attributes are not stored in
1715 replPropertyMetaData in FL above w2k, but we do
1716 raise the seqnum for the object */
1717 if (*seq_num == 0 &&
1718 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1719 return LDB_ERR_OPERATIONS_ERROR;
1724 if (i == omd->ctr.ctr1.count) {
1725 /* we need to add a new one */
1726 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1727 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1728 if (omd->ctr.ctr1.array == NULL) {
1730 return LDB_ERR_OPERATIONS_ERROR;
1732 omd->ctr.ctr1.count++;
1733 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1736 /* Get a new sequence number from the backend. We only do this
1737 * if we have a change that requires a new
1738 * replPropertyMetaData element
1740 if (*seq_num == 0) {
1741 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1742 if (ret != LDB_SUCCESS) {
1743 return LDB_ERR_OPERATIONS_ERROR;
1747 md1 = &omd->ctr.ctr1.array[i];
1751 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1752 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1755 if (rdn_val == NULL) {
1757 return LDB_ERR_OPERATIONS_ERROR;
1760 rdn = (const char*)rdn_val->data;
1761 if (strcmp(rdn, "Deleted Objects") == 0) {
1763 * Set the originating_change_time to 29/12/9999 at 23:59:59
1764 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1766 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1768 md1->originating_change_time = now;
1771 md1->originating_change_time = now;
1773 md1->originating_invocation_id = *our_invocation_id;
1774 md1->originating_usn = *seq_num;
1775 md1->local_usn = *seq_num;
1777 if (is_forced_rodc) {
1778 /* Force version to 0 to be overridden later via replication */
1786 * Bump the replPropertyMetaData version on an attribute, and if it
1787 * has changed (or forced by leaving rdn_old NULL), update the value
1790 * This is important, as calling a modify operation may not change the
1791 * version number if the values appear unchanged, but a rename between
1792 * parents bumps this value.
1795 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1796 struct ldb_message *msg,
1797 const struct ldb_val *rdn_new,
1798 const struct ldb_val *rdn_old,
1799 struct replPropertyMetaDataBlob *omd,
1800 struct replmd_replicated_request *ar,
1803 bool is_forced_rodc)
1805 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1806 const struct dsdb_attribute *rdn_attr =
1807 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1808 const char *attr_name = rdn_attr != NULL ?
1809 rdn_attr->lDAPDisplayName :
1811 struct ldb_message_element new_el = {
1812 .flags = LDB_FLAG_MOD_REPLACE,
1815 .values = discard_const_p(struct ldb_val, rdn_new)
1817 struct ldb_message_element old_el = {
1818 .flags = LDB_FLAG_MOD_REPLACE,
1820 .num_values = rdn_old ? 1 : 0,
1821 .values = discard_const_p(struct ldb_val, rdn_old)
1824 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1825 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1826 if (ret != LDB_SUCCESS) {
1827 return ldb_oom(ldb);
1831 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1832 omd, ar->schema, &ar->seq_num,
1833 &ar->our_invocation_id,
1834 now, is_schema_nc, is_forced_rodc,
1839 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1841 uint32_t count = omd.ctr.ctr1.count;
1844 for (i=0; i < count; i++) {
1845 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1846 if (max < m.local_usn) {
1854 * update the replPropertyMetaData object each time we modify an
1855 * object. This is needed for DRS replication, as the merge on the
1856 * client is based on this object
1858 static int replmd_update_rpmd(struct ldb_module *module,
1859 const struct dsdb_schema *schema,
1860 struct ldb_request *req,
1861 const char * const *rename_attrs,
1862 struct ldb_message *msg, uint64_t *seq_num,
1863 time_t t, bool is_schema_nc,
1864 bool *is_urgent, bool *rodc)
1866 const struct ldb_val *omd_value;
1867 enum ndr_err_code ndr_err;
1868 struct replPropertyMetaDataBlob omd;
1871 const struct GUID *our_invocation_id;
1873 const char * const *attrs = NULL;
1874 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1875 struct ldb_result *res;
1876 struct ldb_context *ldb;
1877 struct ldb_message_element *objectclass_el;
1878 enum urgent_situation situation;
1879 bool rmd_is_provided;
1880 bool rmd_is_just_resorted = false;
1881 const char *not_rename_attrs[4 + msg->num_elements];
1882 bool is_forced_rodc = false;
1885 attrs = rename_attrs;
1887 for (i = 0; i < msg->num_elements; i++) {
1888 not_rename_attrs[i] = msg->elements[i].name;
1890 not_rename_attrs[i] = "replPropertyMetaData";
1891 not_rename_attrs[i+1] = "objectClass";
1892 not_rename_attrs[i+2] = "instanceType";
1893 not_rename_attrs[i+3] = NULL;
1894 attrs = not_rename_attrs;
1897 ldb = ldb_module_get_ctx(module);
1899 ret = samdb_rodc(ldb, rodc);
1900 if (ret != LDB_SUCCESS) {
1901 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1906 ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE)) {
1907 is_forced_rodc = true;
1910 our_invocation_id = samdb_ntds_invocation_id(ldb);
1911 if (!our_invocation_id) {
1912 /* this happens during an initial vampire while
1913 updating the schema */
1914 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1918 unix_to_nt_time(&now, t);
1920 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1921 rmd_is_provided = true;
1922 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1923 rmd_is_just_resorted = true;
1926 rmd_is_provided = false;
1929 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1930 * otherwise we consider we are updating */
1931 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1932 situation = REPL_URGENT_ON_DELETE;
1933 } else if (rename_attrs) {
1934 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1936 situation = REPL_URGENT_ON_UPDATE;
1939 if (rmd_is_provided) {
1940 /* In this case the change_replmetadata control was supplied */
1941 /* We check that it's the only attribute that is provided
1942 * (it's a rare case so it's better to keep the code simpler)
1943 * We also check that the highest local_usn is bigger or the same as
1946 if( msg->num_elements != 1 ||
1947 strncmp(msg->elements[0].name,
1948 "replPropertyMetaData", 20) ) {
1949 DEBUG(0,(__location__ ": changereplmetada control called without "\
1950 "a specified replPropertyMetaData attribute or with others\n"));
1951 return LDB_ERR_OPERATIONS_ERROR;
1953 if (situation != REPL_URGENT_ON_UPDATE) {
1954 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1955 return LDB_ERR_OPERATIONS_ERROR;
1957 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1959 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1960 ldb_dn_get_linearized(msg->dn)));
1961 return LDB_ERR_OPERATIONS_ERROR;
1963 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1964 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1965 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1966 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1967 ldb_dn_get_linearized(msg->dn)));
1968 return LDB_ERR_OPERATIONS_ERROR;
1971 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1972 DSDB_FLAG_NEXT_MODULE |
1973 DSDB_SEARCH_SHOW_RECYCLED |
1974 DSDB_SEARCH_SHOW_EXTENDED_DN |
1975 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1976 DSDB_SEARCH_REVEAL_INTERNALS, req);
1978 if (ret != LDB_SUCCESS) {
1982 if (rmd_is_just_resorted == false) {
1983 *seq_num = find_max_local_usn(omd);
1985 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1988 * The test here now allows for a new
1989 * replPropertyMetaData with no change, if was
1990 * just dbcheck re-sorting the values.
1992 if (*seq_num <= db_seq) {
1993 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1994 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1995 (long long)*seq_num, (long long)db_seq));
1996 return LDB_ERR_OPERATIONS_ERROR;
2001 /* search for the existing replPropertyMetaDataBlob. We need
2002 * to use REVEAL and ask for DNs in storage format to support
2003 * the check for values being the same in
2004 * replmd_update_rpmd_element()
2006 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
2007 DSDB_FLAG_NEXT_MODULE |
2008 DSDB_SEARCH_SHOW_RECYCLED |
2009 DSDB_SEARCH_SHOW_EXTENDED_DN |
2010 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2011 DSDB_SEARCH_REVEAL_INTERNALS, req);
2012 if (ret != LDB_SUCCESS) {
2016 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
2018 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
2019 ldb_dn_get_linearized(msg->dn)));
2020 return LDB_ERR_OPERATIONS_ERROR;
2023 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
2024 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
2025 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2026 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
2027 ldb_dn_get_linearized(msg->dn)));
2028 return LDB_ERR_OPERATIONS_ERROR;
2031 if (omd.version != 1) {
2032 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
2033 omd.version, ldb_dn_get_linearized(msg->dn)));
2034 return LDB_ERR_OPERATIONS_ERROR;
2037 for (i=0; i<msg->num_elements;) {
2038 struct ldb_message_element *el = &msg->elements[i];
2039 struct ldb_message_element *old_el;
2041 old_el = ldb_msg_find_element(res->msgs[0], el->name);
2042 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
2043 &omd, schema, seq_num,
2048 if (ret != LDB_SUCCESS) {
2052 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
2053 *is_urgent = replmd_check_urgent_attribute(el);
2056 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
2061 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
2063 if (el->num_values != 0) {
2068 ldb_msg_remove_element(msg, el);
2073 * Assert that we have an objectClass attribute - this is major
2074 * corruption if we don't have this!
2076 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
2077 if (objectclass_el != NULL) {
2079 * Now check if this objectClass means we need to do urgent replication
2081 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
2085 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
2086 ldb_asprintf_errstring(ldb, __location__
2087 ": objectClass missing on %s\n",
2088 ldb_dn_get_linearized(msg->dn));
2089 return LDB_ERR_OBJECT_CLASS_VIOLATION;
2093 * replmd_update_rpmd_element has done an update if the
2096 if (*seq_num != 0 || rmd_is_just_resorted == true) {
2097 struct ldb_val *md_value;
2098 struct ldb_message_element *el;
2100 /*if we are RODC and this is a DRSR update then its ok*/
2101 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
2102 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)
2103 && !is_forced_rodc) {
2104 unsigned instanceType;
2107 ldb_set_errstring(ldb, "RODC modify is forbidden!");
2108 return LDB_ERR_REFERRAL;
2111 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
2112 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
2113 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
2114 "cannot change replicated attribute on partial replica");
2118 md_value = talloc(msg, struct ldb_val);
2119 if (md_value == NULL) {
2121 return LDB_ERR_OPERATIONS_ERROR;
2124 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
2125 if (ret != LDB_SUCCESS) {
2126 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
2130 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
2131 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2132 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2133 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
2134 ldb_dn_get_linearized(msg->dn)));
2135 return LDB_ERR_OPERATIONS_ERROR;
2138 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
2139 if (ret != LDB_SUCCESS) {
2140 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
2141 ldb_dn_get_linearized(msg->dn)));
2146 el->values = md_value;
2152 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
2154 int ret = ndr_guid_compare(&pdn1->guid, &pdn2->guid);
2156 return data_blob_cmp(&pdn1->dsdb_dn->extra_part,
2157 &pdn2->dsdb_dn->extra_part);
2163 get a series of message element values as an array of DNs and GUIDs
2164 the result is sorted by GUID
2166 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
2167 struct ldb_message_element *el, struct parsed_dn **pdn,
2168 const char *ldap_oid, struct ldb_request *parent)
2171 bool values_are_sorted = true;
2172 struct ldb_context *ldb = ldb_module_get_ctx(module);
2179 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
2181 ldb_module_oom(module);
2182 return LDB_ERR_OPERATIONS_ERROR;
2185 for (i=0; i<el->num_values; i++) {
2186 struct ldb_val *v = &el->values[i];
2189 struct parsed_dn *p;
2193 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
2194 if (p->dsdb_dn == NULL) {
2195 return LDB_ERR_INVALID_DN_SYNTAX;
2198 dn = p->dsdb_dn->dn;
2200 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
2201 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
2202 unlikely(GUID_all_zero(&p->guid))) {
2203 /* we got a DN without a GUID - go find the GUID */
2204 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
2205 if (ret != LDB_SUCCESS) {
2206 char *dn_str = NULL;
2207 dn_str = ldb_dn_get_extended_linearized(mem_ctx,
2209 ldb_asprintf_errstring(ldb,
2210 "Unable to find GUID for DN %s\n",
2212 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
2213 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
2214 ldb_attr_cmp(el->name, "member") == 0) {
2215 return LDB_ERR_UNWILLING_TO_PERFORM;
2219 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
2220 if (ret != LDB_SUCCESS) {
2223 } else if (!NT_STATUS_IS_OK(status)) {
2224 return LDB_ERR_OPERATIONS_ERROR;
2226 if (i > 0 && values_are_sorted) {
2227 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2229 values_are_sorted = false;
2232 /* keep a pointer to the original ldb_val */
2235 if (! values_are_sorted) {
2236 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2242 * Get a series of trusted message element values. The result is sorted by
2243 * GUID, even though the GUIDs might not be known. That works because we trust
2244 * the database to give us the elements like that if the
2245 * replmd_private->sorted_links flag is set.
2247 * We also ensure that the links are in the Functional Level 2003
2248 * linked attributes format.
2250 static int get_parsed_dns_trusted_fallback(struct ldb_module *module,
2251 struct replmd_private *replmd_private,
2252 TALLOC_CTX *mem_ctx,
2253 struct ldb_message_element *el,
2254 struct parsed_dn **pdn,
2255 const char *ldap_oid,
2256 struct ldb_request *parent)
2264 if (!replmd_private->sorted_links) {
2265 /* We need to sort the list. This is the slow old path we want
2268 ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2270 if (ret != LDB_SUCCESS) {
2274 ret = get_parsed_dns_trusted(mem_ctx, el, pdn);
2275 if (ret != LDB_SUCCESS) {
2276 ldb_module_oom(module);
2277 return LDB_ERR_OPERATIONS_ERROR;
2282 * This upgrades links to FL2003 style, and sorts the result
2283 * if that was needed.
2285 * TODO: Add a database feature that asserts we have no FL2000
2286 * style links to avoid this check or add a feature that
2287 * uses a similar check to find sorted/unsorted links
2288 * for an on-the-fly upgrade.
2291 ret = replmd_check_upgrade_links(ldb_module_get_ctx(module),
2292 *pdn, el->num_values,
2295 if (ret != LDB_SUCCESS) {
2303 Return LDB_SUCCESS if a parsed_dn list contains no duplicate values,
2304 otherwise an error code. For compatibility the error code differs depending
2305 on whether or not the attribute is "member".
2307 As always, the parsed_dn list is assumed to be sorted.
2309 static int check_parsed_dn_duplicates(struct ldb_module *module,
2310 struct ldb_message_element *el,
2311 struct parsed_dn *pdn)
2314 struct ldb_context *ldb = ldb_module_get_ctx(module);
2316 for (i = 1; i < el->num_values; i++) {
2317 struct parsed_dn *p = &pdn[i];
2318 if (parsed_dn_compare(p, &pdn[i - 1]) == 0) {
2319 ldb_asprintf_errstring(ldb,
2320 "Linked attribute %s has "
2321 "multiple identical values",
2323 if (ldb_attr_cmp(el->name, "member") == 0) {
2324 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2326 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2334 build a new extended DN, including all meta data fields
2336 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2337 RMD_ADDTIME = originating_add_time
2338 RMD_INVOCID = originating_invocation_id
2339 RMD_CHANGETIME = originating_change_time
2340 RMD_ORIGINATING_USN = originating_usn
2341 RMD_LOCAL_USN = local_usn
2342 RMD_VERSION = version
2344 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v,
2345 struct dsdb_dn *dsdb_dn,
2346 const struct GUID *invocation_id,
2347 uint64_t local_usn, NTTIME nttime)
2349 return replmd_set_la_val(mem_ctx, v, dsdb_dn, NULL, invocation_id,
2350 local_usn, local_usn, nttime,
2351 RMD_VERSION_INITIAL, false);
2354 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2355 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2356 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2360 check if any links need upgrading from w2k format
2362 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2363 struct parsed_dn *dns, uint32_t count,
2364 struct ldb_message_element *el,
2365 const char *ldap_oid)
2368 const struct GUID *invocation_id = NULL;
2369 for (i=0; i<count; i++) {
2373 if (dns[i].dsdb_dn == NULL) {
2374 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2376 if (ret != LDB_SUCCESS) {
2377 return LDB_ERR_INVALID_DN_SYNTAX;
2381 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2382 &version, "RMD_VERSION");
2383 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2385 * We optimistically assume they are all the same; if
2386 * the first one is fixed, they are all fixed.
2388 * If the first one was *not* fixed and we find a
2389 * later one that is, that is an occasion to shout
2395 DEBUG(0, ("Mixed w2k and fixed format "
2396 "linked attributes\n"));
2400 if (invocation_id == NULL) {
2401 invocation_id = samdb_ntds_invocation_id(ldb);
2402 if (invocation_id == NULL) {
2403 return LDB_ERR_OPERATIONS_ERROR;
2408 /* it's an old one that needs upgrading */
2409 ret = replmd_update_la_val(el->values, dns[i].v,
2410 dns[i].dsdb_dn, dns[i].dsdb_dn,
2411 invocation_id, 1, 1, 0, false);
2412 if (ret != LDB_SUCCESS) {
2418 * This sort() is critical for the operation of
2419 * get_parsed_dns_trusted_fallback() because callers of this function
2420 * expect a sorted list, and FL2000 style links are not
2421 * sorted. In particular, as well as the upgrade case,
2422 * get_parsed_dns_trusted_fallback() is called from
2423 * replmd_delete_remove_link() even in FL2000 mode
2425 * We do not normally pay the cost of the qsort() due to the
2426 * early return in the RMD_VERSION found case.
2428 TYPESAFE_QSORT(dns, count, parsed_dn_compare);
2433 Sets the value for a linked attribute, including all meta data fields
2435 see replmd_build_la_val for value names
2437 static int replmd_set_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2438 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2439 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2440 uint32_t version, bool deleted)
2442 struct ldb_dn *dn = dsdb_dn->dn;
2443 const char *tstring, *usn_string, *flags_string;
2444 struct ldb_val tval;
2446 struct ldb_val usnv, local_usnv;
2447 struct ldb_val vers, flagsv;
2448 const struct ldb_val *old_addtime = NULL;
2451 const char *dnstring;
2453 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2455 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2457 return LDB_ERR_OPERATIONS_ERROR;
2459 tval = data_blob_string_const(tstring);
2461 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2463 return LDB_ERR_OPERATIONS_ERROR;
2465 usnv = data_blob_string_const(usn_string);
2467 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2469 return LDB_ERR_OPERATIONS_ERROR;
2471 local_usnv = data_blob_string_const(usn_string);
2473 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2474 if (!NT_STATUS_IS_OK(status)) {
2475 return LDB_ERR_OPERATIONS_ERROR;
2478 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2479 if (!flags_string) {
2480 return LDB_ERR_OPERATIONS_ERROR;
2482 flagsv = data_blob_string_const(flags_string);
2484 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2485 if (ret != LDB_SUCCESS) return ret;
2487 /* get the ADDTIME from the original */
2488 if (old_dsdb_dn != NULL) {
2489 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn,
2492 if (old_addtime == NULL) {
2493 old_addtime = &tval;
2495 if (dsdb_dn != old_dsdb_dn ||
2496 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2497 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2498 if (ret != LDB_SUCCESS) return ret;
2501 /* use our invocation id */
2502 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2503 if (ret != LDB_SUCCESS) return ret;
2505 /* changetime is the current time */
2506 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2507 if (ret != LDB_SUCCESS) return ret;
2509 /* update the USN */
2510 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2511 if (ret != LDB_SUCCESS) return ret;
2513 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2514 if (ret != LDB_SUCCESS) return ret;
2516 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2517 vers = data_blob_string_const(vstring);
2518 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2519 if (ret != LDB_SUCCESS) return ret;
2521 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2522 if (dnstring == NULL) {
2523 return LDB_ERR_OPERATIONS_ERROR;
2525 *v = data_blob_string_const(dnstring);
2531 * Updates the value for a linked attribute, including all meta data fields
2533 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2534 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2535 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2538 uint32_t old_version;
2539 uint32_t version = RMD_VERSION_INITIAL;
2543 * We're updating the linked attribute locally, so increase the version
2544 * by 1 so that other DCs will see the change when it gets replicated out
2546 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version,
2549 if (NT_STATUS_IS_OK(status)) {
2550 version = old_version + 1;
2553 return replmd_set_la_val(mem_ctx, v, dsdb_dn, old_dsdb_dn, invocation_id,
2554 usn, local_usn, nttime, version, deleted);
2558 handle adding a linked attribute
2560 static int replmd_modify_la_add(struct ldb_module *module,
2561 struct replmd_private *replmd_private,
2562 struct replmd_replicated_request *ac,
2563 struct ldb_message *msg,
2564 struct ldb_message_element *el,
2565 struct ldb_message_element *old_el,
2566 const struct dsdb_attribute *schema_attr,
2568 struct ldb_dn *msg_dn,
2569 struct ldb_request *parent)
2572 struct parsed_dn *dns, *old_dns;
2573 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2575 struct ldb_val *new_values = NULL;
2576 unsigned old_num_values = old_el ? old_el->num_values : 0;
2577 unsigned num_values = 0;
2578 unsigned max_num_values;
2579 struct ldb_context *ldb = ldb_module_get_ctx(module);
2581 unix_to_nt_time(&now, t);
2583 /* get the DNs to be added, fully parsed.
2585 * We need full parsing because they came off the wire and we don't
2586 * trust them, besides which we need their details to know where to put
2589 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2590 schema_attr->syntax->ldap_oid, parent);
2591 if (ret != LDB_SUCCESS) {
2592 talloc_free(tmp_ctx);
2596 /* get the existing DNs, lazily parsed */
2597 ret = get_parsed_dns_trusted_fallback(module, replmd_private,
2598 tmp_ctx, old_el, &old_dns,
2599 schema_attr->syntax->ldap_oid,
2602 if (ret != LDB_SUCCESS) {
2603 talloc_free(tmp_ctx);
2607 max_num_values = old_num_values + el->num_values;
2608 if (max_num_values < old_num_values) {
2609 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2610 "old values: %u, new values: %u, sum: %u\n",
2611 old_num_values, el->num_values, max_num_values));
2612 talloc_free(tmp_ctx);
2613 return LDB_ERR_OPERATIONS_ERROR;
2616 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2618 if (new_values == NULL) {
2619 ldb_module_oom(module);
2620 talloc_free(tmp_ctx);
2621 return LDB_ERR_OPERATIONS_ERROR;
2625 * For each new value, find where it would go in the list. If there is
2626 * a matching GUID there, we update the existing value; otherwise we
2630 for (i = 0; i < el->num_values; i++) {
2631 struct parsed_dn *exact;
2632 struct parsed_dn *next;
2634 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2637 dns[i].dsdb_dn->extra_part, 0,
2639 schema_attr->syntax->ldap_oid,
2641 if (err != LDB_SUCCESS) {
2642 talloc_free(tmp_ctx);
2646 if (ac->fix_link_sid) {
2647 char *fixed_dnstring = NULL;
2648 struct dom_sid tmp_sid = { 0, };
2649 DATA_BLOB sid_blob = data_blob_null;
2650 enum ndr_err_code ndr_err;
2654 if (exact == NULL) {
2655 talloc_free(tmp_ctx);
2656 return ldb_operr(ldb);
2659 if (dns[i].dsdb_dn->dn_format != DSDB_NORMAL_DN) {
2660 talloc_free(tmp_ctx);
2661 return ldb_operr(ldb);
2665 * Only "<GUID=...><SID=...>" is allowed.
2667 * We get the GUID to just to find the old
2668 * value and the SID in order to add it
2669 * to the found value.
2672 num = ldb_dn_get_comp_num(dns[i].dsdb_dn->dn);
2674 talloc_free(tmp_ctx);
2675 return ldb_operr(ldb);
2678 num = ldb_dn_get_extended_comp_num(dns[i].dsdb_dn->dn);
2680 talloc_free(tmp_ctx);
2681 return ldb_operr(ldb);
2684 status = dsdb_get_extended_dn_sid(exact->dsdb_dn->dn,
2686 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2687 /* this is what we expect */
2688 } else if (NT_STATUS_IS_OK(status)) {
2689 struct GUID_txt_buf guid_str;
2690 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
2691 "i[%u] SID NOT MISSING... Attribute %s already "
2692 "exists for target GUID %s, SID %s, DN: %s",
2694 GUID_buf_string(&exact->guid,
2696 dom_sid_string(tmp_ctx, &tmp_sid),
2697 dsdb_dn_get_extended_linearized(tmp_ctx,
2698 exact->dsdb_dn, 1));
2699 talloc_free(tmp_ctx);
2700 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2702 talloc_free(tmp_ctx);
2703 return ldb_operr(ldb);
2706 status = dsdb_get_extended_dn_sid(dns[i].dsdb_dn->dn,
2708 if (!NT_STATUS_IS_OK(status)) {
2709 struct GUID_txt_buf guid_str;
2710 ldb_asprintf_errstring(ldb,
2711 "NO SID PROVIDED... Attribute %s already "
2712 "exists for target GUID %s",
2714 GUID_buf_string(&exact->guid,
2716 talloc_free(tmp_ctx);
2717 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2720 ndr_err = ndr_push_struct_blob(&sid_blob, tmp_ctx, &tmp_sid,
2721 (ndr_push_flags_fn_t)ndr_push_dom_sid);
2722 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2723 talloc_free(tmp_ctx);
2724 return ldb_operr(ldb);
2727 ret = ldb_dn_set_extended_component(exact->dsdb_dn->dn, "SID", &sid_blob);
2728 data_blob_free(&sid_blob);
2729 if (ret != LDB_SUCCESS) {
2730 talloc_free(tmp_ctx);
2734 fixed_dnstring = dsdb_dn_get_extended_linearized(
2735 new_values, exact->dsdb_dn, 1);
2736 if (fixed_dnstring == NULL) {
2737 talloc_free(tmp_ctx);
2738 return ldb_operr(ldb);
2742 * We just replace the existing value...
2744 *exact->v = data_blob_string_const(fixed_dnstring);
2749 if (exact != NULL) {
2751 * We are trying to add one that exists, which is only
2752 * allowed if it was previously deleted.
2754 * When we do undelete a link we change it in place.
2755 * It will be copied across into the right spot in due
2759 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2761 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2762 struct GUID_txt_buf guid_str;
2763 ldb_asprintf_errstring(ldb,
2764 "Attribute %s already "
2765 "exists for target GUID %s",
2767 GUID_buf_string(&exact->guid,
2769 talloc_free(tmp_ctx);
2770 /* error codes for 'member' need to be
2772 if (ldb_attr_cmp(el->name, "member") == 0) {
2773 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2775 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2779 ret = replmd_update_la_val(new_values, exact->v,
2782 &ac->our_invocation_id,
2783 ac->seq_num, ac->seq_num,
2785 if (ret != LDB_SUCCESS) {
2786 talloc_free(tmp_ctx);
2790 ret = replmd_add_backlink(module, replmd_private,
2797 if (ret != LDB_SUCCESS) {
2798 talloc_free(tmp_ctx);
2804 * Here we don't have an exact match.
2806 * If next is NULL, this one goes beyond the end of the
2807 * existing list, so we need to add all of those ones first.
2809 * If next is not NULL, we need to add all the ones before
2813 offset = old_num_values;
2815 /* next should have been parsed, but let's make sure */
2816 if (next->dsdb_dn == NULL) {
2817 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2818 schema_attr->syntax->ldap_oid);
2819 if (ret != LDB_SUCCESS) {
2820 talloc_free(tmp_ctx);
2824 offset = MIN(next - old_dns, old_num_values);
2827 /* put all the old ones before next on the list */
2828 for (; j < offset; j++) {
2829 new_values[num_values] = *old_dns[j].v;
2833 ret = replmd_add_backlink(module, replmd_private,
2838 if (ret != LDB_SUCCESS) {
2839 talloc_free(tmp_ctx);
2842 /* Make the new linked attribute ldb_val. */
2843 ret = replmd_build_la_val(new_values, &new_values[num_values],
2844 dns[i].dsdb_dn, &ac->our_invocation_id,
2846 if (ret != LDB_SUCCESS) {
2847 talloc_free(tmp_ctx);
2851 if (ret != LDB_SUCCESS) {
2852 talloc_free(tmp_ctx);
2856 /* copy the rest of the old ones (if any) */
2857 for (; j < old_num_values; j++) {
2858 new_values[num_values] = *old_dns[j].v;
2862 talloc_steal(msg->elements, new_values);
2863 if (old_el != NULL) {
2864 talloc_steal(msg->elements, old_el->values);
2866 el->values = new_values;
2867 el->num_values = num_values;
2869 talloc_free(tmp_ctx);
2871 /* we now tell the backend to replace all existing values
2872 with the one we have constructed */
2873 el->flags = LDB_FLAG_MOD_REPLACE;
2880 handle deleting all active linked attributes
2882 static int replmd_modify_la_delete(struct ldb_module *module,
2883 struct replmd_private *replmd_private,
2884 struct replmd_replicated_request *ac,
2885 struct ldb_message *msg,
2886 struct ldb_message_element *el,
2887 struct ldb_message_element *old_el,
2888 const struct dsdb_attribute *schema_attr,
2890 struct ldb_dn *msg_dn,
2891 struct ldb_request *parent)
2894 struct parsed_dn *dns, *old_dns;
2895 TALLOC_CTX *tmp_ctx = NULL;
2897 struct ldb_context *ldb = ldb_module_get_ctx(module);
2898 struct ldb_control *vanish_links_ctrl = NULL;
2899 bool vanish_links = false;
2900 unsigned int num_to_delete = el->num_values;
2904 unix_to_nt_time(&now, t);
2906 if (old_el == NULL || old_el->num_values == 0) {
2907 /* there is nothing to delete... */
2908 if (num_to_delete == 0) {
2909 /* and we're deleting nothing, so that's OK */
2912 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2915 tmp_ctx = talloc_new(msg);
2916 if (tmp_ctx == NULL) {
2917 return LDB_ERR_OPERATIONS_ERROR;
2920 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2921 schema_attr->syntax->ldap_oid, parent);
2922 if (ret != LDB_SUCCESS) {
2923 talloc_free(tmp_ctx);
2927 ret = get_parsed_dns_trusted_fallback(module, replmd_private,
2928 tmp_ctx, old_el, &old_dns,
2929 schema_attr->syntax->ldap_oid,
2932 if (ret != LDB_SUCCESS) {
2933 talloc_free(tmp_ctx);
2937 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2938 if (vanish_links_ctrl) {
2939 vanish_links = true;
2940 vanish_links_ctrl->critical = false;
2943 /* we empty out el->values here to avoid damage if we return early. */
2948 * If vanish links is set, we are actually removing members of
2949 * old_el->values; otherwise we are just marking them deleted.
2951 * There is a special case when no values are given: we remove them
2952 * all. When we have the vanish_links control we just have to remove
2953 * the backlinks and change our element to replace the existing values
2954 * with the empty list.
2957 if (num_to_delete == 0) {
2958 for (i = 0; i < old_el->num_values; i++) {
2959 struct parsed_dn *p = &old_dns[i];
2960 if (p->dsdb_dn == NULL) {
2961 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2962 schema_attr->syntax->ldap_oid);
2963 if (ret != LDB_SUCCESS) {
2967 ret = replmd_add_backlink(module, replmd_private,
2968 ac->schema, msg_dn, &p->guid,
2971 if (ret != LDB_SUCCESS) {
2972 talloc_free(tmp_ctx);
2979 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2980 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2984 ret = replmd_update_la_val(old_el->values, p->v,
2985 p->dsdb_dn, p->dsdb_dn,
2986 &ac->our_invocation_id,
2987 ac->seq_num, ac->seq_num,
2989 if (ret != LDB_SUCCESS) {
2990 talloc_free(tmp_ctx);
2996 el->flags = LDB_FLAG_MOD_REPLACE;
2997 talloc_free(tmp_ctx);
3003 for (i = 0; i < num_to_delete; i++) {
3004 struct parsed_dn *p = &dns[i];
3005 struct parsed_dn *exact = NULL;
3006 struct parsed_dn *next = NULL;
3007 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
3010 p->dsdb_dn->extra_part, 0,
3012 schema_attr->syntax->ldap_oid,
3014 if (ret != LDB_SUCCESS) {
3015 talloc_free(tmp_ctx);
3018 if (exact == NULL) {
3019 struct GUID_txt_buf buf;
3020 ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
3021 "exist for target GUID %s",
3023 GUID_buf_string(&p->guid, &buf));
3024 if (ldb_attr_cmp(el->name, "member") == 0) {
3025 talloc_free(tmp_ctx);
3026 return LDB_ERR_UNWILLING_TO_PERFORM;
3028 talloc_free(tmp_ctx);
3029 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3034 if (CHECK_DEBUGLVL(5)) {
3035 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
3036 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
3037 struct GUID_txt_buf buf;
3038 const char *guid_str = \
3039 GUID_buf_string(&p->guid, &buf);
3040 DEBUG(5, ("Deleting deleted linked "
3041 "attribute %s to %s, because "
3042 "vanish_links control is set\n",
3043 el->name, guid_str));
3047 /* remove the backlink */
3048 ret = replmd_add_backlink(module,
3055 if (ret != LDB_SUCCESS) {
3056 talloc_free(tmp_ctx);
3060 /* We flag the deletion and tidy it up later. */
3065 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
3067 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
3068 struct GUID_txt_buf buf;
3069 const char *guid_str = GUID_buf_string(&p->guid, &buf);
3070 ldb_asprintf_errstring(ldb, "Attribute %s already "
3071 "deleted for target GUID %s",
3072 el->name, guid_str);
3073 if (ldb_attr_cmp(el->name, "member") == 0) {
3074 talloc_free(tmp_ctx);
3075 return LDB_ERR_UNWILLING_TO_PERFORM;
3077 talloc_free(tmp_ctx);
3078 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3082 ret = replmd_update_la_val(old_el->values, exact->v,
3083 exact->dsdb_dn, exact->dsdb_dn,
3084 &ac->our_invocation_id,
3085 ac->seq_num, ac->seq_num,
3087 if (ret != LDB_SUCCESS) {
3088 talloc_free(tmp_ctx);
3091 ret = replmd_add_backlink(module, replmd_private,
3096 if (ret != LDB_SUCCESS) {
3097 talloc_free(tmp_ctx);
3104 struct ldb_val *tmp_vals = NULL;
3106 tmp_vals = talloc_array(tmp_ctx, struct ldb_val,
3107 old_el->num_values);
3108 if (tmp_vals == NULL) {
3109 talloc_free(tmp_ctx);
3110 return ldb_module_oom(module);
3112 for (i = 0; i < old_el->num_values; i++) {
3113 if (old_dns[i].v == NULL) {
3116 tmp_vals[j] = *old_dns[i].v;
3119 for (i = 0; i < j; i++) {
3120 old_el->values[i] = tmp_vals[i];
3122 old_el->num_values = j;
3125 el->values = talloc_steal(msg->elements, old_el->values);
3126 el->num_values = old_el->num_values;
3128 talloc_free(tmp_ctx);
3130 /* we now tell the backend to replace all existing values
3131 with the one we have constructed */
3132 el->flags = LDB_FLAG_MOD_REPLACE;
3138 handle replacing a linked attribute
3140 static int replmd_modify_la_replace(struct ldb_module *module,
3141 struct replmd_private *replmd_private,
3142 struct replmd_replicated_request *ac,
3143 struct ldb_message *msg,
3144 struct ldb_message_element *el,
3145 struct ldb_message_element *old_el,
3146 const struct dsdb_attribute *schema_attr,
3148 struct ldb_dn *msg_dn,
3149 struct ldb_request *parent)
3151 unsigned int i, old_i, new_i;
3152 struct parsed_dn *dns, *old_dns;
3153 TALLOC_CTX *tmp_ctx = talloc_new(msg);
3155 struct ldb_context *ldb = ldb_module_get_ctx(module);
3156 struct ldb_val *new_values = NULL;
3157 const char *ldap_oid = schema_attr->syntax->ldap_oid;
3158 unsigned int old_num_values;
3159 unsigned int repl_num_values;
3160 unsigned int max_num_values;
3163 unix_to_nt_time(&now, t);
3166 * The replace operation is unlike the replace and delete cases in that
3167 * we need to look at every existing link to see whether it is being
3168 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
3170 * As we are trying to combine two sorted lists, the algorithm we use
3171 * is akin to the merge phase of a merge sort. We interleave the two
3172 * lists, doing different things depending on which side the current
3175 * There are three main cases, with some sub-cases.
3177 * - a DN is in the old list but not the new one. It needs to be
3178 * marked as deleted (but left in the list).
3179 * - maybe it is already deleted, and we have less to do.
3181 * - a DN is in both lists. The old data gets replaced by the new,
3182 * and the list doesn't grow. The old link may have been marked as
3183 * deleted, in which case we undelete it.
3185 * - a DN is in the new list only. We add it in the right place.
3188 old_num_values = old_el ? old_el->num_values : 0;
3189 repl_num_values = el->num_values;
3190 max_num_values = old_num_values + repl_num_values;
3192 if (max_num_values == 0) {
3193 /* There is nothing to do! */
3198 * At the successful end of these functions el->values is
3199 * overwritten with new_values. However get_parsed_dns()
3200 * points p->v at the supplied el and it effectively gets used
3201 * as a working area by replmd_build_la_val(). So we must
3202 * duplicate it because our caller only called
3203 * ldb_msg_copy_shallow().
3206 el->values = talloc_memdup(tmp_ctx,
3208 sizeof(el->values[0]) * el->num_values);
3209 if (el->values == NULL) {
3210 ldb_module_oom(module);
3211 talloc_free(tmp_ctx);
3212 return LDB_ERR_OPERATIONS_ERROR;
3215 ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
3216 if (ret != LDB_SUCCESS) {
3217 talloc_free(tmp_ctx);
3221 ret = check_parsed_dn_duplicates(module, el, dns);
3222 if (ret != LDB_SUCCESS) {
3223 talloc_free(tmp_ctx);
3227 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
3229 if (ret != LDB_SUCCESS) {
3230 talloc_free(tmp_ctx);
3234 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
3236 if (ret != LDB_SUCCESS) {
3237 talloc_free(tmp_ctx);
3241 new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
3242 if (new_values == NULL) {
3243 ldb_module_oom(module);
3244 talloc_free(tmp_ctx);
3245 return LDB_ERR_OPERATIONS_ERROR;
3250 for (i = 0; i < max_num_values; i++) {
3252 struct parsed_dn *old_p, *new_p;
3253 if (old_i < old_num_values && new_i < repl_num_values) {
3254 old_p = &old_dns[old_i];
3255 new_p = &dns[new_i];
3256 cmp = parsed_dn_compare(old_p, new_p);
3257 } else if (old_i < old_num_values) {
3258 /* the new list is empty, read the old list */
3259 old_p = &old_dns[old_i];
3262 } else if (new_i < repl_num_values) {
3263 /* the old list is empty, read new list */
3265 new_p = &dns[new_i];
3273 * An old ones that come before the next replacement
3274 * (if any). We mark it as deleted and add it to the
3277 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
3278 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
3279 ret = replmd_update_la_val(new_values, old_p->v,
3282 &ac->our_invocation_id,
3283 ac->seq_num, ac->seq_num,
3285 if (ret != LDB_SUCCESS) {
3286 talloc_free(tmp_ctx);
3290 ret = replmd_add_backlink(module, replmd_private,
3293 &old_p->guid, false,
3296 if (ret != LDB_SUCCESS) {
3297 talloc_free(tmp_ctx);
3301 new_values[i] = *old_p->v;
3303 } else if (cmp == 0) {
3305 * We are overwriting one. If it was previously
3306 * deleted, we need to add a backlink.
3308 * Note that if any RMD_FLAGs in an extended new DN
3313 ret = replmd_update_la_val(new_values, old_p->v,
3316 &ac->our_invocation_id,
3317 ac->seq_num, ac->seq_num,
3319 if (ret != LDB_SUCCESS) {
3320 talloc_free(tmp_ctx);
3324 rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
3325 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
3326 ret = replmd_add_backlink(module, replmd_private,
3332 if (ret != LDB_SUCCESS) {
3333 talloc_free(tmp_ctx);
3338 new_values[i] = *old_p->v;
3343 * Replacements that don't match an existing one. We
3344 * just add them to the final list.
3346 ret = replmd_build_la_val(new_values,
3349 &ac->our_invocation_id,
3351 if (ret != LDB_SUCCESS) {
3352 talloc_free(tmp_ctx);
3355 ret = replmd_add_backlink(module, replmd_private,
3361 if (ret != LDB_SUCCESS) {
3362 talloc_free(tmp_ctx);
3365 new_values[i] = *new_p->v;
3369 if (old_el != NULL) {
3370 talloc_steal(msg->elements, old_el->values);
3372 el->values = talloc_steal(msg->elements, new_values);
3374 talloc_free(tmp_ctx);
3376 el->flags = LDB_FLAG_MOD_REPLACE;
3383 handle linked attributes in modify requests
3385 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3386 struct replmd_private *replmd_private,
3387 struct replmd_replicated_request *ac,
3388 struct ldb_message *msg,
3390 struct ldb_request *parent)
3392 struct ldb_result *res;
3395 struct ldb_context *ldb = ldb_module_get_ctx(module);
3396 struct ldb_message *old_msg;
3398 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3400 * Nothing special is required for modifying or vanishing links
3401 * in fl2000 since they are just strings in a multi-valued
3404 struct ldb_control *ctrl = ldb_request_get_control(parent,
3405 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3407 ctrl->critical = false;
3415 * We should restrict this to the intersection of the list of
3416 * linked attributes in the schema and the list of attributes
3419 * This will help performance a little, as otherwise we have
3420 * to allocate the entire object value-by-value.
3422 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3423 DSDB_FLAG_NEXT_MODULE |
3424 DSDB_SEARCH_SHOW_RECYCLED |
3425 DSDB_SEARCH_REVEAL_INTERNALS |
3426 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3428 if (ret != LDB_SUCCESS) {
3432 old_msg = res->msgs[0];
3434 for (i=0; i<msg->num_elements; i++) {
3435 struct ldb_message_element *el = &msg->elements[i];
3436 struct ldb_message_element *old_el, *new_el;
3437 unsigned int mod_type = LDB_FLAG_MOD_TYPE(el->flags);
3438 const struct dsdb_attribute *schema_attr
3439 = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
3441 ldb_asprintf_errstring(ldb,
3442 "%s: attribute %s is not a valid attribute in schema",
3443 __FUNCTION__, el->name);
3444 return LDB_ERR_OBJECT_CLASS_VIOLATION;
3446 if (schema_attr->linkID == 0) {
3449 if ((schema_attr->linkID & 1) == 1) {
3450 struct ldb_control *ctrl;
3452 ctrl = ldb_request_get_control(parent,
3453 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3455 ctrl->critical = false;
3458 ctrl = ldb_request_get_control(parent,
3459 DSDB_CONTROL_DBCHECK);
3464 /* Odd is for the target. Illegal to modify */
3465 ldb_asprintf_errstring(ldb,
3466 "attribute %s must not be modified directly, it is a linked attribute", el->name);
3467 return LDB_ERR_UNWILLING_TO_PERFORM;
3469 old_el = ldb_msg_find_element(old_msg, el->name);
3471 case LDB_FLAG_MOD_REPLACE:
3472 ret = replmd_modify_la_replace(module, replmd_private,
3473 ac, msg, el, old_el,
3478 case LDB_FLAG_MOD_DELETE:
3479 ret = replmd_modify_la_delete(module, replmd_private,
3480 ac, msg, el, old_el,
3485 case LDB_FLAG_MOD_ADD:
3486 ret = replmd_modify_la_add(module, replmd_private,
3487 ac, msg, el, old_el,
3493 ldb_asprintf_errstring(ldb,
3494 "invalid flags 0x%x for %s linked attribute",
3495 el->flags, el->name);
3496 return LDB_ERR_UNWILLING_TO_PERFORM;
3498 if (ret != LDB_SUCCESS) {
3501 ret = dsdb_check_single_valued_link(schema_attr, el);
3502 if (ret != LDB_SUCCESS) {
3503 ldb_asprintf_errstring(ldb,
3504 "Attribute %s is single valued but more than one value has been supplied",
3506 /* Return codes as found on Windows 2012r2 */
3507 if (mod_type == LDB_FLAG_MOD_REPLACE) {
3508 return LDB_ERR_CONSTRAINT_VIOLATION;
3510 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3513 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3517 ldb_msg_remove_attr(old_msg, el->name);
3519 ret = ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3520 if (ret != LDB_SUCCESS) {
3523 new_el->num_values = el->num_values;
3524 new_el->values = talloc_steal(msg->elements, el->values);
3526 /* TODO: this relies a bit too heavily on the exact
3527 behaviour of ldb_msg_find_element and
3528 ldb_msg_remove_element */
3529 old_el = ldb_msg_find_element(msg, el->name);
3531 ldb_msg_remove_element(msg, old_el);
3541 static int send_rodc_referral(struct ldb_request *req,
3542 struct ldb_context *ldb,
3545 char *referral = NULL;
3546 struct loadparm_context *lp_ctx = NULL;
3547 struct ldb_dn *fsmo_role_dn = NULL;
3548 struct ldb_dn *role_owner_dn = NULL;
3549 const char *domain = NULL;
3552 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3553 struct loadparm_context);
3555 werr = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3556 &fsmo_role_dn, &role_owner_dn);
3558 if (W_ERROR_IS_OK(werr)) {
3559 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3560 if (server_dn != NULL) {
3561 ldb_dn_remove_child_components(server_dn, 1);
3562 domain = samdb_dn_to_dnshostname(ldb, req,
3567 if (domain == NULL) {
3568 domain = lpcfg_dnsdomain(lp_ctx);
3571 referral = talloc_asprintf(req, "ldap://%s/%s",
3573 ldb_dn_get_linearized(dn));
3574 if (referral == NULL) {
3576 return LDB_ERR_OPERATIONS_ERROR;
3579 return ldb_module_send_referral(req, referral);
3583 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3585 struct ldb_context *ldb;
3586 struct replmd_replicated_request *ac;
3587 struct ldb_request *down_req;
3588 struct ldb_message *msg;
3589 time_t t = time(NULL);
3591 bool is_urgent = false, rodc = false;
3592 bool is_schema_nc = false;
3593 unsigned int functional_level;
3594 const struct ldb_message_element *guid_el = NULL;
3595 struct ldb_control *sd_propagation_control;
3596 struct ldb_control *fix_links_control = NULL;
3597 struct ldb_control *fix_dn_name_control = NULL;
3598 struct ldb_control *fix_dn_sid_control = NULL;
3599 struct replmd_private *replmd_private =
3600 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3602 /* do not manipulate our control entries */
3603 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3604 return ldb_next_request(module, req);
3607 sd_propagation_control = ldb_request_get_control(req,
3608 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3609 if (sd_propagation_control != NULL) {
3610 if (req->op.mod.message->num_elements != 1) {
3611 return ldb_module_operr(module);
3613 ret = strcmp(req->op.mod.message->elements[0].name,
3614 "nTSecurityDescriptor");
3616 return ldb_module_operr(module);
3619 return ldb_next_request(module, req);
3622 ldb = ldb_module_get_ctx(module);
3624 fix_links_control = ldb_request_get_control(req,
3625 DSDB_CONTROL_DBCHECK_FIX_DUPLICATE_LINKS);
3626 if (fix_links_control != NULL) {
3627 struct dsdb_schema *schema = NULL;
3628 const struct dsdb_attribute *sa = NULL;
3630 if (req->op.mod.message->num_elements != 1) {
3631 return ldb_module_operr(module);
3634 if (LDB_FLAG_MOD_TYPE(req->op.mod.message->elements[0].flags) != LDB_FLAG_MOD_REPLACE) {
3635 return ldb_module_operr(module);
3638 schema = dsdb_get_schema(ldb, req);
3639 if (schema == NULL) {
3640 return ldb_module_operr(module);
3643 sa = dsdb_attribute_by_lDAPDisplayName(schema,
3644 req->op.mod.message->elements[0].name);
3646 return ldb_module_operr(module);
3649 if (sa->linkID == 0) {
3650 return ldb_module_operr(module);
3653 fix_links_control->critical = false;
3654 return ldb_next_request(module, req);
3657 fix_dn_name_control = ldb_request_get_control(req,
3658 DSDB_CONTROL_DBCHECK_FIX_LINK_DN_NAME);
3659 if (fix_dn_name_control != NULL) {
3660 struct dsdb_schema *schema = NULL;
3661 const struct dsdb_attribute *sa = NULL;
3663 if (req->op.mod.message->num_elements != 2) {
3664 return ldb_module_operr(module);
3667 if (LDB_FLAG_MOD_TYPE(req->op.mod.message->elements[0].flags) != LDB_FLAG_MOD_DELETE) {
3668 return ldb_module_operr(module);
3671 if (LDB_FLAG_MOD_TYPE(req->op.mod.message->elements[1].flags) != LDB_FLAG_MOD_ADD) {
3672 return ldb_module_operr(module);
3675 if (req->op.mod.message->elements[0].num_values != 1) {
3676 return ldb_module_operr(module);
3679 if (req->op.mod.message->elements[1].num_values != 1) {
3680 return ldb_module_operr(module);
3683 schema = dsdb_get_schema(ldb, req);
3684 if (schema == NULL) {
3685 return ldb_module_operr(module);
3688 if (ldb_attr_cmp(req->op.mod.message->elements[0].name,
3689 req->op.mod.message->elements[1].name) != 0) {
3690 return ldb_module_operr(module);
3693 sa = dsdb_attribute_by_lDAPDisplayName(schema,
3694 req->op.mod.message->elements[0].name);
3696 return ldb_module_operr(module);
3699 if (sa->dn_format == DSDB_INVALID_DN) {
3700 return ldb_module_operr(module);
3703 if (sa->linkID != 0) {
3704 return ldb_module_operr(module);
3708 * If we are run from dbcheck and we are not updating
3709 * a link (as these would need to be sorted and so
3710 * can't go via such a simple update, then do not
3711 * trigger replicated updates and a new USN from this
3712 * change, it wasn't a real change, just a new
3713 * (correct) string DN
3716 fix_dn_name_control->critical = false;
3717 return ldb_next_request(module, req);
3720 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3722 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3723 if (guid_el != NULL) {
3724 ldb_set_errstring(ldb,
3725 "replmd_modify: it's not allowed to change the objectGUID!");
3726 return LDB_ERR_CONSTRAINT_VIOLATION;
3729 ac = replmd_ctx_init(module, req);
3731 return ldb_module_oom(module);
3734 functional_level = dsdb_functional_level(ldb);
3736 /* we have to copy the message as the caller might have it as a const */
3737 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3741 return LDB_ERR_OPERATIONS_ERROR;
3744 fix_dn_sid_control = ldb_request_get_control(req,
3745 DSDB_CONTROL_DBCHECK_FIX_LINK_DN_SID);
3746 if (fix_dn_sid_control != NULL) {
3747 const struct dsdb_attribute *sa = NULL;
3749 if (msg->num_elements != 1) {
3751 return ldb_module_operr(module);
3754 if (LDB_FLAG_MOD_TYPE(msg->elements[0].flags) != LDB_FLAG_MOD_ADD) {
3756 return ldb_module_operr(module);
3759 if (msg->elements[0].num_values != 1) {
3761 return ldb_module_operr(module);
3764 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema,
3765 msg->elements[0].name);
3768 return ldb_module_operr(module);
3771 if (sa->dn_format != DSDB_NORMAL_DN) {
3773 return ldb_module_operr(module);
3776 fix_dn_sid_control->critical = false;
3777 ac->fix_link_sid = true;
3779 goto handle_linked_attribs;
3782 ldb_msg_remove_attr(msg, "whenChanged");
3783 ldb_msg_remove_attr(msg, "uSNChanged");
3785 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3787 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3788 msg, &ac->seq_num, t, is_schema_nc,
3790 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3791 ret = send_rodc_referral(req, ldb, msg->dn);
3797 if (ret != LDB_SUCCESS) {
3802 handle_linked_attribs:
3803 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3805 if (ret != LDB_SUCCESS) {
3811 * - replace the old object with the newly constructed one
3814 ac->is_urgent = is_urgent;
3816 ret = ldb_build_mod_req(&down_req, ldb, ac,
3819 ac, replmd_op_callback,
3821 LDB_REQ_SET_LOCATION(down_req);
3822 if (ret != LDB_SUCCESS) {
3827 /* current partition control is needed by "replmd_op_callback" */
3828 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3829 ret = ldb_request_add_control(down_req,
3830 DSDB_CONTROL_CURRENT_PARTITION_OID,
3832 if (ret != LDB_SUCCESS) {
3838 /* If we are in functional level 2000, then
3839 * replmd_modify_handle_linked_attribs will have done
3841 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3842 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3843 if (ret != LDB_SUCCESS) {
3849 talloc_steal(down_req, msg);
3851 /* we only change whenChanged and uSNChanged if the seq_num
3853 if (ac->seq_num != 0) {
3854 ret = add_time_element(msg, "whenChanged", t);
3855 if (ret != LDB_SUCCESS) {
3861 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3862 if (ret != LDB_SUCCESS) {
3869 /* go on with the call chain */
3870 return ldb_next_request(module, down_req);
3873 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3876 handle a rename request
3878 On a rename we need to do an extra ldb_modify which sets the
3879 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3881 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3883 struct ldb_context *ldb;
3884 struct ldb_control *fix_dn_name_control = NULL;
3885 struct replmd_replicated_request *ac;
3887 struct ldb_request *down_req;
3889 /* do not manipulate our control entries */
3890 if (ldb_dn_is_special(req->op.rename.olddn)) {
3891 return ldb_next_request(module, req);
3894 fix_dn_name_control = ldb_request_get_control(req,
3895 DSDB_CONTROL_DBCHECK_FIX_LINK_DN_NAME);
3896 if (fix_dn_name_control != NULL) {
3897 return ldb_next_request(module, req);
3900 ldb = ldb_module_get_ctx(module);
3902 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3904 ac = replmd_ctx_init(module, req);
3906 return ldb_module_oom(module);
3909 ret = ldb_build_rename_req(&down_req, ldb, ac,
3910 ac->req->op.rename.olddn,
3911 ac->req->op.rename.newdn,
3913 ac, replmd_rename_callback,
3915 LDB_REQ_SET_LOCATION(down_req);
3916 if (ret != LDB_SUCCESS) {
3921 /* go on with the call chain */
3922 return ldb_next_request(module, down_req);
3925 /* After the rename is completed, update the whenchanged etc */
3926 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3928 struct ldb_context *ldb;
3929 struct ldb_request *down_req;
3930 struct ldb_message *msg;
3931 const struct dsdb_attribute *rdn_attr;
3932 const char *rdn_name;
3933 const struct ldb_val *rdn_val;
3934 const char *attrs[5] = { NULL, };
3935 time_t t = time(NULL);
3937 bool is_urgent = false, rodc = false;
3939 struct replmd_replicated_request *ac =
3940 talloc_get_type(req->context, struct replmd_replicated_request);
3941 struct replmd_private *replmd_private =
3942 talloc_get_type(ldb_module_get_private(ac->module),
3943 struct replmd_private);
3945 ldb = ldb_module_get_ctx(ac->module);
3947 if (ares->error != LDB_SUCCESS) {
3948 return ldb_module_done(ac->req, ares->controls,
3949 ares->response, ares->error);
3952 if (ares->type != LDB_REPLY_DONE) {
3953 ldb_set_errstring(ldb,
3954 "invalid reply type in repl_meta_data rename callback");
3956 return ldb_module_done(ac->req, NULL, NULL,
3957 LDB_ERR_OPERATIONS_ERROR);
3961 * - replace the old object with the newly constructed one
3964 msg = ldb_msg_new(ac);
3967 return LDB_ERR_OPERATIONS_ERROR;
3970 msg->dn = ac->req->op.rename.newdn;
3972 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3974 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3975 if (rdn_name == NULL) {
3977 return ldb_module_done(ac->req, NULL, NULL,
3981 /* normalize the rdn attribute name */
3982 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3983 if (rdn_attr == NULL) {
3985 return ldb_module_done(ac->req, NULL, NULL,
3988 rdn_name = rdn_attr->lDAPDisplayName;
3990 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3991 if (rdn_val == NULL) {
3993 return ldb_module_done(ac->req, NULL, NULL,
3997 if (ldb_msg_append_value(msg, rdn_name, rdn_val, LDB_FLAG_MOD_REPLACE) != 0) {
3999 return ldb_module_done(ac->req, NULL, NULL,
4002 if (ldb_msg_append_value(msg, "name", rdn_val, LDB_FLAG_MOD_REPLACE) != 0) {
4004 return ldb_module_done(ac->req, NULL, NULL,
4009 * here we let replmd_update_rpmd() only search for
4010 * the existing "replPropertyMetaData" and rdn_name attributes.
4012 * We do not want the existing "name" attribute as
4013 * the "name" attribute needs to get the version
4014 * updated on rename even if the rdn value hasn't changed.
4016 * This is the diff of the meta data, for a moved user
4017 * on a w2k8r2 server:
4020 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
4021 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
4022 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
4023 * version : 0x00000001 (1)
4024 * reserved : 0x00000000 (0)
4025 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
4026 * local_usn : 0x00000000000037a5 (14245)
4027 * array: struct replPropertyMetaData1
4028 * attid : DRSUAPI_ATTID_name (0x90001)
4029 * - version : 0x00000001 (1)
4030 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
4031 * + version : 0x00000002 (2)
4032 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
4033 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
4034 * - originating_usn : 0x00000000000037a5 (14245)
4035 * - local_usn : 0x00000000000037a5 (14245)
4036 * + originating_usn : 0x0000000000003834 (14388)
4037 * + local_usn : 0x0000000000003834 (14388)
4038 * array: struct replPropertyMetaData1
4039 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
4040 * version : 0x00000004 (4)
4042 attrs[0] = "replPropertyMetaData";
4043 attrs[1] = "objectClass";
4044 attrs[2] = "instanceType";
4045 attrs[3] = rdn_name;
4048 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
4049 msg, &ac->seq_num, t,
4050 is_schema_nc, &is_urgent, &rodc);
4051 if (rodc && (ret == LDB_ERR_REFERRAL)) {
4052 ret = send_rodc_referral(req, ldb, ac->req->op.rename.olddn);
4054 return ldb_module_done(req, NULL, NULL, ret);
4057 if (ret != LDB_SUCCESS) {
4059 return ldb_module_done(ac->req, NULL, NULL, ret);
4062 if (ac->seq_num == 0) {
4064 return ldb_module_done(ac->req, NULL, NULL,
4066 "internal error seq_num == 0"));
4068 ac->is_urgent = is_urgent;
4070 ret = ldb_build_mod_req(&down_req, ldb, ac,
4073 ac, replmd_op_callback,
4075 LDB_REQ_SET_LOCATION(down_req);
4076 if (ret != LDB_SUCCESS) {
4081 /* current partition control is needed by "replmd_op_callback" */
4082 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
4083 ret = ldb_request_add_control(down_req,
4084 DSDB_CONTROL_CURRENT_PARTITION_OID,
4086 if (ret != LDB_SUCCESS) {
4092 talloc_steal(down_req, msg);
4094 ret = add_time_element(msg, "whenChanged", t);
4095 if (ret != LDB_SUCCESS) {
4101 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
4102 if (ret != LDB_SUCCESS) {
4108 /* go on with the call chain - do the modify after the rename */
4109 return ldb_next_request(ac->module, down_req);
4113 * remove links from objects that point at this object when an object
4114 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
4115 * RemoveObj which states that link removal due to the object being
4116 * deleted is NOT an originating update - they just go away!
4119 static int replmd_delete_remove_link(struct ldb_module *module,
4120 const struct dsdb_schema *schema,
4121 struct replmd_private *replmd_private,
4124 struct ldb_message_element *el,
4125 const struct dsdb_attribute *sa,
4126 struct ldb_request *parent,
4127 bool *caller_should_vanish)
4130 TALLOC_CTX *tmp_ctx = talloc_new(module);
4131 struct ldb_context *ldb = ldb_module_get_ctx(module);
4133 for (i=0; i<el->num_values; i++) {
4134 struct dsdb_dn *dsdb_dn;
4136 struct ldb_message *msg;
4137 const struct dsdb_attribute *target_attr;
4138 struct ldb_message_element *el2;
4140 struct ldb_val dn_val;
4141 uint32_t dsdb_flags = 0;
4142 const char *attrs[] = { NULL, NULL };
4143 struct ldb_result *link_res;
4144 struct ldb_message *link_msg;
4145 struct ldb_message_element *link_el;
4146 struct parsed_dn *link_dns;
4147 struct parsed_dn *p = NULL, *unused = NULL;
4149 if (dsdb_dn_is_deleted_val(&el->values[i])) {
4153 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
4155 talloc_free(tmp_ctx);
4156 return LDB_ERR_OPERATIONS_ERROR;
4159 /* remove the link */
4160 msg = ldb_msg_new(tmp_ctx);
4162 ldb_module_oom(module);
4163 talloc_free(tmp_ctx);
4164 return LDB_ERR_OPERATIONS_ERROR;
4167 msg->dn = dsdb_dn->dn;
4169 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
4170 if (target_attr == NULL) {
4173 attrs[0] = target_attr->lDAPDisplayName;
4175 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName,
4176 LDB_FLAG_MOD_DELETE, &el2);
4177 if (ret != LDB_SUCCESS) {
4178 ldb_module_oom(module);
4179 talloc_free(tmp_ctx);
4180 return LDB_ERR_OPERATIONS_ERROR;
4183 ret = dsdb_module_search_dn(module, tmp_ctx, &link_res,
4185 DSDB_FLAG_NEXT_MODULE |
4186 DSDB_SEARCH_SHOW_EXTENDED_DN |
4187 DSDB_SEARCH_SHOW_RECYCLED,
4190 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4191 DBG_WARNING("Failed to find forward link object %s "
4192 "to remove backlink %s on %s\n",
4193 ldb_dn_get_linearized(msg->dn),
4194 sa->lDAPDisplayName,
4195 ldb_dn_get_linearized(dn));
4196 *caller_should_vanish = true;
4200 if (ret != LDB_SUCCESS) {
4201 talloc_free(tmp_ctx);
4205 link_msg = link_res->msgs[0];
4206 link_el = ldb_msg_find_element(link_msg,
4207 target_attr->lDAPDisplayName);
4208 if (link_el == NULL) {
4209 DBG_WARNING("Failed to find forward link on %s "
4210 "as %s to remove backlink %s on %s\n",
4211 ldb_dn_get_linearized(msg->dn),
4212 target_attr->lDAPDisplayName,
4213 sa->lDAPDisplayName,
4214 ldb_dn_get_linearized(dn));
4215 *caller_should_vanish = true;
4220 * This call 'upgrades' the links in link_dns, but we
4221 * do not commit the result back into the database, so
4222 * this is safe to call in FL2000 or on databases that
4223 * have been run at that level in the past.
4225 ret = get_parsed_dns_trusted_fallback(module, replmd_private,
4228 target_attr->syntax->ldap_oid,
4230 if (ret != LDB_SUCCESS) {
4231 talloc_free(tmp_ctx);
4235 ret = parsed_dn_find(ldb, link_dns, link_el->num_values,
4239 target_attr->syntax->ldap_oid, false);
4240 if (ret != LDB_SUCCESS) {
4241 talloc_free(tmp_ctx);
4246 DBG_WARNING("Failed to find forward link on %s "
4247 "as %s to remove backlink %s on %s\n",
4248 ldb_dn_get_linearized(msg->dn),
4249 target_attr->lDAPDisplayName,
4250 sa->lDAPDisplayName,
4251 ldb_dn_get_linearized(dn));
4252 *caller_should_vanish = true;
4257 * If we find a backlink to ourself, we will delete
4258 * the forward link before we get to process that
4259 * properly, so just let the caller process this via
4262 * We do this once we are sure we have the forward
4263 * link (to ourself) in case something is very wrong
4264 * and they are out of sync.
4266 if (ldb_dn_compare(dsdb_dn->dn, dn) == 0) {
4270 /* This needs to get the Binary DN, by first searching */
4271 dn_str = dsdb_dn_get_linearized(tmp_ctx,
4274 dn_val = data_blob_string_const(dn_str);
4275 el2->values = &dn_val;
4276 el2->num_values = 1;
4279 * Ensure that we tell the modification to vanish any linked
4280 * attributes (not simply mark them as isDeleted = TRUE)
4282 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4284 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
4285 if (ret != LDB_SUCCESS) {
4286 talloc_free(tmp_ctx);
4290 talloc_free(tmp_ctx);
4296 handle update of replication meta data for deletion of objects
4298 This also handles the mapping of delete to a rename operation
4299 to allow deletes to be replicated.
4301 It also handles the incoming deleted objects, to ensure they are
4302 fully deleted here. In that case re_delete is true, and we do not
4303 use this as a signal to change the deleted state, just reinforce it.
4306 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
4308 int ret = LDB_ERR_OTHER;
4309 bool retb, disallow_move_on_delete;
4310 struct ldb_dn *old_dn = NULL, *new_dn = NULL;
4311 const char *rdn_name;
4312 const struct ldb_val *rdn_value, *new_rdn_value;
4314 struct ldb_context *ldb = ldb_module_get_ctx(module);
4315 const struct dsdb_schema *schema;
4316 struct ldb_message *msg, *old_msg;
4317 struct ldb_message_element *el;
4318 TALLOC_CTX *tmp_ctx;
4319 struct ldb_result *res, *parent_res;
4320 static const char * const preserved_attrs[] = {
4322 * This list MUST be kept in case-insensitive sorted order,
4323 * as we use it in a binary search with ldb_attr_cmp().
4325 * We get this hard-coded list from
4326 * MS-ADTS section 3.1.1.5.5.1.1 "Tombstone Requirements".
4330 "distinguishedName",
4331 "dNReferenceUpdate",
4343 "msDS-LastKnownRDN",
4348 "nTSecurityDescriptor",
4353 "proxiedObjectName",
4354 "replPropertyMetaData",
4356 "securityIdentifier",
4364 "userAccountControl",
4370 * DO NOT JUST APPEND TO THIS LIST.
4372 * In case you missed the note at the top, this list is kept
4373 * in case-insensitive sorted order. In the unlikely event you
4374 * need to add an attribute, please add it in the RIGHT PLACE.
4377 static const char * const all_attrs[] = {
4378 DSDB_SECRET_ATTRIBUTES,
4382 static const struct ldb_val true_val = {
4383 .data = discard_const_p(uint8_t, "TRUE"),
4388 uint32_t dsdb_flags = 0;
4389 struct replmd_private *replmd_private;
4390 enum deletion_state deletion_state, next_deletion_state;
4392 if (ldb_dn_is_special(req->op.del.dn)) {
4393 return ldb_next_request(module, req);
4397 * We have to allow dbcheck to remove an object that
4398 * is beyond repair, and to do so totally. This could
4399 * mean we we can get a partial object from the other
4400 * DC, causing havoc, so dbcheck suggests
4401 * re-replication first. dbcheck sets both DBCHECK
4402 * and RELAX in this situation.
4404 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
4405 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
4406 /* really, really remove it */
4407 return ldb_next_request(module, req);
4410 tmp_ctx = talloc_new(ldb);
4413 return LDB_ERR_OPERATIONS_ERROR;
4416 schema = dsdb_get_schema(ldb, tmp_ctx);
4418 talloc_free(tmp_ctx);
4419 return LDB_ERR_OPERATIONS_ERROR;
4422 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
4424 /* we need the complete msg off disk, so we can work out which
4425 attributes need to be removed */
4426 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
4427 DSDB_FLAG_NEXT_MODULE |
4428 DSDB_SEARCH_SHOW_RECYCLED |
4429 DSDB_SEARCH_REVEAL_INTERNALS |
4430 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
4431 if (ret != LDB_SUCCESS) {
4432 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4433 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
4434 re_delete ? "re-delete" : "delete",
4435 ldb_dn_get_linearized(old_dn),
4436 ldb_errstring(ldb_module_get_ctx(module)));
4437 talloc_free(tmp_ctx);
4440 old_msg = res->msgs[0];
4442 replmd_deletion_state(module, old_msg,
4444 &next_deletion_state);
4446 /* This supports us noticing an incoming isDeleted and acting on it */
4448 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
4449 next_deletion_state = deletion_state;
4452 if (next_deletion_state == OBJECT_REMOVED) {
4454 * We have to prevent objects being deleted, even if
4455 * the administrator really wants them gone, as
4456 * without the tombstone, we can get a partial object
4457 * from the other DC, causing havoc.
4459 * The only other valid case is when the 180 day
4460 * timeout has expired, when relax is specified.
4462 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
4463 /* it is already deleted - really remove it this time */
4464 talloc_free(tmp_ctx);
4465 return ldb_next_request(module, req);
4468 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
4469 "This check is to prevent corruption of the replicated state.",
4470 ldb_dn_get_linearized(old_msg->dn));
4471 return LDB_ERR_UNWILLING_TO_PERFORM;
4474 rdn_name = ldb_dn_get_rdn_name(old_dn);
4475 rdn_value = ldb_dn_get_rdn_val(old_dn);
4476 if ((rdn_name == NULL) || (rdn_value == NULL)) {
4477 talloc_free(tmp_ctx);
4478 return ldb_operr(ldb);
4481 msg = ldb_msg_new(tmp_ctx);
4483 ldb_module_oom(module);
4484 talloc_free(tmp_ctx);
4485 return LDB_ERR_OPERATIONS_ERROR;
4490 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
4491 disallow_move_on_delete =
4492 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
4493 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
4495 /* work out where we will be renaming this object to */
4496 if (!disallow_move_on_delete) {
4497 struct ldb_dn *deleted_objects_dn;
4498 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
4499 &deleted_objects_dn);
4502 * We should not move objects if we can't find the
4503 * deleted objects DN. Not moving (or otherwise
4504 * harming) the Deleted Objects DN itself is handled
4507 if (re_delete && (ret != LDB_SUCCESS)) {
4508 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4509 if (new_dn == NULL) {
4510 ldb_module_oom(module);
4511 talloc_free(tmp_ctx);
4512 return LDB_ERR_OPERATIONS_ERROR;
4514 } else if (ret != LDB_SUCCESS) {
4515 /* this is probably an attempted delete on a partition
4516 * that doesn't allow delete operations, such as the
4517 * schema partition */
4518 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
4519 ldb_dn_get_linearized(old_dn));
4520 talloc_free(tmp_ctx);
4521 return LDB_ERR_UNWILLING_TO_PERFORM;
4523 new_dn = deleted_objects_dn;
4526 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4527 if (new_dn == NULL) {
4528 ldb_module_oom(module);
4529 talloc_free(tmp_ctx);
4530 return LDB_ERR_OPERATIONS_ERROR;
4534 /* get the objects GUID from the search we just did */
4535 guid = samdb_result_guid(old_msg, "objectGUID");
4537 if (deletion_state == OBJECT_NOT_DELETED) {
4538 struct ldb_message_element *is_deleted_el;
4540 ret = replmd_make_deleted_child_dn(tmp_ctx,
4543 rdn_name, rdn_value,
4546 if (ret != LDB_SUCCESS) {
4547 talloc_free(tmp_ctx);
4551 ret = ldb_msg_add_value(msg, "isDeleted", &true_val,
4553 if (ret != LDB_SUCCESS) {
4554 ldb_asprintf_errstring(ldb, __location__
4555 ": Failed to add isDeleted string to the msg");
4556 talloc_free(tmp_ctx);
4559 is_deleted_el->flags = LDB_FLAG_MOD_REPLACE;
4562 * No matter what has happened with other renames etc, try again to
4563 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
4566 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
4567 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
4569 ldb_asprintf_errstring(ldb, __location__
4570 ": Unable to add a prepare rdn of %s",
4571 ldb_dn_get_linearized(rdn));
4572 talloc_free(tmp_ctx);
4573 return LDB_ERR_OPERATIONS_ERROR;
4575 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
4577 retb = ldb_dn_add_child(new_dn, rdn);
4579 ldb_asprintf_errstring(ldb, __location__
4580 ": Unable to add rdn %s to base dn: %s",
4581 ldb_dn_get_linearized(rdn),
4582 ldb_dn_get_linearized(new_dn));
4583 talloc_free(tmp_ctx);
4584 return LDB_ERR_OPERATIONS_ERROR;
4589 now we need to modify the object in the following ways:
4591 - add isDeleted=TRUE
4592 - update rDN and name, with new rDN
4593 - remove linked attributes
4594 - remove objectCategory and sAMAccountType
4595 - remove attribs not on the preserved list
4596 - preserved if in above list, or is rDN
4597 - remove all linked attribs from this object
4598 - remove all links from other objects to this object
4599 (note we use the backlinks to do this, so we won't find one-way
4600 links that still point to this object, or deactivated two-way
4601 links, i.e. 'member' after the user has been removed from the
4603 - add lastKnownParent
4604 - update replPropertyMetaData?
4606 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4609 if (deletion_state == OBJECT_NOT_DELETED) {
4610 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4611 char *parent_dn_str = NULL;
4612 struct ldb_message_element *p_el;
4614 /* we need the storage form of the parent GUID */
4615 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
4617 DSDB_FLAG_NEXT_MODULE |
4618 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4619 DSDB_SEARCH_REVEAL_INTERNALS|
4620 DSDB_SEARCH_SHOW_RECYCLED, req);
4621 if (ret != LDB_SUCCESS) {
4622 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4623 "repmd_delete: Failed to %s %s, "
4624 "because we failed to find it's parent (%s): %s",
4625 re_delete ? "re-delete" : "delete",
4626 ldb_dn_get_linearized(old_dn),
4627 ldb_dn_get_linearized(parent_dn),
4628 ldb_errstring(ldb_module_get_ctx(module)));
4629 talloc_free(tmp_ctx);
4634 * Now we can use the DB version,
4635 * it will have the extended DN info in it
4637 parent_dn = parent_res->msgs[0]->dn;
4638 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4641 if (parent_dn_str == NULL) {
4642 talloc_free(tmp_ctx);
4643 return ldb_module_oom(module);
4646 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4648 if (ret != LDB_SUCCESS) {
4649 ldb_asprintf_errstring(ldb, __location__
4650 ": Failed to add lastKnownParent "
4651 "string when deleting %s",
4652 ldb_dn_get_linearized(old_dn));
4653 talloc_free(tmp_ctx);
4656 p_el = ldb_msg_find_element(msg,
4659 talloc_free(tmp_ctx);
4660 return ldb_module_operr(module);
4662 p_el->flags = LDB_FLAG_MOD_REPLACE;
4664 if (next_deletion_state == OBJECT_DELETED) {
4665 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4666 if (ret != LDB_SUCCESS) {
4667 ldb_asprintf_errstring(ldb, __location__
4668 ": Failed to add msDS-LastKnownRDN "
4669 "string when deleting %s",
4670 ldb_dn_get_linearized(old_dn));
4671 talloc_free(tmp_ctx);
4674 p_el = ldb_msg_find_element(msg,
4675 "msDS-LastKnownRDN");
4677 talloc_free(tmp_ctx);
4678 return ldb_module_operr(module);
4680 p_el->flags = LDB_FLAG_MOD_ADD;
4684 switch (next_deletion_state) {
4686 case OBJECT_RECYCLED:
4687 case OBJECT_TOMBSTONE:
4690 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4691 * describes what must be removed from a tombstone
4694 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4695 * describes what must be removed from a recycled
4701 * we also mark it as recycled, meaning this object can't be
4702 * recovered (we are stripping its attributes).
4703 * This is done only if we have this schema object of course ...
4704 * This behavior is identical to the one of Windows 2008R2 which
4705 * always set the isRecycled attribute, even if the recycle-bin is
4706 * not activated and what ever the forest level is.
4708 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4709 struct ldb_message_element *is_recycled_el;
4711 ret = ldb_msg_add_value(msg, "isRecycled", &true_val,
4713 if (ret != LDB_SUCCESS) {
4714 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4715 ldb_module_oom(module);
4716 talloc_free(tmp_ctx);
4719 is_recycled_el->flags = LDB_FLAG_MOD_REPLACE;
4722 replmd_private = talloc_get_type(ldb_module_get_private(module),
4723 struct replmd_private);
4724 /* work out which of the old attributes we will be removing */
4725 for (i=0; i<old_msg->num_elements; i++) {
4726 const struct dsdb_attribute *sa;
4727 el = &old_msg->elements[i];
4728 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4730 const char *old_dn_str
4731 = ldb_dn_get_linearized(old_dn);
4733 ldb_asprintf_errstring(ldb,
4736 "not found in schema "
4737 "when deleting %s. "
4738 "Existing record is invalid",
4741 talloc_free(tmp_ctx);
4742 return LDB_ERR_OPERATIONS_ERROR;
4744 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4745 /* don't remove the rDN */
4749 if (sa->linkID & 1) {
4750 bool caller_should_vanish = false;
4752 * we have a backlink in this object
4753 * that needs to be removed. We're not
4754 * allowed to remove it directly
4755 * however, so we instead setup a
4756 * modify to delete the corresponding
4759 ret = replmd_delete_remove_link(module, schema,
4763 &caller_should_vanish);
4764 if (ret != LDB_SUCCESS) {
4765 const char *old_dn_str
4766 = ldb_dn_get_linearized(old_dn);
4767 ldb_asprintf_errstring(ldb,
4769 ": Failed to remove backlink of "
4770 "%s when deleting %s: %s",
4773 ldb_errstring(ldb));
4774 talloc_free(tmp_ctx);
4775 return LDB_ERR_OPERATIONS_ERROR;
4778 if (caller_should_vanish == false) {
4780 * now we continue, which means we
4781 * won't remove this backlink
4788 * Otherwise vanish the link, we are
4789 * out of sync and the controlling
4790 * object does not have the source
4794 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4796 } else if (sa->linkID == 0) {
4797 const char * const *attr = NULL;
4798 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4801 BINARY_ARRAY_SEARCH_V(preserved_attrs,
4802 ARRAY_SIZE(preserved_attrs),
4807 * If we are preserving, do not do the
4808 * ldb_msg_add_empty() below, continue
4809 * to the next element
4816 * Ensure that we tell the modification to vanish any linked
4817 * attributes (not simply mark them as isDeleted = TRUE)
4819 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4821 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, NULL);
4822 if (ret != LDB_SUCCESS) {
4823 talloc_free(tmp_ctx);
4824 ldb_module_oom(module);
4831 case OBJECT_DELETED:
4833 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4834 * describes what must be removed from a deleted
4838 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4839 if (ret != LDB_SUCCESS) {
4840 talloc_free(tmp_ctx);
4841 ldb_module_oom(module);
4845 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4846 if (ret != LDB_SUCCESS) {
4847 talloc_free(tmp_ctx);
4848 ldb_module_oom(module);
4858 if (deletion_state == OBJECT_NOT_DELETED) {
4859 const struct dsdb_attribute *sa;
4861 /* work out what the new rdn value is, for updating the
4862 rDN and name fields */
4863 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4864 if (new_rdn_value == NULL) {
4865 talloc_free(tmp_ctx);
4866 return ldb_operr(ldb);
4869 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4871 talloc_free(tmp_ctx);
4872 return LDB_ERR_OPERATIONS_ERROR;
4875 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4877 if (ret != LDB_SUCCESS) {
4878 talloc_free(tmp_ctx);
4881 el->flags = LDB_FLAG_MOD_REPLACE;
4883 el = ldb_msg_find_element(old_msg, "name");
4885 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4886 if (ret != LDB_SUCCESS) {
4887 talloc_free(tmp_ctx);
4890 el->flags = LDB_FLAG_MOD_REPLACE;
4895 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4900 * No matter what has happned with other renames, try again to
4901 * get this to be under the deleted DN.
4903 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4904 /* now rename onto the new DN */
4905 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4906 if (ret != LDB_SUCCESS){
4907 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4908 ldb_dn_get_linearized(old_dn),
4909 ldb_dn_get_linearized(new_dn),
4910 ldb_errstring(ldb)));
4911 talloc_free(tmp_ctx);
4917 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4918 if (ret != LDB_SUCCESS) {
4921 * This should not fail, so be quite verbose in the
4922 * error handling if it fails
4924 if (strcmp(ldb_dn_get_linearized(old_dn),
4925 ldb_dn_get_linearized(new_dn)) != 0) {
4926 DBG_NOTICE("Failure to handle '%s' of object %s "
4927 "after successful rename to %s. "
4928 "Error during tombstone modification was: %s\n",
4929 re_delete ? "re-delete" : "delete",
4930 ldb_dn_get_linearized(new_dn),
4931 ldb_dn_get_linearized(old_dn),
4932 ldb_errstring(ldb));
4934 DBG_NOTICE("Failure to handle '%s' of object %s. "
4935 "Error during tombstone modification was: %s\n",
4936 re_delete ? "re-delete" : "delete",
4937 ldb_dn_get_linearized(new_dn),
4938 ldb_errstring(ldb));
4940 s = ldb_ldif_message_redacted_string(ldb_module_get_ctx(module),
4942 LDB_CHANGETYPE_MODIFY,
4945 DBG_INFO("Failed tombstone modify%s was:\n%s\n",
4946 (dsdb_flags & DSDB_REPLMD_VANISH_LINKS) ?
4947 " with VANISH_LINKS" : "",
4949 ldb_asprintf_errstring(ldb,
4950 "replmd_delete: Failed to modify"
4951 " object %s in '%s' - %s",
4952 ldb_dn_get_linearized(old_dn),
4953 re_delete ? "re-delete" : "delete",
4954 ldb_errstring(ldb));
4955 talloc_free(tmp_ctx);
4959 talloc_free(tmp_ctx);
4961 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4964 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4966 return replmd_delete_internals(module, req, false);
4970 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4975 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4977 int ret = LDB_ERR_OTHER;
4978 /* TODO: do some error mapping */
4980 /* Let the caller know the full WERROR */
4981 ar->objs->error = status;
4987 static struct replPropertyMetaData1 *
4988 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4989 enum drsuapi_DsAttributeId attid)
4992 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4994 for (i = 0; i < rpmd_ctr->count; i++) {
4995 if (rpmd_ctr->array[i].attid == attid) {
4996 return &rpmd_ctr->array[i];
5004 return true if an update is newer than an existing entry
5005 see section 5.11 of MS-ADTS
5007 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
5008 const struct GUID *update_invocation_id,
5009 uint32_t current_version,
5010 uint32_t update_version,
5011 NTTIME current_change_time,
5012 NTTIME update_change_time)
5014 if (update_version != current_version) {
5015 return update_version > current_version;
5017 if (update_change_time != current_change_time) {
5018 return update_change_time > current_change_time;
5020 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
5023 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
5024 struct replPropertyMetaData1 *new_m)
5026 return replmd_update_is_newer(&cur_m->originating_invocation_id,
5027 &new_m->originating_invocation_id,
5030 cur_m->originating_change_time,
5031 new_m->originating_change_time);
5034 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
5035 struct replPropertyMetaData1 *cur_m,
5036 struct replPropertyMetaData1 *new_m)
5041 * If the new replPropertyMetaData entry for this attribute is
5042 * not provided (this happens in the case where we look for
5043 * ATTID_name, but the name was not changed), then the local
5044 * state is clearly still current, as the remote
5045 * server didn't send it due to being older the high watermark
5048 if (new_m == NULL) {
5052 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
5054 * if we compare equal then do an
5055 * update. This is used when a client
5056 * asks for a FULL_SYNC, and can be
5057 * used to recover a corrupt
5060 * This call is a bit tricky, what we
5061 * are doing it turning the 'is_newer'
5062 * call into a 'not is older' by
5063 * swapping cur_m and new_m, and negating the
5066 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
5069 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
5077 form a DN for a deleted (DEL:) or conflict (CNF:) DN
5079 static int replmd_make_prefix_child_dn(TALLOC_CTX *tmp_ctx,
5080 struct ldb_context *ldb,
5082 const char *four_char_prefix,
5083 const char *rdn_name,
5084 const struct ldb_val *rdn_value,
5087 struct ldb_val deleted_child_rdn_val;
5088 struct GUID_txt_buf guid_str;
5092 GUID_buf_string(&guid, &guid_str);
5094 retb = ldb_dn_add_child_fmt(dn, "X=Y");
5096 ldb_asprintf_errstring(ldb, __location__
5097 ": Unable to add a formatted child to dn: %s",
5098 ldb_dn_get_linearized(dn));
5099 return LDB_ERR_OPERATIONS_ERROR;
5103 * TODO: Per MS-ADTS 3.1.1.5.5 Delete Operation
5104 * we should truncate this value to ensure the RDN is not more than 255 chars.
5106 * However we MS-ADTS 3.1.1.5.1.2 Naming Constraints indicates that:
5108 * "Naming constraints are not enforced for replicated
5109 * updates." so this is safe and we don't have to work out not
5110 * splitting a UTF8 char right now.
5112 deleted_child_rdn_val = ldb_val_dup(tmp_ctx, rdn_value);
5115 * sizeof(guid_str.buf) will always be longer than
5116 * strlen(guid_str.buf) but we allocate using this and
5117 * waste the trailing bytes to avoid scaring folks
5118 * with memcpy() using strlen() below
5121 deleted_child_rdn_val.data
5122 = talloc_realloc(tmp_ctx, deleted_child_rdn_val.data,
5124 rdn_value->length + 5
5125 + sizeof(guid_str.buf));
5126 if (!deleted_child_rdn_val.data) {
5127 ldb_asprintf_errstring(ldb, __location__
5128 ": Unable to add a formatted child to dn: %s",
5129 ldb_dn_get_linearized(dn));
5130 return LDB_ERR_OPERATIONS_ERROR;
5133 deleted_child_rdn_val.length =
5134 rdn_value->length + 5
5135 + strlen(guid_str.buf);
5137 SMB_ASSERT(deleted_child_rdn_val.length <
5138 talloc_get_size(deleted_child_rdn_val.data));
5141 * talloc won't allocate more than 256MB so we can't
5142 * overflow but just to be sure
5144 if (deleted_child_rdn_val.length < rdn_value->length) {
5145 return LDB_ERR_OPERATIONS_ERROR;
5148 deleted_child_rdn_val.data[rdn_value->length] = 0x0a;
5149 memcpy(&deleted_child_rdn_val.data[rdn_value->length + 1],
5150 four_char_prefix, 4);
5151 memcpy(&deleted_child_rdn_val.data[rdn_value->length + 5],
5153 sizeof(guid_str.buf));
5155 /* Now set the value into the RDN, without parsing it */
5156 ret = ldb_dn_set_component(
5160 deleted_child_rdn_val);
5169 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx,
5170 struct ldb_context *ldb,
5174 const struct ldb_val *rdn_val;
5175 const char *rdn_name;
5176 struct ldb_dn *new_dn;
5179 rdn_val = ldb_dn_get_rdn_val(dn);
5180 rdn_name = ldb_dn_get_rdn_name(dn);
5181 if (!rdn_val || !rdn_name) {
5185 new_dn = ldb_dn_get_parent(mem_ctx, dn);
5190 ret = replmd_make_prefix_child_dn(mem_ctx,
5196 if (ret != LDB_SUCCESS) {
5205 static int replmd_make_deleted_child_dn(TALLOC_CTX *tmp_ctx,
5206 struct ldb_context *ldb,
5208 const char *rdn_name,
5209 const struct ldb_val *rdn_value,
5212 return replmd_make_prefix_child_dn(tmp_ctx,
5222 perform a modify operation which sets the rDN and name attributes to
5223 their current values. This has the effect of changing these
5224 attributes to have been last updated by the current DC. This is
5225 needed to ensure that renames performed as part of conflict
5226 resolution are propagated to other DCs
5228 static int replmd_name_modify(struct replmd_replicated_request *ar,
5229 struct ldb_request *req, struct ldb_dn *dn)
5231 struct ldb_message *msg;
5232 const char *rdn_name;
5233 const struct ldb_val *rdn_val;
5234 const struct dsdb_attribute *rdn_attr;
5237 msg = ldb_msg_new(req);
5243 rdn_name = ldb_dn_get_rdn_name(dn);
5244 if (rdn_name == NULL) {
5248 /* normalize the rdn attribute name */
5249 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
5250 if (rdn_attr == NULL) {
5253 rdn_name = rdn_attr->lDAPDisplayName;
5255 rdn_val = ldb_dn_get_rdn_val(dn);
5256 if (rdn_val == NULL) {
5260 if (ldb_msg_append_value(msg, rdn_name, rdn_val, LDB_FLAG_MOD_REPLACE) != 0) {
5263 if (ldb_msg_append_value(msg, "name", rdn_val, LDB_FLAG_MOD_REPLACE) != 0) {
5268 * We have to mark this as a replicated update otherwise
5269 * schema_data may reject a rename in the schema partition
5272 ret = dsdb_module_modify(ar->module, msg,
5273 DSDB_FLAG_OWN_MODULE|DSDB_FLAG_REPLICATED_UPDATE,
5275 if (ret != LDB_SUCCESS) {
5276 DEBUG(0,(__location__ ": Failed to modify rDN/name of DN being DRS renamed '%s' - %s\n",
5277 ldb_dn_get_linearized(dn),
5278 ldb_errstring(ldb_module_get_ctx(ar->module))));
5288 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of DN being DRS renamed '%s'\n",
5289 ldb_dn_get_linearized(dn)));
5290 return LDB_ERR_OPERATIONS_ERROR;
5295 callback for conflict DN handling where we have renamed the incoming
5296 record. After renaming it, we need to ensure the change of name and
5297 rDN for the incoming record is seen as an originating update by this DC.
5299 This also handles updating lastKnownParent for entries sent to lostAndFound
5301 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
5303 struct replmd_replicated_request *ar =
5304 talloc_get_type_abort(req->context, struct replmd_replicated_request);
5305 struct ldb_dn *conflict_dn = NULL;
5308 if (ares->error != LDB_SUCCESS) {
5309 /* call the normal callback for everything except success */
5310 return replmd_op_callback(req, ares);
5313 switch (req->operation) {
5315 conflict_dn = req->op.add.message->dn;
5318 conflict_dn = req->op.mod.message->dn;
5321 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
5324 /* perform a modify of the rDN and name of the record */
5325 ret = replmd_name_modify(ar, req, conflict_dn);
5326 if (ret != LDB_SUCCESS) {
5328 return replmd_op_callback(req, ares);
5331 if (ar->objs->objects[ar->index_current].last_known_parent) {
5332 struct ldb_message *msg = ldb_msg_new(req);
5334 ldb_module_oom(ar->module);
5335 return LDB_ERR_OPERATIONS_ERROR;
5338 msg->dn = req->op.add.message->dn;
5340 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
5341 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
5342 if (ret != LDB_SUCCESS) {
5343 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
5344 ldb_module_oom(ar->module);
5347 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
5349 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
5350 if (ret != LDB_SUCCESS) {
5351 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s\n",
5352 ldb_dn_get_linearized(msg->dn),
5353 ldb_errstring(ldb_module_get_ctx(ar->module))));
5359 return replmd_op_callback(req, ares);
5365 * A helper for replmd_op_possible_conflict_callback() and
5366 * replmd_replicated_handle_rename()
5368 static int incoming_dn_should_be_renamed(TALLOC_CTX *mem_ctx,
5369 struct replmd_replicated_request *ar,
5370 struct ldb_dn *conflict_dn,
5371 struct ldb_result **res,
5372 bool *rename_incoming_record)
5376 enum ndr_err_code ndr_err;
5377 const struct ldb_val *omd_value = NULL;
5378 struct replPropertyMetaDataBlob omd, *rmd = NULL;
5379 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
5380 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5381 struct replPropertyMetaData1 *omd_name = NULL;
5382 struct replPropertyMetaData1 *rmd_name = NULL;
5383 struct ldb_message *msg = NULL;
5385 ret = samdb_rodc(ldb, &rodc);
5386 if (ret != LDB_SUCCESS) {
5387 ldb_asprintf_errstring(
5389 "Failed to determine if we are an RODC when attempting "
5390 "to form conflict DN: %s",
5391 ldb_errstring(ldb));
5392 return LDB_ERR_OPERATIONS_ERROR;
5397 * We are on an RODC, or were a GC for this
5398 * partition, so we have to fail this until
5399 * someone who owns the partition sorts it
5402 ldb_asprintf_errstring(
5404 "Conflict adding object '%s' from incoming replication "
5405 "but we are read only for the partition. \n"
5406 " - We must fail the operation until a master for this "
5407 "partition resolves the conflict",
5408 ldb_dn_get_linearized(conflict_dn));
5409 return LDB_ERR_OPERATIONS_ERROR;
5413 * first we need the replPropertyMetaData attribute from the
5416 ret = dsdb_module_search_dn(ar->module, mem_ctx, res, conflict_dn,
5418 DSDB_FLAG_NEXT_MODULE |
5419 DSDB_SEARCH_SHOW_DELETED |
5420 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5421 if (ret != LDB_SUCCESS) {
5422 DBG_ERR(__location__
5423 ": Unable to find object for conflicting record '%s'\n",
5424 ldb_dn_get_linearized(conflict_dn));
5425 return LDB_ERR_OPERATIONS_ERROR;
5428 msg = (*res)->msgs[0];
5429 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
5430 if (omd_value == NULL) {
5431 DBG_ERR(__location__
5432 ": Unable to find replPropertyMetaData for conflicting "
5434 ldb_dn_get_linearized(conflict_dn));
5435 return LDB_ERR_OPERATIONS_ERROR;
5438 ndr_err = ndr_pull_struct_blob(
5439 omd_value, msg, &omd,
5440 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5441 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5442 DBG_ERR(__location__
5443 ": Failed to parse old replPropertyMetaData for %s\n",
5444 ldb_dn_get_linearized(conflict_dn));
5445 return LDB_ERR_OPERATIONS_ERROR;
5448 rmd = ar->objs->objects[ar->index_current].meta_data;
5451 * we decide which is newer based on the RPMD on the name
5452 * attribute. See [MS-DRSR] ResolveNameConflict.
5454 * We expect omd_name to be present, as this is from a local
5455 * search, but while rmd_name should have been given to us by
5456 * the remote server, if it is missing we just prefer the
5458 * replmd_replPropertyMetaData1_new_should_be_taken()
5460 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd,
5461 DRSUAPI_ATTID_name);
5462 omd_name = replmd_replPropertyMetaData1_find_attid(&omd,
5463 DRSUAPI_ATTID_name);
5465 DBG_ERR(__location__
5466 ": Failed to find name attribute in "
5467 "local LDB replPropertyMetaData for %s\n",
5468 ldb_dn_get_linearized(conflict_dn));
5469 return LDB_ERR_OPERATIONS_ERROR;
5473 * Should we preserve the current record, and so rename the
5474 * incoming record to be a conflict?
5476 *rename_incoming_record =
5477 !replmd_replPropertyMetaData1_new_should_be_taken(
5478 (ar->objs->dsdb_repl_flags &
5479 DSDB_REPL_FLAG_PRIORITISE_INCOMING),
5480 omd_name, rmd_name);
5487 callback for replmd_replicated_apply_add()
5488 This copes with the creation of conflict records in the case where
5489 the DN exists, but with a different objectGUID
5491 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))
5493 struct ldb_dn *conflict_dn;
5494 struct replmd_replicated_request *ar =
5495 talloc_get_type_abort(req->context, struct replmd_replicated_request);
5496 struct ldb_result *res;
5498 bool rename_incoming_record;
5499 struct ldb_message *msg;
5500 struct ldb_request *down_req = NULL;
5502 /* call the normal callback for success */
5503 if (ares->error == LDB_SUCCESS) {
5504 return callback(req, ares);
5508 * we have a conflict, and need to decide if we will keep the
5509 * new record or the old record
5512 msg = ar->objs->objects[ar->index_current].msg;
5513 conflict_dn = msg->dn;
5515 /* For failures other than conflicts, fail the whole operation here */
5516 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5517 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
5518 ldb_dn_get_linearized(conflict_dn),
5519 ldb_errstring(ldb_module_get_ctx(ar->module)));
5521 return ldb_module_done(ar->req, NULL, NULL,
5522 LDB_ERR_OPERATIONS_ERROR);
5526 ret = incoming_dn_should_be_renamed(req, ar, conflict_dn, &res,
5527 &rename_incoming_record);
5528 if (ret != LDB_SUCCESS) {
5532 if (rename_incoming_record) {
5534 struct ldb_dn *new_dn;
5536 guid = samdb_result_guid(msg, "objectGUID");
5537 if (GUID_all_zero(&guid)) {
5538 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
5539 ldb_dn_get_linearized(conflict_dn)));
5542 new_dn = replmd_conflict_dn(req,
5543 ldb_module_get_ctx(ar->module),
5544 conflict_dn, &guid);
5545 if (new_dn == NULL) {
5546 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5547 ldb_dn_get_linearized(conflict_dn)));
5551 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
5552 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5554 /* re-submit the request, but with the new DN */
5555 callback = replmd_op_name_modify_callback;
5558 /* we are renaming the existing record */
5560 struct ldb_dn *new_dn;
5562 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5563 if (GUID_all_zero(&guid)) {
5564 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5565 ldb_dn_get_linearized(conflict_dn)));
5569 new_dn = replmd_conflict_dn(req,
5570 ldb_module_get_ctx(ar->module),
5571 conflict_dn, &guid);
5572 if (new_dn == NULL) {
5573 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5574 ldb_dn_get_linearized(conflict_dn)));
5578 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5579 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5581 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5582 DSDB_FLAG_OWN_MODULE, req);
5583 if (ret != LDB_SUCCESS) {
5584 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5585 ldb_dn_get_linearized(conflict_dn),
5586 ldb_dn_get_linearized(new_dn),
5587 ldb_errstring(ldb_module_get_ctx(ar->module))));
5592 * now we need to ensure that the rename is seen as an
5593 * originating update. We do that with a modify.
5595 ret = replmd_name_modify(ar, req, new_dn);
5596 if (ret != LDB_SUCCESS) {
5600 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
5601 ldb_dn_get_linearized(req->op.add.message->dn)));
5604 ret = ldb_build_add_req(&down_req,
5605 ldb_module_get_ctx(ar->module),
5612 if (ret != LDB_SUCCESS) {
5615 LDB_REQ_SET_LOCATION(down_req);
5617 /* current partition control needed by "repmd_op_callback" */
5618 ret = ldb_request_add_control(down_req,
5619 DSDB_CONTROL_CURRENT_PARTITION_OID,
5621 if (ret != LDB_SUCCESS) {
5622 return replmd_replicated_request_error(ar, ret);
5625 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5626 /* this tells the partition module to make it a
5627 partial replica if creating an NC */
5628 ret = ldb_request_add_control(down_req,
5629 DSDB_CONTROL_PARTIAL_REPLICA,
5631 if (ret != LDB_SUCCESS) {
5632 return replmd_replicated_request_error(ar, ret);
5637 * Finally we re-run the add, otherwise the new record won't
5638 * exist, as we are here because of that exact failure!
5640 return ldb_next_request(ar->module, down_req);
5643 /* on failure make the caller get the error. This means
5644 * replication will stop with an error, but there is not much
5647 if (ret == LDB_SUCCESS) {
5648 ret = LDB_ERR_OPERATIONS_ERROR;
5650 return ldb_module_done(ar->req, NULL, NULL,
5655 callback for replmd_replicated_apply_add()
5656 This copes with the creation of conflict records in the case where
5657 the DN exists, but with a different objectGUID
5659 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
5661 struct replmd_replicated_request *ar =
5662 talloc_get_type_abort(req->context, struct replmd_replicated_request);
5664 if (ar->objs->objects[ar->index_current].last_known_parent) {
5665 /* This is like a conflict DN, where we put the object in LostAndFound
5666 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
5667 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
5670 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
5674 this is called when a new object comes in over DRS
5676 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
5678 struct ldb_context *ldb;
5679 struct ldb_request *change_req;
5680 enum ndr_err_code ndr_err;
5681 struct ldb_message *msg;
5682 struct replPropertyMetaDataBlob *md;
5683 struct ldb_val md_value;
5686 bool remote_isDeleted = false;
5689 time_t t = time(NULL);
5690 const struct ldb_val *rdn_val;
5691 struct replmd_private *replmd_private =
5692 talloc_get_type(ldb_module_get_private(ar->module),
5693 struct replmd_private);
5694 unix_to_nt_time(&now, t);
5696 ldb = ldb_module_get_ctx(ar->module);
5697 msg = ar->objs->objects[ar->index_current].msg;
5698 md = ar->objs->objects[ar->index_current].meta_data;
5699 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5701 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5702 if (ret != LDB_SUCCESS) {
5703 return replmd_replicated_request_error(ar, ret);
5706 ret = dsdb_msg_add_guid(msg,
5707 &ar->objs->objects[ar->index_current].object_guid,
5709 if (ret != LDB_SUCCESS) {
5710 return replmd_replicated_request_error(ar, ret);
5713 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5714 if (ret != LDB_SUCCESS) {
5715 return replmd_replicated_request_error(ar, ret);
5718 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
5719 if (ret != LDB_SUCCESS) {
5720 return replmd_replicated_request_error(ar, ret);
5723 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5724 if (ret != LDB_SUCCESS) {
5725 return replmd_replicated_request_error(ar, ret);
5728 /* remove any message elements that have zero values */
5729 for (i=0; i<msg->num_elements; i++) {
5730 struct ldb_message_element *el = &msg->elements[i];
5732 if (el->num_values == 0) {
5733 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5734 ldb_asprintf_errstring(ldb, __location__
5735 ": empty objectClass sent on %s, aborting replication\n",
5736 ldb_dn_get_linearized(msg->dn));
5737 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5740 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
5742 ldb_msg_remove_element(msg, &msg->elements[i]);
5749 struct GUID_txt_buf guid_txt;
5751 char *s = ldb_ldif_message_redacted_string(ldb, ar,
5754 DEBUG(8, ("DRS replication add message of %s:\n%s\n",
5755 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5758 } else if (DEBUGLVL(4)) {
5759 struct GUID_txt_buf guid_txt;
5760 DEBUG(4, ("DRS replication add DN of %s is %s\n",
5761 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5762 ldb_dn_get_linearized(msg->dn)));
5764 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5765 "isDeleted", false);
5768 * the meta data array is already sorted by the caller, except
5769 * for the RDN, which needs to be added.
5773 rdn_val = ldb_dn_get_rdn_val(msg->dn);
5774 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
5775 md, ar, now, is_schema_nc,
5777 if (ret != LDB_SUCCESS) {
5778 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5779 return replmd_replicated_request_error(ar, ret);
5782 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
5783 if (ret != LDB_SUCCESS) {
5784 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5785 return replmd_replicated_request_error(ar, ret);
5788 for (i=0; i < md->ctr.ctr1.count; i++) {
5789 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
5791 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
5792 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5793 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5794 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5795 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5797 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
5798 if (ret != LDB_SUCCESS) {
5799 return replmd_replicated_request_error(ar, ret);
5802 replmd_ldb_message_sort(msg, ar->schema);
5804 if (!remote_isDeleted) {
5806 * Ensure any local ACL inheritance is applied from
5807 * the parent object.
5809 * This is needed because descriptor is above
5810 * repl_meta_data in the module stack, so this will
5811 * not be triggered 'naturally' by the flow of
5814 ret = dsdb_module_schedule_sd_propagation(ar->module,
5815 ar->objs->partition_dn,
5816 ar->objs->objects[ar->index_current].object_guid,
5817 ar->objs->objects[ar->index_current].parent_guid ?
5818 *ar->objs->objects[ar->index_current].parent_guid :
5821 if (ret != LDB_SUCCESS) {
5822 return replmd_replicated_request_error(ar, ret);
5826 ar->isDeleted = remote_isDeleted;
5828 ret = ldb_build_add_req(&change_req,
5834 replmd_op_add_callback,
5836 LDB_REQ_SET_LOCATION(change_req);
5837 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5839 /* current partition control needed by "repmd_op_callback" */
5840 ret = ldb_request_add_control(change_req,
5841 DSDB_CONTROL_CURRENT_PARTITION_OID,
5843 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5845 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5846 /* this tells the partition module to make it a
5847 partial replica if creating an NC */
5848 ret = ldb_request_add_control(change_req,
5849 DSDB_CONTROL_PARTIAL_REPLICA,
5851 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5854 return ldb_next_request(ar->module, change_req);
5857 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
5858 struct ldb_reply *ares)
5860 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5861 struct replmd_replicated_request);
5865 return ldb_module_done(ar->req, NULL, NULL,
5866 LDB_ERR_OPERATIONS_ERROR);
5870 * The error NO_SUCH_OBJECT is not expected, unless the search
5871 * base is the partition DN, and that case doesn't happen here
5872 * because then we wouldn't get a parent_guid_value in any
5875 if (ares->error != LDB_SUCCESS) {
5876 return ldb_module_done(ar->req, ares->controls,
5877 ares->response, ares->error);
5880 switch (ares->type) {
5881 case LDB_REPLY_ENTRY:
5883 struct ldb_message *parent_msg = ares->message;
5884 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5885 struct ldb_dn *parent_dn = NULL;
5888 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
5889 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
5890 /* Per MS-DRSR 4.1.10.6.10
5891 * FindBestParentObject we need to move this
5892 * new object under a deleted object to
5894 struct ldb_dn *nc_root;
5896 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
5897 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
5898 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5899 "No suitable NC root found for %s. "
5900 "We need to move this object because parent object %s "
5901 "is deleted, but this object is not.",
5902 ldb_dn_get_linearized(msg->dn),
5903 ldb_dn_get_linearized(parent_msg->dn));
5904 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5905 } else if (ret != LDB_SUCCESS) {
5906 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5907 "Unable to find NC root for %s: %s. "
5908 "We need to move this object because parent object %s "
5909 "is deleted, but this object is not.",
5910 ldb_dn_get_linearized(msg->dn),
5911 ldb_errstring(ldb_module_get_ctx(ar->module)),
5912 ldb_dn_get_linearized(parent_msg->dn));
5913 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5916 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5918 DS_GUID_LOSTANDFOUND_CONTAINER,
5920 if (ret != LDB_SUCCESS) {
5921 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5922 "Unable to find LostAndFound Container for %s "
5923 "in partition %s: %s. "
5924 "We need to move this object because parent object %s "
5925 "is deleted, but this object is not.",
5926 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5927 ldb_errstring(ldb_module_get_ctx(ar->module)),
5928 ldb_dn_get_linearized(parent_msg->dn));
5929 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5931 ar->objs->objects[ar->index_current].last_known_parent
5932 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5936 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5939 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5941 comp_num = ldb_dn_get_comp_num(msg->dn);
5943 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5945 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5948 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5950 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5954 case LDB_REPLY_REFERRAL:
5955 /* we ignore referrals */
5958 case LDB_REPLY_DONE:
5960 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5961 struct GUID_txt_buf str_buf;
5962 if (ar->search_msg != NULL) {
5963 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5964 "No parent with GUID %s found for object locally known as %s",
5965 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5966 ldb_dn_get_linearized(ar->search_msg->dn));
5968 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5969 "No parent with GUID %s found for object remotely known as %s",
5970 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5971 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5975 * This error code is really important, as it
5976 * is the flag back to the callers to retry
5977 * this with DRSUAPI_DRS_GET_ANC, and so get
5978 * the parent objects before the child
5981 return ldb_module_done(ar->req, NULL, NULL,
5982 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5985 if (ar->search_msg != NULL) {
5986 ret = replmd_replicated_apply_merge(ar);
5988 ret = replmd_replicated_apply_add(ar);
5990 if (ret != LDB_SUCCESS) {
5991 return ldb_module_done(ar->req, NULL, NULL, ret);
6000 * Look for the parent object, so we put the new object in the right
6001 * place This is akin to NameObject in MS-DRSR - this routine and the
6002 * callbacks find the right parent name, and correct name for this
6006 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
6008 struct ldb_context *ldb;
6012 struct ldb_request *search_req;
6013 static const char *attrs[] = {"isDeleted", NULL};
6014 struct GUID_txt_buf guid_str_buf;
6016 ldb = ldb_module_get_ctx(ar->module);
6018 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
6019 if (ar->search_msg != NULL) {
6020 return replmd_replicated_apply_merge(ar);
6022 return replmd_replicated_apply_add(ar);
6026 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6029 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
6030 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6032 ret = ldb_build_search_req(&search_req,
6035 ar->objs->partition_dn,
6041 replmd_replicated_apply_search_for_parent_callback,
6043 LDB_REQ_SET_LOCATION(search_req);
6045 ret = dsdb_request_add_controls(search_req,
6046 DSDB_SEARCH_SHOW_RECYCLED|
6047 DSDB_SEARCH_SHOW_DELETED|
6048 DSDB_SEARCH_SHOW_EXTENDED_DN);
6049 if (ret != LDB_SUCCESS) {
6053 return ldb_next_request(ar->module, search_req);
6057 handle renames that come in over DRS replication
6059 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
6060 struct ldb_message *msg,
6061 struct ldb_request *parent,
6062 bool *renamed_to_conflict)
6065 TALLOC_CTX *tmp_ctx = talloc_new(msg);
6066 struct ldb_result *res;
6067 struct ldb_dn *conflict_dn;
6068 bool rename_incoming_record;
6069 struct ldb_dn *new_dn;
6072 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
6073 ldb_dn_get_linearized(ar->search_msg->dn),
6074 ldb_dn_get_linearized(msg->dn)));
6077 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
6078 DSDB_FLAG_NEXT_MODULE, ar->req);
6079 if (ret == LDB_SUCCESS) {
6080 talloc_free(tmp_ctx);
6084 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
6085 talloc_free(tmp_ctx);
6086 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
6087 ldb_dn_get_linearized(ar->search_msg->dn),
6088 ldb_dn_get_linearized(msg->dn),
6089 ldb_errstring(ldb_module_get_ctx(ar->module)));
6093 conflict_dn = msg->dn;
6096 ret = incoming_dn_should_be_renamed(tmp_ctx, ar, conflict_dn, &res,
6097 &rename_incoming_record);
6098 if (ret != LDB_SUCCESS) {
6102 if (rename_incoming_record) {
6104 new_dn = replmd_conflict_dn(msg,
6105 ldb_module_get_ctx(ar->module),
6107 &ar->objs->objects[ar->index_current].object_guid);
6108 if (new_dn == NULL) {
6109 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
6110 "Failed to form conflict DN for %s\n",
6111 ldb_dn_get_linearized(msg->dn));
6113 talloc_free(tmp_ctx);
6114 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6117 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
6118 DSDB_FLAG_NEXT_MODULE, ar->req);
6119 if (ret != LDB_SUCCESS) {
6120 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
6121 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
6122 ldb_dn_get_linearized(conflict_dn),
6123 ldb_dn_get_linearized(ar->search_msg->dn),
6124 ldb_dn_get_linearized(new_dn),
6125 ldb_errstring(ldb_module_get_ctx(ar->module)));
6126 talloc_free(tmp_ctx);
6127 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
6131 *renamed_to_conflict = true;
6132 talloc_free(tmp_ctx);
6136 /* we are renaming the existing record */
6138 guid = samdb_result_guid(res->msgs[0], "objectGUID");
6139 if (GUID_all_zero(&guid)) {
6140 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
6141 ldb_dn_get_linearized(conflict_dn)));
6145 new_dn = replmd_conflict_dn(tmp_ctx,
6146 ldb_module_get_ctx(ar->module),
6147 conflict_dn, &guid);
6148 if (new_dn == NULL) {
6149 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
6150 ldb_dn_get_linearized(conflict_dn)));
6154 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
6155 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
6157 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
6158 DSDB_FLAG_OWN_MODULE, ar->req);
6159 if (ret != LDB_SUCCESS) {
6160 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
6161 ldb_dn_get_linearized(conflict_dn),
6162 ldb_dn_get_linearized(new_dn),
6163 ldb_errstring(ldb_module_get_ctx(ar->module))));
6168 * now we need to ensure that the rename is seen as an
6169 * originating update. We do that with a modify.
6171 ret = replmd_name_modify(ar, ar->req, new_dn);
6172 if (ret != LDB_SUCCESS) {
6176 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
6177 ldb_dn_get_linearized(ar->search_msg->dn),
6178 ldb_dn_get_linearized(msg->dn)));
6181 * With the other record out of the way, do the rename we had
6184 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
6185 DSDB_FLAG_NEXT_MODULE, ar->req);
6186 if (ret != LDB_SUCCESS) {
6187 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
6188 ldb_dn_get_linearized(ar->search_msg->dn),
6189 ldb_dn_get_linearized(msg->dn),
6190 ldb_errstring(ldb_module_get_ctx(ar->module))));
6194 talloc_free(tmp_ctx);
6198 * On failure make the caller get the error
6199 * This means replication will stop with an error,
6200 * but there is not much else we can do. In the
6201 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
6204 if (ret == LDB_SUCCESS) {
6205 ret = LDB_ERR_OPERATIONS_ERROR;
6208 talloc_free(tmp_ctx);
6213 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
6215 struct ldb_context *ldb;
6216 struct ldb_request *change_req;
6217 enum ndr_err_code ndr_err;
6218 struct ldb_message *msg;
6219 struct replPropertyMetaDataBlob *rmd;
6220 struct replPropertyMetaDataBlob omd;
6221 const struct ldb_val *omd_value;
6222 struct replPropertyMetaDataBlob nmd;
6223 struct ldb_val nmd_value;
6224 struct GUID remote_parent_guid;
6227 unsigned int removed_attrs = 0;
6229 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
6230 bool isDeleted = false;
6231 bool local_isDeleted = false;
6232 bool remote_isDeleted = false;
6233 bool take_remote_isDeleted = false;
6234 bool sd_updated = false;
6235 bool renamed = false;
6236 bool renamed_to_conflict = false;
6237 bool is_schema_nc = false;
6239 const struct ldb_val *old_rdn, *new_rdn;
6240 struct replmd_private *replmd_private =
6241 talloc_get_type(ldb_module_get_private(ar->module),
6242 struct replmd_private);
6244 time_t t = time(NULL);
6245 unix_to_nt_time(&now, t);
6247 ldb = ldb_module_get_ctx(ar->module);
6248 msg = ar->objs->objects[ar->index_current].msg;
6250 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
6252 rmd = ar->objs->objects[ar->index_current].meta_data;
6256 /* find existing meta data */
6257 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
6259 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
6260 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
6261 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6262 nt_status = ndr_map_error2ntstatus(ndr_err);
6263 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6266 if (omd.version != 1) {
6267 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6272 struct GUID_txt_buf guid_txt;
6274 char *s = ldb_ldif_message_redacted_string(ldb, ar,
6275 LDB_CHANGETYPE_MODIFY, msg);
6276 DEBUG(8, ("Initial DRS replication modify message of %s is:\n%s\n"
6279 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
6281 ndr_print_struct_string(s,
6282 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
6283 "existing replPropertyMetaData",
6285 ndr_print_struct_string(s,
6286 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
6287 "incoming replPropertyMetaData",
6290 } else if (DEBUGLVL(4)) {
6291 struct GUID_txt_buf guid_txt;
6293 DEBUG(4, ("Initial DRS replication modify DN of %s is: %s\n",
6294 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6296 ldb_dn_get_linearized(msg->dn)));
6299 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
6300 "isDeleted", false);
6301 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
6302 "isDeleted", false);
6305 * Fill in the remote_parent_guid with the GUID or an all-zero
6308 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
6309 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
6311 remote_parent_guid = GUID_zero();
6315 * To ensure we follow a complex rename chain around, we have
6316 * to confirm that the DN is the same (mostly to confirm the
6317 * RDN) and the parentGUID is the same.
6319 * This ensures we keep things under the correct parent, which
6320 * replmd_replicated_handle_rename() will do.
6323 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
6324 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
6328 * handle renames, even just by case that come in over
6329 * DRS. Changes in the parent DN don't hit us here,
6330 * because the search for a parent will clean up those
6333 * We also have already filtered out the case where
6334 * the peer has an older name to what we have (see
6335 * replmd_replicated_apply_search_callback())
6337 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed_to_conflict);
6340 * This looks strange, but we must set this after any
6341 * rename, otherwise the SD propegation will not
6342 * happen (which might matter if we have a new parent)
6344 * The additional case of calling
6345 * replmd_op_name_modify_callback (below) is
6346 * controlled by renamed_to_conflict.
6351 if (ret != LDB_SUCCESS) {
6352 ldb_debug(ldb, LDB_DEBUG_FATAL,
6353 "replmd_replicated_request rename %s => %s failed - %s\n",
6354 ldb_dn_get_linearized(ar->search_msg->dn),
6355 ldb_dn_get_linearized(msg->dn),
6356 ldb_errstring(ldb));
6357 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
6360 if (renamed_to_conflict == true) {
6362 * Set the callback to one that will fix up the name
6363 * metadata on the new conflict DN
6365 callback = replmd_op_name_modify_callback;
6370 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
6371 nmd.ctr.ctr1.array = talloc_array(ar,
6372 struct replPropertyMetaData1,
6373 nmd.ctr.ctr1.count);
6374 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6376 /* first copy the old meta data */
6377 for (i=0; i < omd.ctr.ctr1.count; i++) {
6378 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
6383 /* now merge in the new meta data */
6384 for (i=0; i < rmd->ctr.ctr1.count; i++) {
6387 for (j=0; j < ni; j++) {
6390 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
6394 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
6395 ar->objs->dsdb_repl_flags,
6396 &nmd.ctr.ctr1.array[j],
6397 &rmd->ctr.ctr1.array[i]);
6399 /* replace the entry */
6400 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
6401 if (ar->seq_num == 0) {
6402 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
6403 if (ret != LDB_SUCCESS) {
6404 return replmd_replicated_request_error(ar, ret);
6407 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
6408 switch (nmd.ctr.ctr1.array[j].attid) {
6409 case DRSUAPI_ATTID_ntSecurityDescriptor:
6412 case DRSUAPI_ATTID_isDeleted:
6413 take_remote_isDeleted = true;
6422 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
6423 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
6424 msg->elements[i-removed_attrs].name,
6425 ldb_dn_get_linearized(msg->dn),
6426 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
6429 /* we don't want to apply this change so remove the attribute */
6430 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
6437 if (found) continue;
6439 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
6440 if (ar->seq_num == 0) {
6441 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
6442 if (ret != LDB_SUCCESS) {
6443 return replmd_replicated_request_error(ar, ret);
6446 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
6447 switch (nmd.ctr.ctr1.array[ni].attid) {
6448 case DRSUAPI_ATTID_ntSecurityDescriptor:
6451 case DRSUAPI_ATTID_isDeleted:
6452 take_remote_isDeleted = true;
6461 * finally correct the size of the meta_data array
6463 nmd.ctr.ctr1.count = ni;
6465 new_rdn = ldb_dn_get_rdn_val(msg->dn);
6466 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
6469 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
6470 &nmd, ar, now, is_schema_nc,
6472 if (ret != LDB_SUCCESS) {
6473 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
6474 return replmd_replicated_request_error(ar, ret);
6478 * sort the new meta data array
6480 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
6481 if (ret != LDB_SUCCESS) {
6482 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
6487 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
6490 * This also controls SD propagation below
6492 if (take_remote_isDeleted) {
6493 isDeleted = remote_isDeleted;
6495 isDeleted = local_isDeleted;
6498 ar->isDeleted = isDeleted;
6501 * check if some replicated attributes left, otherwise skip the ldb_modify() call
6503 if (msg->num_elements == 0) {
6504 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
6507 return replmd_replicated_apply_isDeleted(ar);
6510 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
6511 ar->index_current, msg->num_elements);
6515 * This is an new name for this object, so we must
6516 * inherit from the parent
6518 * This is needed because descriptor is above
6519 * repl_meta_data in the module stack, so this will
6520 * not be triggered 'naturally' by the flow of
6523 ret = dsdb_module_schedule_sd_propagation(ar->module,
6524 ar->objs->partition_dn,
6525 ar->objs->objects[ar->index_current].object_guid,
6526 ar->objs->objects[ar->index_current].parent_guid ?
6527 *ar->objs->objects[ar->index_current].parent_guid :
6530 if (ret != LDB_SUCCESS) {
6531 return ldb_operr(ldb);
6535 if (sd_updated && !isDeleted) {
6537 * This is an existing object, so there is no need to
6538 * inherit from the parent, but we must inherit any
6539 * incoming changes to our child objects.
6541 * This is needed because descriptor is above
6542 * repl_meta_data in the module stack, so this will
6543 * not be triggered 'naturally' by the flow of
6546 ret = dsdb_module_schedule_sd_propagation(ar->module,
6547 ar->objs->partition_dn,
6548 ar->objs->objects[ar->index_current].object_guid,
6549 ar->objs->objects[ar->index_current].parent_guid ?
6550 *ar->objs->objects[ar->index_current].parent_guid :
6553 if (ret != LDB_SUCCESS) {
6554 return ldb_operr(ldb);
6558 /* create the meta data value */
6559 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
6560 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
6561 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6562 nt_status = ndr_map_error2ntstatus(ndr_err);
6563 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6567 * when we know that we'll modify the record, add the whenChanged, uSNChanged
6568 * and replPopertyMetaData attributes
6570 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
6571 if (ret != LDB_SUCCESS) {
6572 return replmd_replicated_request_error(ar, ret);
6574 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
6575 if (ret != LDB_SUCCESS) {
6576 return replmd_replicated_request_error(ar, ret);
6578 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
6579 if (ret != LDB_SUCCESS) {
6580 return replmd_replicated_request_error(ar, ret);
6583 replmd_ldb_message_sort(msg, ar->schema);
6585 /* we want to replace the old values */
6586 for (i=0; i < msg->num_elements; i++) {
6587 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
6588 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
6589 if (msg->elements[i].num_values == 0) {
6590 ldb_asprintf_errstring(ldb, __location__
6591 ": objectClass removed on %s, aborting replication\n",
6592 ldb_dn_get_linearized(msg->dn));
6593 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
6599 struct GUID_txt_buf guid_txt;
6601 char *s = ldb_ldif_message_redacted_string(ldb, ar,
6602 LDB_CHANGETYPE_MODIFY,
6604 DEBUG(8, ("Final DRS replication modify message of %s:\n%s\n",
6605 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6609 } else if (DEBUGLVL(4)) {
6610 struct GUID_txt_buf guid_txt;
6612 DEBUG(4, ("Final DRS replication modify DN of %s is %s\n",
6613 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6615 ldb_dn_get_linearized(msg->dn)));
6618 ret = ldb_build_mod_req(&change_req,
6626 LDB_REQ_SET_LOCATION(change_req);
6627 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6629 /* current partition control needed by "repmd_op_callback" */
6630 ret = ldb_request_add_control(change_req,
6631 DSDB_CONTROL_CURRENT_PARTITION_OID,
6633 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6635 return ldb_next_request(ar->module, change_req);
6638 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
6639 struct ldb_reply *ares)
6641 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6642 struct replmd_replicated_request);
6646 return ldb_module_done(ar->req, NULL, NULL,
6647 LDB_ERR_OPERATIONS_ERROR);
6649 if (ares->error != LDB_SUCCESS &&
6650 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6651 return ldb_module_done(ar->req, ares->controls,
6652 ares->response, ares->error);
6655 switch (ares->type) {
6656 case LDB_REPLY_ENTRY:
6657 ar->search_msg = talloc_steal(ar, ares->message);
6660 case LDB_REPLY_REFERRAL:
6661 /* we ignore referrals */
6664 case LDB_REPLY_DONE:
6666 struct replPropertyMetaData1 *md_remote;
6667 struct replPropertyMetaData1 *md_local;
6669 struct replPropertyMetaDataBlob omd;
6670 const struct ldb_val *omd_value;
6671 struct replPropertyMetaDataBlob *rmd;
6672 struct ldb_message *msg;
6674 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
6675 ar->objs->objects[ar->index_current].last_known_parent = NULL;
6678 * This is the ADD case, find the appropriate parent,
6679 * as this object doesn't exist locally:
6681 if (ar->search_msg == NULL) {
6682 ret = replmd_replicated_apply_search_for_parent(ar);
6683 if (ret != LDB_SUCCESS) {
6684 return ldb_module_done(ar->req, NULL, NULL, ret);
6691 * Otherwise, in the MERGE case, work out if we are
6692 * attempting a rename, and if so find the parent the
6693 * newly renamed object wants to belong under (which
6694 * may not be the parent in it's attached string DN
6696 rmd = ar->objs->objects[ar->index_current].meta_data;
6700 /* find existing meta data */
6701 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
6703 enum ndr_err_code ndr_err;
6704 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
6705 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
6706 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6707 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6708 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6711 if (omd.version != 1) {
6712 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6716 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
6718 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
6719 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
6720 && GUID_all_zero(&ar->local_parent_guid)) {
6721 DEBUG(0, ("Refusing to replicate new version of %s "
6722 "as local object has an all-zero parentGUID attribute, "
6723 "despite not being an NC root\n",
6724 ldb_dn_get_linearized(ar->search_msg->dn)));
6725 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6729 * now we need to check for double renames. We could have a
6730 * local rename pending which our replication partner hasn't
6731 * received yet. We choose which one wins by looking at the
6732 * attribute stamps on the two objects, the newer one wins.
6734 * This also simply applies the correct algorithms for
6735 * determining if a change was made to name at all, or
6736 * if the object has just been renamed under the same
6739 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
6740 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
6742 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
6743 ldb_dn_get_linearized(ar->search_msg->dn)));
6744 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
6748 * if there is no name attribute given then we have to assume the
6749 * object we've received has the older name
6751 if (replmd_replPropertyMetaData1_new_should_be_taken(
6752 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
6753 md_local, md_remote)) {
6754 struct GUID_txt_buf p_guid_local;
6755 struct GUID_txt_buf p_guid_remote;
6756 msg = ar->objs->objects[ar->index_current].msg;
6758 /* Merge on the existing object, with rename */
6760 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
6761 "as incoming object changing to %s under %s\n",
6762 ldb_dn_get_linearized(ar->search_msg->dn),
6763 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6764 ldb_dn_get_linearized(msg->dn),
6765 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6767 ret = replmd_replicated_apply_search_for_parent(ar);
6769 struct GUID_txt_buf p_guid_local;
6770 struct GUID_txt_buf p_guid_remote;
6771 msg = ar->objs->objects[ar->index_current].msg;
6774 * Merge on the existing object, force no
6775 * rename (code below just to explain why in
6779 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
6780 ldb_dn_get_linearized(msg->dn)) == 0) {
6781 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
6782 GUID_equal(&ar->local_parent_guid,
6783 ar->objs->objects[ar->index_current].parent_guid)
6785 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6786 "despite incoming object changing parent to %s\n",
6787 ldb_dn_get_linearized(ar->search_msg->dn),
6788 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6789 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6793 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6794 " and rejecting older rename to %s under %s\n",
6795 ldb_dn_get_linearized(ar->search_msg->dn),
6796 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6797 ldb_dn_get_linearized(msg->dn),
6798 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6802 * This assignment ensures that the strcmp()
6803 * and GUID_equal() calls in
6804 * replmd_replicated_apply_merge() avoids the
6807 ar->objs->objects[ar->index_current].parent_guid =
6808 &ar->local_parent_guid;
6810 msg->dn = ar->search_msg->dn;
6811 ret = replmd_replicated_apply_merge(ar);
6813 if (ret != LDB_SUCCESS) {
6814 return ldb_module_done(ar->req, NULL, NULL, ret);
6824 * Returns true if we can group together processing this link attribute,
6825 * i.e. it has the same source-object and attribute ID as other links
6826 * already in the group
6828 static bool la_entry_matches_group(struct la_entry *la_entry,
6829 struct la_group *la_group)
6831 struct la_entry *prev = la_group->la_entries;
6833 return (la_entry->la->attid == prev->la->attid &&
6834 GUID_equal(&la_entry->la->identifier->guid,
6835 &prev->la->identifier->guid));
6839 * Creates a new la_entry to store replication info for a single
6842 static struct la_entry *
6843 create_la_entry(struct replmd_private *replmd_private,
6844 struct drsuapi_DsReplicaLinkedAttribute *la,
6845 uint32_t dsdb_repl_flags)
6847 struct la_entry *la_entry;
6849 if (replmd_private->la_ctx == NULL) {
6850 replmd_private->la_ctx = talloc_new(replmd_private);
6852 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6853 if (la_entry == NULL) {
6856 la_entry->la = talloc(la_entry,
6857 struct drsuapi_DsReplicaLinkedAttribute);
6858 if (la_entry->la == NULL) {
6859 talloc_free(la_entry);
6862 *la_entry->la = *la;
6863 la_entry->dsdb_repl_flags = dsdb_repl_flags;
6866 * we need to steal the non-scalars so they stay
6867 * around until the end of the transaction
6869 talloc_steal(la_entry->la, la_entry->la->identifier);
6870 talloc_steal(la_entry->la, la_entry->la->value.blob);
6876 * Stores the linked attributes received in the replication chunk - these get
6877 * applied at the end of the transaction. We also check that each linked
6878 * attribute is valid, i.e. source and target objects are known.
6880 static int replmd_store_linked_attributes(struct replmd_replicated_request *ar)
6882 int ret = LDB_SUCCESS;
6884 struct ldb_module *module = ar->module;
6885 struct replmd_private *replmd_private =
6886 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6887 struct la_group *la_group = NULL;
6888 struct ldb_context *ldb;
6889 TALLOC_CTX *tmp_ctx = NULL;
6890 struct ldb_message *src_msg = NULL;
6891 const struct dsdb_attribute *attr = NULL;
6893 ldb = ldb_module_get_ctx(module);
6895 DEBUG(4,("linked_attributes_count=%u\n", ar->objs->linked_attributes_count));
6897 /* save away the linked attributes for the end of the transaction */
6898 for (i = 0; i < ar->objs->linked_attributes_count; i++) {
6899 struct la_entry *la_entry;
6902 /* create an entry to store the received link attribute info */
6903 la_entry = create_la_entry(replmd_private,
6904 &ar->objs->linked_attributes[i],
6905 ar->objs->dsdb_repl_flags);
6906 if (la_entry == NULL) {
6908 return LDB_ERR_OPERATIONS_ERROR;
6912 * check if we're still dealing with the same source object
6915 new_srcobj = (la_group == NULL ||
6916 !la_entry_matches_group(la_entry, la_group));
6920 /* get a new mem_ctx to lookup the source object */
6921 TALLOC_FREE(tmp_ctx);
6922 tmp_ctx = talloc_new(ar);
6923 if (tmp_ctx == NULL) {
6925 return LDB_ERR_OPERATIONS_ERROR;
6928 /* verify the link source exists */
6929 ret = replmd_get_la_entry_source(module, la_entry,
6934 * When we fail to find the source object, the error
6935 * code we pass back here is really important. It flags
6936 * back to the callers to retry this request with
6937 * DRSUAPI_DRS_GET_ANC. This case should never happen
6938 * if we're replicating from a Samba DC, but it is
6939 * needed to talk to a Windows DC
6941 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
6942 WERROR err = WERR_DS_DRA_MISSING_PARENT;
6943 ret = replmd_replicated_request_werror(ar,
6949 ret = replmd_verify_link_target(ar, tmp_ctx, la_entry,
6951 if (ret != LDB_SUCCESS) {
6955 /* group the links together by source-object for efficiency */
6957 la_group = talloc_zero(replmd_private->la_ctx,
6959 if (la_group == NULL) {
6961 return LDB_ERR_OPERATIONS_ERROR;
6963 DLIST_ADD(replmd_private->la_list, la_group);
6965 DLIST_ADD(la_group->la_entries, la_entry);
6966 replmd_private->total_links++;
6969 TALLOC_FREE(tmp_ctx);
6973 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
6975 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
6977 struct ldb_context *ldb;
6981 struct ldb_request *search_req;
6982 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
6983 "parentGUID", "instanceType",
6984 "replPropertyMetaData", "nTSecurityDescriptor",
6985 "isDeleted", NULL };
6986 struct GUID_txt_buf guid_str_buf;
6988 if (ar->index_current >= ar->objs->num_objects) {
6991 * Now that we've applied all the objects, check the new linked
6992 * attributes and store them (we apply them in .prepare_commit)
6994 ret = replmd_store_linked_attributes(ar);
6996 if (ret != LDB_SUCCESS) {
7000 /* done applying objects, move on to the next stage */
7001 return replmd_replicated_uptodate_vector(ar);
7004 ldb = ldb_module_get_ctx(ar->module);
7005 ar->search_msg = NULL;
7006 ar->isDeleted = false;
7008 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
7011 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
7012 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
7014 ret = ldb_build_search_req(&search_req,
7017 ar->objs->partition_dn,
7023 replmd_replicated_apply_search_callback,
7025 LDB_REQ_SET_LOCATION(search_req);
7028 * We set DSDB_SEARCH_SHOW_EXTENDED_DN to get the GUID on the
7029 * DN. This in turn helps our operational module find the
7030 * record by GUID, not DN lookup which is more error prone if
7031 * DN indexing changes. We prefer to keep chasing GUIDs
7032 * around if possible, even within a transaction.
7034 * The aim here is to keep replication moving and allow a
7037 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED
7038 |DSDB_SEARCH_SHOW_EXTENDED_DN);
7040 if (ret != LDB_SUCCESS) {
7044 return ldb_next_request(ar->module, search_req);
7048 * Returns true if we need to do extra processing to handle deleted object
7049 * changes received via replication
7051 static bool replmd_should_apply_isDeleted(struct replmd_replicated_request *ar,
7052 struct ldb_message *msg)
7054 struct ldb_dn *deleted_objects_dn;
7057 if (!ar->isDeleted) {
7059 /* not a deleted object, so don't set isDeleted */
7063 ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module),
7065 &deleted_objects_dn);
7068 * if the Deleted Object container lookup failed, then just apply
7069 * isDeleted (note that it doesn't exist for the Schema partition)
7071 if (ret != LDB_SUCCESS) {
7076 * the Deleted Objects container has isDeleted set but is not entirely
7077 * a deleted object, so DON'T re-apply isDeleted to it
7079 if (ldb_dn_compare(msg->dn, deleted_objects_dn) == 0) {
7087 * This is essentially a wrapper for replmd_replicated_apply_next()
7089 * This is needed to ensure that both codepaths call this handler.
7091 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
7093 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
7095 bool apply_isDeleted;
7096 struct ldb_request *del_req = NULL;
7097 struct ldb_result *res = NULL;
7098 TALLOC_CTX *tmp_ctx = NULL;
7100 apply_isDeleted = replmd_should_apply_isDeleted(ar, msg);
7102 if (!apply_isDeleted) {
7105 ar->index_current++;
7106 return replmd_replicated_apply_next(ar);
7110 * Do a delete here again, so that if there is
7111 * anything local that conflicts with this
7112 * object being deleted, it is removed. This
7113 * includes links. See MS-DRSR 4.1.10.6.9
7116 * If the object is already deleted, and there
7117 * is no more work required, it doesn't do
7121 /* This has been updated to point to the DN we eventually did the modify on */
7123 tmp_ctx = talloc_new(ar);
7125 ret = ldb_oom(ldb_module_get_ctx(ar->module));
7129 res = talloc_zero(tmp_ctx, struct ldb_result);
7131 ret = ldb_oom(ldb_module_get_ctx(ar->module));
7132 talloc_free(tmp_ctx);
7136 /* Build a delete request, which hopefully will artually turn into nothing */
7137 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
7141 ldb_modify_default_callback,
7143 LDB_REQ_SET_LOCATION(del_req);
7144 if (ret != LDB_SUCCESS) {
7145 talloc_free(tmp_ctx);
7150 * This is the guts of the call, call back
7151 * into our delete code, but setting the
7152 * re_delete flag so we delete anything that
7153 * shouldn't be there on a deleted or recycled
7156 ret = replmd_delete_internals(ar->module, del_req, true);
7157 if (ret == LDB_SUCCESS) {
7158 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
7161 talloc_free(tmp_ctx);
7162 if (ret != LDB_SUCCESS) {
7166 ar->index_current++;
7167 return replmd_replicated_apply_next(ar);
7170 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
7171 struct ldb_reply *ares)
7173 struct ldb_context *ldb;
7174 struct replmd_replicated_request *ar = talloc_get_type(req->context,
7175 struct replmd_replicated_request);
7176 ldb = ldb_module_get_ctx(ar->module);
7179 return ldb_module_done(ar->req, NULL, NULL,
7180 LDB_ERR_OPERATIONS_ERROR);
7182 if (ares->error != LDB_SUCCESS) {
7183 return ldb_module_done(ar->req, ares->controls,
7184 ares->response, ares->error);
7187 if (ares->type != LDB_REPLY_DONE) {
7188 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
7189 return ldb_module_done(ar->req, NULL, NULL,
7190 LDB_ERR_OPERATIONS_ERROR);
7195 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
7198 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
7200 struct ldb_context *ldb;
7201 struct ldb_request *change_req;
7202 enum ndr_err_code ndr_err;
7203 struct ldb_message *msg;
7204 struct replUpToDateVectorBlob ouv;
7205 const struct ldb_val *ouv_value;
7206 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
7207 struct replUpToDateVectorBlob nuv;
7208 struct ldb_val nuv_value;
7209 struct ldb_message_element *nuv_el = NULL;
7210 struct ldb_message_element *orf_el = NULL;
7211 struct repsFromToBlob nrf;
7212 struct ldb_val *nrf_value = NULL;
7213 struct ldb_message_element *nrf_el = NULL;
7217 time_t t = time(NULL);
7220 uint32_t instanceType;
7222 ldb = ldb_module_get_ctx(ar->module);
7223 ruv = ar->objs->uptodateness_vector;
7229 unix_to_nt_time(&now, t);
7231 if (ar->search_msg == NULL) {
7232 /* this happens for a REPL_OBJ call where we are
7233 creating the target object by replicating it. The
7234 subdomain join code does this for the partition DN
7236 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
7237 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
7240 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
7241 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
7242 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
7243 ldb_dn_get_linearized(ar->search_msg->dn)));
7244 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
7248 * first create the new replUpToDateVector
7250 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
7252 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
7253 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
7254 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
7255 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
7256 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
7259 if (ouv.version != 2) {
7260 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
7265 * the new uptodateness vector will at least
7266 * contain 1 entry, one for the source_dsa
7268 * plus optional values from our old vector and the one from the source_dsa
7270 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
7271 if (ruv) nuv.ctr.ctr2.count += ruv->count;
7272 nuv.ctr.ctr2.cursors = talloc_array(ar,
7273 struct drsuapi_DsReplicaCursor2,
7274 nuv.ctr.ctr2.count);
7275 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
7277 /* first copy the old vector */
7278 for (i=0; i < ouv.ctr.ctr2.count; i++) {
7279 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
7283 /* merge in the source_dsa vector is available */
7284 for (i=0; (ruv && i < ruv->count); i++) {
7287 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
7288 &ar->our_invocation_id)) {
7292 for (j=0; j < ni; j++) {
7293 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
7294 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
7300 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
7301 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
7306 if (found) continue;
7308 /* if it's not there yet, add it */
7309 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
7314 * finally correct the size of the cursors array
7316 nuv.ctr.ctr2.count = ni;
7321 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
7324 * create the change ldb_message
7326 msg = ldb_msg_new(ar);
7327 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
7328 msg->dn = ar->search_msg->dn;
7330 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
7331 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
7332 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
7333 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
7334 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
7336 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
7337 if (ret != LDB_SUCCESS) {
7338 return replmd_replicated_request_error(ar, ret);
7340 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
7343 * now create the new repsFrom value from the given repsFromTo1 structure
7347 nrf.ctr.ctr1 = *ar->objs->source_dsa;
7348 nrf.ctr.ctr1.last_attempt = now;
7349 nrf.ctr.ctr1.last_success = now;
7350 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
7353 * first see if we already have a repsFrom value for the current source dsa
7354 * if so we'll later replace this value
7356 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
7358 for (i=0; i < orf_el->num_values; i++) {
7359 struct repsFromToBlob *trf;
7361 trf = talloc(ar, struct repsFromToBlob);
7362 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
7364 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
7365 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
7366 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
7367 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
7368 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
7371 if (trf->version != 1) {
7372 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
7376 * we compare the source dsa objectGUID not the invocation_id
7377 * because we want only one repsFrom value per source dsa
7378 * and when the invocation_id of the source dsa has changed we don't need
7379 * the old repsFrom with the old invocation_id
7381 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
7382 &ar->objs->source_dsa->source_dsa_obj_guid)) {
7388 nrf_value = &orf_el->values[i];
7393 * copy over all old values to the new ldb_message
7395 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
7396 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
7401 * if we haven't found an old repsFrom value for the current source dsa
7402 * we'll add a new value
7405 struct ldb_val zero_value;
7406 ZERO_STRUCT(zero_value);
7407 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
7408 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
7410 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
7413 /* we now fill the value which is already attached to ldb_message */
7414 ndr_err = ndr_push_struct_blob(nrf_value, msg,
7416 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
7417 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
7418 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
7419 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
7423 * the ldb_message_element for the attribute, has all the old values and the new one
7424 * so we'll replace the whole attribute with all values
7426 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
7428 if (CHECK_DEBUGLVL(4)) {
7429 char *s = ldb_ldif_message_redacted_string(ldb, ar,
7430 LDB_CHANGETYPE_MODIFY,
7432 DEBUG(4, ("DRS replication up-to-date modify message:\n%s\n", s));
7436 /* prepare the ldb_modify() request */
7437 ret = ldb_build_mod_req(&change_req,
7443 replmd_replicated_uptodate_modify_callback,
7445 LDB_REQ_SET_LOCATION(change_req);
7446 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
7448 return ldb_next_request(ar->module, change_req);
7451 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
7452 struct ldb_reply *ares)
7454 struct replmd_replicated_request *ar = talloc_get_type(req->context,
7455 struct replmd_replicated_request);
7459 return ldb_module_done(ar->req, NULL, NULL,
7460 LDB_ERR_OPERATIONS_ERROR);
7462 if (ares->error != LDB_SUCCESS &&
7463 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
7464 return ldb_module_done(ar->req, ares->controls,
7465 ares->response, ares->error);
7468 switch (ares->type) {
7469 case LDB_REPLY_ENTRY:
7470 ar->search_msg = talloc_steal(ar, ares->message);
7473 case LDB_REPLY_REFERRAL:
7474 /* we ignore referrals */
7477 case LDB_REPLY_DONE:
7478 ret = replmd_replicated_uptodate_modify(ar);
7479 if (ret != LDB_SUCCESS) {
7480 return ldb_module_done(ar->req, NULL, NULL, ret);
7489 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
7491 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
7492 struct replmd_private *replmd_private =
7493 talloc_get_type_abort(ldb_module_get_private(ar->module),
7494 struct replmd_private);
7496 static const char *attrs[] = {
7497 "replUpToDateVector",
7502 struct ldb_request *search_req;
7504 ar->search_msg = NULL;
7507 * Let the caller know that we did an originating updates
7509 ar->objs->originating_updates = replmd_private->originating_updates;
7511 ret = ldb_build_search_req(&search_req,
7514 ar->objs->partition_dn,
7520 replmd_replicated_uptodate_search_callback,
7522 LDB_REQ_SET_LOCATION(search_req);
7523 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
7525 return ldb_next_request(ar->module, search_req);
7530 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
7532 struct ldb_context *ldb;
7533 struct dsdb_extended_replicated_objects *objs;
7534 struct replmd_replicated_request *ar;
7535 struct ldb_control **ctrls;
7538 ldb = ldb_module_get_ctx(module);
7540 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
7542 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
7544 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
7545 return LDB_ERR_PROTOCOL_ERROR;
7548 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
7549 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
7550 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
7551 return LDB_ERR_PROTOCOL_ERROR;
7554 ar = replmd_ctx_init(module, req);
7556 return LDB_ERR_OPERATIONS_ERROR;
7558 /* Set the flags to have the replmd_op_callback run over the full set of objects */
7559 ar->apply_mode = true;
7561 ar->schema = dsdb_get_schema(ldb, ar);
7563 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
7565 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
7566 return LDB_ERR_CONSTRAINT_VIOLATION;
7569 ctrls = req->controls;
7571 if (req->controls) {
7572 req->controls = talloc_memdup(ar, req->controls,
7573 talloc_get_size(req->controls));
7574 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
7577 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
7578 if (ret != LDB_SUCCESS) {
7582 /* If this change contained linked attributes in the body
7583 * (rather than in the links section) we need to update
7584 * backlinks in linked_attributes */
7585 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
7586 if (ret != LDB_SUCCESS) {
7590 ar->controls = req->controls;
7591 req->controls = ctrls;
7593 return replmd_replicated_apply_next(ar);
7597 * Checks how to handle an missing target - either we need to fail the
7598 * replication and retry with GET_TGT, ignore the link and continue, or try to
7599 * add a partial link to an unknown target.
7601 static int replmd_allow_missing_target(struct ldb_module *module,
7602 TALLOC_CTX *mem_ctx,
7603 struct ldb_dn *target_dn,
7604 struct ldb_dn *source_dn,
7607 uint32_t dsdb_repl_flags,
7609 const char * missing_str)
7611 struct ldb_context *ldb = ldb_module_get_ctx(module);
7615 * we may not be able to resolve link targets properly when
7616 * dealing with subsets of objects, e.g. the source is a
7617 * critical object and the target isn't
7620 * When we implement Trusted Domains we need to consider
7621 * whether they get treated as an incomplete replica here or not
7623 if (dsdb_repl_flags & DSDB_REPL_FLAG_OBJECT_SUBSET) {
7626 * Ignore the link. We don't increase the highwater-mark in
7627 * the object subset cases, so subsequent replications should
7628 * resolve any missing links
7630 DEBUG(2, ("%s target %s linked from %s\n", missing_str,
7631 ldb_dn_get_linearized(target_dn),
7632 ldb_dn_get_linearized(source_dn)));
7633 *ignore_link = true;
7637 is_in_same_nc = dsdb_objects_have_same_nc(ldb,
7641 if (is_in_same_nc) {
7643 * We allow the join.py code to point out that all
7644 * replication is completed, so failing now would just
7645 * trigger errors, rather than trigger a GET_TGT
7647 int *finished_full_join_ptr =
7648 talloc_get_type(ldb_get_opaque(ldb,
7649 DSDB_FULL_JOIN_REPLICATION_COMPLETED_OPAQUE_NAME),
7651 bool finished_full_join = finished_full_join_ptr && *finished_full_join_ptr;
7654 * if the target is already be up-to-date there's no point in
7655 * retrying. This could be due to bad timing, or if a target
7656 * on a one-way link was deleted. We ignore the link rather
7657 * than failing the replication cycle completely
7659 if (finished_full_join
7660 || dsdb_repl_flags & DSDB_REPL_FLAG_TARGETS_UPTODATE) {
7661 *ignore_link = true;
7662 DBG_WARNING("%s is %s "
7663 "but up to date. Ignoring link from %s\n",
7664 ldb_dn_get_linearized(target_dn), missing_str,
7665 ldb_dn_get_linearized(source_dn));
7669 /* otherwise fail the replication and retry with GET_TGT */
7670 ldb_asprintf_errstring(ldb, "%s target %s GUID %s linked from %s\n",
7672 ldb_dn_get_linearized(target_dn),
7673 GUID_string(mem_ctx, guid),
7674 ldb_dn_get_linearized(source_dn));
7675 return LDB_ERR_NO_SUCH_OBJECT;
7679 * The target of the cross-partition link is missing. Continue
7680 * and try to at least add the forward-link. This isn't great,
7681 * but a partial link can be fixed by dbcheck, so it's better
7682 * than dropping the link completely.
7684 *ignore_link = false;
7686 if (is_obj_commit) {
7689 * Only log this when we're actually committing the objects.
7690 * This avoids spurious logs, i.e. if we're just verifying the
7691 * received link during a join.
7693 DBG_WARNING("%s cross-partition target %s linked from %s\n",
7694 missing_str, ldb_dn_get_linearized(target_dn),
7695 ldb_dn_get_linearized(source_dn));
7702 * Checks that the target object for a linked attribute exists.
7703 * @param guid returns the target object's GUID (is returned)if it exists)
7704 * @param ignore_link set to true if the linked attribute should be ignored
7705 * (i.e. the target doesn't exist, but that it's OK to skip the link)
7707 static int replmd_check_target_exists(struct ldb_module *module,
7708 struct dsdb_dn *dsdb_dn,
7709 struct la_entry *la_entry,
7710 struct ldb_dn *source_dn,
7715 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7716 struct ldb_context *ldb = ldb_module_get_ctx(module);
7717 struct ldb_result *target_res;
7718 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
7719 const char *attrs[] = { "isDeleted", "isRecycled", NULL };
7722 enum deletion_state target_deletion_state = OBJECT_REMOVED;
7723 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) ? true : false;
7725 *ignore_link = false;
7726 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, guid, "GUID");
7728 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
7731 * This strange behaviour (allowing a NULL/missing
7732 * GUID) originally comes from:
7734 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
7735 * Author: Andrew Tridgell <tridge@samba.org>
7736 * Date: Mon Dec 21 21:21:55 2009 +1100
7738 * s4-drs: cope better with NULL GUIDS from DRS
7740 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
7741 * need to match by DN if possible when seeing if we should update an
7744 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
7746 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
7748 DSDB_FLAG_NEXT_MODULE |
7749 DSDB_SEARCH_SHOW_RECYCLED |
7750 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7751 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
7753 } else if (!NT_STATUS_IS_OK(ntstatus)) {
7754 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute 0x%x blob for %s from %s",
7756 ldb_dn_get_linearized(dsdb_dn->dn),
7757 ldb_dn_get_linearized(source_dn));
7758 talloc_free(tmp_ctx);
7759 return LDB_ERR_OPERATIONS_ERROR;
7761 ret = dsdb_module_search(module, tmp_ctx, &target_res,
7762 NULL, LDB_SCOPE_SUBTREE,
7764 DSDB_FLAG_NEXT_MODULE |
7765 DSDB_SEARCH_SHOW_RECYCLED |
7766 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7767 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
7770 GUID_string(tmp_ctx, guid));
7773 if (ret != LDB_SUCCESS) {
7774 ldb_asprintf_errstring(ldb, "Failed to re-resolve GUID %s: %s\n",
7775 GUID_string(tmp_ctx, guid),
7776 ldb_errstring(ldb));
7777 talloc_free(tmp_ctx);
7781 if (target_res->count == 0) {
7784 * target object is unknown. Check whether to ignore the link,
7785 * fail the replication, or add a partial link
7787 ret = replmd_allow_missing_target(module, tmp_ctx, dsdb_dn->dn,
7788 source_dn, is_obj_commit, guid,
7789 la_entry->dsdb_repl_flags,
7790 ignore_link, "Unknown");
7792 } else if (target_res->count != 1) {
7793 ldb_asprintf_errstring(ldb, "More than one object found matching objectGUID %s\n",
7794 GUID_string(tmp_ctx, guid));
7795 ret = LDB_ERR_OPERATIONS_ERROR;
7797 struct ldb_message *target_msg = target_res->msgs[0];
7799 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
7801 /* Get the object's state (i.e. Not Deleted, Tombstone, etc) */
7802 replmd_deletion_state(module, target_msg,
7803 &target_deletion_state, NULL);
7806 * Check for deleted objects as per MS-DRSR 4.1.10.6.14
7807 * ProcessLinkValue(). Link updates should not be sent for
7808 * recycled and tombstone objects (deleting the links should
7809 * happen when we delete the object). This probably means our
7810 * copy of the target object isn't up to date.
7812 if (target_deletion_state >= OBJECT_RECYCLED) {
7815 * target object is deleted. Check whether to ignore the
7816 * link, fail the replication, or add a partial link
7818 ret = replmd_allow_missing_target(module, tmp_ctx,
7819 dsdb_dn->dn, source_dn,
7820 is_obj_commit, guid,
7821 la_entry->dsdb_repl_flags,
7822 ignore_link, "Deleted");
7826 talloc_free(tmp_ctx);
7831 * Extracts the key details about the source object for a
7832 * linked-attribute entry.
7833 * This returns the following details:
7834 * @param ret_attr the schema details for the linked attribute
7835 * @param source_msg the search result for the source object
7837 static int replmd_get_la_entry_source(struct ldb_module *module,
7838 struct la_entry *la_entry,
7839 TALLOC_CTX *mem_ctx,
7840 const struct dsdb_attribute **ret_attr,
7841 struct ldb_message **source_msg)
7843 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7844 struct ldb_context *ldb = ldb_module_get_ctx(module);
7845 const struct dsdb_schema *schema = dsdb_get_schema(ldb, mem_ctx);
7847 const struct dsdb_attribute *attr;
7848 struct ldb_result *res;
7849 const char *attrs[4];
7852 linked_attributes[0]:
7853 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
7855 identifier: struct drsuapi_DsReplicaObjectIdentifier
7856 __ndr_size : 0x0000003a (58)
7857 __ndr_size_sid : 0x00000000 (0)
7858 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
7860 __ndr_size_dn : 0x00000000 (0)
7862 attid : DRSUAPI_ATTID_member (0x1F)
7863 value: struct drsuapi_DsAttributeValue
7864 __ndr_size : 0x0000007e (126)
7866 blob : DATA_BLOB length=126
7867 flags : 0x00000001 (1)
7868 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
7869 originating_add_time : Wed Sep 2 22:20:01 2009 EST
7870 meta_data: struct drsuapi_DsReplicaMetaData
7871 version : 0x00000015 (21)
7872 originating_change_time : Wed Sep 2 23:39:07 2009 EST
7873 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
7874 originating_usn : 0x000000000001e19c (123292)
7876 (for cases where the link is to a normal DN)
7877 &target: struct drsuapi_DsReplicaObjectIdentifier3
7878 __ndr_size : 0x0000007e (126)
7879 __ndr_size_sid : 0x0000001c (28)
7880 guid : 7639e594-db75-4086-b0d4-67890ae46031
7881 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
7882 __ndr_size_dn : 0x00000022 (34)
7883 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
7886 /* find the attribute being modified */
7887 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
7889 struct GUID_txt_buf guid_str;
7890 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
7892 GUID_buf_string(&la->identifier->guid,
7894 return LDB_ERR_OPERATIONS_ERROR;
7898 * All attributes listed here must be dealt with in some way
7899 * by replmd_process_linked_attribute() otherwise in the case
7900 * of isDeleted: FALSE the modify will fail with:
7902 * Failed to apply linked attribute change 'attribute 'isDeleted':
7903 * invalid modify flags on
7904 * 'CN=g1_1527570609273,CN=Users,DC=samba,DC=example,DC=com':
7907 * This is because isDeleted is a Boolean, so FALSE is a
7908 * legitimate value (set by Samba's deletetest.py)
7910 attrs[0] = attr->lDAPDisplayName;
7911 attrs[1] = "isDeleted";
7912 attrs[2] = "isRecycled";
7916 * get the existing message from the db for the object with
7917 * this GUID, returning attribute being modified. We will then
7918 * use this msg as the basis for a modify call
7920 ret = dsdb_module_search(module, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
7921 DSDB_FLAG_NEXT_MODULE |
7922 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7923 DSDB_SEARCH_SHOW_RECYCLED |
7924 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
7925 DSDB_SEARCH_REVEAL_INTERNALS,
7927 "objectGUID=%s", GUID_string(mem_ctx, &la->identifier->guid));
7928 if (ret != LDB_SUCCESS) {
7931 if (res->count != 1) {
7932 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
7933 GUID_string(mem_ctx, &la->identifier->guid));
7934 return LDB_ERR_NO_SUCH_OBJECT;
7937 *source_msg = res->msgs[0];
7944 * Verifies the target object is known for a linked attribute
7946 static int replmd_verify_link_target(struct replmd_replicated_request *ar,
7947 TALLOC_CTX *mem_ctx,
7948 struct la_entry *la_entry,
7949 struct ldb_dn *src_dn,
7950 const struct dsdb_attribute *attr)
7952 int ret = LDB_SUCCESS;
7953 struct ldb_module *module = ar->module;
7954 struct dsdb_dn *tgt_dsdb_dn = NULL;
7955 struct GUID guid = GUID_zero();
7958 struct ldb_context *ldb = ldb_module_get_ctx(module);
7959 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7960 const struct dsdb_schema *schema = dsdb_get_schema(ldb, mem_ctx);
7962 /* the value blob for the attribute holds the target object DN */
7963 status = dsdb_dn_la_from_blob(ldb, attr, schema, mem_ctx,
7964 la->value.blob, &tgt_dsdb_dn);
7965 if (!W_ERROR_IS_OK(status)) {
7966 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
7967 attr->lDAPDisplayName,
7968 ldb_dn_get_linearized(src_dn),
7969 win_errstr(status));
7970 return LDB_ERR_OPERATIONS_ERROR;
7974 * We can skip the target object checks if we're only syncing critical
7975 * objects, or we know the target is up-to-date. If either case, we
7976 * still continue even if the target doesn't exist
7978 if ((la_entry->dsdb_repl_flags & (DSDB_REPL_FLAG_OBJECT_SUBSET |
7979 DSDB_REPL_FLAG_TARGETS_UPTODATE)) == 0) {
7981 ret = replmd_check_target_exists(module, tgt_dsdb_dn, la_entry,
7982 src_dn, false, &guid, &dummy);
7986 * When we fail to find the target object, the error code we pass
7987 * back here is really important. It flags back to the callers to
7988 * retry this request with DRSUAPI_DRS_GET_TGT
7990 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
7991 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_RECYCLED_TARGET);
7998 * Finds the current active Parsed-DN value for a single-valued linked
7999 * attribute, if one exists.
8000 * @param ret_pdn assigned the active Parsed-DN, or NULL if none was found
8001 * @returns LDB_SUCCESS (regardless of whether a match was found), unless
8004 static int replmd_get_active_singleval_link(struct ldb_module *module,
8005 TALLOC_CTX *mem_ctx,
8006 struct parsed_dn pdn_list[],
8008 const struct dsdb_attribute *attr,
8009 struct parsed_dn **ret_pdn)
8015 if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE)) {
8017 /* nothing to do for multi-valued linked attributes */
8021 for (i = 0; i < count; i++) {
8022 int ret = LDB_SUCCESS;
8023 struct parsed_dn *pdn = &pdn_list[i];
8025 /* skip any inactive links */
8026 if (dsdb_dn_is_deleted_val(pdn->v)) {
8030 /* we've found an active value for this attribute */
8033 if (pdn->dsdb_dn == NULL) {
8034 struct ldb_context *ldb = ldb_module_get_ctx(module);
8036 ret = really_parse_trusted_dn(mem_ctx, ldb, pdn,
8037 attr->syntax->ldap_oid);
8043 /* no active link found */
8048 * @returns true if the replication linked attribute info is newer than we
8049 * already have in our DB
8050 * @param pdn the existing linked attribute info in our DB
8051 * @param la the new linked attribute info received during replication
8053 static bool replmd_link_update_is_newer(struct parsed_dn *pdn,
8054 struct drsuapi_DsReplicaLinkedAttribute *la)
8056 /* see if this update is newer than what we have already */
8057 struct GUID invocation_id = GUID_zero();
8058 uint32_t version = 0;
8059 NTTIME change_time = 0;
8063 /* no existing info so update is newer */
8067 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
8068 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
8069 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
8071 return replmd_update_is_newer(&invocation_id,
8072 &la->meta_data.originating_invocation_id,
8074 la->meta_data.version,
8076 la->meta_data.originating_change_time);
8080 * Marks an existing linked attribute value as deleted in the DB
8081 * @param pdn the parsed-DN of the target-value to delete
8083 static int replmd_delete_link_value(struct ldb_module *module,
8084 struct replmd_private *replmd_private,
8085 TALLOC_CTX *mem_ctx,
8086 struct ldb_dn *src_obj_dn,
8087 const struct dsdb_schema *schema,
8088 const struct dsdb_attribute *attr,
8091 struct GUID *target_guid,
8092 struct dsdb_dn *target_dsdb_dn,
8093 struct ldb_val *output_val)
8095 struct ldb_context *ldb = ldb_module_get_ctx(module);
8098 const struct GUID *invocation_id = NULL;
8102 unix_to_nt_time(&now, t);
8104 invocation_id = samdb_ntds_invocation_id(ldb);
8105 if (invocation_id == NULL) {
8106 return LDB_ERR_OPERATIONS_ERROR;
8109 /* if the existing link is active, remove its backlink */
8113 * NOTE WELL: After this we will never (at runtime) be
8114 * able to find this forward link (for instant
8115 * removal) if/when the link target is deleted.
8117 * We have dbcheck rules to cover this and cope otherwise
8118 * by filtering at runtime (i.e. in the extended_dn module).
8120 ret = replmd_add_backlink(module, replmd_private, schema,
8121 src_obj_dn, target_guid, false,
8123 if (ret != LDB_SUCCESS) {
8128 /* mark the existing value as deleted */
8129 ret = replmd_update_la_val(mem_ctx, output_val, target_dsdb_dn,
8130 target_dsdb_dn, invocation_id, seq_num,
8131 seq_num, now, true);
8136 * Checks for a conflict in single-valued link attributes, and tries to
8137 * resolve the problem if possible.
8139 * Single-valued links should only ever have one active value. If we already
8140 * have an active link value, and during replication we receive an active link
8141 * value for a different target DN, then we need to resolve this inconsistency
8142 * and determine which value should be active. If the received info is better/
8143 * newer than the existing link attribute, then we need to set our existing
8144 * link as deleted. If the received info is worse/older, then we should continue
8145 * to add it, but set it as an inactive link.
8147 * Note that this is a corner-case that is unlikely to happen (but if it does
8148 * happen, we don't want it to break replication completely).
8150 * @param pdn_being_modified the parsed DN corresponding to the received link
8151 * target (note this is NULL if the link does not already exist in our DB)
8152 * @param pdn_list all the source object's Parsed-DNs for this attribute, i.e.
8153 * any existing active or inactive values for the attribute in our DB.
8154 * @param dsdb_dn the target DN for the received link attribute
8155 * @param add_as_inactive gets set to true if the received link is worse than
8156 * the existing link - it should still be added, but as an inactive link.
8158 static int replmd_check_singleval_la_conflict(struct ldb_module *module,
8159 struct replmd_private *replmd_private,
8160 TALLOC_CTX *mem_ctx,
8161 struct ldb_dn *src_obj_dn,
8162 struct drsuapi_DsReplicaLinkedAttribute *la,
8163 struct dsdb_dn *dsdb_dn,
8164 struct parsed_dn *pdn_being_modified,
8165 struct parsed_dn *pdn_list,
8166 struct ldb_message_element *old_el,
8167 const struct dsdb_schema *schema,
8168 const struct dsdb_attribute *attr,
8170 bool *add_as_inactive)
8172 struct parsed_dn *active_pdn = NULL;
8173 bool update_is_newer = false;
8177 * check if there's a conflict for single-valued links, i.e. an active
8178 * linked attribute already exists, but it has a different target value
8180 ret = replmd_get_active_singleval_link(module, mem_ctx, pdn_list,
8181 old_el->num_values, attr,
8184 if (ret != LDB_SUCCESS) {
8189 * If no active value exists (or the received info is for the currently
8190 * active value), then no conflict exists
8192 if (active_pdn == NULL || active_pdn == pdn_being_modified) {
8196 DBG_WARNING("Link conflict for %s attribute on %s\n",
8197 attr->lDAPDisplayName, ldb_dn_get_linearized(src_obj_dn));
8199 /* Work out how to resolve the conflict based on which info is better */
8200 update_is_newer = replmd_link_update_is_newer(active_pdn, la);
8202 if (update_is_newer) {
8203 DBG_WARNING("Using received value %s, over existing target %s\n",
8204 ldb_dn_get_linearized(dsdb_dn->dn),
8205 ldb_dn_get_linearized(active_pdn->dsdb_dn->dn));
8208 * Delete our existing active link. The received info will then
8209 * be added (through normal link processing) as the active value
8211 ret = replmd_delete_link_value(module, replmd_private, old_el,
8212 src_obj_dn, schema, attr,
8213 seq_num, true, &active_pdn->guid,
8214 active_pdn->dsdb_dn,
8217 if (ret != LDB_SUCCESS) {
8221 DBG_WARNING("Using existing target %s, over received value %s\n",
8222 ldb_dn_get_linearized(active_pdn->dsdb_dn->dn),
8223 ldb_dn_get_linearized(dsdb_dn->dn));
8226 * we want to keep our existing active link and add the
8227 * received link as inactive
8229 *add_as_inactive = true;
8236 * Processes one linked attribute received via replication.
8237 * @param src_dn the DN of the source object for the link
8238 * @param attr schema info for the linked attribute
8239 * @param la_entry the linked attribute info received via DRS
8240 * @param element_ctx mem context for msg->element[] (when adding a new value
8241 * we need to realloc old_el->values)
8242 * @param old_el the corresponding msg->element[] for the linked attribute
8243 * @param pdn_list a (binary-searchable) parsed DN array for the existing link
8244 * values in the msg. E.g. for a group, this is the existing members.
8245 * @param change what got modified: either nothing, an existing link value was
8246 * modified, or a new link value was added.
8247 * @returns LDB_SUCCESS if OK, an error otherwise
8249 static int replmd_process_linked_attribute(struct ldb_module *module,
8250 TALLOC_CTX *mem_ctx,
8251 struct replmd_private *replmd_private,
8252 struct ldb_dn *src_dn,
8253 const struct dsdb_attribute *attr,
8254 struct la_entry *la_entry,
8255 struct ldb_request *parent,
8256 TALLOC_CTX *element_ctx,
8257 struct ldb_message_element *old_el,
8258 struct parsed_dn *pdn_list,
8259 replmd_link_changed *change)
8261 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
8262 struct ldb_context *ldb = ldb_module_get_ctx(module);
8263 const struct dsdb_schema *schema = dsdb_get_schema(ldb, mem_ctx);
8265 struct dsdb_dn *dsdb_dn = NULL;
8266 uint64_t seq_num = 0;
8267 struct parsed_dn *pdn, *next;
8268 struct GUID guid = GUID_zero();
8269 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
8271 struct dsdb_dn *old_dsdb_dn = NULL;
8272 struct ldb_val *val_to_update = NULL;
8273 bool add_as_inactive = false;
8276 *change = LINK_CHANGE_NONE;
8278 /* the value blob for the attribute holds the target object DN */
8279 status = dsdb_dn_la_from_blob(ldb, attr, schema, mem_ctx,
8280 la->value.blob, &dsdb_dn);
8281 if (!W_ERROR_IS_OK(status)) {
8282 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
8283 attr->lDAPDisplayName,
8284 ldb_dn_get_linearized(src_dn),
8285 win_errstr(status));
8286 return LDB_ERR_OPERATIONS_ERROR;
8289 ret = replmd_check_target_exists(module, dsdb_dn, la_entry, src_dn,
8290 true, &guid, &ignore_link);
8292 if (ret != LDB_SUCCESS) {
8297 * there are some cases where the target object doesn't exist, but it's
8298 * OK to ignore the linked attribute
8304 /* see if this link already exists */
8305 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
8308 dsdb_dn->extra_part, 0,
8310 attr->syntax->ldap_oid,
8312 if (ret != LDB_SUCCESS) {
8316 if (!replmd_link_update_is_newer(pdn, la)) {
8317 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
8318 old_el->name, ldb_dn_get_linearized(src_dn),
8319 GUID_string(mem_ctx, &la->meta_data.originating_invocation_id)));
8323 /* get a seq_num for this change */
8324 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
8325 if (ret != LDB_SUCCESS) {
8330 * check for single-valued link conflicts, i.e. an active linked
8331 * attribute already exists, but it has a different target value
8334 ret = replmd_check_singleval_la_conflict(module, replmd_private,
8335 mem_ctx, src_dn, la,
8336 dsdb_dn, pdn, pdn_list,
8337 old_el, schema, attr,
8340 if (ret != LDB_SUCCESS) {
8346 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
8348 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
8349 /* remove the existing backlink */
8350 ret = replmd_add_backlink(module, replmd_private,
8353 &pdn->guid, false, attr,
8355 if (ret != LDB_SUCCESS) {
8360 val_to_update = pdn->v;
8361 old_dsdb_dn = pdn->dsdb_dn;
8362 *change = LINK_CHANGE_MODIFIED;
8368 * We know where the new one needs to be, from the *next
8369 * pointer into pdn_list.
8372 offset = old_el->num_values;
8374 if (next->dsdb_dn == NULL) {
8375 ret = really_parse_trusted_dn(mem_ctx, ldb, next,
8376 attr->syntax->ldap_oid);
8377 if (ret != LDB_SUCCESS) {
8381 offset = next - pdn_list;
8382 if (offset > old_el->num_values) {
8383 return LDB_ERR_OPERATIONS_ERROR;
8387 old_el->values = talloc_realloc(element_ctx, old_el->values,
8388 struct ldb_val, old_el->num_values+1);
8389 if (!old_el->values) {
8390 ldb_module_oom(module);
8391 return LDB_ERR_OPERATIONS_ERROR;
8394 if (offset != old_el->num_values) {
8395 memmove(&old_el->values[offset + 1], &old_el->values[offset],
8396 (old_el->num_values - offset) * sizeof(old_el->values[0]));
8399 old_el->num_values++;
8401 val_to_update = &old_el->values[offset];
8403 *change = LINK_CHANGE_ADDED;
8406 /* set the link attribute's value to the info that was received */
8407 ret = replmd_set_la_val(mem_ctx, val_to_update, dsdb_dn, old_dsdb_dn,
8408 &la->meta_data.originating_invocation_id,
8409 la->meta_data.originating_usn, seq_num,
8410 la->meta_data.originating_change_time,
8411 la->meta_data.version,
8413 if (ret != LDB_SUCCESS) {
8417 if (add_as_inactive) {
8419 /* Set the new link as inactive/deleted to avoid conflicts */
8420 ret = replmd_delete_link_value(module, replmd_private, old_el,
8421 src_dn, schema, attr, seq_num,
8422 false, &guid, dsdb_dn,
8425 if (ret != LDB_SUCCESS) {
8429 } else if (active) {
8431 /* if the new link is active, then add the new backlink */
8432 ret = replmd_add_backlink(module, replmd_private,
8437 if (ret != LDB_SUCCESS) {
8442 ret = dsdb_check_single_valued_link(attr, old_el);
8443 if (ret != LDB_SUCCESS) {
8447 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
8452 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
8454 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
8455 return replmd_extended_replicated_objects(module, req);
8458 return ldb_next_request(module, req);
8463 we hook into the transaction operations to allow us to
8464 perform the linked attribute updates at the end of the whole
8465 transaction. This allows a forward linked attribute to be created
8466 before the object is created. During a vampire, w2k8 sends us linked
8467 attributes before the objects they are part of.
8469 static int replmd_start_transaction(struct ldb_module *module)
8471 /* create our private structure for this transaction */
8472 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
8473 struct replmd_private);
8474 replmd_txn_cleanup(replmd_private);
8476 /* free any leftover mod_usn records from cancelled
8478 while (replmd_private->ncs) {
8479 struct nc_entry *e = replmd_private->ncs;
8480 DLIST_REMOVE(replmd_private->ncs, e);
8484 replmd_private->originating_updates = false;
8486 return ldb_next_start_trans(module);
8490 * Processes a group of linked attributes that apply to the same source-object
8491 * and attribute-ID (and were received in the same replication chunk).
8493 static int replmd_process_la_group(struct ldb_module *module,
8494 struct replmd_private *replmd_private,
8495 struct la_group *la_group)
8497 struct la_entry *la = NULL;
8498 struct la_entry *prev = NULL;
8500 TALLOC_CTX *tmp_ctx = NULL;
8501 struct la_entry *first_la = DLIST_TAIL(la_group->la_entries);
8502 struct ldb_message *msg = NULL;
8503 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
8504 struct ldb_context *ldb = ldb_module_get_ctx(module);
8505 const struct dsdb_attribute *attr = NULL;
8506 struct ldb_message_element *old_el = NULL;
8507 struct parsed_dn *pdn_list = NULL;
8508 replmd_link_changed change_type;
8509 uint32_t num_changes = 0;
8511 uint64_t seq_num = 0;
8513 tmp_ctx = talloc_new(la_group);
8514 if (tmp_ctx == NULL) {
8515 return ldb_oom(ldb);
8519 * get the attribute being modified and the search result for the
8522 ret = replmd_get_la_entry_source(module, first_la, tmp_ctx, &attr,
8525 if (ret != LDB_SUCCESS) {
8530 * Check for deleted objects per MS-DRSR 4.1.10.6.14
8531 * ProcessLinkValue, because link updates are not applied to
8532 * recycled and tombstone objects. We don't have to delete
8533 * any existing link, that should have happened when the
8534 * object deletion was replicated or initiated.
8536 * This needs isDeleted and isRecycled to be included as
8537 * attributes in the search and so in msg if set.
8539 replmd_deletion_state(module, msg, &deletion_state, NULL);
8541 if (deletion_state >= OBJECT_RECYCLED) {
8542 TALLOC_FREE(tmp_ctx);
8547 * Now that we know the deletion_state, remove the extra
8548 * attributes added for that purpose. We need to do this
8549 * otherwise in the case of isDeleted: FALSE the modify will
8552 * Failed to apply linked attribute change 'attribute 'isDeleted':
8553 * invalid modify flags on
8554 * 'CN=g1_1527570609273,CN=Users,DC=samba,DC=example,DC=com':
8557 * This is because isDeleted is a Boolean, so FALSE is a
8558 * legitimate value (set by Samba's deletetest.py)
8560 ldb_msg_remove_attr(msg, "isDeleted");
8561 ldb_msg_remove_attr(msg, "isRecycled");
8563 /* get the msg->element[] for the link attribute being processed */
8564 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
8565 if (old_el == NULL) {
8566 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName,
8567 LDB_FLAG_MOD_REPLACE, &old_el);
8568 if (ret != LDB_SUCCESS) {
8569 ldb_module_oom(module);
8570 return LDB_ERR_OPERATIONS_ERROR;
8573 old_el->flags = LDB_FLAG_MOD_REPLACE;
8577 * go through and process the link target value(s) for this particular
8578 * source object and attribute. For optimization, the same msg is used
8579 * across multiple calls to replmd_process_linked_attribute().
8580 * Note that we should not add or remove any msg attributes inside the
8581 * loop (we should only add/modify *values* for the attribute being
8582 * processed). Otherwise msg->elements is realloc'd and old_el/pdn_list
8583 * pointers will be invalidated
8585 for (la = DLIST_TAIL(la_group->la_entries); la; la=prev) {
8586 prev = DLIST_PREV(la);
8587 DLIST_REMOVE(la_group->la_entries, la);
8590 * parse the existing links (this can be costly for a large
8591 * group, so we try to minimize the times we do it)
8593 if (pdn_list == NULL) {
8594 ret = get_parsed_dns_trusted_fallback(module,
8598 attr->syntax->ldap_oid,
8601 if (ret != LDB_SUCCESS) {
8605 ret = replmd_process_linked_attribute(module, tmp_ctx,
8607 msg->dn, attr, la, NULL,
8608 msg->elements, old_el,
8609 pdn_list, &change_type);
8610 if (ret != LDB_SUCCESS) {
8611 replmd_txn_cleanup(replmd_private);
8616 * Adding a link reallocs memory, and so invalidates all the
8617 * pointers in pdn_list. Reparse the PDNs on the next loop
8619 if (change_type == LINK_CHANGE_ADDED) {
8620 TALLOC_FREE(pdn_list);
8623 if (change_type != LINK_CHANGE_NONE) {
8627 if ((++replmd_private->num_processed % 8192) == 0) {
8628 DBG_NOTICE("Processed %u/%u linked attributes\n",
8629 replmd_private->num_processed,
8630 replmd_private->total_links);
8635 * it's possible we're already up-to-date and so don't need to modify
8636 * the object at all (e.g. doing a 'drs replicate --full-sync')
8638 if (num_changes == 0) {
8639 TALLOC_FREE(tmp_ctx);
8644 * Note that adding the whenChanged/etc attributes below will realloc
8645 * msg->elements, invalidating the existing element/parsed-DN pointers
8648 TALLOC_FREE(pdn_list);
8650 /* update whenChanged/uSNChanged as the object has changed */
8652 ret = ldb_sequence_number(ldb, LDB_SEQ_HIGHEST_SEQ,
8654 if (ret != LDB_SUCCESS) {
8658 ret = add_time_element(msg, "whenChanged", t);
8659 if (ret != LDB_SUCCESS) {
8664 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
8665 if (ret != LDB_SUCCESS) {
8670 /* apply the link changes to the source object */
8671 ret = linked_attr_modify(module, msg, NULL);
8672 if (ret != LDB_SUCCESS) {
8673 ldb_debug(ldb, LDB_DEBUG_WARNING,
8674 "Failed to apply linked attribute change "
8675 "Error: '%s' DN: '%s' Attribute: '%s'\n",
8677 ldb_dn_get_linearized(msg->dn),
8678 attr->lDAPDisplayName);
8679 TALLOC_FREE(tmp_ctx);
8683 TALLOC_FREE(tmp_ctx);
8688 on prepare commit we loop over our queued la_context structures and
8691 static int replmd_prepare_commit(struct ldb_module *module)
8693 struct replmd_private *replmd_private =
8694 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
8695 struct la_group *la_group, *prev;
8698 if (replmd_private->la_list != NULL) {
8699 DBG_NOTICE("Processing linked attributes\n");
8703 * Walk the list of linked attributes from DRS replication.
8705 * We walk backwards, to do the first entry first, as we
8706 * added the entries with DLIST_ADD() which puts them at the
8709 * Links are grouped together so we process links for the same
8710 * source object in one go.
8712 for (la_group = DLIST_TAIL(replmd_private->la_list);
8716 prev = DLIST_PREV(la_group);
8717 DLIST_REMOVE(replmd_private->la_list, la_group);
8718 ret = replmd_process_la_group(module, replmd_private,
8720 if (ret != LDB_SUCCESS) {
8721 replmd_txn_cleanup(replmd_private);
8726 replmd_txn_cleanup(replmd_private);
8728 /* possibly change @REPLCHANGED */
8729 ret = replmd_notify_store(module, NULL);
8730 if (ret != LDB_SUCCESS) {
8734 return ldb_next_prepare_commit(module);
8737 static int replmd_del_transaction(struct ldb_module *module)
8739 struct replmd_private *replmd_private =
8740 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
8741 replmd_txn_cleanup(replmd_private);
8743 return ldb_next_del_trans(module);
8747 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
8748 .name = "repl_meta_data",
8749 .init_context = replmd_init,
8751 .modify = replmd_modify,
8752 .rename = replmd_rename,
8753 .del = replmd_delete,
8754 .extended = replmd_extended,
8755 .start_transaction = replmd_start_transaction,
8756 .prepare_commit = replmd_prepare_commit,
8757 .del_transaction = replmd_del_transaction,
8760 int ldb_repl_meta_data_module_init(const char *version)
8762 LDB_MODULE_CHECK_VERSION(version);
8763 return ldb_register_module(&ldb_repl_meta_data_module_ops);