4 Copyright (C) Simo Sorce 2004-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2013
6 Copyright (C) Andrew Tridgell 2005-2009
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8 Copyright (C) Matthieu Patou <mat@samba.org> 2010-2011
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 * Component: ldb repl_meta_data module
29 * Description: - add a unique objectGUID onto every new record,
30 * - handle whenCreated, whenChanged timestamps
31 * - handle uSNCreated, uSNChanged numbers
32 * - handle replPropertyMetaData attribute
35 * Author: Stefan Metzmacher
39 #include "ldb_module.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "dsdb/common/proto.h"
42 #include "dsdb/common/util.h"
43 #include "../libds/common/flags.h"
44 #include "librpc/gen_ndr/irpc.h"
45 #include "librpc/gen_ndr/ndr_misc.h"
46 #include "librpc/gen_ndr/ndr_drsuapi.h"
47 #include "librpc/gen_ndr/ndr_drsblobs.h"
48 #include "param/param.h"
49 #include "libcli/security/security.h"
50 #include "lib/util/dlinklist.h"
51 #include "dsdb/samdb/ldb_modules/util.h"
52 #include "lib/util/tsort.h"
55 * It's 29/12/9999 at 23:59:59 UTC as specified in MS-ADTS 7.1.1.4.2
56 * Deleted Objects Container
58 static const NTTIME DELETED_OBJECT_CONTAINER_CHANGE_TIME = 2650466015990000000ULL;
60 struct replmd_private {
62 struct la_entry *la_list;
64 struct nc_entry *prev, *next;
67 uint64_t mod_usn_urgent;
69 struct ldb_dn *schema_dn;
70 bool originating_updates;
75 struct la_entry *next, *prev;
76 struct drsuapi_DsReplicaLinkedAttribute *la;
77 bool incomplete_replica;
80 struct replmd_replicated_request {
81 struct ldb_module *module;
82 struct ldb_request *req;
84 const struct dsdb_schema *schema;
85 struct GUID our_invocation_id;
87 /* the controls we pass down */
88 struct ldb_control **controls;
91 * Backlinks for the replmd_add() case (we want to create
92 * backlinks after creating the user, but before the end of
95 struct la_backlink *la_backlinks;
97 /* details for the mode where we apply a bunch of inbound replication meessages */
99 uint32_t index_current;
100 struct dsdb_extended_replicated_objects *objs;
102 struct ldb_message *search_msg;
103 struct GUID local_parent_guid;
111 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
112 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
113 static int replmd_check_upgrade_links(struct ldb_context *ldb,
114 struct parsed_dn *dns, uint32_t count,
115 struct ldb_message_element *el,
116 const char *ldap_oid);
117 static int replmd_verify_linked_attribute(struct replmd_replicated_request *ar,
118 struct la_entry *la);
120 enum urgent_situation {
121 REPL_URGENT_ON_CREATE = 1,
122 REPL_URGENT_ON_UPDATE = 2,
123 REPL_URGENT_ON_DELETE = 4
126 enum deletion_state {
127 OBJECT_NOT_DELETED=1,
134 static void replmd_deletion_state(struct ldb_module *module,
135 const struct ldb_message *msg,
136 enum deletion_state *current_state,
137 enum deletion_state *next_state)
140 bool enabled = false;
143 *current_state = OBJECT_REMOVED;
144 if (next_state != NULL) {
145 *next_state = OBJECT_REMOVED;
150 ret = dsdb_recyclebin_enabled(module, &enabled);
151 if (ret != LDB_SUCCESS) {
155 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
157 *current_state = OBJECT_TOMBSTONE;
158 if (next_state != NULL) {
159 *next_state = OBJECT_REMOVED;
164 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
165 *current_state = OBJECT_RECYCLED;
166 if (next_state != NULL) {
167 *next_state = OBJECT_REMOVED;
172 *current_state = OBJECT_DELETED;
173 if (next_state != NULL) {
174 *next_state = OBJECT_RECYCLED;
179 *current_state = OBJECT_NOT_DELETED;
180 if (next_state == NULL) {
185 *next_state = OBJECT_DELETED;
187 *next_state = OBJECT_TOMBSTONE;
191 static const struct {
192 const char *update_name;
193 enum urgent_situation repl_situation;
194 } urgent_objects[] = {
195 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
196 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
197 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
198 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
199 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
200 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
204 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
205 static const char *urgent_attrs[] = {
208 "userAccountControl",
213 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
214 enum urgent_situation situation)
217 for (i=0; urgent_objects[i].update_name; i++) {
219 if ((situation & urgent_objects[i].repl_situation) == 0) {
223 for (j=0; j<objectclass_el->num_values; j++) {
224 const struct ldb_val *v = &objectclass_el->values[j];
225 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
233 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
235 if (ldb_attr_in_list(urgent_attrs, el->name)) {
241 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
244 initialise the module
245 allocate the private structure and build the list
246 of partition DNs for use by replmd_notify()
248 static int replmd_init(struct ldb_module *module)
250 struct replmd_private *replmd_private;
251 struct ldb_context *ldb = ldb_module_get_ctx(module);
252 static const char *samba_dsdb_attrs[] = { SAMBA_COMPATIBLE_FEATURES_ATTR, NULL };
253 struct ldb_dn *samba_dsdb_dn;
254 struct ldb_result *res;
256 TALLOC_CTX *frame = talloc_stackframe();
257 replmd_private = talloc_zero(module, struct replmd_private);
258 if (replmd_private == NULL) {
261 return LDB_ERR_OPERATIONS_ERROR;
263 ldb_module_set_private(module, replmd_private);
265 replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
267 samba_dsdb_dn = ldb_dn_new(frame, ldb, "@SAMBA_DSDB");
268 if (!samba_dsdb_dn) {
273 ret = dsdb_module_search_dn(module, frame, &res, samba_dsdb_dn,
274 samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
275 if (ret == LDB_SUCCESS) {
276 replmd_private->sorted_links
277 = ldb_msg_check_string_attribute(res->msgs[0],
278 SAMBA_COMPATIBLE_FEATURES_ATTR,
279 SAMBA_SORTED_LINKS_FEATURE);
283 return ldb_next_init(module);
287 cleanup our per-transaction contexts
289 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
291 talloc_free(replmd_private->la_ctx);
292 replmd_private->la_list = NULL;
293 replmd_private->la_ctx = NULL;
299 struct la_backlink *next, *prev;
300 const char *attr_name;
301 struct ldb_dn *forward_dn;
302 struct GUID target_guid;
307 a ldb_modify request operating on modules below the
310 static int linked_attr_modify(struct ldb_module *module,
311 const struct ldb_message *message,
312 struct ldb_request *parent)
314 struct ldb_request *mod_req;
316 struct ldb_context *ldb = ldb_module_get_ctx(module);
317 TALLOC_CTX *tmp_ctx = talloc_new(module);
318 struct ldb_result *res;
320 res = talloc_zero(tmp_ctx, struct ldb_result);
322 talloc_free(tmp_ctx);
323 return ldb_oom(ldb_module_get_ctx(module));
326 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
330 ldb_modify_default_callback,
332 LDB_REQ_SET_LOCATION(mod_req);
333 if (ret != LDB_SUCCESS) {
334 talloc_free(tmp_ctx);
338 ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
340 if (ret != LDB_SUCCESS) {
344 /* Run the new request */
345 ret = ldb_next_request(module, mod_req);
347 if (ret == LDB_SUCCESS) {
348 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
351 talloc_free(tmp_ctx);
356 process a backlinks we accumulated during a transaction, adding and
357 deleting the backlinks from the target objects
359 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
361 struct ldb_dn *target_dn, *source_dn;
363 struct ldb_context *ldb = ldb_module_get_ctx(module);
364 struct ldb_message *msg;
365 TALLOC_CTX *frame = talloc_stackframe();
371 - construct ldb_message
372 - either an add or a delete
374 ret = dsdb_module_dn_by_guid(module, frame, &bl->target_guid, &target_dn, parent);
375 if (ret != LDB_SUCCESS) {
376 struct GUID_txt_buf guid_str;
377 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
378 GUID_buf_string(&bl->target_guid, &guid_str)));
383 msg = ldb_msg_new(frame);
385 ldb_module_oom(module);
387 return LDB_ERR_OPERATIONS_ERROR;
390 source_dn = ldb_dn_copy(frame, bl->forward_dn);
392 ldb_module_oom(module);
394 return LDB_ERR_OPERATIONS_ERROR;
396 /* Filter down to the attributes we want in the backlink */
397 const char *accept[] = { "GUID", "SID", NULL };
398 ldb_dn_extended_filter(source_dn, accept);
401 /* construct a ldb_message for adding/deleting the backlink */
403 dn_string = ldb_dn_get_extended_linearized(frame, bl->forward_dn, 1);
405 ldb_module_oom(module);
407 return LDB_ERR_OPERATIONS_ERROR;
409 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
410 if (ret != LDB_SUCCESS) {
414 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
416 /* a backlink should never be single valued. Unfortunately the
417 exchange schema has a attribute
418 msExchBridgeheadedLocalConnectorsDNBL which is single
419 valued and a backlink. We need to cope with that by
420 ignoring the single value flag */
421 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
423 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
424 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
425 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
426 cope with possible corruption where the backlink has
427 already been removed */
428 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
429 ldb_dn_get_linearized(target_dn),
430 ldb_dn_get_linearized(source_dn),
431 ldb_errstring(ldb)));
433 } else if (ret != LDB_SUCCESS) {
434 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
435 bl->active?"add":"remove",
436 ldb_dn_get_linearized(source_dn),
437 ldb_dn_get_linearized(target_dn),
447 add a backlink to the list of backlinks to add/delete in the prepare
450 forward_dn is stolen onto the defereed context
452 static int replmd_defer_add_backlink(struct ldb_module *module,
453 struct replmd_private *replmd_private,
454 const struct dsdb_schema *schema,
455 struct replmd_replicated_request *ac,
456 struct ldb_dn *forward_dn,
457 struct GUID *target_guid, bool active,
458 const struct dsdb_attribute *schema_attr,
459 struct ldb_request *parent)
461 const struct dsdb_attribute *target_attr;
462 struct la_backlink *bl;
464 bl = talloc(ac, struct la_backlink);
466 ldb_module_oom(module);
467 return LDB_ERR_OPERATIONS_ERROR;
470 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
473 * windows 2003 has a broken schema where the
474 * definition of msDS-IsDomainFor is missing (which is
475 * supposed to be the backlink of the
476 * msDS-HasDomainNCs attribute
481 bl->attr_name = target_attr->lDAPDisplayName;
482 bl->forward_dn = talloc_steal(bl, forward_dn);
483 bl->target_guid = *target_guid;
486 DLIST_ADD(ac->la_backlinks, bl);
492 add a backlink to the list of backlinks to add/delete in the prepare
495 static int replmd_add_backlink(struct ldb_module *module,
496 struct replmd_private *replmd_private,
497 const struct dsdb_schema *schema,
498 struct ldb_dn *forward_dn,
499 struct GUID *target_guid, bool active,
500 const struct dsdb_attribute *schema_attr,
501 struct ldb_request *parent)
503 const struct dsdb_attribute *target_attr;
504 struct la_backlink bl;
507 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
510 * windows 2003 has a broken schema where the
511 * definition of msDS-IsDomainFor is missing (which is
512 * supposed to be the backlink of the
513 * msDS-HasDomainNCs attribute
518 bl.attr_name = target_attr->lDAPDisplayName;
519 bl.forward_dn = forward_dn;
520 bl.target_guid = *target_guid;
523 ret = replmd_process_backlink(module, &bl, parent);
529 * Callback for most write operations in this module:
531 * notify the repl task that a object has changed. The notifies are
532 * gathered up in the replmd_private structure then written to the
533 * @REPLCHANGED object in each partition during the prepare_commit
535 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
538 struct replmd_replicated_request *ac =
539 talloc_get_type_abort(req->context, struct replmd_replicated_request);
540 struct replmd_private *replmd_private =
541 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
542 struct nc_entry *modified_partition;
543 struct ldb_control *partition_ctrl;
544 const struct dsdb_control_current_partition *partition;
546 struct ldb_control **controls;
548 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
550 controls = ares->controls;
551 if (ldb_request_get_control(ac->req,
552 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
554 * Remove the current partition control from what we pass up
555 * the chain if it hasn't been requested manually.
557 controls = ldb_controls_except_specified(ares->controls, ares,
561 if (ares->error != LDB_SUCCESS) {
562 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
563 return ldb_module_done(ac->req, controls,
564 ares->response, ares->error);
567 if (ares->type != LDB_REPLY_DONE) {
568 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
569 return ldb_module_done(ac->req, NULL,
570 NULL, LDB_ERR_OPERATIONS_ERROR);
573 if (ac->apply_mode == false) {
574 struct la_backlink *bl;
576 * process our backlink list after an replmd_add(),
577 * creating and deleting backlinks as necessary (this
578 * code is sync). The other cases are handled inline
581 for (bl=ac->la_backlinks; bl; bl=bl->next) {
582 ret = replmd_process_backlink(ac->module, bl, ac->req);
583 if (ret != LDB_SUCCESS) {
584 return ldb_module_done(ac->req, NULL,
590 if (!partition_ctrl) {
591 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
592 return ldb_module_done(ac->req, NULL,
593 NULL, LDB_ERR_OPERATIONS_ERROR);
596 partition = talloc_get_type_abort(partition_ctrl->data,
597 struct dsdb_control_current_partition);
599 if (ac->seq_num > 0) {
600 for (modified_partition = replmd_private->ncs; modified_partition;
601 modified_partition = modified_partition->next) {
602 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
607 if (modified_partition == NULL) {
608 modified_partition = talloc_zero(replmd_private, struct nc_entry);
609 if (!modified_partition) {
610 ldb_oom(ldb_module_get_ctx(ac->module));
611 return ldb_module_done(ac->req, NULL,
612 NULL, LDB_ERR_OPERATIONS_ERROR);
614 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
615 if (!modified_partition->dn) {
616 ldb_oom(ldb_module_get_ctx(ac->module));
617 return ldb_module_done(ac->req, NULL,
618 NULL, LDB_ERR_OPERATIONS_ERROR);
620 DLIST_ADD(replmd_private->ncs, modified_partition);
623 if (ac->seq_num > modified_partition->mod_usn) {
624 modified_partition->mod_usn = ac->seq_num;
626 modified_partition->mod_usn_urgent = ac->seq_num;
629 if (!ac->apply_mode) {
630 replmd_private->originating_updates = true;
634 if (ac->apply_mode) {
635 ret = replmd_replicated_apply_isDeleted(ac);
636 if (ret != LDB_SUCCESS) {
637 return ldb_module_done(ac->req, NULL, NULL, ret);
641 /* free the partition control container here, for the
642 * common path. Other cases will have it cleaned up
643 * eventually with the ares */
644 talloc_free(partition_ctrl);
645 return ldb_module_done(ac->req, controls,
646 ares->response, LDB_SUCCESS);
652 * update a @REPLCHANGED record in each partition if there have been
653 * any writes of replicated data in the partition
655 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
657 struct replmd_private *replmd_private =
658 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
660 while (replmd_private->ncs) {
662 struct nc_entry *modified_partition = replmd_private->ncs;
664 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
665 modified_partition->mod_usn,
666 modified_partition->mod_usn_urgent, parent);
667 if (ret != LDB_SUCCESS) {
668 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
669 ldb_dn_get_linearized(modified_partition->dn)));
673 if (ldb_dn_compare(modified_partition->dn,
674 replmd_private->schema_dn) == 0) {
675 struct ldb_result *ext_res;
676 ret = dsdb_module_extended(module,
677 replmd_private->schema_dn,
679 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
681 DSDB_FLAG_NEXT_MODULE,
683 if (ret != LDB_SUCCESS) {
686 talloc_free(ext_res);
689 DLIST_REMOVE(replmd_private->ncs, modified_partition);
690 talloc_free(modified_partition);
698 created a replmd_replicated_request context
700 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
701 struct ldb_request *req)
703 struct ldb_context *ldb;
704 struct replmd_replicated_request *ac;
705 const struct GUID *our_invocation_id;
707 ldb = ldb_module_get_ctx(module);
709 ac = talloc_zero(req, struct replmd_replicated_request);
718 ac->schema = dsdb_get_schema(ldb, ac);
720 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
721 "replmd_modify: no dsdb_schema loaded");
722 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
727 /* get our invocationId */
728 our_invocation_id = samdb_ntds_invocation_id(ldb);
729 if (!our_invocation_id) {
730 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
731 "replmd_add: unable to find invocationId\n");
735 ac->our_invocation_id = *our_invocation_id;
741 add a time element to a record
743 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
745 struct ldb_message_element *el;
749 if (ldb_msg_find_element(msg, attr) != NULL) {
753 s = ldb_timestring(msg, t);
755 return LDB_ERR_OPERATIONS_ERROR;
758 ret = ldb_msg_add_string(msg, attr, s);
759 if (ret != LDB_SUCCESS) {
763 el = ldb_msg_find_element(msg, attr);
764 /* always set as replace. This works because on add ops, the flag
766 el->flags = LDB_FLAG_MOD_REPLACE;
772 add a uint64_t element to a record
774 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
775 const char *attr, uint64_t v)
777 struct ldb_message_element *el;
780 if (ldb_msg_find_element(msg, attr) != NULL) {
784 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
785 if (ret != LDB_SUCCESS) {
789 el = ldb_msg_find_element(msg, attr);
790 /* always set as replace. This works because on add ops, the flag
792 el->flags = LDB_FLAG_MOD_REPLACE;
797 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
798 const struct replPropertyMetaData1 *m2,
799 const uint32_t *rdn_attid)
802 * This assignment seems inoccous, but it is critical for the
803 * system, as we need to do the comparisons as a unsigned
804 * quantity, not signed (enums are signed integers)
806 uint32_t attid_1 = m1->attid;
807 uint32_t attid_2 = m2->attid;
809 if (attid_1 == attid_2) {
814 * See above regarding this being an unsigned comparison.
815 * Otherwise when the high bit is set on non-standard
816 * attributes, they would end up first, before objectClass
819 return attid_1 > attid_2 ? 1 : -1;
822 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
823 struct replPropertyMetaDataCtr1 *ctr1,
826 if (ctr1->count == 0) {
827 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
828 "No elements found in replPropertyMetaData for %s!\n",
829 ldb_dn_get_linearized(dn));
830 return LDB_ERR_CONSTRAINT_VIOLATION;
833 /* the objectClass attribute is value 0x00000000, so must be first */
834 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
835 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
836 "No objectClass found in replPropertyMetaData for %s!\n",
837 ldb_dn_get_linearized(dn));
838 return LDB_ERR_OBJECT_CLASS_VIOLATION;
844 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
845 struct replPropertyMetaDataCtr1 *ctr1,
848 /* Note this is O(n^2) for the almost-sorted case, which this is */
849 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
850 replmd_replPropertyMetaData1_attid_sort);
851 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
854 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
855 const struct ldb_message_element *e2,
856 const struct dsdb_schema *schema)
858 const struct dsdb_attribute *a1;
859 const struct dsdb_attribute *a2;
862 * TODO: make this faster by caching the dsdb_attribute pointer
863 * on the ldb_messag_element
866 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
867 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
870 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
874 return strcasecmp(e1->name, e2->name);
876 if (a1->attributeID_id == a2->attributeID_id) {
879 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
882 static void replmd_ldb_message_sort(struct ldb_message *msg,
883 const struct dsdb_schema *schema)
885 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
888 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
889 const struct GUID *invocation_id, uint64_t seq_num,
890 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
892 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2);
894 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
895 struct ldb_message_element *el, struct parsed_dn **pdn,
896 const char *ldap_oid, struct ldb_request *parent);
899 fix up linked attributes in replmd_add.
900 This involves setting up the right meta-data in extended DN
901 components, and creating backlinks to the object
903 static int replmd_add_fix_la(struct ldb_module *module, TALLOC_CTX *mem_ctx,
904 struct replmd_private *replmd_private,
905 struct ldb_message_element *el,
906 struct replmd_replicated_request *ac,
908 struct ldb_dn *forward_dn,
909 const struct dsdb_attribute *sa,
910 struct ldb_request *parent)
913 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
914 struct ldb_context *ldb = ldb_module_get_ctx(module);
915 struct parsed_dn *pdn;
916 /* We will take a reference to the schema in replmd_add_backlink */
917 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
918 struct ldb_val *new_values = NULL;
921 if (dsdb_check_single_valued_link(sa, el) == LDB_SUCCESS) {
922 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
924 ldb_asprintf_errstring(ldb,
925 "Attribute %s is single valued but "
926 "more than one value has been supplied",
928 talloc_free(tmp_ctx);
929 return LDB_ERR_CONSTRAINT_VIOLATION;
932 ret = get_parsed_dns(module, tmp_ctx, el, &pdn,
933 sa->syntax->ldap_oid, parent);
934 if (ret != LDB_SUCCESS) {
935 talloc_free(tmp_ctx);
939 new_values = talloc_array(tmp_ctx, struct ldb_val, el->num_values);
940 if (new_values == NULL) {
941 ldb_module_oom(module);
942 talloc_free(tmp_ctx);
943 return LDB_ERR_OPERATIONS_ERROR;
946 for (i = 0; i < el->num_values; i++) {
947 struct parsed_dn *p = &pdn[i];
948 if (i > 0 && parsed_dn_compare(p, &pdn[i - 1]) == 0) {
949 ldb_asprintf_errstring(ldb,
950 "Linked attribute %s has "
951 "multiple identical values", el->name);
952 talloc_free(tmp_ctx);
953 if (ldb_attr_cmp(el->name, "member") == 0) {
954 return LDB_ERR_ENTRY_ALREADY_EXISTS;
956 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
959 ret = replmd_build_la_val(el->values, p->v, p->dsdb_dn,
960 &ac->our_invocation_id,
961 ac->seq_num, ac->seq_num, now, 0, false);
962 if (ret != LDB_SUCCESS) {
963 talloc_free(tmp_ctx);
967 ret = replmd_defer_add_backlink(module, replmd_private,
969 forward_dn, &p->guid, true, sa,
971 if (ret != LDB_SUCCESS) {
972 talloc_free(tmp_ctx);
976 new_values[i] = *p->v;
978 el->values = talloc_steal(mem_ctx, new_values);
980 talloc_free(tmp_ctx);
984 static int replmd_add_make_extended_dn(struct ldb_request *req,
985 const DATA_BLOB *guid_blob,
986 struct ldb_dn **_extended_dn)
989 const DATA_BLOB *sid_blob;
990 /* Calculate an extended DN for any linked attributes */
991 struct ldb_dn *extended_dn = ldb_dn_copy(req, req->op.add.message->dn);
993 return LDB_ERR_OPERATIONS_ERROR;
995 ret = ldb_dn_set_extended_component(extended_dn, "GUID", guid_blob);
996 if (ret != LDB_SUCCESS) {
1000 sid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectSID");
1001 if (sid_blob != NULL) {
1002 ret = ldb_dn_set_extended_component(extended_dn, "SID", sid_blob);
1003 if (ret != LDB_SUCCESS) {
1007 *_extended_dn = extended_dn;
1012 intercept add requests
1014 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
1016 struct ldb_context *ldb;
1017 struct ldb_control *control;
1018 struct replmd_replicated_request *ac;
1019 enum ndr_err_code ndr_err;
1020 struct ldb_request *down_req;
1021 struct ldb_message *msg;
1022 const DATA_BLOB *guid_blob;
1023 DATA_BLOB guid_blob_stack;
1025 uint8_t guid_data[16];
1026 struct replPropertyMetaDataBlob nmd;
1027 struct ldb_val nmd_value;
1028 struct ldb_dn *extended_dn = NULL;
1031 * The use of a time_t here seems odd, but as the NTTIME
1032 * elements are actually declared as NTTIME_1sec in the IDL,
1033 * getting a higher resolution timestamp is not required.
1035 time_t t = time(NULL);
1040 unsigned int functional_level;
1042 bool allow_add_guid = false;
1043 bool remove_current_guid = false;
1044 bool is_urgent = false;
1045 bool is_schema_nc = false;
1046 struct ldb_message_element *objectclass_el;
1047 struct replmd_private *replmd_private =
1048 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
1050 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
1051 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
1053 allow_add_guid = true;
1056 /* do not manipulate our control entries */
1057 if (ldb_dn_is_special(req->op.add.message->dn)) {
1058 return ldb_next_request(module, req);
1061 ldb = ldb_module_get_ctx(module);
1063 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
1065 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
1066 if (guid_blob != NULL) {
1067 if (!allow_add_guid) {
1068 ldb_set_errstring(ldb,
1069 "replmd_add: it's not allowed to add an object with objectGUID!");
1070 return LDB_ERR_UNWILLING_TO_PERFORM;
1072 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
1073 if (!NT_STATUS_IS_OK(status)) {
1074 ldb_set_errstring(ldb,
1075 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1076 return LDB_ERR_UNWILLING_TO_PERFORM;
1078 /* we remove this attribute as it can be a string and
1079 * will not be treated correctly and then we will re-add
1080 * it later on in the good format */
1081 remove_current_guid = true;
1085 guid = GUID_random();
1087 guid_blob_stack = data_blob_const(guid_data, sizeof(guid_data));
1089 /* This can't fail */
1090 ndr_push_struct_into_fixed_blob(&guid_blob_stack, &guid,
1091 (ndr_push_flags_fn_t)ndr_push_GUID);
1092 guid_blob = &guid_blob_stack;
1095 ac = replmd_ctx_init(module, req);
1097 return ldb_module_oom(module);
1100 functional_level = dsdb_functional_level(ldb);
1102 /* Get a sequence number from the backend */
1103 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1104 if (ret != LDB_SUCCESS) {
1109 /* we have to copy the message as the caller might have it as a const */
1110 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1114 return LDB_ERR_OPERATIONS_ERROR;
1117 /* generated times */
1118 unix_to_nt_time(&now, t);
1119 time_str = ldb_timestring(msg, t);
1123 return LDB_ERR_OPERATIONS_ERROR;
1125 if (remove_current_guid) {
1126 ldb_msg_remove_attr(msg,"objectGUID");
1130 * remove autogenerated attributes
1132 ldb_msg_remove_attr(msg, "whenCreated");
1133 ldb_msg_remove_attr(msg, "whenChanged");
1134 ldb_msg_remove_attr(msg, "uSNCreated");
1135 ldb_msg_remove_attr(msg, "uSNChanged");
1136 ldb_msg_remove_attr(msg, "replPropertyMetaData");
1139 * readd replicated attributes
1141 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1142 if (ret != LDB_SUCCESS) {
1148 /* build the replication meta_data */
1151 nmd.ctr.ctr1.count = msg->num_elements;
1152 nmd.ctr.ctr1.array = talloc_array(msg,
1153 struct replPropertyMetaData1,
1154 nmd.ctr.ctr1.count);
1155 if (!nmd.ctr.ctr1.array) {
1158 return LDB_ERR_OPERATIONS_ERROR;
1161 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1163 for (i=0; i < msg->num_elements;) {
1164 struct ldb_message_element *e = &msg->elements[i];
1165 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1166 const struct dsdb_attribute *sa;
1168 if (e->name[0] == '@') {
1173 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1175 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1176 "replmd_add: attribute '%s' not defined in schema\n",
1179 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1182 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1183 /* if the attribute is not replicated (0x00000001)
1184 * or constructed (0x00000004) it has no metadata
1190 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1191 if (extended_dn == NULL) {
1192 ret = replmd_add_make_extended_dn(req,
1195 if (ret != LDB_SUCCESS) {
1202 * Prepare the context for the backlinks and
1203 * create metadata for the forward links. The
1204 * backlinks are created in
1205 * replmd_op_callback() after the successful
1206 * ADD of the object.
1208 ret = replmd_add_fix_la(module, msg->elements,
1213 if (ret != LDB_SUCCESS) {
1217 /* linked attributes are not stored in
1218 replPropertyMetaData in FL above w2k */
1223 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1225 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1226 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1229 if (rdn_val == NULL) {
1232 return LDB_ERR_OPERATIONS_ERROR;
1235 rdn = (const char*)rdn_val->data;
1236 if (strcmp(rdn, "Deleted Objects") == 0) {
1238 * Set the originating_change_time to 29/12/9999 at 23:59:59
1239 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1241 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1243 m->originating_change_time = now;
1246 m->originating_change_time = now;
1248 m->originating_invocation_id = ac->our_invocation_id;
1249 m->originating_usn = ac->seq_num;
1250 m->local_usn = ac->seq_num;
1253 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1258 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1260 if (e->num_values != 0) {
1265 ldb_msg_remove_element(msg, e);
1268 /* fix meta data count */
1269 nmd.ctr.ctr1.count = ni;
1272 * sort meta data array
1274 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1275 if (ret != LDB_SUCCESS) {
1276 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1281 /* generated NDR encoded values */
1282 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1284 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1285 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1288 return LDB_ERR_OPERATIONS_ERROR;
1292 * add the autogenerated values
1294 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1295 if (ret != LDB_SUCCESS) {
1300 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1301 if (ret != LDB_SUCCESS) {
1306 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1307 if (ret != LDB_SUCCESS) {
1312 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1313 if (ret != LDB_SUCCESS) {
1318 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1319 if (ret != LDB_SUCCESS) {
1326 * sort the attributes by attid before storing the object
1328 replmd_ldb_message_sort(msg, ac->schema);
1331 * Assert that we do have an objectClass
1333 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1334 if (objectclass_el == NULL) {
1335 ldb_asprintf_errstring(ldb, __location__
1336 ": objectClass missing on %s\n",
1337 ldb_dn_get_linearized(msg->dn));
1339 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1341 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1342 REPL_URGENT_ON_CREATE);
1344 ac->is_urgent = is_urgent;
1345 ret = ldb_build_add_req(&down_req, ldb, ac,
1348 ac, replmd_op_callback,
1351 LDB_REQ_SET_LOCATION(down_req);
1352 if (ret != LDB_SUCCESS) {
1357 /* current partition control is needed by "replmd_op_callback" */
1358 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1359 ret = ldb_request_add_control(down_req,
1360 DSDB_CONTROL_CURRENT_PARTITION_OID,
1362 if (ret != LDB_SUCCESS) {
1368 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1369 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1370 if (ret != LDB_SUCCESS) {
1376 /* mark the control done */
1378 control->critical = 0;
1380 /* go on with the call chain */
1381 return ldb_next_request(module, down_req);
1386 * update the replPropertyMetaData for one element
1388 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1389 struct ldb_message *msg,
1390 struct ldb_message_element *el,
1391 struct ldb_message_element *old_el,
1392 struct replPropertyMetaDataBlob *omd,
1393 const struct dsdb_schema *schema,
1395 const struct GUID *our_invocation_id,
1398 bool is_forced_rodc,
1399 struct ldb_request *req)
1402 const struct dsdb_attribute *a;
1403 struct replPropertyMetaData1 *md1;
1404 bool may_skip = false;
1407 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1409 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1410 /* allow this to make it possible for dbcheck
1411 to remove bad attributes */
1415 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1417 return LDB_ERR_OPERATIONS_ERROR;
1420 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1422 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1427 * if the attribute's value haven't changed, and this isn't
1428 * just a delete of everything then return LDB_SUCCESS Unless
1429 * we have the provision control or if the attribute is
1430 * interSiteTopologyGenerator as this page explain:
1431 * http://support.microsoft.com/kb/224815 this attribute is
1432 * periodicaly written by the DC responsible for the intersite
1433 * generation in a given site
1435 * Unchanged could be deleting or replacing an already-gone
1436 * thing with an unconstrained delete/empty replace or a
1437 * replace with the same value, but not an add with the same
1438 * value because that could be about adding a duplicate (which
1439 * is for someone else to error out on).
1441 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1442 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1445 } else if (old_el == NULL && el->num_values == 0) {
1446 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1448 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1451 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1452 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1454 * We intentionally skip the version bump when attempting to
1457 * The control is set by dbcheck and expunge-tombstones which
1458 * both attempt to be non-replicating. Otherwise, making an
1459 * alteration to the replication state would trigger a
1460 * broadcast of all expunged objects.
1465 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1467 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1471 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1472 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1474 * allow this to make it possible for dbcheck
1475 * to rebuild broken metadata
1481 for (i=0; i<omd->ctr.ctr1.count; i++) {
1483 * First check if we find it under the msDS-IntID,
1484 * then check if we find it under the OID and
1487 * This allows the administrator to simply re-write
1488 * the attributes and so restore replication, which is
1489 * likely what they will try to do.
1491 if (attid == omd->ctr.ctr1.array[i].attid) {
1495 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1500 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1501 /* linked attributes are not stored in
1502 replPropertyMetaData in FL above w2k, but we do
1503 raise the seqnum for the object */
1504 if (*seq_num == 0 &&
1505 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1506 return LDB_ERR_OPERATIONS_ERROR;
1511 if (i == omd->ctr.ctr1.count) {
1512 /* we need to add a new one */
1513 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1514 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1515 if (omd->ctr.ctr1.array == NULL) {
1517 return LDB_ERR_OPERATIONS_ERROR;
1519 omd->ctr.ctr1.count++;
1520 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1523 /* Get a new sequence number from the backend. We only do this
1524 * if we have a change that requires a new
1525 * replPropertyMetaData element
1527 if (*seq_num == 0) {
1528 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1529 if (ret != LDB_SUCCESS) {
1530 return LDB_ERR_OPERATIONS_ERROR;
1534 md1 = &omd->ctr.ctr1.array[i];
1538 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1539 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1542 if (rdn_val == NULL) {
1544 return LDB_ERR_OPERATIONS_ERROR;
1547 rdn = (const char*)rdn_val->data;
1548 if (strcmp(rdn, "Deleted Objects") == 0) {
1550 * Set the originating_change_time to 29/12/9999 at 23:59:59
1551 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1553 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1555 md1->originating_change_time = now;
1558 md1->originating_change_time = now;
1560 md1->originating_invocation_id = *our_invocation_id;
1561 md1->originating_usn = *seq_num;
1562 md1->local_usn = *seq_num;
1564 if (is_forced_rodc) {
1565 /* Force version to 0 to be overriden later via replication */
1573 * Bump the replPropertyMetaData version on an attribute, and if it
1574 * has changed (or forced by leaving rdn_old NULL), update the value
1577 * This is important, as calling a modify operation may not change the
1578 * version number if the values appear unchanged, but a rename between
1579 * parents bumps this value.
1582 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1583 struct ldb_message *msg,
1584 const struct ldb_val *rdn_new,
1585 const struct ldb_val *rdn_old,
1586 struct replPropertyMetaDataBlob *omd,
1587 struct replmd_replicated_request *ar,
1590 bool is_forced_rodc)
1592 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1593 const struct dsdb_attribute *rdn_attr =
1594 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1595 const char *attr_name = rdn_attr != NULL ?
1596 rdn_attr->lDAPDisplayName :
1598 struct ldb_message_element new_el = {
1599 .flags = LDB_FLAG_MOD_REPLACE,
1602 .values = discard_const_p(struct ldb_val, rdn_new)
1604 struct ldb_message_element old_el = {
1605 .flags = LDB_FLAG_MOD_REPLACE,
1607 .num_values = rdn_old ? 1 : 0,
1608 .values = discard_const_p(struct ldb_val, rdn_old)
1611 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1612 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1613 if (ret != LDB_SUCCESS) {
1614 return ldb_oom(ldb);
1618 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1619 omd, ar->schema, &ar->seq_num,
1620 &ar->our_invocation_id,
1621 now, is_schema_nc, is_forced_rodc,
1626 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1628 uint32_t count = omd.ctr.ctr1.count;
1631 for (i=0; i < count; i++) {
1632 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1633 if (max < m.local_usn) {
1641 * update the replPropertyMetaData object each time we modify an
1642 * object. This is needed for DRS replication, as the merge on the
1643 * client is based on this object
1645 static int replmd_update_rpmd(struct ldb_module *module,
1646 const struct dsdb_schema *schema,
1647 struct ldb_request *req,
1648 const char * const *rename_attrs,
1649 struct ldb_message *msg, uint64_t *seq_num,
1650 time_t t, bool is_schema_nc,
1651 bool *is_urgent, bool *rodc)
1653 const struct ldb_val *omd_value;
1654 enum ndr_err_code ndr_err;
1655 struct replPropertyMetaDataBlob omd;
1658 const struct GUID *our_invocation_id;
1660 const char * const *attrs = NULL;
1661 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1662 struct ldb_result *res;
1663 struct ldb_context *ldb;
1664 struct ldb_message_element *objectclass_el;
1665 enum urgent_situation situation;
1666 bool rmd_is_provided;
1667 bool rmd_is_just_resorted = false;
1668 const char *not_rename_attrs[4 + msg->num_elements];
1669 bool is_forced_rodc = false;
1672 attrs = rename_attrs;
1674 for (i = 0; i < msg->num_elements; i++) {
1675 not_rename_attrs[i] = msg->elements[i].name;
1677 not_rename_attrs[i] = "replPropertyMetaData";
1678 not_rename_attrs[i+1] = "objectClass";
1679 not_rename_attrs[i+2] = "instanceType";
1680 not_rename_attrs[i+3] = NULL;
1681 attrs = not_rename_attrs;
1684 ldb = ldb_module_get_ctx(module);
1686 ret = samdb_rodc(ldb, rodc);
1687 if (ret != LDB_SUCCESS) {
1688 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1693 ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE)) {
1694 is_forced_rodc = true;
1697 our_invocation_id = samdb_ntds_invocation_id(ldb);
1698 if (!our_invocation_id) {
1699 /* this happens during an initial vampire while
1700 updating the schema */
1701 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1705 unix_to_nt_time(&now, t);
1707 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1708 rmd_is_provided = true;
1709 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1710 rmd_is_just_resorted = true;
1713 rmd_is_provided = false;
1716 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1717 * otherwise we consider we are updating */
1718 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1719 situation = REPL_URGENT_ON_DELETE;
1720 } else if (rename_attrs) {
1721 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1723 situation = REPL_URGENT_ON_UPDATE;
1726 if (rmd_is_provided) {
1727 /* In this case the change_replmetadata control was supplied */
1728 /* We check that it's the only attribute that is provided
1729 * (it's a rare case so it's better to keep the code simplier)
1730 * We also check that the highest local_usn is bigger or the same as
1733 if( msg->num_elements != 1 ||
1734 strncmp(msg->elements[0].name,
1735 "replPropertyMetaData", 20) ) {
1736 DEBUG(0,(__location__ ": changereplmetada control called without "\
1737 "a specified replPropertyMetaData attribute or with others\n"));
1738 return LDB_ERR_OPERATIONS_ERROR;
1740 if (situation != REPL_URGENT_ON_UPDATE) {
1741 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1742 return LDB_ERR_OPERATIONS_ERROR;
1744 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1746 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1747 ldb_dn_get_linearized(msg->dn)));
1748 return LDB_ERR_OPERATIONS_ERROR;
1750 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1751 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1752 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1753 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1754 ldb_dn_get_linearized(msg->dn)));
1755 return LDB_ERR_OPERATIONS_ERROR;
1758 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1759 DSDB_FLAG_NEXT_MODULE |
1760 DSDB_SEARCH_SHOW_RECYCLED |
1761 DSDB_SEARCH_SHOW_EXTENDED_DN |
1762 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1763 DSDB_SEARCH_REVEAL_INTERNALS, req);
1765 if (ret != LDB_SUCCESS) {
1769 if (rmd_is_just_resorted == false) {
1770 *seq_num = find_max_local_usn(omd);
1772 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1775 * The test here now allows for a new
1776 * replPropertyMetaData with no change, if was
1777 * just dbcheck re-sorting the values.
1779 if (*seq_num <= db_seq) {
1780 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1781 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1782 (long long)*seq_num, (long long)db_seq));
1783 return LDB_ERR_OPERATIONS_ERROR;
1788 /* search for the existing replPropertyMetaDataBlob. We need
1789 * to use REVEAL and ask for DNs in storage format to support
1790 * the check for values being the same in
1791 * replmd_update_rpmd_element()
1793 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1794 DSDB_FLAG_NEXT_MODULE |
1795 DSDB_SEARCH_SHOW_RECYCLED |
1796 DSDB_SEARCH_SHOW_EXTENDED_DN |
1797 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1798 DSDB_SEARCH_REVEAL_INTERNALS, req);
1799 if (ret != LDB_SUCCESS) {
1803 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1805 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1806 ldb_dn_get_linearized(msg->dn)));
1807 return LDB_ERR_OPERATIONS_ERROR;
1810 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1811 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1812 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1813 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1814 ldb_dn_get_linearized(msg->dn)));
1815 return LDB_ERR_OPERATIONS_ERROR;
1818 if (omd.version != 1) {
1819 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1820 omd.version, ldb_dn_get_linearized(msg->dn)));
1821 return LDB_ERR_OPERATIONS_ERROR;
1824 for (i=0; i<msg->num_elements;) {
1825 struct ldb_message_element *el = &msg->elements[i];
1826 struct ldb_message_element *old_el;
1828 old_el = ldb_msg_find_element(res->msgs[0], el->name);
1829 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1830 &omd, schema, seq_num,
1835 if (ret != LDB_SUCCESS) {
1839 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1840 *is_urgent = replmd_check_urgent_attribute(el);
1843 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1848 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1850 if (el->num_values != 0) {
1855 ldb_msg_remove_element(msg, el);
1860 * Assert that we have an objectClass attribute - this is major
1861 * corruption if we don't have this!
1863 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1864 if (objectclass_el != NULL) {
1866 * Now check if this objectClass means we need to do urgent replication
1868 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1872 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1873 ldb_asprintf_errstring(ldb, __location__
1874 ": objectClass missing on %s\n",
1875 ldb_dn_get_linearized(msg->dn));
1876 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1880 * replmd_update_rpmd_element has done an update if the
1883 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1884 struct ldb_val *md_value;
1885 struct ldb_message_element *el;
1887 /*if we are RODC and this is a DRSR update then its ok*/
1888 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1889 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)
1890 && !is_forced_rodc) {
1891 unsigned instanceType;
1894 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1895 return LDB_ERR_REFERRAL;
1898 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1899 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1900 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1901 "cannot change replicated attribute on partial replica");
1905 md_value = talloc(msg, struct ldb_val);
1906 if (md_value == NULL) {
1908 return LDB_ERR_OPERATIONS_ERROR;
1911 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1912 if (ret != LDB_SUCCESS) {
1913 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1917 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1918 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1919 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1920 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1921 ldb_dn_get_linearized(msg->dn)));
1922 return LDB_ERR_OPERATIONS_ERROR;
1925 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1926 if (ret != LDB_SUCCESS) {
1927 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1928 ldb_dn_get_linearized(msg->dn)));
1933 el->values = md_value;
1939 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1941 int ret = ndr_guid_compare(&pdn1->guid, &pdn2->guid);
1943 return data_blob_cmp(&pdn1->dsdb_dn->extra_part,
1944 &pdn2->dsdb_dn->extra_part);
1950 get a series of message element values as an array of DNs and GUIDs
1951 the result is sorted by GUID
1953 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1954 struct ldb_message_element *el, struct parsed_dn **pdn,
1955 const char *ldap_oid, struct ldb_request *parent)
1958 bool values_are_sorted = true;
1959 struct ldb_context *ldb = ldb_module_get_ctx(module);
1966 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1968 ldb_module_oom(module);
1969 return LDB_ERR_OPERATIONS_ERROR;
1972 for (i=0; i<el->num_values; i++) {
1973 struct ldb_val *v = &el->values[i];
1976 struct parsed_dn *p;
1980 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1981 if (p->dsdb_dn == NULL) {
1982 return LDB_ERR_INVALID_DN_SYNTAX;
1985 dn = p->dsdb_dn->dn;
1987 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
1988 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
1989 unlikely(GUID_all_zero(&p->guid))) {
1990 /* we got a DN without a GUID - go find the GUID */
1991 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
1992 if (ret != LDB_SUCCESS) {
1993 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1994 ldb_dn_get_linearized(dn));
1995 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1996 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1997 ldb_attr_cmp(el->name, "member") == 0) {
1998 return LDB_ERR_UNWILLING_TO_PERFORM;
2002 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
2003 if (ret != LDB_SUCCESS) {
2006 } else if (!NT_STATUS_IS_OK(status)) {
2007 return LDB_ERR_OPERATIONS_ERROR;
2009 if (i > 0 && values_are_sorted) {
2010 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2012 values_are_sorted = false;
2015 /* keep a pointer to the original ldb_val */
2018 if (! values_are_sorted) {
2019 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2025 * Get a series of trusted message element values. The result is sorted by
2026 * GUID, even though the GUIDs might not be known. That works because we trust
2027 * the database to give us the elements like that if the
2028 * replmd_private->sorted_links flag is set.
2030 * We also ensure that the links are in the Functional Level 2003
2031 * linked attributes format.
2033 static int get_parsed_dns_trusted(struct ldb_module *module,
2034 struct replmd_private *replmd_private,
2035 TALLOC_CTX *mem_ctx,
2036 struct ldb_message_element *el,
2037 struct parsed_dn **pdn,
2038 const char *ldap_oid,
2039 struct ldb_request *parent)
2048 if (!replmd_private->sorted_links) {
2049 /* We need to sort the list. This is the slow old path we want
2052 ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2054 if (ret != LDB_SUCCESS) {
2058 /* Here we get a list of 'struct parsed_dns' without the parsing */
2059 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2062 ldb_module_oom(module);
2063 return LDB_ERR_OPERATIONS_ERROR;
2066 for (i = 0; i < el->num_values; i++) {
2067 (*pdn)[i].v = &el->values[i];
2072 * This upgrades links to FL2003 style, and sorts the result
2073 * if that was needed.
2075 * TODO: Add a database feature that asserts we have no FL2000
2076 * style links to avoid this check or add a feature that
2077 * uses a similar check to find sorted/unsorted links
2078 * for an on-the-fly upgrade.
2081 ret = replmd_check_upgrade_links(ldb_module_get_ctx(module),
2082 *pdn, el->num_values,
2085 if (ret != LDB_SUCCESS) {
2093 build a new extended DN, including all meta data fields
2095 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2096 RMD_ADDTIME = originating_add_time
2097 RMD_INVOCID = originating_invocation_id
2098 RMD_CHANGETIME = originating_change_time
2099 RMD_ORIGINATING_USN = originating_usn
2100 RMD_LOCAL_USN = local_usn
2101 RMD_VERSION = version
2103 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2104 const struct GUID *invocation_id, uint64_t seq_num,
2105 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
2107 struct ldb_dn *dn = dsdb_dn->dn;
2108 const char *tstring, *usn_string, *flags_string;
2109 struct ldb_val tval;
2111 struct ldb_val usnv, local_usnv;
2112 struct ldb_val vers, flagsv;
2115 const char *dnstring;
2117 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2119 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2121 return LDB_ERR_OPERATIONS_ERROR;
2123 tval = data_blob_string_const(tstring);
2125 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
2127 return LDB_ERR_OPERATIONS_ERROR;
2129 usnv = data_blob_string_const(usn_string);
2131 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2133 return LDB_ERR_OPERATIONS_ERROR;
2135 local_usnv = data_blob_string_const(usn_string);
2137 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2139 return LDB_ERR_OPERATIONS_ERROR;
2141 vers = data_blob_string_const(vstring);
2143 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2144 if (!NT_STATUS_IS_OK(status)) {
2145 return LDB_ERR_OPERATIONS_ERROR;
2148 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2149 if (!flags_string) {
2150 return LDB_ERR_OPERATIONS_ERROR;
2152 flagsv = data_blob_string_const(flags_string);
2154 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2155 if (ret != LDB_SUCCESS) return ret;
2156 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
2157 if (ret != LDB_SUCCESS) return ret;
2158 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2159 if (ret != LDB_SUCCESS) return ret;
2160 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2161 if (ret != LDB_SUCCESS) return ret;
2162 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2163 if (ret != LDB_SUCCESS) return ret;
2164 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2165 if (ret != LDB_SUCCESS) return ret;
2166 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2167 if (ret != LDB_SUCCESS) return ret;
2169 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2170 if (dnstring == NULL) {
2171 return LDB_ERR_OPERATIONS_ERROR;
2173 *v = data_blob_string_const(dnstring);
2178 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2179 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2180 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2181 uint32_t version, bool deleted);
2184 check if any links need upgrading from w2k format
2186 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2187 struct parsed_dn *dns, uint32_t count,
2188 struct ldb_message_element *el,
2189 const char *ldap_oid)
2192 const struct GUID *invocation_id = NULL;
2193 for (i=0; i<count; i++) {
2197 if (dns[i].dsdb_dn == NULL) {
2198 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2200 if (ret != LDB_SUCCESS) {
2201 return LDB_ERR_INVALID_DN_SYNTAX;
2205 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2206 &version, "RMD_VERSION");
2207 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2209 * We optimistically assume they are all the same; if
2210 * the first one is fixed, they are all fixed.
2212 * If the first one was *not* fixed and we find a
2213 * later one that is, that is an occasion to shout
2219 DEBUG(0, ("Mixed w2k and fixed format "
2220 "linked attributes\n"));
2224 if (invocation_id == NULL) {
2225 invocation_id = samdb_ntds_invocation_id(ldb);
2226 if (invocation_id == NULL) {
2227 return LDB_ERR_OPERATIONS_ERROR;
2232 /* it's an old one that needs upgrading */
2233 ret = replmd_update_la_val(el->values, dns[i].v,
2234 dns[i].dsdb_dn, dns[i].dsdb_dn,
2235 invocation_id, 1, 1, 0, 0, false);
2236 if (ret != LDB_SUCCESS) {
2242 * This sort() is critical for the operation of
2243 * get_parsed_dns_trusted() because callers of this function
2244 * expect a sorted list, and FL2000 style links are not
2245 * sorted. In particular, as well as the upgrade case,
2246 * get_parsed_dns_trusted() is called from
2247 * replmd_delete_remove_link() even in FL2000 mode
2249 * We do not normally pay the cost of the qsort() due to the
2250 * early return in the RMD_VERSION found case.
2252 TYPESAFE_QSORT(dns, count, parsed_dn_compare);
2257 update an extended DN, including all meta data fields
2259 see replmd_build_la_val for value names
2261 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2262 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2263 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2264 uint32_t version, bool deleted)
2266 struct ldb_dn *dn = dsdb_dn->dn;
2267 const char *tstring, *usn_string, *flags_string;
2268 struct ldb_val tval;
2270 struct ldb_val usnv, local_usnv;
2271 struct ldb_val vers, flagsv;
2272 const struct ldb_val *old_addtime;
2273 uint32_t old_version;
2276 const char *dnstring;
2278 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2280 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2282 return LDB_ERR_OPERATIONS_ERROR;
2284 tval = data_blob_string_const(tstring);
2286 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2288 return LDB_ERR_OPERATIONS_ERROR;
2290 usnv = data_blob_string_const(usn_string);
2292 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2294 return LDB_ERR_OPERATIONS_ERROR;
2296 local_usnv = data_blob_string_const(usn_string);
2298 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2299 if (!NT_STATUS_IS_OK(status)) {
2300 return LDB_ERR_OPERATIONS_ERROR;
2303 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2304 if (!flags_string) {
2305 return LDB_ERR_OPERATIONS_ERROR;
2307 flagsv = data_blob_string_const(flags_string);
2309 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2310 if (ret != LDB_SUCCESS) return ret;
2312 /* get the ADDTIME from the original */
2313 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2314 if (old_addtime == NULL) {
2315 old_addtime = &tval;
2317 if (dsdb_dn != old_dsdb_dn ||
2318 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2319 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2320 if (ret != LDB_SUCCESS) return ret;
2323 /* use our invocation id */
2324 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2325 if (ret != LDB_SUCCESS) return ret;
2327 /* changetime is the current time */
2328 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2329 if (ret != LDB_SUCCESS) return ret;
2331 /* update the USN */
2332 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2333 if (ret != LDB_SUCCESS) return ret;
2335 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2336 if (ret != LDB_SUCCESS) return ret;
2338 /* increase the version by 1 */
2339 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2340 if (NT_STATUS_IS_OK(status) && old_version >= version) {
2341 version = old_version+1;
2343 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2344 vers = data_blob_string_const(vstring);
2345 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2346 if (ret != LDB_SUCCESS) return ret;
2348 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2349 if (dnstring == NULL) {
2350 return LDB_ERR_OPERATIONS_ERROR;
2352 *v = data_blob_string_const(dnstring);
2358 handle adding a linked attribute
2360 static int replmd_modify_la_add(struct ldb_module *module,
2361 struct replmd_private *replmd_private,
2362 const struct dsdb_schema *schema,
2363 struct ldb_message *msg,
2364 struct ldb_message_element *el,
2365 struct ldb_message_element *old_el,
2366 const struct dsdb_attribute *schema_attr,
2369 struct ldb_dn *msg_dn,
2370 struct ldb_request *parent)
2373 struct parsed_dn *dns, *old_dns;
2374 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2376 struct ldb_val *new_values = NULL;
2377 unsigned old_num_values = old_el ? old_el->num_values : 0;
2378 unsigned num_values = 0;
2379 unsigned max_num_values;
2380 const struct GUID *invocation_id;
2381 struct ldb_context *ldb = ldb_module_get_ctx(module);
2383 unix_to_nt_time(&now, t);
2385 invocation_id = samdb_ntds_invocation_id(ldb);
2386 if (!invocation_id) {
2387 talloc_free(tmp_ctx);
2388 return LDB_ERR_OPERATIONS_ERROR;
2391 /* get the DNs to be added, fully parsed.
2393 * We need full parsing because they came off the wire and we don't
2394 * trust them, besides which we need their details to know where to put
2397 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2398 schema_attr->syntax->ldap_oid, parent);
2399 if (ret != LDB_SUCCESS) {
2400 talloc_free(tmp_ctx);
2404 /* get the existing DNs, lazily parsed */
2405 ret = get_parsed_dns_trusted(module, replmd_private,
2406 tmp_ctx, old_el, &old_dns,
2407 schema_attr->syntax->ldap_oid, parent);
2409 if (ret != LDB_SUCCESS) {
2410 talloc_free(tmp_ctx);
2414 max_num_values = old_num_values + el->num_values;
2415 if (max_num_values < old_num_values) {
2416 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2417 "old values: %u, new values: %u, sum: %u",
2418 old_num_values, el->num_values, max_num_values));
2419 talloc_free(tmp_ctx);
2420 return LDB_ERR_OPERATIONS_ERROR;
2423 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2425 if (new_values == NULL) {
2426 ldb_module_oom(module);
2427 talloc_free(tmp_ctx);
2428 return LDB_ERR_OPERATIONS_ERROR;
2432 * For each new value, find where it would go in the list. If there is
2433 * a matching GUID there, we update the existing value; otherwise we
2437 for (i = 0; i < el->num_values; i++) {
2438 struct parsed_dn *exact;
2439 struct parsed_dn *next;
2441 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2444 dns[i].dsdb_dn->extra_part, 0,
2446 schema_attr->syntax->ldap_oid,
2448 if (err != LDB_SUCCESS) {
2449 talloc_free(tmp_ctx);
2453 if (exact != NULL) {
2455 * We are trying to add one that exists, which is only
2456 * allowed if it was previously deleted.
2458 * When we do undelete a link we change it in place.
2459 * It will be copied across into the right spot in due
2463 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2465 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2466 struct GUID_txt_buf guid_str;
2467 ldb_asprintf_errstring(ldb,
2468 "Attribute %s already "
2469 "exists for target GUID %s",
2471 GUID_buf_string(&exact->guid,
2473 talloc_free(tmp_ctx);
2474 /* error codes for 'member' need to be
2476 if (ldb_attr_cmp(el->name, "member") == 0) {
2477 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2479 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2483 ret = replmd_update_la_val(new_values, exact->v,
2486 invocation_id, seq_num,
2487 seq_num, now, 0, false);
2488 if (ret != LDB_SUCCESS) {
2489 talloc_free(tmp_ctx);
2493 ret = replmd_add_backlink(module, replmd_private,
2500 if (ret != LDB_SUCCESS) {
2501 talloc_free(tmp_ctx);
2507 * Here we don't have an exact match.
2509 * If next is NULL, this one goes beyond the end of the
2510 * existing list, so we need to add all of those ones first.
2512 * If next is not NULL, we need to add all the ones before
2516 offset = old_num_values;
2518 /* next should have been parsed, but let's make sure */
2519 if (next->dsdb_dn == NULL) {
2520 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2521 schema_attr->syntax->ldap_oid);
2522 if (ret != LDB_SUCCESS) {
2526 offset = MIN(next - old_dns, old_num_values);
2529 /* put all the old ones before next on the list */
2530 for (; j < offset; j++) {
2531 new_values[num_values] = *old_dns[j].v;
2535 ret = replmd_add_backlink(module, replmd_private,
2540 /* Make the new linked attribute ldb_val. */
2541 ret = replmd_build_la_val(new_values, &new_values[num_values],
2542 dns[i].dsdb_dn, invocation_id,
2545 if (ret != LDB_SUCCESS) {
2546 talloc_free(tmp_ctx);
2550 if (ret != LDB_SUCCESS) {
2551 talloc_free(tmp_ctx);
2555 /* copy the rest of the old ones (if any) */
2556 for (; j < old_num_values; j++) {
2557 new_values[num_values] = *old_dns[j].v;
2561 talloc_steal(msg->elements, new_values);
2562 if (old_el != NULL) {
2563 talloc_steal(msg->elements, old_el->values);
2565 el->values = new_values;
2566 el->num_values = num_values;
2568 talloc_free(tmp_ctx);
2570 /* we now tell the backend to replace all existing values
2571 with the one we have constructed */
2572 el->flags = LDB_FLAG_MOD_REPLACE;
2579 handle deleting all active linked attributes
2581 static int replmd_modify_la_delete(struct ldb_module *module,
2582 struct replmd_private *replmd_private,
2583 const struct dsdb_schema *schema,
2584 struct ldb_message *msg,
2585 struct ldb_message_element *el,
2586 struct ldb_message_element *old_el,
2587 const struct dsdb_attribute *schema_attr,
2590 struct ldb_dn *msg_dn,
2591 struct ldb_request *parent)
2594 struct parsed_dn *dns, *old_dns;
2595 TALLOC_CTX *tmp_ctx = NULL;
2597 struct ldb_context *ldb = ldb_module_get_ctx(module);
2598 struct ldb_control *vanish_links_ctrl = NULL;
2599 bool vanish_links = false;
2600 unsigned int num_to_delete = el->num_values;
2602 const struct GUID *invocation_id;
2605 unix_to_nt_time(&now, t);
2607 invocation_id = samdb_ntds_invocation_id(ldb);
2608 if (!invocation_id) {
2609 return LDB_ERR_OPERATIONS_ERROR;
2612 if (old_el == NULL || old_el->num_values == 0) {
2613 /* there is nothing to delete... */
2614 if (num_to_delete == 0) {
2615 /* and we're deleting nothing, so that's OK */
2618 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2621 tmp_ctx = talloc_new(msg);
2622 if (tmp_ctx == NULL) {
2623 return LDB_ERR_OPERATIONS_ERROR;
2626 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2627 schema_attr->syntax->ldap_oid, parent);
2628 if (ret != LDB_SUCCESS) {
2629 talloc_free(tmp_ctx);
2633 ret = get_parsed_dns_trusted(module, replmd_private,
2634 tmp_ctx, old_el, &old_dns,
2635 schema_attr->syntax->ldap_oid, parent);
2637 if (ret != LDB_SUCCESS) {
2638 talloc_free(tmp_ctx);
2643 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2644 if (vanish_links_ctrl) {
2645 vanish_links = true;
2646 vanish_links_ctrl->critical = false;
2650 /* we empty out el->values here to avoid damage if we return early. */
2655 * If vanish links is set, we are actually removing members of
2656 * old_el->values; otherwise we are just marking them deleted.
2658 * There is a special case when no values are given: we remove them
2659 * all. When we have the vanish_links control we just have to remove
2660 * the backlinks and change our element to replace the existing values
2661 * with the empty list.
2664 if (num_to_delete == 0) {
2665 for (i = 0; i < old_el->num_values; i++) {
2666 struct parsed_dn *p = &old_dns[i];
2667 if (p->dsdb_dn == NULL) {
2668 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2669 schema_attr->syntax->ldap_oid);
2670 if (ret != LDB_SUCCESS) {
2674 ret = replmd_add_backlink(module, replmd_private,
2675 schema, msg_dn, &p->guid,
2678 if (ret != LDB_SUCCESS) {
2679 talloc_free(tmp_ctx);
2686 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2687 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2691 ret = replmd_update_la_val(old_el->values, p->v,
2692 p->dsdb_dn, p->dsdb_dn,
2693 invocation_id, seq_num,
2694 seq_num, now, 0, true);
2695 if (ret != LDB_SUCCESS) {
2696 talloc_free(tmp_ctx);
2702 el->flags = LDB_FLAG_MOD_REPLACE;
2703 talloc_free(tmp_ctx);
2709 for (i = 0; i < num_to_delete; i++) {
2710 struct parsed_dn *p = &dns[i];
2711 struct parsed_dn *exact = NULL;
2712 struct parsed_dn *next = NULL;
2713 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2716 p->dsdb_dn->extra_part, 0,
2718 schema_attr->syntax->ldap_oid,
2720 if (ret != LDB_SUCCESS) {
2721 talloc_free(tmp_ctx);
2724 if (exact == NULL) {
2725 struct GUID_txt_buf buf;
2726 ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2727 "exist for target GUID %s",
2729 GUID_buf_string(&p->guid, &buf));
2730 if (ldb_attr_cmp(el->name, "member") == 0) {
2731 talloc_free(tmp_ctx);
2732 return LDB_ERR_UNWILLING_TO_PERFORM;
2734 talloc_free(tmp_ctx);
2735 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2740 if (CHECK_DEBUGLVL(5)) {
2741 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2742 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2743 struct GUID_txt_buf buf;
2744 const char *guid_str = \
2745 GUID_buf_string(&p->guid, &buf);
2746 DEBUG(5, ("Deleting deleted linked "
2747 "attribute %s to %s, because "
2748 "vanish_links control is set\n",
2749 el->name, guid_str));
2753 /* remove the backlink */
2754 ret = replmd_add_backlink(module,
2761 if (ret != LDB_SUCCESS) {
2762 talloc_free(tmp_ctx);
2766 /* We flag the deletion and tidy it up later. */
2771 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2773 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2774 struct GUID_txt_buf buf;
2775 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2776 ldb_asprintf_errstring(ldb, "Attribute %s already "
2777 "deleted for target GUID %s",
2778 el->name, guid_str);
2779 if (ldb_attr_cmp(el->name, "member") == 0) {
2780 talloc_free(tmp_ctx);
2781 return LDB_ERR_UNWILLING_TO_PERFORM;
2783 talloc_free(tmp_ctx);
2784 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2788 ret = replmd_update_la_val(old_el->values, exact->v,
2789 exact->dsdb_dn, exact->dsdb_dn,
2790 invocation_id, seq_num, seq_num,
2792 if (ret != LDB_SUCCESS) {
2793 talloc_free(tmp_ctx);
2796 ret = replmd_add_backlink(module, replmd_private,
2801 if (ret != LDB_SUCCESS) {
2802 talloc_free(tmp_ctx);
2809 for (i = 0; i < old_el->num_values; i++) {
2810 if (old_dns[i].v != NULL) {
2811 old_el->values[j] = *old_dns[i].v;
2815 old_el->num_values = j;
2818 el->values = talloc_steal(msg->elements, old_el->values);
2819 el->num_values = old_el->num_values;
2821 talloc_free(tmp_ctx);
2823 /* we now tell the backend to replace all existing values
2824 with the one we have constructed */
2825 el->flags = LDB_FLAG_MOD_REPLACE;
2831 handle replacing a linked attribute
2833 static int replmd_modify_la_replace(struct ldb_module *module,
2834 struct replmd_private *replmd_private,
2835 const struct dsdb_schema *schema,
2836 struct ldb_message *msg,
2837 struct ldb_message_element *el,
2838 struct ldb_message_element *old_el,
2839 const struct dsdb_attribute *schema_attr,
2842 struct ldb_dn *msg_dn,
2843 struct ldb_request *parent)
2845 unsigned int i, old_i, new_i;
2846 struct parsed_dn *dns, *old_dns;
2847 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2849 const struct GUID *invocation_id;
2850 struct ldb_context *ldb = ldb_module_get_ctx(module);
2851 struct ldb_val *new_values = NULL;
2852 const char *ldap_oid = schema_attr->syntax->ldap_oid;
2853 unsigned int old_num_values;
2854 unsigned int repl_num_values;
2855 unsigned int max_num_values;
2858 unix_to_nt_time(&now, t);
2860 invocation_id = samdb_ntds_invocation_id(ldb);
2861 if (!invocation_id) {
2862 return LDB_ERR_OPERATIONS_ERROR;
2866 * The replace operation is unlike the replace and delete cases in that
2867 * we need to look at every existing link to see whether it is being
2868 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
2870 * As we are trying to combine two sorted lists, the algorithm we use
2871 * is akin to the merge phase of a merge sort. We interleave the two
2872 * lists, doing different things depending on which side the current
2875 * There are three main cases, with some sub-cases.
2877 * - a DN is in the old list but not the new one. It needs to be
2878 * marked as deleted (but left in the list).
2879 * - maybe it is already deleted, and we have less to do.
2881 * - a DN is in both lists. The old data gets replaced by the new,
2882 * and the list doesn't grow. The old link may have been marked as
2883 * deleted, in which case we undelete it.
2885 * - a DN is in the new list only. We add it in the right place.
2888 old_num_values = old_el ? old_el->num_values : 0;
2889 repl_num_values = el->num_values;
2890 max_num_values = old_num_values + repl_num_values;
2892 if (max_num_values == 0) {
2893 /* There is nothing to do! */
2897 ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
2898 if (ret != LDB_SUCCESS) {
2899 talloc_free(tmp_ctx);
2903 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
2905 if (ret != LDB_SUCCESS) {
2906 talloc_free(tmp_ctx);
2910 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2912 if (ret != LDB_SUCCESS) {
2913 talloc_free(tmp_ctx);
2917 new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
2918 if (new_values == NULL) {
2919 ldb_module_oom(module);
2920 talloc_free(tmp_ctx);
2921 return LDB_ERR_OPERATIONS_ERROR;
2926 for (i = 0; i < max_num_values; i++) {
2928 struct parsed_dn *old_p, *new_p;
2929 if (old_i < old_num_values && new_i < repl_num_values) {
2930 old_p = &old_dns[old_i];
2931 new_p = &dns[new_i];
2932 cmp = parsed_dn_compare(old_p, new_p);
2933 } else if (old_i < old_num_values) {
2934 /* the new list is empty, read the old list */
2935 old_p = &old_dns[old_i];
2938 } else if (new_i < repl_num_values) {
2939 /* the old list is empty, read new list */
2941 new_p = &dns[new_i];
2949 * An old ones that come before the next replacement
2950 * (if any). We mark it as deleted and add it to the
2953 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2954 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
2955 ret = replmd_update_la_val(new_values, old_p->v,
2961 if (ret != LDB_SUCCESS) {
2962 talloc_free(tmp_ctx);
2966 ret = replmd_add_backlink(module, replmd_private,
2969 &old_p->guid, false,
2972 if (ret != LDB_SUCCESS) {
2973 talloc_free(tmp_ctx);
2977 new_values[i] = *old_p->v;
2979 } else if (cmp == 0) {
2981 * We are overwriting one. If it was previously
2982 * deleted, we need to add a backlink.
2984 * Note that if any RMD_FLAGs in an extended new DN
2989 ret = replmd_update_la_val(new_values, old_p->v,
2995 if (ret != LDB_SUCCESS) {
2996 talloc_free(tmp_ctx);
3000 rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
3001 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
3002 ret = replmd_add_backlink(module, replmd_private,
3008 if (ret != LDB_SUCCESS) {
3009 talloc_free(tmp_ctx);
3014 new_values[i] = *old_p->v;
3019 * Replacements that don't match an existing one. We
3020 * just add them to the final list.
3022 ret = replmd_build_la_val(new_values,
3028 if (ret != LDB_SUCCESS) {
3029 talloc_free(tmp_ctx);
3032 ret = replmd_add_backlink(module, replmd_private,
3038 if (ret != LDB_SUCCESS) {
3039 talloc_free(tmp_ctx);
3042 new_values[i] = *new_p->v;
3046 if (old_el != NULL) {
3047 talloc_steal(msg->elements, old_el->values);
3049 el->values = talloc_steal(msg->elements, new_values);
3051 talloc_free(tmp_ctx);
3053 el->flags = LDB_FLAG_MOD_REPLACE;
3060 handle linked attributes in modify requests
3062 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3063 struct replmd_private *replmd_private,
3064 struct ldb_message *msg,
3065 uint64_t seq_num, time_t t,
3066 struct ldb_request *parent)
3068 struct ldb_result *res;
3071 struct ldb_context *ldb = ldb_module_get_ctx(module);
3072 struct ldb_message *old_msg;
3074 const struct dsdb_schema *schema;
3076 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3078 * Nothing special is required for modifying or vanishing links
3079 * in fl2000 since they are just strings in a multi-valued
3082 struct ldb_control *ctrl = ldb_request_get_control(parent,
3083 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3085 ctrl->critical = false;
3093 * We should restrict this to the intersection of the list of
3094 * linked attributes in the schema and the list of attributes
3097 * This will help performance a little, as otherwise we have
3098 * to allocate the entire object value-by-value.
3100 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3101 DSDB_FLAG_NEXT_MODULE |
3102 DSDB_SEARCH_SHOW_RECYCLED |
3103 DSDB_SEARCH_REVEAL_INTERNALS |
3104 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3106 if (ret != LDB_SUCCESS) {
3109 schema = dsdb_get_schema(ldb, res);
3111 return LDB_ERR_OPERATIONS_ERROR;
3114 old_msg = res->msgs[0];
3116 for (i=0; i<msg->num_elements; i++) {
3117 struct ldb_message_element *el = &msg->elements[i];
3118 struct ldb_message_element *old_el, *new_el;
3119 unsigned int mod_type = LDB_FLAG_MOD_TYPE(el->flags);
3120 const struct dsdb_attribute *schema_attr
3121 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3123 ldb_asprintf_errstring(ldb,
3124 "%s: attribute %s is not a valid attribute in schema",
3125 __FUNCTION__, el->name);
3126 return LDB_ERR_OBJECT_CLASS_VIOLATION;
3128 if (schema_attr->linkID == 0) {
3131 if ((schema_attr->linkID & 1) == 1) {
3132 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
3135 /* Odd is for the target. Illegal to modify */
3136 ldb_asprintf_errstring(ldb,
3137 "attribute %s must not be modified directly, it is a linked attribute", el->name);
3138 return LDB_ERR_UNWILLING_TO_PERFORM;
3140 old_el = ldb_msg_find_element(old_msg, el->name);
3142 case LDB_FLAG_MOD_REPLACE:
3143 ret = replmd_modify_la_replace(module, replmd_private,
3144 schema, msg, el, old_el,
3145 schema_attr, seq_num, t,
3149 case LDB_FLAG_MOD_DELETE:
3150 ret = replmd_modify_la_delete(module, replmd_private,
3151 schema, msg, el, old_el,
3152 schema_attr, seq_num, t,
3156 case LDB_FLAG_MOD_ADD:
3157 ret = replmd_modify_la_add(module, replmd_private,
3158 schema, msg, el, old_el,
3159 schema_attr, seq_num, t,
3164 ldb_asprintf_errstring(ldb,
3165 "invalid flags 0x%x for %s linked attribute",
3166 el->flags, el->name);
3167 return LDB_ERR_UNWILLING_TO_PERFORM;
3169 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3170 ldb_asprintf_errstring(ldb,
3171 "Attribute %s is single valued but more than one value has been supplied",
3173 /* Return codes as found on Windows 2012r2 */
3174 if (mod_type == LDB_FLAG_MOD_REPLACE) {
3175 return LDB_ERR_CONSTRAINT_VIOLATION;
3177 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3180 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3183 if (ret != LDB_SUCCESS) {
3187 ldb_msg_remove_attr(old_msg, el->name);
3189 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3190 new_el->num_values = el->num_values;
3191 new_el->values = talloc_steal(msg->elements, el->values);
3193 /* TODO: this relises a bit too heavily on the exact
3194 behaviour of ldb_msg_find_element and
3195 ldb_msg_remove_element */
3196 old_el = ldb_msg_find_element(msg, el->name);
3198 ldb_msg_remove_element(msg, old_el);
3208 static int send_rodc_referral(struct ldb_request *req,
3209 struct ldb_context *ldb,
3212 char *referral = NULL;
3213 struct loadparm_context *lp_ctx = NULL;
3214 struct ldb_dn *fsmo_role_dn = NULL;
3215 struct ldb_dn *role_owner_dn = NULL;
3216 const char *domain = NULL;
3219 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3220 struct loadparm_context);
3222 werr = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3223 &fsmo_role_dn, &role_owner_dn);
3225 if (W_ERROR_IS_OK(werr)) {
3226 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3227 if (server_dn != NULL) {
3228 ldb_dn_remove_child_components(server_dn, 1);
3229 domain = samdb_dn_to_dnshostname(ldb, req,
3234 if (domain == NULL) {
3235 domain = lpcfg_dnsdomain(lp_ctx);
3238 referral = talloc_asprintf(req, "ldap://%s/%s",
3240 ldb_dn_get_linearized(dn));
3241 if (referral == NULL) {
3243 return LDB_ERR_OPERATIONS_ERROR;
3246 return ldb_module_send_referral(req, referral);
3250 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3252 struct ldb_context *ldb;
3253 struct replmd_replicated_request *ac;
3254 struct ldb_request *down_req;
3255 struct ldb_message *msg;
3256 time_t t = time(NULL);
3258 bool is_urgent = false, rodc = false;
3259 bool is_schema_nc = false;
3260 unsigned int functional_level;
3261 const struct ldb_message_element *guid_el = NULL;
3262 struct ldb_control *sd_propagation_control;
3263 struct replmd_private *replmd_private =
3264 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3266 /* do not manipulate our control entries */
3267 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3268 return ldb_next_request(module, req);
3271 sd_propagation_control = ldb_request_get_control(req,
3272 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3273 if (sd_propagation_control != NULL) {
3274 if (req->op.mod.message->num_elements != 1) {
3275 return ldb_module_operr(module);
3277 ret = strcmp(req->op.mod.message->elements[0].name,
3278 "nTSecurityDescriptor");
3280 return ldb_module_operr(module);
3283 return ldb_next_request(module, req);
3286 ldb = ldb_module_get_ctx(module);
3288 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3290 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3291 if (guid_el != NULL) {
3292 ldb_set_errstring(ldb,
3293 "replmd_modify: it's not allowed to change the objectGUID!");
3294 return LDB_ERR_CONSTRAINT_VIOLATION;
3297 ac = replmd_ctx_init(module, req);
3299 return ldb_module_oom(module);
3302 functional_level = dsdb_functional_level(ldb);
3304 /* we have to copy the message as the caller might have it as a const */
3305 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3309 return LDB_ERR_OPERATIONS_ERROR;
3312 ldb_msg_remove_attr(msg, "whenChanged");
3313 ldb_msg_remove_attr(msg, "uSNChanged");
3315 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3317 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3318 msg, &ac->seq_num, t, is_schema_nc,
3320 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3321 ret = send_rodc_referral(req, ldb, msg->dn);
3327 if (ret != LDB_SUCCESS) {
3332 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3333 msg, ac->seq_num, t, req);
3334 if (ret != LDB_SUCCESS) {
3340 * - replace the old object with the newly constructed one
3343 ac->is_urgent = is_urgent;
3345 ret = ldb_build_mod_req(&down_req, ldb, ac,
3348 ac, replmd_op_callback,
3350 LDB_REQ_SET_LOCATION(down_req);
3351 if (ret != LDB_SUCCESS) {
3356 /* current partition control is needed by "replmd_op_callback" */
3357 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3358 ret = ldb_request_add_control(down_req,
3359 DSDB_CONTROL_CURRENT_PARTITION_OID,
3361 if (ret != LDB_SUCCESS) {
3367 /* If we are in functional level 2000, then
3368 * replmd_modify_handle_linked_attribs will have done
3370 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3371 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3372 if (ret != LDB_SUCCESS) {
3378 talloc_steal(down_req, msg);
3380 /* we only change whenChanged and uSNChanged if the seq_num
3382 if (ac->seq_num != 0) {
3383 ret = add_time_element(msg, "whenChanged", t);
3384 if (ret != LDB_SUCCESS) {
3390 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3391 if (ret != LDB_SUCCESS) {
3398 /* go on with the call chain */
3399 return ldb_next_request(module, down_req);
3402 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3405 handle a rename request
3407 On a rename we need to do an extra ldb_modify which sets the
3408 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3410 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3412 struct ldb_context *ldb;
3413 struct replmd_replicated_request *ac;
3415 struct ldb_request *down_req;
3417 /* do not manipulate our control entries */
3418 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3419 return ldb_next_request(module, req);
3422 ldb = ldb_module_get_ctx(module);
3424 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3426 ac = replmd_ctx_init(module, req);
3428 return ldb_module_oom(module);
3431 ret = ldb_build_rename_req(&down_req, ldb, ac,
3432 ac->req->op.rename.olddn,
3433 ac->req->op.rename.newdn,
3435 ac, replmd_rename_callback,
3437 LDB_REQ_SET_LOCATION(down_req);
3438 if (ret != LDB_SUCCESS) {
3443 /* go on with the call chain */
3444 return ldb_next_request(module, down_req);
3447 /* After the rename is compleated, update the whenchanged etc */
3448 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3450 struct ldb_context *ldb;
3451 struct ldb_request *down_req;
3452 struct ldb_message *msg;
3453 const struct dsdb_attribute *rdn_attr;
3454 const char *rdn_name;
3455 const struct ldb_val *rdn_val;
3456 const char *attrs[5] = { NULL, };
3457 time_t t = time(NULL);
3459 bool is_urgent = false, rodc = false;
3461 struct replmd_replicated_request *ac =
3462 talloc_get_type(req->context, struct replmd_replicated_request);
3463 struct replmd_private *replmd_private =
3464 talloc_get_type(ldb_module_get_private(ac->module),
3465 struct replmd_private);
3467 ldb = ldb_module_get_ctx(ac->module);
3469 if (ares->error != LDB_SUCCESS) {
3470 return ldb_module_done(ac->req, ares->controls,
3471 ares->response, ares->error);
3474 if (ares->type != LDB_REPLY_DONE) {
3475 ldb_set_errstring(ldb,
3476 "invalid ldb_reply_type in callback");
3478 return ldb_module_done(ac->req, NULL, NULL,
3479 LDB_ERR_OPERATIONS_ERROR);
3483 * - replace the old object with the newly constructed one
3486 msg = ldb_msg_new(ac);
3489 return LDB_ERR_OPERATIONS_ERROR;
3492 msg->dn = ac->req->op.rename.newdn;
3494 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3496 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3497 if (rdn_name == NULL) {
3499 return ldb_module_done(ac->req, NULL, NULL,
3503 /* normalize the rdn attribute name */
3504 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3505 if (rdn_attr == NULL) {
3507 return ldb_module_done(ac->req, NULL, NULL,
3510 rdn_name = rdn_attr->lDAPDisplayName;
3512 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3513 if (rdn_val == NULL) {
3515 return ldb_module_done(ac->req, NULL, NULL,
3519 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3521 return ldb_module_done(ac->req, NULL, NULL,
3524 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3526 return ldb_module_done(ac->req, NULL, NULL,
3529 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3531 return ldb_module_done(ac->req, NULL, NULL,
3534 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3536 return ldb_module_done(ac->req, NULL, NULL,
3541 * here we let replmd_update_rpmd() only search for
3542 * the existing "replPropertyMetaData" and rdn_name attributes.
3544 * We do not want the existing "name" attribute as
3545 * the "name" attribute needs to get the version
3546 * updated on rename even if the rdn value hasn't changed.
3548 * This is the diff of the meta data, for a moved user
3549 * on a w2k8r2 server:
3552 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3553 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3554 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3555 * version : 0x00000001 (1)
3556 * reserved : 0x00000000 (0)
3557 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3558 * local_usn : 0x00000000000037a5 (14245)
3559 * array: struct replPropertyMetaData1
3560 * attid : DRSUAPI_ATTID_name (0x90001)
3561 * - version : 0x00000001 (1)
3562 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3563 * + version : 0x00000002 (2)
3564 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3565 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3566 * - originating_usn : 0x00000000000037a5 (14245)
3567 * - local_usn : 0x00000000000037a5 (14245)
3568 * + originating_usn : 0x0000000000003834 (14388)
3569 * + local_usn : 0x0000000000003834 (14388)
3570 * array: struct replPropertyMetaData1
3571 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3572 * version : 0x00000004 (4)
3574 attrs[0] = "replPropertyMetaData";
3575 attrs[1] = "objectClass";
3576 attrs[2] = "instanceType";
3577 attrs[3] = rdn_name;
3580 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3581 msg, &ac->seq_num, t,
3582 is_schema_nc, &is_urgent, &rodc);
3583 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3584 ret = send_rodc_referral(req, ldb, ac->req->op.rename.olddn);
3586 return ldb_module_done(req, NULL, NULL, ret);
3589 if (ret != LDB_SUCCESS) {
3591 return ldb_module_done(ac->req, NULL, NULL, ret);
3594 if (ac->seq_num == 0) {
3596 return ldb_module_done(ac->req, NULL, NULL,
3598 "internal error seq_num == 0"));
3600 ac->is_urgent = is_urgent;
3602 ret = ldb_build_mod_req(&down_req, ldb, ac,
3605 ac, replmd_op_callback,
3607 LDB_REQ_SET_LOCATION(down_req);
3608 if (ret != LDB_SUCCESS) {
3613 /* current partition control is needed by "replmd_op_callback" */
3614 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3615 ret = ldb_request_add_control(down_req,
3616 DSDB_CONTROL_CURRENT_PARTITION_OID,
3618 if (ret != LDB_SUCCESS) {
3624 talloc_steal(down_req, msg);
3626 ret = add_time_element(msg, "whenChanged", t);
3627 if (ret != LDB_SUCCESS) {
3633 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3634 if (ret != LDB_SUCCESS) {
3640 /* go on with the call chain - do the modify after the rename */
3641 return ldb_next_request(ac->module, down_req);
3645 * remove links from objects that point at this object when an object
3646 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3647 * RemoveObj which states that link removal due to the object being
3648 * deleted is NOT an originating update - they just go away!
3651 static int replmd_delete_remove_link(struct ldb_module *module,
3652 const struct dsdb_schema *schema,
3653 struct replmd_private *replmd_private,
3656 struct ldb_message_element *el,
3657 const struct dsdb_attribute *sa,
3658 struct ldb_request *parent)
3661 TALLOC_CTX *tmp_ctx = talloc_new(module);
3662 struct ldb_context *ldb = ldb_module_get_ctx(module);
3664 for (i=0; i<el->num_values; i++) {
3665 struct dsdb_dn *dsdb_dn;
3667 struct ldb_message *msg;
3668 const struct dsdb_attribute *target_attr;
3669 struct ldb_message_element *el2;
3671 struct ldb_val dn_val;
3672 uint32_t dsdb_flags = 0;
3673 const char *attrs[] = { NULL, NULL };
3674 struct ldb_result *link_res;
3675 struct ldb_message *link_msg;
3676 struct ldb_message_element *link_el;
3677 struct parsed_dn *link_dns;
3678 struct parsed_dn *p = NULL, *unused = NULL;
3680 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3684 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3686 talloc_free(tmp_ctx);
3687 return LDB_ERR_OPERATIONS_ERROR;
3690 /* remove the link */
3691 msg = ldb_msg_new(tmp_ctx);
3693 ldb_module_oom(module);
3694 talloc_free(tmp_ctx);
3695 return LDB_ERR_OPERATIONS_ERROR;
3699 msg->dn = dsdb_dn->dn;
3701 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3702 if (target_attr == NULL) {
3705 attrs[0] = target_attr->lDAPDisplayName;
3707 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName,
3708 LDB_FLAG_MOD_DELETE, &el2);
3709 if (ret != LDB_SUCCESS) {
3710 ldb_module_oom(module);
3711 talloc_free(tmp_ctx);
3712 return LDB_ERR_OPERATIONS_ERROR;
3715 ret = dsdb_module_search_dn(module, tmp_ctx, &link_res,
3717 DSDB_FLAG_NEXT_MODULE |
3718 DSDB_SEARCH_SHOW_EXTENDED_DN,
3721 if (ret != LDB_SUCCESS) {
3722 talloc_free(tmp_ctx);
3726 link_msg = link_res->msgs[0];
3727 link_el = ldb_msg_find_element(link_msg,
3728 target_attr->lDAPDisplayName);
3729 if (link_el == NULL) {
3730 talloc_free(tmp_ctx);
3731 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3735 * This call 'upgrades' the links in link_dns, but we
3736 * do not commit the result back into the database, so
3737 * this is safe to call in FL2000 or on databases that
3738 * have been run at that level in the past.
3740 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx,
3742 target_attr->syntax->ldap_oid, parent);
3743 if (ret != LDB_SUCCESS) {
3744 talloc_free(tmp_ctx);
3748 ret = parsed_dn_find(ldb, link_dns, link_el->num_values,
3752 target_attr->syntax->ldap_oid, false);
3753 if (ret != LDB_SUCCESS) {
3754 talloc_free(tmp_ctx);
3759 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3760 "Failed to find forward link on %s "
3761 "as %s to remove backlink %s on %s",
3762 ldb_dn_get_linearized(msg->dn),
3763 target_attr->lDAPDisplayName,
3764 sa->lDAPDisplayName,
3765 ldb_dn_get_linearized(dn));
3766 talloc_free(tmp_ctx);
3767 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3771 /* This needs to get the Binary DN, by first searching */
3772 dn_str = dsdb_dn_get_linearized(tmp_ctx,
3775 dn_val = data_blob_string_const(dn_str);
3776 el2->values = &dn_val;
3777 el2->num_values = 1;
3780 * Ensure that we tell the modification to vanish any linked
3781 * attributes (not simply mark them as isDeleted = TRUE)
3783 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3785 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3786 if (ret != LDB_SUCCESS) {
3787 talloc_free(tmp_ctx);
3791 talloc_free(tmp_ctx);
3797 handle update of replication meta data for deletion of objects
3799 This also handles the mapping of delete to a rename operation
3800 to allow deletes to be replicated.
3802 It also handles the incoming deleted objects, to ensure they are
3803 fully deleted here. In that case re_delete is true, and we do not
3804 use this as a signal to change the deleted state, just reinforce it.
3807 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3809 int ret = LDB_ERR_OTHER;
3810 bool retb, disallow_move_on_delete;
3811 struct ldb_dn *old_dn, *new_dn;
3812 const char *rdn_name;
3813 const struct ldb_val *rdn_value, *new_rdn_value;
3815 struct ldb_context *ldb = ldb_module_get_ctx(module);
3816 const struct dsdb_schema *schema;
3817 struct ldb_message *msg, *old_msg;
3818 struct ldb_message_element *el;
3819 TALLOC_CTX *tmp_ctx;
3820 struct ldb_result *res, *parent_res;
3821 static const char * const preserved_attrs[] = {
3822 /* yes, this really is a hard coded list. See MS-ADTS
3823 section 3.1.1.5.5.1.1 */
3826 "dNReferenceUpdate",
3837 "msDS-LastKnownRDN",
3843 "distinguishedName",
3847 "proxiedObjectName",
3849 "nTSecurityDescriptor",
3850 "replPropertyMetaData",
3852 "securityIdentifier",
3860 "userAccountControl",
3867 static const char * const all_attrs[] = {
3868 DSDB_SECRET_ATTRIBUTES,
3872 unsigned int i, el_count = 0;
3873 uint32_t dsdb_flags = 0;
3874 struct replmd_private *replmd_private;
3875 enum deletion_state deletion_state, next_deletion_state;
3877 if (ldb_dn_is_special(req->op.del.dn)) {
3878 return ldb_next_request(module, req);
3882 * We have to allow dbcheck to remove an object that
3883 * is beyond repair, and to do so totally. This could
3884 * mean we we can get a partial object from the other
3885 * DC, causing havoc, so dbcheck suggests
3886 * re-replication first. dbcheck sets both DBCHECK
3887 * and RELAX in this situation.
3889 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3890 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3891 /* really, really remove it */
3892 return ldb_next_request(module, req);
3895 tmp_ctx = talloc_new(ldb);
3898 return LDB_ERR_OPERATIONS_ERROR;
3901 schema = dsdb_get_schema(ldb, tmp_ctx);
3903 talloc_free(tmp_ctx);
3904 return LDB_ERR_OPERATIONS_ERROR;
3907 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3909 /* we need the complete msg off disk, so we can work out which
3910 attributes need to be removed */
3911 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3912 DSDB_FLAG_NEXT_MODULE |
3913 DSDB_SEARCH_SHOW_RECYCLED |
3914 DSDB_SEARCH_REVEAL_INTERNALS |
3915 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3916 if (ret != LDB_SUCCESS) {
3917 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3918 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3919 re_delete ? "re-delete" : "delete",
3920 ldb_dn_get_linearized(old_dn),
3921 ldb_errstring(ldb_module_get_ctx(module)));
3922 talloc_free(tmp_ctx);
3925 old_msg = res->msgs[0];
3927 replmd_deletion_state(module, old_msg,
3929 &next_deletion_state);
3931 /* This supports us noticing an incoming isDeleted and acting on it */
3933 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3934 next_deletion_state = deletion_state;
3937 if (next_deletion_state == OBJECT_REMOVED) {
3939 * We have to prevent objects being deleted, even if
3940 * the administrator really wants them gone, as
3941 * without the tombstone, we can get a partial object
3942 * from the other DC, causing havoc.
3944 * The only other valid case is when the 180 day
3945 * timeout has expired, when relax is specified.
3947 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3948 /* it is already deleted - really remove it this time */
3949 talloc_free(tmp_ctx);
3950 return ldb_next_request(module, req);
3953 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3954 "This check is to prevent corruption of the replicated state.",
3955 ldb_dn_get_linearized(old_msg->dn));
3956 return LDB_ERR_UNWILLING_TO_PERFORM;
3959 rdn_name = ldb_dn_get_rdn_name(old_dn);
3960 rdn_value = ldb_dn_get_rdn_val(old_dn);
3961 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3962 talloc_free(tmp_ctx);
3963 return ldb_operr(ldb);
3966 msg = ldb_msg_new(tmp_ctx);
3968 ldb_module_oom(module);
3969 talloc_free(tmp_ctx);
3970 return LDB_ERR_OPERATIONS_ERROR;
3975 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3976 disallow_move_on_delete =
3977 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3978 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3980 /* work out where we will be renaming this object to */
3981 if (!disallow_move_on_delete) {
3982 struct ldb_dn *deleted_objects_dn;
3983 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3984 &deleted_objects_dn);
3987 * We should not move objects if we can't find the
3988 * deleted objects DN. Not moving (or otherwise
3989 * harming) the Deleted Objects DN itself is handled
3992 if (re_delete && (ret != LDB_SUCCESS)) {
3993 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3994 if (new_dn == NULL) {
3995 ldb_module_oom(module);
3996 talloc_free(tmp_ctx);
3997 return LDB_ERR_OPERATIONS_ERROR;
3999 } else if (ret != LDB_SUCCESS) {
4000 /* this is probably an attempted delete on a partition
4001 * that doesn't allow delete operations, such as the
4002 * schema partition */
4003 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
4004 ldb_dn_get_linearized(old_dn));
4005 talloc_free(tmp_ctx);
4006 return LDB_ERR_UNWILLING_TO_PERFORM;
4008 new_dn = deleted_objects_dn;
4011 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4012 if (new_dn == NULL) {
4013 ldb_module_oom(module);
4014 talloc_free(tmp_ctx);
4015 return LDB_ERR_OPERATIONS_ERROR;
4019 /* get the objects GUID from the search we just did */
4020 guid = samdb_result_guid(old_msg, "objectGUID");
4022 if (deletion_state == OBJECT_NOT_DELETED) {
4023 /* Add a formatted child */
4024 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
4026 ldb_dn_escape_value(tmp_ctx, *rdn_value),
4027 GUID_string(tmp_ctx, &guid));
4029 ldb_asprintf_errstring(ldb, __location__
4030 ": Unable to add a formatted child to dn: %s",
4031 ldb_dn_get_linearized(new_dn));
4032 talloc_free(tmp_ctx);
4033 return LDB_ERR_OPERATIONS_ERROR;
4036 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
4037 if (ret != LDB_SUCCESS) {
4038 ldb_asprintf_errstring(ldb, __location__
4039 ": Failed to add isDeleted string to the msg");
4040 talloc_free(tmp_ctx);
4043 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4046 * No matter what has happened with other renames etc, try again to
4047 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
4050 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
4051 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
4053 ldb_asprintf_errstring(ldb, __location__
4054 ": Unable to add a prepare rdn of %s",
4055 ldb_dn_get_linearized(rdn));
4056 talloc_free(tmp_ctx);
4057 return LDB_ERR_OPERATIONS_ERROR;
4059 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
4061 retb = ldb_dn_add_child(new_dn, rdn);
4063 ldb_asprintf_errstring(ldb, __location__
4064 ": Unable to add rdn %s to base dn: %s",
4065 ldb_dn_get_linearized(rdn),
4066 ldb_dn_get_linearized(new_dn));
4067 talloc_free(tmp_ctx);
4068 return LDB_ERR_OPERATIONS_ERROR;
4073 now we need to modify the object in the following ways:
4075 - add isDeleted=TRUE
4076 - update rDN and name, with new rDN
4077 - remove linked attributes
4078 - remove objectCategory and sAMAccountType
4079 - remove attribs not on the preserved list
4080 - preserved if in above list, or is rDN
4081 - remove all linked attribs from this object
4082 - remove all links from other objects to this object
4083 - add lastKnownParent
4084 - update replPropertyMetaData?
4086 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4089 if (deletion_state == OBJECT_NOT_DELETED) {
4090 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4091 char *parent_dn_str = NULL;
4093 /* we need the storage form of the parent GUID */
4094 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
4096 DSDB_FLAG_NEXT_MODULE |
4097 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4098 DSDB_SEARCH_REVEAL_INTERNALS|
4099 DSDB_SEARCH_SHOW_RECYCLED, req);
4100 if (ret != LDB_SUCCESS) {
4101 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4102 "repmd_delete: Failed to %s %s, "
4103 "because we failed to find it's parent (%s): %s",
4104 re_delete ? "re-delete" : "delete",
4105 ldb_dn_get_linearized(old_dn),
4106 ldb_dn_get_linearized(parent_dn),
4107 ldb_errstring(ldb_module_get_ctx(module)));
4108 talloc_free(tmp_ctx);
4113 * Now we can use the DB version,
4114 * it will have the extended DN info in it
4116 parent_dn = parent_res->msgs[0]->dn;
4117 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4120 if (parent_dn_str == NULL) {
4121 talloc_free(tmp_ctx);
4122 return ldb_module_oom(module);
4125 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4127 if (ret != LDB_SUCCESS) {
4128 ldb_asprintf_errstring(ldb, __location__
4129 ": Failed to add lastKnownParent "
4130 "string when deleting %s",
4131 ldb_dn_get_linearized(old_dn));
4132 talloc_free(tmp_ctx);
4135 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4137 if (next_deletion_state == OBJECT_DELETED) {
4138 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4139 if (ret != LDB_SUCCESS) {
4140 ldb_asprintf_errstring(ldb, __location__
4141 ": Failed to add msDS-LastKnownRDN "
4142 "string when deleting %s",
4143 ldb_dn_get_linearized(old_dn));
4144 talloc_free(tmp_ctx);
4147 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
4151 switch (next_deletion_state) {
4153 case OBJECT_RECYCLED:
4154 case OBJECT_TOMBSTONE:
4157 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4158 * describes what must be removed from a tombstone
4161 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4162 * describes what must be removed from a recycled
4168 * we also mark it as recycled, meaning this object can't be
4169 * recovered (we are stripping its attributes).
4170 * This is done only if we have this schema object of course ...
4171 * This behavior is identical to the one of Windows 2008R2 which
4172 * always set the isRecycled attribute, even if the recycle-bin is
4173 * not activated and what ever the forest level is.
4175 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4176 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
4177 if (ret != LDB_SUCCESS) {
4178 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4179 ldb_module_oom(module);
4180 talloc_free(tmp_ctx);
4183 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4186 replmd_private = talloc_get_type(ldb_module_get_private(module),
4187 struct replmd_private);
4188 /* work out which of the old attributes we will be removing */
4189 for (i=0; i<old_msg->num_elements; i++) {
4190 const struct dsdb_attribute *sa;
4191 el = &old_msg->elements[i];
4192 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4194 talloc_free(tmp_ctx);
4195 return LDB_ERR_OPERATIONS_ERROR;
4197 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4198 /* don't remove the rDN */
4201 if (sa->linkID & 1) {
4203 we have a backlink in this object
4204 that needs to be removed. We're not
4205 allowed to remove it directly
4206 however, so we instead setup a
4207 modify to delete the corresponding
4210 ret = replmd_delete_remove_link(module, schema,
4214 if (ret != LDB_SUCCESS) {
4215 const char *old_dn_str
4216 = ldb_dn_get_linearized(old_dn);
4217 ldb_asprintf_errstring(ldb,
4219 ": Failed to remove backlink of "
4220 "%s when deleting %s: %s",
4223 ldb_errstring(ldb));
4224 talloc_free(tmp_ctx);
4225 return LDB_ERR_OPERATIONS_ERROR;
4227 /* now we continue, which means we
4228 won't remove this backlink
4232 } else if (sa->linkID == 0) {
4233 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4236 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4241 * Ensure that we tell the modification to vanish any linked
4242 * attributes (not simply mark them as isDeleted = TRUE)
4244 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4246 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4247 if (ret != LDB_SUCCESS) {
4248 talloc_free(tmp_ctx);
4249 ldb_module_oom(module);
4256 case OBJECT_DELETED:
4258 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4259 * describes what must be removed from a deleted
4263 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4264 if (ret != LDB_SUCCESS) {
4265 talloc_free(tmp_ctx);
4266 ldb_module_oom(module);
4270 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4271 if (ret != LDB_SUCCESS) {
4272 talloc_free(tmp_ctx);
4273 ldb_module_oom(module);
4283 if (deletion_state == OBJECT_NOT_DELETED) {
4284 const struct dsdb_attribute *sa;
4286 /* work out what the new rdn value is, for updating the
4287 rDN and name fields */
4288 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4289 if (new_rdn_value == NULL) {
4290 talloc_free(tmp_ctx);
4291 return ldb_operr(ldb);
4294 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4296 talloc_free(tmp_ctx);
4297 return LDB_ERR_OPERATIONS_ERROR;
4300 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4302 if (ret != LDB_SUCCESS) {
4303 talloc_free(tmp_ctx);
4306 el->flags = LDB_FLAG_MOD_REPLACE;
4308 el = ldb_msg_find_element(old_msg, "name");
4310 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4311 if (ret != LDB_SUCCESS) {
4312 talloc_free(tmp_ctx);
4315 el->flags = LDB_FLAG_MOD_REPLACE;
4320 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4325 * No matter what has happned with other renames, try again to
4326 * get this to be under the deleted DN.
4328 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4329 /* now rename onto the new DN */
4330 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4331 if (ret != LDB_SUCCESS){
4332 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4333 ldb_dn_get_linearized(old_dn),
4334 ldb_dn_get_linearized(new_dn),
4335 ldb_errstring(ldb)));
4336 talloc_free(tmp_ctx);
4342 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4343 if (ret != LDB_SUCCESS) {
4344 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4345 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4346 talloc_free(tmp_ctx);
4350 talloc_free(tmp_ctx);
4352 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4355 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4357 return replmd_delete_internals(module, req, false);
4361 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4366 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4368 int ret = LDB_ERR_OTHER;
4369 /* TODO: do some error mapping */
4371 /* Let the caller know the full WERROR */
4372 ar->objs->error = status;
4378 static struct replPropertyMetaData1 *
4379 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4380 enum drsuapi_DsAttributeId attid)
4383 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4385 for (i = 0; i < rpmd_ctr->count; i++) {
4386 if (rpmd_ctr->array[i].attid == attid) {
4387 return &rpmd_ctr->array[i];
4395 return true if an update is newer than an existing entry
4396 see section 5.11 of MS-ADTS
4398 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4399 const struct GUID *update_invocation_id,
4400 uint32_t current_version,
4401 uint32_t update_version,
4402 NTTIME current_change_time,
4403 NTTIME update_change_time)
4405 if (update_version != current_version) {
4406 return update_version > current_version;
4408 if (update_change_time != current_change_time) {
4409 return update_change_time > current_change_time;
4411 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4414 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4415 struct replPropertyMetaData1 *new_m)
4417 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4418 &new_m->originating_invocation_id,
4421 cur_m->originating_change_time,
4422 new_m->originating_change_time);
4425 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4426 struct replPropertyMetaData1 *cur_m,
4427 struct replPropertyMetaData1 *new_m)
4432 * If the new replPropertyMetaData entry for this attribute is
4433 * not provided (this happens in the case where we look for
4434 * ATTID_name, but the name was not changed), then the local
4435 * state is clearly still current, as the remote
4436 * server didn't send it due to being older the high watermark
4439 if (new_m == NULL) {
4443 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4445 * if we compare equal then do an
4446 * update. This is used when a client
4447 * asks for a FULL_SYNC, and can be
4448 * used to recover a corrupt
4451 * This call is a bit tricky, what we
4452 * are doing it turning the 'is_newer'
4453 * call into a 'not is older' by
4454 * swapping cur_m and new_m, and negating the
4457 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4460 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4470 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4472 const struct ldb_val *rdn_val;
4473 const char *rdn_name;
4474 struct ldb_dn *new_dn;
4476 rdn_val = ldb_dn_get_rdn_val(dn);
4477 rdn_name = ldb_dn_get_rdn_name(dn);
4478 if (!rdn_val || !rdn_name) {
4482 new_dn = ldb_dn_copy(mem_ctx, dn);
4487 if (!ldb_dn_remove_child_components(new_dn, 1)) {
4491 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4493 ldb_dn_escape_value(new_dn, *rdn_val),
4494 GUID_string(new_dn, guid))) {
4503 perform a modify operation which sets the rDN and name attributes to
4504 their current values. This has the effect of changing these
4505 attributes to have been last updated by the current DC. This is
4506 needed to ensure that renames performed as part of conflict
4507 resolution are propogated to other DCs
4509 static int replmd_name_modify(struct replmd_replicated_request *ar,
4510 struct ldb_request *req, struct ldb_dn *dn)
4512 struct ldb_message *msg;
4513 const char *rdn_name;
4514 const struct ldb_val *rdn_val;
4515 const struct dsdb_attribute *rdn_attr;
4518 msg = ldb_msg_new(req);
4524 rdn_name = ldb_dn_get_rdn_name(dn);
4525 if (rdn_name == NULL) {
4529 /* normalize the rdn attribute name */
4530 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4531 if (rdn_attr == NULL) {
4534 rdn_name = rdn_attr->lDAPDisplayName;
4536 rdn_val = ldb_dn_get_rdn_val(dn);
4537 if (rdn_val == NULL) {
4541 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4544 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4547 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4550 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4555 * We have to mark this as a replicated update otherwise
4556 * schema_data may reject a rename in the schema partition
4559 ret = dsdb_module_modify(ar->module, msg,
4560 DSDB_FLAG_OWN_MODULE|DSDB_FLAG_REPLICATED_UPDATE,
4562 if (ret != LDB_SUCCESS) {
4563 DEBUG(0,(__location__ ": Failed to modify rDN/name of DN being DRS renamed '%s' - %s",
4564 ldb_dn_get_linearized(dn),
4565 ldb_errstring(ldb_module_get_ctx(ar->module))));
4575 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of DN being DRS renamed '%s'",
4576 ldb_dn_get_linearized(dn)));
4577 return LDB_ERR_OPERATIONS_ERROR;
4582 callback for conflict DN handling where we have renamed the incoming
4583 record. After renaming it, we need to ensure the change of name and
4584 rDN for the incoming record is seen as an originating update by this DC.
4586 This also handles updating lastKnownParent for entries sent to lostAndFound
4588 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4590 struct replmd_replicated_request *ar =
4591 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4592 struct ldb_dn *conflict_dn = NULL;
4595 if (ares->error != LDB_SUCCESS) {
4596 /* call the normal callback for everything except success */
4597 return replmd_op_callback(req, ares);
4600 switch (req->operation) {
4602 conflict_dn = req->op.add.message->dn;
4605 conflict_dn = req->op.mod.message->dn;
4608 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4611 /* perform a modify of the rDN and name of the record */
4612 ret = replmd_name_modify(ar, req, conflict_dn);
4613 if (ret != LDB_SUCCESS) {
4615 return replmd_op_callback(req, ares);
4618 if (ar->objs->objects[ar->index_current].last_known_parent) {
4619 struct ldb_message *msg = ldb_msg_new(req);
4621 ldb_module_oom(ar->module);
4622 return LDB_ERR_OPERATIONS_ERROR;
4625 msg->dn = req->op.add.message->dn;
4627 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4628 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4629 if (ret != LDB_SUCCESS) {
4630 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4631 ldb_module_oom(ar->module);
4634 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4636 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4637 if (ret != LDB_SUCCESS) {
4638 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4639 ldb_dn_get_linearized(msg->dn),
4640 ldb_errstring(ldb_module_get_ctx(ar->module))));
4646 return replmd_op_callback(req, ares);
4650 callback for replmd_replicated_apply_add()
4651 This copes with the creation of conflict records in the case where
4652 the DN exists, but with a different objectGUID
4654 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))
4656 struct ldb_dn *conflict_dn;
4657 struct replmd_replicated_request *ar =
4658 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4659 struct ldb_result *res;
4660 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4662 const struct ldb_val *omd_value;
4663 struct replPropertyMetaDataBlob omd, *rmd;
4664 enum ndr_err_code ndr_err;
4665 bool rename_incoming_record, rodc;
4666 struct replPropertyMetaData1 *rmd_name, *omd_name;
4667 struct ldb_message *msg;
4668 struct ldb_request *down_req = NULL;
4670 /* call the normal callback for success */
4671 if (ares->error == LDB_SUCCESS) {
4672 return callback(req, ares);
4676 * we have a conflict, and need to decide if we will keep the
4677 * new record or the old record
4680 msg = ar->objs->objects[ar->index_current].msg;
4681 conflict_dn = msg->dn;
4683 /* For failures other than conflicts, fail the whole operation here */
4684 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4685 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4686 ldb_dn_get_linearized(conflict_dn),
4687 ldb_errstring(ldb_module_get_ctx(ar->module)));
4689 return ldb_module_done(ar->req, NULL, NULL,
4690 LDB_ERR_OPERATIONS_ERROR);
4693 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4694 if (ret != LDB_SUCCESS) {
4695 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to determine if we are an RODC when attempting to form conflict DN: %s", ldb_errstring(ldb_module_get_ctx(ar->module)));
4696 return ldb_module_done(ar->req, NULL, NULL,
4697 LDB_ERR_OPERATIONS_ERROR);
4703 * We are on an RODC, or were a GC for this
4704 * partition, so we have to fail this until
4705 * someone who owns the partition sorts it
4708 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4709 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
4710 " - We must fail the operation until a master for this partition resolves the conflict",
4711 ldb_dn_get_linearized(conflict_dn));
4716 * first we need the replPropertyMetaData attribute from the
4717 * local, conflicting record
4719 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4721 DSDB_FLAG_NEXT_MODULE |
4722 DSDB_SEARCH_SHOW_DELETED |
4723 DSDB_SEARCH_SHOW_RECYCLED, req);
4724 if (ret != LDB_SUCCESS) {
4725 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4726 ldb_dn_get_linearized(conflict_dn)));
4730 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4731 if (omd_value == NULL) {
4732 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4733 ldb_dn_get_linearized(conflict_dn)));
4737 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4738 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4739 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4740 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4741 ldb_dn_get_linearized(conflict_dn)));
4745 rmd = ar->objs->objects[ar->index_current].meta_data;
4748 * we decide which is newer based on the RPMD on the name
4749 * attribute. See [MS-DRSR] ResolveNameConflict.
4751 * We expect omd_name to be present, as this is from a local
4752 * search, but while rmd_name should have been given to us by
4753 * the remote server, if it is missing we just prefer the
4755 * replmd_replPropertyMetaData1_new_should_be_taken()
4757 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4758 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4760 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4761 ldb_dn_get_linearized(conflict_dn)));
4766 * Should we preserve the current record, and so rename the
4767 * incoming record to be a conflict?
4769 rename_incoming_record
4770 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4771 omd_name, rmd_name);
4773 if (rename_incoming_record) {
4775 struct ldb_dn *new_dn;
4777 guid = samdb_result_guid(msg, "objectGUID");
4778 if (GUID_all_zero(&guid)) {
4779 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4780 ldb_dn_get_linearized(conflict_dn)));
4783 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4784 if (new_dn == NULL) {
4785 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4786 ldb_dn_get_linearized(conflict_dn)));
4790 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4791 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4793 /* re-submit the request, but with the new DN */
4794 callback = replmd_op_name_modify_callback;
4797 /* we are renaming the existing record */
4799 struct ldb_dn *new_dn;
4801 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4802 if (GUID_all_zero(&guid)) {
4803 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4804 ldb_dn_get_linearized(conflict_dn)));
4808 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4809 if (new_dn == NULL) {
4810 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4811 ldb_dn_get_linearized(conflict_dn)));
4815 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4816 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4818 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4819 DSDB_FLAG_OWN_MODULE, req);
4820 if (ret != LDB_SUCCESS) {
4821 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4822 ldb_dn_get_linearized(conflict_dn),
4823 ldb_dn_get_linearized(new_dn),
4824 ldb_errstring(ldb_module_get_ctx(ar->module))));
4829 * now we need to ensure that the rename is seen as an
4830 * originating update. We do that with a modify.
4832 ret = replmd_name_modify(ar, req, new_dn);
4833 if (ret != LDB_SUCCESS) {
4837 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4838 ldb_dn_get_linearized(req->op.add.message->dn)));
4841 ret = ldb_build_add_req(&down_req,
4842 ldb_module_get_ctx(ar->module),
4849 if (ret != LDB_SUCCESS) {
4852 LDB_REQ_SET_LOCATION(down_req);
4854 /* current partition control needed by "repmd_op_callback" */
4855 ret = ldb_request_add_control(down_req,
4856 DSDB_CONTROL_CURRENT_PARTITION_OID,
4858 if (ret != LDB_SUCCESS) {
4859 return replmd_replicated_request_error(ar, ret);
4862 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4863 /* this tells the partition module to make it a
4864 partial replica if creating an NC */
4865 ret = ldb_request_add_control(down_req,
4866 DSDB_CONTROL_PARTIAL_REPLICA,
4868 if (ret != LDB_SUCCESS) {
4869 return replmd_replicated_request_error(ar, ret);
4874 * Finally we re-run the add, otherwise the new record won't
4875 * exist, as we are here because of that exact failure!
4877 return ldb_next_request(ar->module, down_req);
4880 /* on failure make the caller get the error. This means
4881 * replication will stop with an error, but there is not much
4884 return ldb_module_done(ar->req, NULL, NULL,
4889 callback for replmd_replicated_apply_add()
4890 This copes with the creation of conflict records in the case where
4891 the DN exists, but with a different objectGUID
4893 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4895 struct replmd_replicated_request *ar =
4896 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4898 if (ar->objs->objects[ar->index_current].last_known_parent) {
4899 /* This is like a conflict DN, where we put the object in LostAndFound
4900 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4901 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4904 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4908 this is called when a new object comes in over DRS
4910 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4912 struct ldb_context *ldb;
4913 struct ldb_request *change_req;
4914 enum ndr_err_code ndr_err;
4915 struct ldb_message *msg;
4916 struct replPropertyMetaDataBlob *md;
4917 struct ldb_val md_value;
4920 bool remote_isDeleted = false;
4923 time_t t = time(NULL);
4924 const struct ldb_val *rdn_val;
4925 struct replmd_private *replmd_private =
4926 talloc_get_type(ldb_module_get_private(ar->module),
4927 struct replmd_private);
4928 unix_to_nt_time(&now, t);
4930 ldb = ldb_module_get_ctx(ar->module);
4931 msg = ar->objs->objects[ar->index_current].msg;
4932 md = ar->objs->objects[ar->index_current].meta_data;
4933 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4935 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4936 if (ret != LDB_SUCCESS) {
4937 return replmd_replicated_request_error(ar, ret);
4940 ret = dsdb_msg_add_guid(msg,
4941 &ar->objs->objects[ar->index_current].object_guid,
4943 if (ret != LDB_SUCCESS) {
4944 return replmd_replicated_request_error(ar, ret);
4947 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4948 if (ret != LDB_SUCCESS) {
4949 return replmd_replicated_request_error(ar, ret);
4952 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4953 if (ret != LDB_SUCCESS) {
4954 return replmd_replicated_request_error(ar, ret);
4957 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4958 if (ret != LDB_SUCCESS) {
4959 return replmd_replicated_request_error(ar, ret);
4962 /* remove any message elements that have zero values */
4963 for (i=0; i<msg->num_elements; i++) {
4964 struct ldb_message_element *el = &msg->elements[i];
4966 if (el->num_values == 0) {
4967 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4968 ldb_asprintf_errstring(ldb, __location__
4969 ": empty objectClass sent on %s, aborting replication\n",
4970 ldb_dn_get_linearized(msg->dn));
4971 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4974 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4976 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4977 msg->num_elements--;
4984 struct GUID_txt_buf guid_txt;
4986 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4987 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4988 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4993 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4994 "isDeleted", false);
4997 * the meta data array is already sorted by the caller, except
4998 * for the RDN, which needs to be added.
5002 rdn_val = ldb_dn_get_rdn_val(msg->dn);
5003 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
5004 md, ar, now, is_schema_nc,
5006 if (ret != LDB_SUCCESS) {
5007 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5008 return replmd_replicated_request_error(ar, ret);
5011 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
5012 if (ret != LDB_SUCCESS) {
5013 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5014 return replmd_replicated_request_error(ar, ret);
5017 for (i=0; i < md->ctr.ctr1.count; i++) {
5018 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
5020 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
5021 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5022 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5023 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5024 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5026 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
5027 if (ret != LDB_SUCCESS) {
5028 return replmd_replicated_request_error(ar, ret);
5031 replmd_ldb_message_sort(msg, ar->schema);
5033 if (!remote_isDeleted) {
5034 ret = dsdb_module_schedule_sd_propagation(ar->module,
5035 ar->objs->partition_dn,
5037 if (ret != LDB_SUCCESS) {
5038 return replmd_replicated_request_error(ar, ret);
5042 ar->isDeleted = remote_isDeleted;
5044 ret = ldb_build_add_req(&change_req,
5050 replmd_op_add_callback,
5052 LDB_REQ_SET_LOCATION(change_req);
5053 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5055 /* current partition control needed by "repmd_op_callback" */
5056 ret = ldb_request_add_control(change_req,
5057 DSDB_CONTROL_CURRENT_PARTITION_OID,
5059 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5061 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5062 /* this tells the partition module to make it a
5063 partial replica if creating an NC */
5064 ret = ldb_request_add_control(change_req,
5065 DSDB_CONTROL_PARTIAL_REPLICA,
5067 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5070 return ldb_next_request(ar->module, change_req);
5073 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
5074 struct ldb_reply *ares)
5076 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5077 struct replmd_replicated_request);
5081 return ldb_module_done(ar->req, NULL, NULL,
5082 LDB_ERR_OPERATIONS_ERROR);
5086 * The error NO_SUCH_OBJECT is not expected, unless the search
5087 * base is the partition DN, and that case doesn't happen here
5088 * because then we wouldn't get a parent_guid_value in any
5091 if (ares->error != LDB_SUCCESS) {
5092 return ldb_module_done(ar->req, ares->controls,
5093 ares->response, ares->error);
5096 switch (ares->type) {
5097 case LDB_REPLY_ENTRY:
5099 struct ldb_message *parent_msg = ares->message;
5100 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5101 struct ldb_dn *parent_dn;
5104 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
5105 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
5106 /* Per MS-DRSR 4.1.10.6.10
5107 * FindBestParentObject we need to move this
5108 * new object under a deleted object to
5110 struct ldb_dn *nc_root;
5112 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
5113 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
5114 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5115 "No suitable NC root found for %s. "
5116 "We need to move this object because parent object %s "
5117 "is deleted, but this object is not.",
5118 ldb_dn_get_linearized(msg->dn),
5119 ldb_dn_get_linearized(parent_msg->dn));
5120 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5121 } else if (ret != LDB_SUCCESS) {
5122 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5123 "Unable to find NC root for %s: %s. "
5124 "We need to move this object because parent object %s "
5125 "is deleted, but this object is not.",
5126 ldb_dn_get_linearized(msg->dn),
5127 ldb_errstring(ldb_module_get_ctx(ar->module)),
5128 ldb_dn_get_linearized(parent_msg->dn));
5129 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5132 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5134 DS_GUID_LOSTANDFOUND_CONTAINER,
5136 if (ret != LDB_SUCCESS) {
5137 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5138 "Unable to find LostAndFound Container for %s "
5139 "in partition %s: %s. "
5140 "We need to move this object because parent object %s "
5141 "is deleted, but this object is not.",
5142 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5143 ldb_errstring(ldb_module_get_ctx(ar->module)),
5144 ldb_dn_get_linearized(parent_msg->dn));
5145 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5147 ar->objs->objects[ar->index_current].last_known_parent
5148 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5152 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5155 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5157 comp_num = ldb_dn_get_comp_num(msg->dn);
5159 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5161 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5164 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5166 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5170 case LDB_REPLY_REFERRAL:
5171 /* we ignore referrals */
5174 case LDB_REPLY_DONE:
5176 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5177 struct GUID_txt_buf str_buf;
5178 if (ar->search_msg != NULL) {
5179 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5180 "No parent with GUID %s found for object locally known as %s",
5181 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5182 ldb_dn_get_linearized(ar->search_msg->dn));
5184 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5185 "No parent with GUID %s found for object remotely known as %s",
5186 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5187 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5191 * This error code is really important, as it
5192 * is the flag back to the callers to retry
5193 * this with DRSUAPI_DRS_GET_ANC, and so get
5194 * the parent objects before the child
5197 return ldb_module_done(ar->req, NULL, NULL,
5198 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5201 if (ar->search_msg != NULL) {
5202 ret = replmd_replicated_apply_merge(ar);
5204 ret = replmd_replicated_apply_add(ar);
5206 if (ret != LDB_SUCCESS) {
5207 return ldb_module_done(ar->req, NULL, NULL, ret);
5216 * Look for the parent object, so we put the new object in the right
5217 * place This is akin to NameObject in MS-DRSR - this routine and the
5218 * callbacks find the right parent name, and correct name for this
5222 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5224 struct ldb_context *ldb;
5228 struct ldb_request *search_req;
5229 static const char *attrs[] = {"isDeleted", NULL};
5230 struct GUID_txt_buf guid_str_buf;
5232 ldb = ldb_module_get_ctx(ar->module);
5234 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5235 if (ar->search_msg != NULL) {
5236 return replmd_replicated_apply_merge(ar);
5238 return replmd_replicated_apply_add(ar);
5242 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5245 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5246 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5248 ret = ldb_build_search_req(&search_req,
5251 ar->objs->partition_dn,
5257 replmd_replicated_apply_search_for_parent_callback,
5259 LDB_REQ_SET_LOCATION(search_req);
5261 ret = dsdb_request_add_controls(search_req,
5262 DSDB_SEARCH_SHOW_RECYCLED|
5263 DSDB_SEARCH_SHOW_DELETED|
5264 DSDB_SEARCH_SHOW_EXTENDED_DN);
5265 if (ret != LDB_SUCCESS) {
5269 return ldb_next_request(ar->module, search_req);
5273 handle renames that come in over DRS replication
5275 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5276 struct ldb_message *msg,
5277 struct ldb_request *parent,
5281 TALLOC_CTX *tmp_ctx = talloc_new(msg);
5282 struct ldb_result *res;
5283 struct ldb_dn *conflict_dn;
5284 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5285 const struct ldb_val *omd_value;
5286 struct replPropertyMetaDataBlob omd, *rmd;
5287 enum ndr_err_code ndr_err;
5288 bool rename_incoming_record, rodc;
5289 struct replPropertyMetaData1 *rmd_name, *omd_name;
5290 struct ldb_dn *new_dn;
5293 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5294 ldb_dn_get_linearized(ar->search_msg->dn),
5295 ldb_dn_get_linearized(msg->dn)));
5298 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5299 DSDB_FLAG_NEXT_MODULE, ar->req);
5300 if (ret == LDB_SUCCESS) {
5301 talloc_free(tmp_ctx);
5306 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5307 talloc_free(tmp_ctx);
5308 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5309 ldb_dn_get_linearized(ar->search_msg->dn),
5310 ldb_dn_get_linearized(msg->dn),
5311 ldb_errstring(ldb_module_get_ctx(ar->module)));
5315 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5316 if (ret != LDB_SUCCESS) {
5317 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5318 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5319 ldb_errstring(ldb_module_get_ctx(ar->module)));
5320 return LDB_ERR_OPERATIONS_ERROR;
5323 * we have a conflict, and need to decide if we will keep the
5324 * new record or the old record
5327 conflict_dn = msg->dn;
5331 * We are on an RODC, or were a GC for this
5332 * partition, so we have to fail this until
5333 * someone who owns the partition sorts it
5336 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5337 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5338 " - We must fail the operation until a master for this partition resolves the conflict",
5339 ldb_dn_get_linearized(conflict_dn));
5344 * first we need the replPropertyMetaData attribute from the
5347 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5349 DSDB_FLAG_NEXT_MODULE |
5350 DSDB_SEARCH_SHOW_DELETED |
5351 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5352 if (ret != LDB_SUCCESS) {
5353 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5354 ldb_dn_get_linearized(conflict_dn)));
5358 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5359 if (omd_value == NULL) {
5360 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5361 ldb_dn_get_linearized(conflict_dn)));
5365 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5366 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5367 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5368 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5369 ldb_dn_get_linearized(conflict_dn)));
5373 rmd = ar->objs->objects[ar->index_current].meta_data;
5376 * we decide which is newer based on the RPMD on the name
5377 * attribute. See [MS-DRSR] ResolveNameConflict.
5379 * We expect omd_name to be present, as this is from a local
5380 * search, but while rmd_name should have been given to us by
5381 * the remote server, if it is missing we just prefer the
5383 * replmd_replPropertyMetaData1_new_should_be_taken()
5385 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5386 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5388 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5389 ldb_dn_get_linearized(conflict_dn)));
5394 * Should we preserve the current record, and so rename the
5395 * incoming record to be a conflict?
5397 rename_incoming_record =
5398 !replmd_replPropertyMetaData1_new_should_be_taken(
5399 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5400 omd_name, rmd_name);
5402 if (rename_incoming_record) {
5404 new_dn = replmd_conflict_dn(msg, msg->dn,
5405 &ar->objs->objects[ar->index_current].object_guid);
5406 if (new_dn == NULL) {
5407 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5408 "Failed to form conflict DN for %s\n",
5409 ldb_dn_get_linearized(msg->dn));
5411 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5414 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5415 DSDB_FLAG_NEXT_MODULE, ar->req);
5416 if (ret != LDB_SUCCESS) {
5417 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5418 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5419 ldb_dn_get_linearized(conflict_dn),
5420 ldb_dn_get_linearized(ar->search_msg->dn),
5421 ldb_dn_get_linearized(new_dn),
5422 ldb_errstring(ldb_module_get_ctx(ar->module)));
5423 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5431 /* we are renaming the existing record */
5433 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5434 if (GUID_all_zero(&guid)) {
5435 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5436 ldb_dn_get_linearized(conflict_dn)));
5440 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5441 if (new_dn == NULL) {
5442 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5443 ldb_dn_get_linearized(conflict_dn)));
5447 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5448 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5450 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5451 DSDB_FLAG_OWN_MODULE, ar->req);
5452 if (ret != LDB_SUCCESS) {
5453 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5454 ldb_dn_get_linearized(conflict_dn),
5455 ldb_dn_get_linearized(new_dn),
5456 ldb_errstring(ldb_module_get_ctx(ar->module))));
5461 * now we need to ensure that the rename is seen as an
5462 * originating update. We do that with a modify.
5464 ret = replmd_name_modify(ar, ar->req, new_dn);
5465 if (ret != LDB_SUCCESS) {
5469 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5470 ldb_dn_get_linearized(ar->search_msg->dn),
5471 ldb_dn_get_linearized(msg->dn)));
5474 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5475 DSDB_FLAG_NEXT_MODULE, ar->req);
5476 if (ret != LDB_SUCCESS) {
5477 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5478 ldb_dn_get_linearized(ar->search_msg->dn),
5479 ldb_dn_get_linearized(msg->dn),
5480 ldb_errstring(ldb_module_get_ctx(ar->module))));
5486 * On failure make the caller get the error
5487 * This means replication will stop with an error,
5488 * but there is not much else we can do. In the
5489 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5493 talloc_free(tmp_ctx);
5498 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5500 struct ldb_context *ldb;
5501 struct ldb_request *change_req;
5502 enum ndr_err_code ndr_err;
5503 struct ldb_message *msg;
5504 struct replPropertyMetaDataBlob *rmd;
5505 struct replPropertyMetaDataBlob omd;
5506 const struct ldb_val *omd_value;
5507 struct replPropertyMetaDataBlob nmd;
5508 struct ldb_val nmd_value;
5509 struct GUID remote_parent_guid;
5512 unsigned int removed_attrs = 0;
5514 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5515 bool isDeleted = false;
5516 bool local_isDeleted = false;
5517 bool remote_isDeleted = false;
5518 bool take_remote_isDeleted = false;
5519 bool sd_updated = false;
5520 bool renamed = false;
5521 bool is_schema_nc = false;
5523 const struct ldb_val *old_rdn, *new_rdn;
5524 struct replmd_private *replmd_private =
5525 talloc_get_type(ldb_module_get_private(ar->module),
5526 struct replmd_private);
5528 time_t t = time(NULL);
5529 unix_to_nt_time(&now, t);
5531 ldb = ldb_module_get_ctx(ar->module);
5532 msg = ar->objs->objects[ar->index_current].msg;
5534 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5536 rmd = ar->objs->objects[ar->index_current].meta_data;
5540 /* find existing meta data */
5541 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5543 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5544 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5545 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5546 nt_status = ndr_map_error2ntstatus(ndr_err);
5547 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5550 if (omd.version != 1) {
5551 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5556 struct GUID_txt_buf guid_txt;
5558 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5559 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
5562 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5564 ndr_print_struct_string(s,
5565 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5566 "existing replPropertyMetaData",
5568 ndr_print_struct_string(s,
5569 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5570 "incoming replPropertyMetaData",
5575 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5576 "isDeleted", false);
5577 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5578 "isDeleted", false);
5581 * Fill in the remote_parent_guid with the GUID or an all-zero
5584 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5585 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5587 remote_parent_guid = GUID_zero();
5591 * To ensure we follow a complex rename chain around, we have
5592 * to confirm that the DN is the same (mostly to confirm the
5593 * RDN) and the parentGUID is the same.
5595 * This ensures we keep things under the correct parent, which
5596 * replmd_replicated_handle_rename() will do.
5599 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5600 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5604 * handle renames, even just by case that come in over
5605 * DRS. Changes in the parent DN don't hit us here,
5606 * because the search for a parent will clean up those
5609 * We also have already filtered out the case where
5610 * the peer has an older name to what we have (see
5611 * replmd_replicated_apply_search_callback())
5613 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5616 if (ret != LDB_SUCCESS) {
5617 ldb_debug(ldb, LDB_DEBUG_FATAL,
5618 "replmd_replicated_request rename %s => %s failed - %s\n",
5619 ldb_dn_get_linearized(ar->search_msg->dn),
5620 ldb_dn_get_linearized(msg->dn),
5621 ldb_errstring(ldb));
5622 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5625 if (renamed == true) {
5627 * Set the callback to one that will fix up the name
5628 * metadata on the new conflict DN
5630 callback = replmd_op_name_modify_callback;
5635 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5636 nmd.ctr.ctr1.array = talloc_array(ar,
5637 struct replPropertyMetaData1,
5638 nmd.ctr.ctr1.count);
5639 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5641 /* first copy the old meta data */
5642 for (i=0; i < omd.ctr.ctr1.count; i++) {
5643 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5648 /* now merge in the new meta data */
5649 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5652 for (j=0; j < ni; j++) {
5655 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5659 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5660 ar->objs->dsdb_repl_flags,
5661 &nmd.ctr.ctr1.array[j],
5662 &rmd->ctr.ctr1.array[i]);
5664 /* replace the entry */
5665 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5666 if (ar->seq_num == 0) {
5667 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5668 if (ret != LDB_SUCCESS) {
5669 return replmd_replicated_request_error(ar, ret);
5672 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5673 switch (nmd.ctr.ctr1.array[j].attid) {
5674 case DRSUAPI_ATTID_ntSecurityDescriptor:
5677 case DRSUAPI_ATTID_isDeleted:
5678 take_remote_isDeleted = true;
5687 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5688 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5689 msg->elements[i-removed_attrs].name,
5690 ldb_dn_get_linearized(msg->dn),
5691 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5694 /* we don't want to apply this change so remove the attribute */
5695 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5702 if (found) continue;
5704 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5705 if (ar->seq_num == 0) {
5706 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5707 if (ret != LDB_SUCCESS) {
5708 return replmd_replicated_request_error(ar, ret);
5711 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5712 switch (nmd.ctr.ctr1.array[ni].attid) {
5713 case DRSUAPI_ATTID_ntSecurityDescriptor:
5716 case DRSUAPI_ATTID_isDeleted:
5717 take_remote_isDeleted = true;
5726 * finally correct the size of the meta_data array
5728 nmd.ctr.ctr1.count = ni;
5730 new_rdn = ldb_dn_get_rdn_val(msg->dn);
5731 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5734 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5735 &nmd, ar, now, is_schema_nc,
5737 if (ret != LDB_SUCCESS) {
5738 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5739 return replmd_replicated_request_error(ar, ret);
5743 * sort the new meta data array
5745 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5746 if (ret != LDB_SUCCESS) {
5747 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5752 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
5755 * This also controls SD propagation below
5757 if (take_remote_isDeleted) {
5758 isDeleted = remote_isDeleted;
5760 isDeleted = local_isDeleted;
5763 ar->isDeleted = isDeleted;
5766 * check if some replicated attributes left, otherwise skip the ldb_modify() call
5768 if (msg->num_elements == 0) {
5769 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5772 return replmd_replicated_apply_isDeleted(ar);
5775 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5776 ar->index_current, msg->num_elements);
5782 if (sd_updated && !isDeleted) {
5783 ret = dsdb_module_schedule_sd_propagation(ar->module,
5784 ar->objs->partition_dn,
5786 if (ret != LDB_SUCCESS) {
5787 return ldb_operr(ldb);
5791 /* create the meta data value */
5792 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5793 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5794 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5795 nt_status = ndr_map_error2ntstatus(ndr_err);
5796 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5800 * when we know that we'll modify the record, add the whenChanged, uSNChanged
5801 * and replPopertyMetaData attributes
5803 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5804 if (ret != LDB_SUCCESS) {
5805 return replmd_replicated_request_error(ar, ret);
5807 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5808 if (ret != LDB_SUCCESS) {
5809 return replmd_replicated_request_error(ar, ret);
5811 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5812 if (ret != LDB_SUCCESS) {
5813 return replmd_replicated_request_error(ar, ret);
5816 replmd_ldb_message_sort(msg, ar->schema);
5818 /* we want to replace the old values */
5819 for (i=0; i < msg->num_elements; i++) {
5820 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5821 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5822 if (msg->elements[i].num_values == 0) {
5823 ldb_asprintf_errstring(ldb, __location__
5824 ": objectClass removed on %s, aborting replication\n",
5825 ldb_dn_get_linearized(msg->dn));
5826 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5832 struct GUID_txt_buf guid_txt;
5834 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5835 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5836 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5841 ret = ldb_build_mod_req(&change_req,
5849 LDB_REQ_SET_LOCATION(change_req);
5850 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5852 /* current partition control needed by "repmd_op_callback" */
5853 ret = ldb_request_add_control(change_req,
5854 DSDB_CONTROL_CURRENT_PARTITION_OID,
5856 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5858 return ldb_next_request(ar->module, change_req);
5861 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5862 struct ldb_reply *ares)
5864 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5865 struct replmd_replicated_request);
5869 return ldb_module_done(ar->req, NULL, NULL,
5870 LDB_ERR_OPERATIONS_ERROR);
5872 if (ares->error != LDB_SUCCESS &&
5873 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5874 return ldb_module_done(ar->req, ares->controls,
5875 ares->response, ares->error);
5878 switch (ares->type) {
5879 case LDB_REPLY_ENTRY:
5880 ar->search_msg = talloc_steal(ar, ares->message);
5883 case LDB_REPLY_REFERRAL:
5884 /* we ignore referrals */
5887 case LDB_REPLY_DONE:
5889 struct replPropertyMetaData1 *md_remote;
5890 struct replPropertyMetaData1 *md_local;
5892 struct replPropertyMetaDataBlob omd;
5893 const struct ldb_val *omd_value;
5894 struct replPropertyMetaDataBlob *rmd;
5895 struct ldb_message *msg;
5897 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5898 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5901 * This is the ADD case, find the appropriate parent,
5902 * as this object doesn't exist locally:
5904 if (ar->search_msg == NULL) {
5905 ret = replmd_replicated_apply_search_for_parent(ar);
5906 if (ret != LDB_SUCCESS) {
5907 return ldb_module_done(ar->req, NULL, NULL, ret);
5914 * Otherwise, in the MERGE case, work out if we are
5915 * attempting a rename, and if so find the parent the
5916 * newly renamed object wants to belong under (which
5917 * may not be the parent in it's attached string DN
5919 rmd = ar->objs->objects[ar->index_current].meta_data;
5923 /* find existing meta data */
5924 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5926 enum ndr_err_code ndr_err;
5927 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5928 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5929 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5930 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5931 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5934 if (omd.version != 1) {
5935 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5939 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5941 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5942 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5943 && GUID_all_zero(&ar->local_parent_guid)) {
5944 DEBUG(0, ("Refusing to replicate new version of %s "
5945 "as local object has an all-zero parentGUID attribute, "
5946 "despite not being an NC root\n",
5947 ldb_dn_get_linearized(ar->search_msg->dn)));
5948 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5952 * now we need to check for double renames. We could have a
5953 * local rename pending which our replication partner hasn't
5954 * received yet. We choose which one wins by looking at the
5955 * attribute stamps on the two objects, the newer one wins.
5957 * This also simply applies the correct algorithms for
5958 * determining if a change was made to name at all, or
5959 * if the object has just been renamed under the same
5962 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5963 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5965 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5966 ldb_dn_get_linearized(ar->search_msg->dn)));
5967 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5971 * if there is no name attribute given then we have to assume the
5972 * object we've received has the older name
5974 if (replmd_replPropertyMetaData1_new_should_be_taken(
5975 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5976 md_local, md_remote)) {
5977 struct GUID_txt_buf p_guid_local;
5978 struct GUID_txt_buf p_guid_remote;
5979 msg = ar->objs->objects[ar->index_current].msg;
5981 /* Merge on the existing object, with rename */
5983 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5984 "as incoming object changing to %s under %s\n",
5985 ldb_dn_get_linearized(ar->search_msg->dn),
5986 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5987 ldb_dn_get_linearized(msg->dn),
5988 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5990 ret = replmd_replicated_apply_search_for_parent(ar);
5992 struct GUID_txt_buf p_guid_local;
5993 struct GUID_txt_buf p_guid_remote;
5994 msg = ar->objs->objects[ar->index_current].msg;
5997 * Merge on the existing object, force no
5998 * rename (code below just to explain why in
6002 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
6003 ldb_dn_get_linearized(msg->dn)) == 0) {
6004 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
6005 GUID_equal(&ar->local_parent_guid,
6006 ar->objs->objects[ar->index_current].parent_guid)
6008 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6009 "despite incoming object changing parent to %s\n",
6010 ldb_dn_get_linearized(ar->search_msg->dn),
6011 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6012 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6016 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6017 " and rejecting older rename to %s under %s\n",
6018 ldb_dn_get_linearized(ar->search_msg->dn),
6019 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6020 ldb_dn_get_linearized(msg->dn),
6021 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6025 * This assignment ensures that the strcmp()
6026 * and GUID_equal() calls in
6027 * replmd_replicated_apply_merge() avoids the
6030 ar->objs->objects[ar->index_current].parent_guid =
6031 &ar->local_parent_guid;
6033 msg->dn = ar->search_msg->dn;
6034 ret = replmd_replicated_apply_merge(ar);
6036 if (ret != LDB_SUCCESS) {
6037 return ldb_module_done(ar->req, NULL, NULL, ret);
6047 * Stores the linked attributes received in the replication chunk - these get
6048 * applied at the end of the transaction. We also check that each linked
6049 * attribute is valid, i.e. source and target objects are known.
6051 static int replmd_store_linked_attributes(struct replmd_replicated_request *ar)
6053 int ret = LDB_SUCCESS;
6055 bool incomplete_subset;
6056 struct ldb_module *module = ar->module;
6057 struct replmd_private *replmd_private =
6058 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6059 struct ldb_context *ldb;
6061 ldb = ldb_module_get_ctx(module);
6062 incomplete_subset = (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_OBJECT_SUBSET);
6064 DEBUG(4,("linked_attributes_count=%u\n", ar->objs->linked_attributes_count));
6066 /* save away the linked attributes for the end of the transaction */
6067 for (i = 0; i < ar->objs->linked_attributes_count; i++) {
6068 struct la_entry *la_entry;
6070 if (replmd_private->la_ctx == NULL) {
6071 replmd_private->la_ctx = talloc_new(replmd_private);
6073 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6074 if (la_entry == NULL) {
6076 return LDB_ERR_OPERATIONS_ERROR;
6078 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6079 if (la_entry->la == NULL) {
6080 talloc_free(la_entry);
6082 return LDB_ERR_OPERATIONS_ERROR;
6084 *la_entry->la = ar->objs->linked_attributes[i];
6087 * we may not be able to resolve link targets properly when
6088 * dealing with subsets of objects, e.g. the source is a
6089 * critical object and the target isn't
6091 la_entry->incomplete_replica = incomplete_subset;
6093 /* we need to steal the non-scalars so they stay
6094 around until the end of the transaction */
6095 talloc_steal(la_entry->la, la_entry->la->identifier);
6096 talloc_steal(la_entry->la, la_entry->la->value.blob);
6098 ret = replmd_verify_linked_attribute(ar, la_entry);
6100 if (ret != LDB_SUCCESS) {
6104 DLIST_ADD(replmd_private->la_list, la_entry);
6110 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
6112 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
6114 struct ldb_context *ldb;
6118 struct ldb_request *search_req;
6119 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
6120 "parentGUID", "instanceType",
6121 "replPropertyMetaData", "nTSecurityDescriptor",
6122 "isDeleted", NULL };
6123 struct GUID_txt_buf guid_str_buf;
6125 if (ar->index_current >= ar->objs->num_objects) {
6128 * Now that we've applied all the objects, check the new linked
6129 * attributes and store them (we apply them in .prepare_commit)
6131 ret = replmd_store_linked_attributes(ar);
6133 if (ret != LDB_SUCCESS) {
6137 /* done applying objects, move on to the next stage */
6138 return replmd_replicated_uptodate_vector(ar);
6141 ldb = ldb_module_get_ctx(ar->module);
6142 ar->search_msg = NULL;
6143 ar->isDeleted = false;
6145 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6148 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
6149 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6151 ret = ldb_build_search_req(&search_req,
6154 ar->objs->partition_dn,
6160 replmd_replicated_apply_search_callback,
6162 LDB_REQ_SET_LOCATION(search_req);
6164 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
6166 if (ret != LDB_SUCCESS) {
6170 return ldb_next_request(ar->module, search_req);
6174 * This is essentially a wrapper for replmd_replicated_apply_next()
6176 * This is needed to ensure that both codepaths call this handler.
6178 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
6180 struct ldb_dn *deleted_objects_dn;
6181 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
6182 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
6183 &deleted_objects_dn);
6184 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
6186 * Do a delete here again, so that if there is
6187 * anything local that conflicts with this
6188 * object being deleted, it is removed. This
6189 * includes links. See MS-DRSR 4.1.10.6.9
6192 * If the object is already deleted, and there
6193 * is no more work required, it doesn't do
6197 /* This has been updated to point to the DN we eventually did the modify on */
6199 struct ldb_request *del_req;
6200 struct ldb_result *res;
6202 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6204 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6208 res = talloc_zero(tmp_ctx, struct ldb_result);
6210 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6211 talloc_free(tmp_ctx);
6215 /* Build a delete request, which hopefully will artually turn into nothing */
6216 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6220 ldb_modify_default_callback,
6222 LDB_REQ_SET_LOCATION(del_req);
6223 if (ret != LDB_SUCCESS) {
6224 talloc_free(tmp_ctx);
6229 * This is the guts of the call, call back
6230 * into our delete code, but setting the
6231 * re_delete flag so we delete anything that
6232 * shouldn't be there on a deleted or recycled
6235 ret = replmd_delete_internals(ar->module, del_req, true);
6236 if (ret == LDB_SUCCESS) {
6237 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6240 talloc_free(tmp_ctx);
6241 if (ret != LDB_SUCCESS) {
6246 ar->index_current++;
6247 return replmd_replicated_apply_next(ar);
6250 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6251 struct ldb_reply *ares)
6253 struct ldb_context *ldb;
6254 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6255 struct replmd_replicated_request);
6256 ldb = ldb_module_get_ctx(ar->module);
6259 return ldb_module_done(ar->req, NULL, NULL,
6260 LDB_ERR_OPERATIONS_ERROR);
6262 if (ares->error != LDB_SUCCESS) {
6263 return ldb_module_done(ar->req, ares->controls,
6264 ares->response, ares->error);
6267 if (ares->type != LDB_REPLY_DONE) {
6268 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6269 return ldb_module_done(ar->req, NULL, NULL,
6270 LDB_ERR_OPERATIONS_ERROR);
6275 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6278 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6280 struct ldb_context *ldb;
6281 struct ldb_request *change_req;
6282 enum ndr_err_code ndr_err;
6283 struct ldb_message *msg;
6284 struct replUpToDateVectorBlob ouv;
6285 const struct ldb_val *ouv_value;
6286 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6287 struct replUpToDateVectorBlob nuv;
6288 struct ldb_val nuv_value;
6289 struct ldb_message_element *nuv_el = NULL;
6290 struct ldb_message_element *orf_el = NULL;
6291 struct repsFromToBlob nrf;
6292 struct ldb_val *nrf_value = NULL;
6293 struct ldb_message_element *nrf_el = NULL;
6297 time_t t = time(NULL);
6300 uint32_t instanceType;
6302 ldb = ldb_module_get_ctx(ar->module);
6303 ruv = ar->objs->uptodateness_vector;
6309 unix_to_nt_time(&now, t);
6311 if (ar->search_msg == NULL) {
6312 /* this happens for a REPL_OBJ call where we are
6313 creating the target object by replicating it. The
6314 subdomain join code does this for the partition DN
6316 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6317 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6320 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6321 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6322 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6323 ldb_dn_get_linearized(ar->search_msg->dn)));
6324 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6328 * first create the new replUpToDateVector
6330 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6332 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6333 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6334 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6335 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6336 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6339 if (ouv.version != 2) {
6340 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6345 * the new uptodateness vector will at least
6346 * contain 1 entry, one for the source_dsa
6348 * plus optional values from our old vector and the one from the source_dsa
6350 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6351 if (ruv) nuv.ctr.ctr2.count += ruv->count;
6352 nuv.ctr.ctr2.cursors = talloc_array(ar,
6353 struct drsuapi_DsReplicaCursor2,
6354 nuv.ctr.ctr2.count);
6355 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6357 /* first copy the old vector */
6358 for (i=0; i < ouv.ctr.ctr2.count; i++) {
6359 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6363 /* merge in the source_dsa vector is available */
6364 for (i=0; (ruv && i < ruv->count); i++) {
6367 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6368 &ar->our_invocation_id)) {
6372 for (j=0; j < ni; j++) {
6373 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6374 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6380 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6381 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6386 if (found) continue;
6388 /* if it's not there yet, add it */
6389 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6394 * finally correct the size of the cursors array
6396 nuv.ctr.ctr2.count = ni;
6401 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6404 * create the change ldb_message
6406 msg = ldb_msg_new(ar);
6407 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6408 msg->dn = ar->search_msg->dn;
6410 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6411 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6412 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6413 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6414 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6416 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6417 if (ret != LDB_SUCCESS) {
6418 return replmd_replicated_request_error(ar, ret);
6420 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6423 * now create the new repsFrom value from the given repsFromTo1 structure
6427 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6428 nrf.ctr.ctr1.last_attempt = now;
6429 nrf.ctr.ctr1.last_success = now;
6430 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6433 * first see if we already have a repsFrom value for the current source dsa
6434 * if so we'll later replace this value
6436 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6438 for (i=0; i < orf_el->num_values; i++) {
6439 struct repsFromToBlob *trf;
6441 trf = talloc(ar, struct repsFromToBlob);
6442 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6444 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6445 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6446 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6447 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6448 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6451 if (trf->version != 1) {
6452 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6456 * we compare the source dsa objectGUID not the invocation_id
6457 * because we want only one repsFrom value per source dsa
6458 * and when the invocation_id of the source dsa has changed we don't need
6459 * the old repsFrom with the old invocation_id
6461 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6462 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6468 nrf_value = &orf_el->values[i];
6473 * copy over all old values to the new ldb_message
6475 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6476 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6481 * if we haven't found an old repsFrom value for the current source dsa
6482 * we'll add a new value
6485 struct ldb_val zero_value;
6486 ZERO_STRUCT(zero_value);
6487 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6488 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6490 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6493 /* we now fill the value which is already attached to ldb_message */
6494 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6496 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6497 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6498 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6499 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6503 * the ldb_message_element for the attribute, has all the old values and the new one
6504 * so we'll replace the whole attribute with all values
6506 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6508 if (CHECK_DEBUGLVL(4)) {
6509 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
6510 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6514 /* prepare the ldb_modify() request */
6515 ret = ldb_build_mod_req(&change_req,
6521 replmd_replicated_uptodate_modify_callback,
6523 LDB_REQ_SET_LOCATION(change_req);
6524 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6526 return ldb_next_request(ar->module, change_req);
6529 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6530 struct ldb_reply *ares)
6532 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6533 struct replmd_replicated_request);
6537 return ldb_module_done(ar->req, NULL, NULL,
6538 LDB_ERR_OPERATIONS_ERROR);
6540 if (ares->error != LDB_SUCCESS &&
6541 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6542 return ldb_module_done(ar->req, ares->controls,
6543 ares->response, ares->error);
6546 switch (ares->type) {
6547 case LDB_REPLY_ENTRY:
6548 ar->search_msg = talloc_steal(ar, ares->message);
6551 case LDB_REPLY_REFERRAL:
6552 /* we ignore referrals */
6555 case LDB_REPLY_DONE:
6556 ret = replmd_replicated_uptodate_modify(ar);
6557 if (ret != LDB_SUCCESS) {
6558 return ldb_module_done(ar->req, NULL, NULL, ret);
6567 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6569 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6570 struct replmd_private *replmd_private =
6571 talloc_get_type_abort(ldb_module_get_private(ar->module),
6572 struct replmd_private);
6574 static const char *attrs[] = {
6575 "replUpToDateVector",
6580 struct ldb_request *search_req;
6582 ar->search_msg = NULL;
6585 * Let the caller know that we did an originating updates
6587 ar->objs->originating_updates = replmd_private->originating_updates;
6589 ret = ldb_build_search_req(&search_req,
6592 ar->objs->partition_dn,
6598 replmd_replicated_uptodate_search_callback,
6600 LDB_REQ_SET_LOCATION(search_req);
6601 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6603 return ldb_next_request(ar->module, search_req);
6608 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6610 struct ldb_context *ldb;
6611 struct dsdb_extended_replicated_objects *objs;
6612 struct replmd_replicated_request *ar;
6613 struct ldb_control **ctrls;
6616 ldb = ldb_module_get_ctx(module);
6618 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6620 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6622 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6623 return LDB_ERR_PROTOCOL_ERROR;
6626 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6627 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6628 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6629 return LDB_ERR_PROTOCOL_ERROR;
6632 ar = replmd_ctx_init(module, req);
6634 return LDB_ERR_OPERATIONS_ERROR;
6636 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6637 ar->apply_mode = true;
6639 ar->schema = dsdb_get_schema(ldb, ar);
6641 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6643 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6644 return LDB_ERR_CONSTRAINT_VIOLATION;
6647 ctrls = req->controls;
6649 if (req->controls) {
6650 req->controls = talloc_memdup(ar, req->controls,
6651 talloc_get_size(req->controls));
6652 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6655 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6656 if (ret != LDB_SUCCESS) {
6660 /* If this change contained linked attributes in the body
6661 * (rather than in the links section) we need to update
6662 * backlinks in linked_attributes */
6663 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6664 if (ret != LDB_SUCCESS) {
6668 ar->controls = req->controls;
6669 req->controls = ctrls;
6671 return replmd_replicated_apply_next(ar);
6675 * Returns True if the source and target DNs both have the same naming context,
6676 * i.e. they're both in the same partition.
6678 static bool replmd_objects_have_same_nc(struct ldb_context *ldb,
6679 TALLOC_CTX *mem_ctx,
6680 struct ldb_dn *source_dn,
6681 struct ldb_dn *target_dn)
6683 TALLOC_CTX *tmp_ctx;
6684 struct ldb_dn *source_nc;
6685 struct ldb_dn *target_nc;
6687 bool same_nc = true;
6689 tmp_ctx = talloc_new(mem_ctx);
6691 ret = dsdb_find_nc_root(ldb, tmp_ctx, source_dn, &source_nc);
6692 if (ret != LDB_SUCCESS) {
6693 DBG_ERR("Failed to find base DN for source %s\n",
6694 ldb_dn_get_linearized(source_dn));
6695 talloc_free(tmp_ctx);
6699 ret = dsdb_find_nc_root(ldb, tmp_ctx, target_dn, &target_nc);
6700 if (ret != LDB_SUCCESS) {
6701 DBG_ERR("Failed to find base DN for target %s\n",
6702 ldb_dn_get_linearized(target_dn));
6703 talloc_free(tmp_ctx);
6707 same_nc = (ldb_dn_compare(source_nc, target_nc) == 0);
6709 talloc_free(tmp_ctx);
6715 * Checks that the target object for a linked attribute exists.
6716 * @param guid returns the target object's GUID (is returned)if it exists)
6717 * @param ignore_link set to true if the linked attribute should be ignored
6718 * (i.e. the target doesn't exist, but that it's OK to skip the link)
6720 static int replmd_check_target_exists(struct ldb_module *module,
6721 struct dsdb_dn *dsdb_dn,
6722 struct la_entry *la_entry,
6723 struct ldb_dn *source_dn,
6727 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6728 struct ldb_context *ldb = ldb_module_get_ctx(module);
6729 struct ldb_result *target_res;
6730 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6731 const char *attrs[] = { "isDeleted", "isRecycled", NULL };
6734 enum deletion_state target_deletion_state = OBJECT_REMOVED;
6735 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) ? true : false;
6737 *ignore_link = false;
6738 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, guid, "GUID");
6740 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6743 * This strange behaviour (allowing a NULL/missing
6744 * GUID) originally comes from:
6746 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6747 * Author: Andrew Tridgell <tridge@samba.org>
6748 * Date: Mon Dec 21 21:21:55 2009 +1100
6750 * s4-drs: cope better with NULL GUIDS from DRS
6752 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
6753 * need to match by DN if possible when seeing if we should update an
6756 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6758 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6760 DSDB_FLAG_NEXT_MODULE |
6761 DSDB_SEARCH_SHOW_RECYCLED |
6762 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6763 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6765 } else if (!NT_STATUS_IS_OK(ntstatus)) {
6766 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute 0x%x blob for %s from %s",
6768 ldb_dn_get_linearized(dsdb_dn->dn),
6769 ldb_dn_get_linearized(source_dn));
6770 talloc_free(tmp_ctx);
6771 return LDB_ERR_OPERATIONS_ERROR;
6773 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6774 NULL, LDB_SCOPE_SUBTREE,
6776 DSDB_FLAG_NEXT_MODULE |
6777 DSDB_SEARCH_SHOW_RECYCLED |
6778 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6779 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6782 GUID_string(tmp_ctx, guid));
6785 if (ret != LDB_SUCCESS) {
6786 ldb_asprintf_errstring(ldb, "Failed to re-resolve GUID %s: %s\n",
6787 GUID_string(tmp_ctx, guid),
6788 ldb_errstring(ldb));
6789 talloc_free(tmp_ctx);
6793 if (target_res->count == 0) {
6797 * When we implement Trusted Domains we need to consider
6798 * whether they get treated as an incomplete replica here or not
6800 if (la_entry->incomplete_replica) {
6803 * If we're only replicating a subset of objects (e.g.
6804 * critical-only, single-object), then an unknown target
6805 * is probably not a critical problem. We don't increase
6806 * the highwater-mark so subsequent replications should
6807 * resolve any missing links
6809 DEBUG(2,(__location__
6810 ": Failed to find target %s linked from %s\n",
6811 ldb_dn_get_linearized(dsdb_dn->dn),
6812 ldb_dn_get_linearized(source_dn)));
6813 *ignore_link = true;
6815 } else if (replmd_objects_have_same_nc(ldb, tmp_ctx, source_dn,
6817 ldb_asprintf_errstring(ldb, "Unknown target %s GUID %s linked from %s\n",
6818 ldb_dn_get_linearized(dsdb_dn->dn),
6819 GUID_string(tmp_ctx, guid),
6820 ldb_dn_get_linearized(source_dn));
6821 ret = LDB_ERR_NO_SUCH_OBJECT;
6826 * We don't handle cross-partition links well here (we
6827 * could potentially lose them), but don't fail the
6830 DEBUG(2,("Failed to resolve cross-partition link between %s and %s\n",
6831 ldb_dn_get_linearized(source_dn),
6832 ldb_dn_get_linearized(dsdb_dn->dn)));
6833 *ignore_link = true;
6835 } else if (target_res->count != 1) {
6836 ldb_asprintf_errstring(ldb, "More than one object found matching objectGUID %s\n",
6837 GUID_string(tmp_ctx, guid));
6838 ret = LDB_ERR_OPERATIONS_ERROR;
6840 struct ldb_message *target_msg = target_res->msgs[0];
6842 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6844 /* Get the object's state (i.e. Not Deleted, Tombstone, etc) */
6845 replmd_deletion_state(module, target_msg,
6846 &target_deletion_state, NULL);
6849 * Check for deleted objects as per MS-DRSR 4.1.10.6.14
6850 * ProcessLinkValue(). Link updates should not be sent for
6851 * recycled and tombstone objects (deleting the links should
6852 * happen when we delete the object). This probably means our
6853 * copy of the target object isn't up to date.
6855 if (target_deletion_state >= OBJECT_RECYCLED) {
6856 ldb_asprintf_errstring(ldb,
6857 "Deleted target %s GUID %s linked from %s\n",
6858 ldb_dn_get_linearized(dsdb_dn->dn),
6859 GUID_string(tmp_ctx, guid),
6860 ldb_dn_get_linearized(source_dn));
6861 ret = LDB_ERR_NO_SUCH_OBJECT;
6865 talloc_free(tmp_ctx);
6870 * Extracts the key details about the source/target object for a
6871 * linked-attribute entry.
6872 * This returns the following details:
6873 * @param ret_attr the schema details for the linked attribute
6874 * @param source_msg the search result for the source object
6875 * @param target_dsdb_dn the unpacked DN info for the target object
6877 static int replmd_extract_la_entry_details(struct ldb_module *module,
6878 struct la_entry *la_entry,
6879 TALLOC_CTX *mem_ctx,
6880 const struct dsdb_attribute **ret_attr,
6881 struct ldb_message **source_msg,
6882 struct dsdb_dn **target_dsdb_dn)
6884 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6885 struct ldb_context *ldb = ldb_module_get_ctx(module);
6886 const struct dsdb_schema *schema = dsdb_get_schema(ldb, mem_ctx);
6888 const struct dsdb_attribute *attr;
6890 struct ldb_result *res;
6891 const char *attrs[4];
6894 linked_attributes[0]:
6895 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6897 identifier: struct drsuapi_DsReplicaObjectIdentifier
6898 __ndr_size : 0x0000003a (58)
6899 __ndr_size_sid : 0x00000000 (0)
6900 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6902 __ndr_size_dn : 0x00000000 (0)
6904 attid : DRSUAPI_ATTID_member (0x1F)
6905 value: struct drsuapi_DsAttributeValue
6906 __ndr_size : 0x0000007e (126)
6908 blob : DATA_BLOB length=126
6909 flags : 0x00000001 (1)
6910 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6911 originating_add_time : Wed Sep 2 22:20:01 2009 EST
6912 meta_data: struct drsuapi_DsReplicaMetaData
6913 version : 0x00000015 (21)
6914 originating_change_time : Wed Sep 2 23:39:07 2009 EST
6915 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6916 originating_usn : 0x000000000001e19c (123292)
6918 (for cases where the link is to a normal DN)
6919 &target: struct drsuapi_DsReplicaObjectIdentifier3
6920 __ndr_size : 0x0000007e (126)
6921 __ndr_size_sid : 0x0000001c (28)
6922 guid : 7639e594-db75-4086-b0d4-67890ae46031
6923 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
6924 __ndr_size_dn : 0x00000022 (34)
6925 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
6928 /* find the attribute being modified */
6929 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
6931 struct GUID_txt_buf guid_str;
6932 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
6934 GUID_buf_string(&la->identifier->guid,
6936 return LDB_ERR_OPERATIONS_ERROR;
6939 attrs[0] = attr->lDAPDisplayName;
6940 attrs[1] = "isDeleted";
6941 attrs[2] = "isRecycled";
6945 * get the existing message from the db for the object with
6946 * this GUID, returning attribute being modified. We will then
6947 * use this msg as the basis for a modify call
6949 ret = dsdb_module_search(module, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
6950 DSDB_FLAG_NEXT_MODULE |
6951 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6952 DSDB_SEARCH_SHOW_RECYCLED |
6953 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
6954 DSDB_SEARCH_REVEAL_INTERNALS,
6956 "objectGUID=%s", GUID_string(mem_ctx, &la->identifier->guid));
6957 if (ret != LDB_SUCCESS) {
6960 if (res->count != 1) {
6961 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
6962 GUID_string(mem_ctx, &la->identifier->guid));
6963 return LDB_ERR_NO_SUCH_OBJECT;
6966 *source_msg = res->msgs[0];
6968 /* the value blob for the attribute holds the target object DN */
6969 status = dsdb_dn_la_from_blob(ldb, attr, schema, mem_ctx, la->value.blob, target_dsdb_dn);
6970 if (!W_ERROR_IS_OK(status)) {
6971 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
6972 attr->lDAPDisplayName,
6973 ldb_dn_get_linearized(res->msgs[0]->dn),
6974 win_errstr(status));
6975 return LDB_ERR_OPERATIONS_ERROR;
6984 * Verifies the source and target objects are known for a linked attribute
6986 static int replmd_verify_linked_attribute(struct replmd_replicated_request *ar,
6987 struct la_entry *la)
6989 int ret = LDB_SUCCESS;
6990 TALLOC_CTX *tmp_ctx = talloc_new(la);
6991 struct ldb_module *module = ar->module;
6992 struct ldb_message *src_msg;
6993 const struct dsdb_attribute *attr;
6994 struct dsdb_dn *tgt_dsdb_dn;
6995 struct GUID guid = GUID_zero();
6998 ret = replmd_extract_la_entry_details(module, la, tmp_ctx, &attr,
6999 &src_msg, &tgt_dsdb_dn);
7002 * When we fail to find the source object, the error code we pass
7003 * back here is really important. It flags back to the callers to
7004 * retry this request with DRSUAPI_DRS_GET_ANC. This case should
7005 * never happen if we're replicating from a Samba DC, but it is
7006 * needed to talk to a Windows DC
7008 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
7009 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT);
7012 if (ret != LDB_SUCCESS) {
7013 talloc_free(tmp_ctx);
7017 ret = replmd_check_target_exists(module, tgt_dsdb_dn, la,
7018 src_msg->dn, &guid, &dummy);
7021 * When we fail to find the target object, the error code we pass
7022 * back here is really important. It flags back to the callers to
7023 * retry this request with DRSUAPI_DRS_GET_TGT
7025 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
7026 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_RECYCLED_TARGET);
7029 talloc_free(tmp_ctx);
7034 process one linked attribute structure
7036 static int replmd_process_linked_attribute(struct ldb_module *module,
7037 struct replmd_private *replmd_private,
7038 struct la_entry *la_entry,
7039 struct ldb_request *parent)
7041 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7042 struct ldb_context *ldb = ldb_module_get_ctx(module);
7043 struct ldb_message *msg;
7044 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
7045 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
7047 const struct dsdb_attribute *attr;
7048 struct dsdb_dn *dsdb_dn;
7049 uint64_t seq_num = 0;
7050 struct ldb_message_element *old_el;
7051 time_t t = time(NULL);
7052 struct parsed_dn *pdn_list, *pdn, *next;
7053 struct GUID guid = GUID_zero();
7054 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
7056 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
7059 * get the attribute being modified, the search result for the source object,
7060 * and the target object's DN details
7062 ret = replmd_extract_la_entry_details(module, la_entry, tmp_ctx, &attr,
7065 if (ret != LDB_SUCCESS) {
7066 talloc_free(tmp_ctx);
7071 * Check for deleted objects per MS-DRSR 4.1.10.6.14
7072 * ProcessLinkValue, because link updates are not applied to
7073 * recycled and tombstone objects. We don't have to delete
7074 * any existing link, that should have happened when the
7075 * object deletion was replicated or initiated.
7077 replmd_deletion_state(module, msg, &deletion_state, NULL);
7079 if (deletion_state >= OBJECT_RECYCLED) {
7080 talloc_free(tmp_ctx);
7084 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7085 if (old_el == NULL) {
7086 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
7087 if (ret != LDB_SUCCESS) {
7088 ldb_module_oom(module);
7089 talloc_free(tmp_ctx);
7090 return LDB_ERR_OPERATIONS_ERROR;
7093 old_el->flags = LDB_FLAG_MOD_REPLACE;
7096 /* parse the existing links */
7097 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
7098 attr->syntax->ldap_oid, parent);
7100 if (ret != LDB_SUCCESS) {
7101 talloc_free(tmp_ctx);
7105 ret = replmd_check_target_exists(module, dsdb_dn, la_entry, msg->dn,
7106 &guid, &ignore_link);
7108 if (ret != LDB_SUCCESS) {
7109 talloc_free(tmp_ctx);
7114 * there are some cases where the target object doesn't exist, but it's
7115 * OK to ignore the linked attribute
7118 talloc_free(tmp_ctx);
7122 /* see if this link already exists */
7123 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
7126 dsdb_dn->extra_part, 0,
7128 attr->syntax->ldap_oid,
7130 if (ret != LDB_SUCCESS) {
7131 talloc_free(tmp_ctx);
7137 /* see if this update is newer than what we have already */
7138 struct GUID invocation_id = GUID_zero();
7139 uint32_t version = 0;
7140 uint32_t originating_usn = 0;
7141 NTTIME change_time = 0;
7142 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
7144 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
7145 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
7146 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
7147 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
7149 if (!replmd_update_is_newer(&invocation_id,
7150 &la->meta_data.originating_invocation_id,
7152 la->meta_data.version,
7154 la->meta_data.originating_change_time)) {
7155 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
7156 old_el->name, ldb_dn_get_linearized(msg->dn),
7157 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
7158 talloc_free(tmp_ctx);
7162 /* get a seq_num for this change */
7163 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
7164 if (ret != LDB_SUCCESS) {
7165 talloc_free(tmp_ctx);
7169 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
7170 /* remove the existing backlink */
7171 ret = replmd_add_backlink(module, replmd_private,
7176 if (ret != LDB_SUCCESS) {
7177 talloc_free(tmp_ctx);
7182 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
7183 &la->meta_data.originating_invocation_id,
7184 la->meta_data.originating_usn, seq_num,
7185 la->meta_data.originating_change_time,
7186 la->meta_data.version,
7188 if (ret != LDB_SUCCESS) {
7189 talloc_free(tmp_ctx);
7194 /* add the new backlink */
7195 ret = replmd_add_backlink(module, replmd_private,
7200 if (ret != LDB_SUCCESS) {
7201 talloc_free(tmp_ctx);
7207 /* get a seq_num for this change */
7208 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
7209 if (ret != LDB_SUCCESS) {
7210 talloc_free(tmp_ctx);
7214 * We know where the new one needs to be, from the *next
7215 * pointer into pdn_list.
7218 offset = old_el->num_values;
7220 if (next->dsdb_dn == NULL) {
7221 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
7222 attr->syntax->ldap_oid);
7223 if (ret != LDB_SUCCESS) {
7227 offset = next - pdn_list;
7228 if (offset > old_el->num_values) {
7229 talloc_free(tmp_ctx);
7230 return LDB_ERR_OPERATIONS_ERROR;
7234 old_el->values = talloc_realloc(msg->elements, old_el->values,
7235 struct ldb_val, old_el->num_values+1);
7236 if (!old_el->values) {
7237 ldb_module_oom(module);
7238 return LDB_ERR_OPERATIONS_ERROR;
7241 if (offset != old_el->num_values) {
7242 memmove(&old_el->values[offset + 1], &old_el->values[offset],
7243 (old_el->num_values - offset) * sizeof(old_el->values[0]));
7246 old_el->num_values++;
7248 ret = replmd_build_la_val(tmp_ctx, &old_el->values[offset], dsdb_dn,
7249 &la->meta_data.originating_invocation_id,
7250 la->meta_data.originating_usn, seq_num,
7251 la->meta_data.originating_change_time,
7252 la->meta_data.version,
7254 if (ret != LDB_SUCCESS) {
7255 talloc_free(tmp_ctx);
7260 ret = replmd_add_backlink(module, replmd_private,
7265 if (ret != LDB_SUCCESS) {
7266 talloc_free(tmp_ctx);
7272 /* we only change whenChanged and uSNChanged if the seq_num
7274 ret = add_time_element(msg, "whenChanged", t);
7275 if (ret != LDB_SUCCESS) {
7276 talloc_free(tmp_ctx);
7281 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
7282 if (ret != LDB_SUCCESS) {
7283 talloc_free(tmp_ctx);
7288 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7289 if (old_el == NULL) {
7290 talloc_free(tmp_ctx);
7291 return ldb_operr(ldb);
7294 ret = dsdb_check_single_valued_link(attr, old_el);
7295 if (ret != LDB_SUCCESS) {
7296 talloc_free(tmp_ctx);
7300 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
7302 ret = linked_attr_modify(module, msg, parent);
7303 if (ret != LDB_SUCCESS) {
7304 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
7306 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
7307 talloc_free(tmp_ctx);
7311 talloc_free(tmp_ctx);
7316 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
7318 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
7319 return replmd_extended_replicated_objects(module, req);
7322 return ldb_next_request(module, req);
7327 we hook into the transaction operations to allow us to
7328 perform the linked attribute updates at the end of the whole
7329 transaction. This allows a forward linked attribute to be created
7330 before the object is created. During a vampire, w2k8 sends us linked
7331 attributes before the objects they are part of.
7333 static int replmd_start_transaction(struct ldb_module *module)
7335 /* create our private structure for this transaction */
7336 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
7337 struct replmd_private);
7338 replmd_txn_cleanup(replmd_private);
7340 /* free any leftover mod_usn records from cancelled
7342 while (replmd_private->ncs) {
7343 struct nc_entry *e = replmd_private->ncs;
7344 DLIST_REMOVE(replmd_private->ncs, e);
7348 replmd_private->originating_updates = false;
7350 return ldb_next_start_trans(module);
7354 on prepare commit we loop over our queued la_context structures and
7357 static int replmd_prepare_commit(struct ldb_module *module)
7359 struct replmd_private *replmd_private =
7360 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7361 struct la_entry *la, *prev;
7365 * Walk the list of linked attributes from DRS replication.
7367 * We walk backwards, to do the first entry first, as we
7368 * added the entries with DLIST_ADD() which puts them at the
7371 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
7372 prev = DLIST_PREV(la);
7373 DLIST_REMOVE(replmd_private->la_list, la);
7374 ret = replmd_process_linked_attribute(module, replmd_private,
7376 if (ret != LDB_SUCCESS) {
7377 replmd_txn_cleanup(replmd_private);
7382 replmd_txn_cleanup(replmd_private);
7384 /* possibly change @REPLCHANGED */
7385 ret = replmd_notify_store(module, NULL);
7386 if (ret != LDB_SUCCESS) {
7390 return ldb_next_prepare_commit(module);
7393 static int replmd_del_transaction(struct ldb_module *module)
7395 struct replmd_private *replmd_private =
7396 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7397 replmd_txn_cleanup(replmd_private);
7399 return ldb_next_del_trans(module);
7403 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
7404 .name = "repl_meta_data",
7405 .init_context = replmd_init,
7407 .modify = replmd_modify,
7408 .rename = replmd_rename,
7409 .del = replmd_delete,
7410 .extended = replmd_extended,
7411 .start_transaction = replmd_start_transaction,
7412 .prepare_commit = replmd_prepare_commit,
7413 .del_transaction = replmd_del_transaction,
7416 int ldb_repl_meta_data_module_init(const char *version)
7418 LDB_MODULE_CHECK_VERSION(version);
7419 return ldb_register_module(&ldb_repl_meta_data_module_ops);