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;
79 struct replmd_replicated_request {
80 struct ldb_module *module;
81 struct ldb_request *req;
83 const struct dsdb_schema *schema;
84 struct GUID our_invocation_id;
86 /* the controls we pass down */
87 struct ldb_control **controls;
90 * Backlinks for the replmd_add() case (we want to create
91 * backlinks after creating the user, but before the end of
94 struct la_backlink *la_backlinks;
96 /* details for the mode where we apply a bunch of inbound replication meessages */
98 uint32_t index_current;
99 struct dsdb_extended_replicated_objects *objs;
101 struct ldb_message *search_msg;
102 struct GUID local_parent_guid;
110 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
111 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
112 static int replmd_check_upgrade_links(struct ldb_context *ldb,
113 struct parsed_dn *dns, uint32_t count,
114 struct ldb_message_element *el,
115 const char *ldap_oid);
117 enum urgent_situation {
118 REPL_URGENT_ON_CREATE = 1,
119 REPL_URGENT_ON_UPDATE = 2,
120 REPL_URGENT_ON_DELETE = 4
123 enum deletion_state {
124 OBJECT_NOT_DELETED=1,
131 static void replmd_deletion_state(struct ldb_module *module,
132 const struct ldb_message *msg,
133 enum deletion_state *current_state,
134 enum deletion_state *next_state)
137 bool enabled = false;
140 *current_state = OBJECT_REMOVED;
141 if (next_state != NULL) {
142 *next_state = OBJECT_REMOVED;
147 ret = dsdb_recyclebin_enabled(module, &enabled);
148 if (ret != LDB_SUCCESS) {
152 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
154 *current_state = OBJECT_TOMBSTONE;
155 if (next_state != NULL) {
156 *next_state = OBJECT_REMOVED;
161 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
162 *current_state = OBJECT_RECYCLED;
163 if (next_state != NULL) {
164 *next_state = OBJECT_REMOVED;
169 *current_state = OBJECT_DELETED;
170 if (next_state != NULL) {
171 *next_state = OBJECT_RECYCLED;
176 *current_state = OBJECT_NOT_DELETED;
177 if (next_state == NULL) {
182 *next_state = OBJECT_DELETED;
184 *next_state = OBJECT_TOMBSTONE;
188 static const struct {
189 const char *update_name;
190 enum urgent_situation repl_situation;
191 } urgent_objects[] = {
192 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
193 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
194 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
195 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
196 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
197 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
201 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
202 static const char *urgent_attrs[] = {
205 "userAccountControl",
210 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
211 enum urgent_situation situation)
214 for (i=0; urgent_objects[i].update_name; i++) {
216 if ((situation & urgent_objects[i].repl_situation) == 0) {
220 for (j=0; j<objectclass_el->num_values; j++) {
221 const struct ldb_val *v = &objectclass_el->values[j];
222 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
230 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
232 if (ldb_attr_in_list(urgent_attrs, el->name)) {
239 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
242 initialise the module
243 allocate the private structure and build the list
244 of partition DNs for use by replmd_notify()
246 static int replmd_init(struct ldb_module *module)
248 struct replmd_private *replmd_private;
249 struct ldb_context *ldb = ldb_module_get_ctx(module);
250 static const char *samba_dsdb_attrs[] = { SAMBA_COMPATIBLE_FEATURES_ATTR, NULL };
251 struct ldb_dn *samba_dsdb_dn;
252 struct ldb_result *res;
254 TALLOC_CTX *frame = talloc_stackframe();
255 replmd_private = talloc_zero(module, struct replmd_private);
256 if (replmd_private == NULL) {
259 return LDB_ERR_OPERATIONS_ERROR;
261 ldb_module_set_private(module, replmd_private);
263 replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
265 samba_dsdb_dn = ldb_dn_new(frame, ldb, "@SAMBA_DSDB");
266 if (!samba_dsdb_dn) {
271 ret = dsdb_module_search_dn(module, frame, &res, samba_dsdb_dn,
272 samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
273 if (ret == LDB_SUCCESS) {
274 replmd_private->sorted_links
275 = ldb_msg_check_string_attribute(res->msgs[0],
276 SAMBA_COMPATIBLE_FEATURES_ATTR,
277 SAMBA_SORTED_LINKS_FEATURE);
281 return ldb_next_init(module);
285 cleanup our per-transaction contexts
287 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
289 talloc_free(replmd_private->la_ctx);
290 replmd_private->la_list = NULL;
291 replmd_private->la_ctx = NULL;
297 struct la_backlink *next, *prev;
298 const char *attr_name;
299 struct ldb_dn *forward_dn;
300 struct GUID target_guid;
305 a ldb_modify request operating on modules below the
308 static int linked_attr_modify(struct ldb_module *module,
309 const struct ldb_message *message,
310 struct ldb_request *parent)
312 struct ldb_request *mod_req;
314 struct ldb_context *ldb = ldb_module_get_ctx(module);
315 TALLOC_CTX *tmp_ctx = talloc_new(module);
316 struct ldb_result *res;
318 res = talloc_zero(tmp_ctx, struct ldb_result);
320 talloc_free(tmp_ctx);
321 return ldb_oom(ldb_module_get_ctx(module));
324 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
328 ldb_modify_default_callback,
330 LDB_REQ_SET_LOCATION(mod_req);
331 if (ret != LDB_SUCCESS) {
332 talloc_free(tmp_ctx);
336 ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
338 if (ret != LDB_SUCCESS) {
342 /* Run the new request */
343 ret = ldb_next_request(module, mod_req);
345 if (ret == LDB_SUCCESS) {
346 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
349 talloc_free(tmp_ctx);
354 process a backlinks we accumulated during a transaction, adding and
355 deleting the backlinks from the target objects
357 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
359 struct ldb_dn *target_dn, *source_dn;
361 struct ldb_context *ldb = ldb_module_get_ctx(module);
362 struct ldb_message *msg;
363 TALLOC_CTX *frame = talloc_stackframe();
369 - construct ldb_message
370 - either an add or a delete
372 ret = dsdb_module_dn_by_guid(module, frame, &bl->target_guid, &target_dn, parent);
373 if (ret != LDB_SUCCESS) {
374 struct GUID_txt_buf guid_str;
375 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
376 GUID_buf_string(&bl->target_guid, &guid_str)));
381 msg = ldb_msg_new(frame);
383 ldb_module_oom(module);
385 return LDB_ERR_OPERATIONS_ERROR;
388 source_dn = ldb_dn_copy(frame, bl->forward_dn);
390 ldb_module_oom(module);
392 return LDB_ERR_OPERATIONS_ERROR;
394 /* Filter down to the attributes we want in the backlink */
395 const char *accept[] = { "GUID", "SID", NULL };
396 ldb_dn_extended_filter(source_dn, accept);
399 /* construct a ldb_message for adding/deleting the backlink */
401 dn_string = ldb_dn_get_extended_linearized(frame, bl->forward_dn, 1);
403 ldb_module_oom(module);
405 return LDB_ERR_OPERATIONS_ERROR;
407 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
408 if (ret != LDB_SUCCESS) {
412 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
414 /* a backlink should never be single valued. Unfortunately the
415 exchange schema has a attribute
416 msExchBridgeheadedLocalConnectorsDNBL which is single
417 valued and a backlink. We need to cope with that by
418 ignoring the single value flag */
419 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
421 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
422 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
423 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
424 cope with possible corruption where the backlink has
425 already been removed */
426 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
427 ldb_dn_get_linearized(target_dn),
428 ldb_dn_get_linearized(source_dn),
429 ldb_errstring(ldb)));
431 } else if (ret != LDB_SUCCESS) {
432 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
433 bl->active?"add":"remove",
434 ldb_dn_get_linearized(source_dn),
435 ldb_dn_get_linearized(target_dn),
445 add a backlink to the list of backlinks to add/delete in the prepare
448 forward_dn is stolen onto the defereed context
450 static int replmd_defer_add_backlink(struct ldb_module *module,
451 struct replmd_private *replmd_private,
452 const struct dsdb_schema *schema,
453 struct replmd_replicated_request *ac,
454 struct ldb_dn *forward_dn,
455 struct GUID *target_guid, bool active,
456 const struct dsdb_attribute *schema_attr,
457 struct ldb_request *parent)
459 const struct dsdb_attribute *target_attr;
460 struct la_backlink *bl;
462 bl = talloc(ac, struct la_backlink);
464 ldb_module_oom(module);
465 return LDB_ERR_OPERATIONS_ERROR;
468 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
471 * windows 2003 has a broken schema where the
472 * definition of msDS-IsDomainFor is missing (which is
473 * supposed to be the backlink of the
474 * msDS-HasDomainNCs attribute
479 bl->attr_name = target_attr->lDAPDisplayName;
480 bl->forward_dn = talloc_steal(bl, forward_dn);
481 bl->target_guid = *target_guid;
484 DLIST_ADD(ac->la_backlinks, bl);
490 add a backlink to the list of backlinks to add/delete in the prepare
493 static int replmd_add_backlink(struct ldb_module *module,
494 struct replmd_private *replmd_private,
495 const struct dsdb_schema *schema,
496 struct ldb_dn *forward_dn,
497 struct GUID *target_guid, bool active,
498 const struct dsdb_attribute *schema_attr,
499 struct ldb_request *parent)
501 const struct dsdb_attribute *target_attr;
502 struct la_backlink bl;
505 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
508 * windows 2003 has a broken schema where the
509 * definition of msDS-IsDomainFor is missing (which is
510 * supposed to be the backlink of the
511 * msDS-HasDomainNCs attribute
516 bl.attr_name = target_attr->lDAPDisplayName;
517 bl.forward_dn = forward_dn;
518 bl.target_guid = *target_guid;
521 ret = replmd_process_backlink(module, &bl, parent);
527 * Callback for most write operations in this module:
529 * notify the repl task that a object has changed. The notifies are
530 * gathered up in the replmd_private structure then written to the
531 * @REPLCHANGED object in each partition during the prepare_commit
533 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
536 struct replmd_replicated_request *ac =
537 talloc_get_type_abort(req->context, struct replmd_replicated_request);
538 struct replmd_private *replmd_private =
539 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
540 struct nc_entry *modified_partition;
541 struct ldb_control *partition_ctrl;
542 const struct dsdb_control_current_partition *partition;
544 struct ldb_control **controls;
546 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
548 controls = ares->controls;
549 if (ldb_request_get_control(ac->req,
550 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
552 * Remove the current partition control from what we pass up
553 * the chain if it hasn't been requested manually.
555 controls = ldb_controls_except_specified(ares->controls, ares,
559 if (ares->error != LDB_SUCCESS) {
560 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
561 return ldb_module_done(ac->req, controls,
562 ares->response, ares->error);
565 if (ares->type != LDB_REPLY_DONE) {
566 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
567 return ldb_module_done(ac->req, NULL,
568 NULL, LDB_ERR_OPERATIONS_ERROR);
571 if (ac->apply_mode == false) {
572 struct la_backlink *bl;
574 * process our backlink list after an replmd_add(),
575 * creating and deleting backlinks as necessary (this
576 * code is sync). The other cases are handled inline
579 for (bl=ac->la_backlinks; bl; bl=bl->next) {
580 ret = replmd_process_backlink(ac->module, bl, ac->req);
581 if (ret != LDB_SUCCESS) {
582 return ldb_module_done(ac->req, NULL,
588 if (!partition_ctrl) {
589 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
590 return ldb_module_done(ac->req, NULL,
591 NULL, LDB_ERR_OPERATIONS_ERROR);
594 partition = talloc_get_type_abort(partition_ctrl->data,
595 struct dsdb_control_current_partition);
597 if (ac->seq_num > 0) {
598 for (modified_partition = replmd_private->ncs; modified_partition;
599 modified_partition = modified_partition->next) {
600 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
605 if (modified_partition == NULL) {
606 modified_partition = talloc_zero(replmd_private, struct nc_entry);
607 if (!modified_partition) {
608 ldb_oom(ldb_module_get_ctx(ac->module));
609 return ldb_module_done(ac->req, NULL,
610 NULL, LDB_ERR_OPERATIONS_ERROR);
612 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
613 if (!modified_partition->dn) {
614 ldb_oom(ldb_module_get_ctx(ac->module));
615 return ldb_module_done(ac->req, NULL,
616 NULL, LDB_ERR_OPERATIONS_ERROR);
618 DLIST_ADD(replmd_private->ncs, modified_partition);
621 if (ac->seq_num > modified_partition->mod_usn) {
622 modified_partition->mod_usn = ac->seq_num;
624 modified_partition->mod_usn_urgent = ac->seq_num;
627 if (!ac->apply_mode) {
628 replmd_private->originating_updates = true;
632 if (ac->apply_mode) {
633 ret = replmd_replicated_apply_isDeleted(ac);
634 if (ret != LDB_SUCCESS) {
635 return ldb_module_done(ac->req, NULL, NULL, ret);
639 /* free the partition control container here, for the
640 * common path. Other cases will have it cleaned up
641 * eventually with the ares */
642 talloc_free(partition_ctrl);
643 return ldb_module_done(ac->req, controls,
644 ares->response, LDB_SUCCESS);
650 * update a @REPLCHANGED record in each partition if there have been
651 * any writes of replicated data in the partition
653 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
655 struct replmd_private *replmd_private =
656 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
658 while (replmd_private->ncs) {
660 struct nc_entry *modified_partition = replmd_private->ncs;
662 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
663 modified_partition->mod_usn,
664 modified_partition->mod_usn_urgent, parent);
665 if (ret != LDB_SUCCESS) {
666 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
667 ldb_dn_get_linearized(modified_partition->dn)));
671 if (ldb_dn_compare(modified_partition->dn,
672 replmd_private->schema_dn) == 0) {
673 struct ldb_result *ext_res;
674 ret = dsdb_module_extended(module,
675 replmd_private->schema_dn,
677 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
679 DSDB_FLAG_NEXT_MODULE,
681 if (ret != LDB_SUCCESS) {
684 talloc_free(ext_res);
687 DLIST_REMOVE(replmd_private->ncs, modified_partition);
688 talloc_free(modified_partition);
696 created a replmd_replicated_request context
698 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
699 struct ldb_request *req)
701 struct ldb_context *ldb;
702 struct replmd_replicated_request *ac;
703 const struct GUID *our_invocation_id;
705 ldb = ldb_module_get_ctx(module);
707 ac = talloc_zero(req, struct replmd_replicated_request);
716 ac->schema = dsdb_get_schema(ldb, ac);
718 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
719 "replmd_modify: no dsdb_schema loaded");
720 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
725 /* get our invocationId */
726 our_invocation_id = samdb_ntds_invocation_id(ldb);
727 if (!our_invocation_id) {
728 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
729 "replmd_add: unable to find invocationId\n");
733 ac->our_invocation_id = *our_invocation_id;
739 add a time element to a record
741 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
743 struct ldb_message_element *el;
747 if (ldb_msg_find_element(msg, attr) != NULL) {
751 s = ldb_timestring(msg, t);
753 return LDB_ERR_OPERATIONS_ERROR;
756 ret = ldb_msg_add_string(msg, attr, s);
757 if (ret != LDB_SUCCESS) {
761 el = ldb_msg_find_element(msg, attr);
762 /* always set as replace. This works because on add ops, the flag
764 el->flags = LDB_FLAG_MOD_REPLACE;
770 add a uint64_t element to a record
772 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
773 const char *attr, uint64_t v)
775 struct ldb_message_element *el;
778 if (ldb_msg_find_element(msg, attr) != NULL) {
782 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
783 if (ret != LDB_SUCCESS) {
787 el = ldb_msg_find_element(msg, attr);
788 /* always set as replace. This works because on add ops, the flag
790 el->flags = LDB_FLAG_MOD_REPLACE;
795 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
796 const struct replPropertyMetaData1 *m2,
797 const uint32_t *rdn_attid)
800 * This assignment seems inoccous, but it is critical for the
801 * system, as we need to do the comparisons as a unsigned
802 * quantity, not signed (enums are signed integers)
804 uint32_t attid_1 = m1->attid;
805 uint32_t attid_2 = m2->attid;
807 if (attid_1 == attid_2) {
812 * See above regarding this being an unsigned comparison.
813 * Otherwise when the high bit is set on non-standard
814 * attributes, they would end up first, before objectClass
817 return attid_1 > attid_2 ? 1 : -1;
820 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
821 struct replPropertyMetaDataCtr1 *ctr1,
824 if (ctr1->count == 0) {
825 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
826 "No elements found in replPropertyMetaData for %s!\n",
827 ldb_dn_get_linearized(dn));
828 return LDB_ERR_CONSTRAINT_VIOLATION;
831 /* the objectClass attribute is value 0x00000000, so must be first */
832 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
833 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
834 "No objectClass found in replPropertyMetaData for %s!\n",
835 ldb_dn_get_linearized(dn));
836 return LDB_ERR_OBJECT_CLASS_VIOLATION;
842 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
843 struct replPropertyMetaDataCtr1 *ctr1,
846 /* Note this is O(n^2) for the almost-sorted case, which this is */
847 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
848 replmd_replPropertyMetaData1_attid_sort);
849 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
852 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
853 const struct ldb_message_element *e2,
854 const struct dsdb_schema *schema)
856 const struct dsdb_attribute *a1;
857 const struct dsdb_attribute *a2;
860 * TODO: make this faster by caching the dsdb_attribute pointer
861 * on the ldb_messag_element
864 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
865 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
868 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
872 return strcasecmp(e1->name, e2->name);
874 if (a1->attributeID_id == a2->attributeID_id) {
877 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
880 static void replmd_ldb_message_sort(struct ldb_message *msg,
881 const struct dsdb_schema *schema)
883 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
886 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
887 const struct GUID *invocation_id, uint64_t seq_num,
888 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
890 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
891 struct ldb_message_element *el, struct parsed_dn **pdn,
892 const char *ldap_oid, struct ldb_request *parent);
895 fix up linked attributes in replmd_add.
896 This involves setting up the right meta-data in extended DN
897 components, and creating backlinks to the object
899 static int replmd_add_fix_la(struct ldb_module *module, TALLOC_CTX *mem_ctx,
900 struct replmd_private *replmd_private,
901 struct ldb_message_element *el,
902 struct replmd_replicated_request *ac,
904 struct ldb_dn *forward_dn,
905 const struct dsdb_attribute *sa,
906 struct ldb_request *parent)
909 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
910 struct ldb_context *ldb = ldb_module_get_ctx(module);
911 struct parsed_dn *pdn;
912 /* We will take a reference to the schema in replmd_add_backlink */
913 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
914 struct ldb_val *new_values = NULL;
916 int ret = get_parsed_dns(module, tmp_ctx, el, &pdn,
917 sa->syntax->ldap_oid, parent);
918 if (ret != LDB_SUCCESS) {
919 talloc_free(tmp_ctx);
923 new_values = talloc_array(tmp_ctx, struct ldb_val, el->num_values);
924 if (new_values == NULL) {
925 ldb_module_oom(module);
926 talloc_free(tmp_ctx);
927 return LDB_ERR_OPERATIONS_ERROR;
930 for (i = 0; i < el->num_values; i++) {
931 struct parsed_dn *p = &pdn[i];
932 ret = replmd_build_la_val(el->values, p->v, p->dsdb_dn,
933 &ac->our_invocation_id,
934 ac->seq_num, ac->seq_num, now, 0, false);
935 if (ret != LDB_SUCCESS) {
936 talloc_free(tmp_ctx);
940 ret = replmd_defer_add_backlink(module, replmd_private,
942 forward_dn, &p->guid, true, sa,
944 if (ret != LDB_SUCCESS) {
945 talloc_free(tmp_ctx);
949 new_values[i] = *p->v;
951 el->values = talloc_steal(mem_ctx, new_values);
953 talloc_free(tmp_ctx);
957 static int replmd_add_make_extended_dn(struct ldb_request *req,
958 const DATA_BLOB *guid_blob,
959 struct ldb_dn **_extended_dn)
962 const DATA_BLOB *sid_blob;
963 /* Calculate an extended DN for any linked attributes */
964 struct ldb_dn *extended_dn = ldb_dn_copy(req, req->op.add.message->dn);
966 return LDB_ERR_OPERATIONS_ERROR;
968 ret = ldb_dn_set_extended_component(extended_dn, "GUID", guid_blob);
969 if (ret != LDB_SUCCESS) {
973 sid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectSID");
974 if (sid_blob != NULL) {
975 ret = ldb_dn_set_extended_component(extended_dn, "SID", sid_blob);
976 if (ret != LDB_SUCCESS) {
980 *_extended_dn = extended_dn;
985 intercept add requests
987 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
989 struct ldb_context *ldb;
990 struct ldb_control *control;
991 struct replmd_replicated_request *ac;
992 enum ndr_err_code ndr_err;
993 struct ldb_request *down_req;
994 struct ldb_message *msg;
995 const DATA_BLOB *guid_blob;
996 DATA_BLOB guid_blob_stack;
998 uint8_t guid_data[16];
999 struct replPropertyMetaDataBlob nmd;
1000 struct ldb_val nmd_value;
1001 struct ldb_dn *extended_dn = NULL;
1004 * The use of a time_t here seems odd, but as the NTTIME
1005 * elements are actually declared as NTTIME_1sec in the IDL,
1006 * getting a higher resolution timestamp is not required.
1008 time_t t = time(NULL);
1013 unsigned int functional_level;
1015 bool allow_add_guid = false;
1016 bool remove_current_guid = false;
1017 bool is_urgent = false;
1018 bool is_schema_nc = false;
1019 struct ldb_message_element *objectclass_el;
1020 struct replmd_private *replmd_private =
1021 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
1023 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
1024 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
1026 allow_add_guid = true;
1029 /* do not manipulate our control entries */
1030 if (ldb_dn_is_special(req->op.add.message->dn)) {
1031 return ldb_next_request(module, req);
1034 ldb = ldb_module_get_ctx(module);
1036 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
1038 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
1039 if (guid_blob != NULL) {
1040 if (!allow_add_guid) {
1041 ldb_set_errstring(ldb,
1042 "replmd_add: it's not allowed to add an object with objectGUID!");
1043 return LDB_ERR_UNWILLING_TO_PERFORM;
1045 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
1046 if (!NT_STATUS_IS_OK(status)) {
1047 ldb_set_errstring(ldb,
1048 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1049 return LDB_ERR_UNWILLING_TO_PERFORM;
1051 /* we remove this attribute as it can be a string and
1052 * will not be treated correctly and then we will re-add
1053 * it later on in the good format */
1054 remove_current_guid = true;
1058 guid = GUID_random();
1060 guid_blob_stack = data_blob_const(guid_data, sizeof(guid_data));
1062 /* This can't fail */
1063 ndr_push_struct_into_fixed_blob(&guid_blob_stack, &guid,
1064 (ndr_push_flags_fn_t)ndr_push_GUID);
1065 guid_blob = &guid_blob_stack;
1068 ac = replmd_ctx_init(module, req);
1070 return ldb_module_oom(module);
1073 functional_level = dsdb_functional_level(ldb);
1075 /* Get a sequence number from the backend */
1076 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1077 if (ret != LDB_SUCCESS) {
1082 /* we have to copy the message as the caller might have it as a const */
1083 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1087 return LDB_ERR_OPERATIONS_ERROR;
1090 /* generated times */
1091 unix_to_nt_time(&now, t);
1092 time_str = ldb_timestring(msg, t);
1096 return LDB_ERR_OPERATIONS_ERROR;
1098 if (remove_current_guid) {
1099 ldb_msg_remove_attr(msg,"objectGUID");
1103 * remove autogenerated attributes
1105 ldb_msg_remove_attr(msg, "whenCreated");
1106 ldb_msg_remove_attr(msg, "whenChanged");
1107 ldb_msg_remove_attr(msg, "uSNCreated");
1108 ldb_msg_remove_attr(msg, "uSNChanged");
1109 ldb_msg_remove_attr(msg, "replPropertyMetaData");
1112 * readd replicated attributes
1114 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1115 if (ret != LDB_SUCCESS) {
1121 /* build the replication meta_data */
1124 nmd.ctr.ctr1.count = msg->num_elements;
1125 nmd.ctr.ctr1.array = talloc_array(msg,
1126 struct replPropertyMetaData1,
1127 nmd.ctr.ctr1.count);
1128 if (!nmd.ctr.ctr1.array) {
1131 return LDB_ERR_OPERATIONS_ERROR;
1134 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1136 for (i=0; i < msg->num_elements;) {
1137 struct ldb_message_element *e = &msg->elements[i];
1138 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1139 const struct dsdb_attribute *sa;
1141 if (e->name[0] == '@') {
1146 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1148 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1149 "replmd_add: attribute '%s' not defined in schema\n",
1152 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1155 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1156 /* if the attribute is not replicated (0x00000001)
1157 * or constructed (0x00000004) it has no metadata
1163 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1164 if (extended_dn == NULL) {
1165 ret = replmd_add_make_extended_dn(req,
1168 if (ret != LDB_SUCCESS) {
1175 * Prepare the context for the backlinks and
1176 * create metadata for the forward links. The
1177 * backlinks are created in
1178 * replmd_op_callback() after the successful
1179 * ADD of the object.
1181 ret = replmd_add_fix_la(module, msg->elements,
1186 if (ret != LDB_SUCCESS) {
1190 /* linked attributes are not stored in
1191 replPropertyMetaData in FL above w2k */
1196 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1198 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1199 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1202 if (rdn_val == NULL) {
1205 return LDB_ERR_OPERATIONS_ERROR;
1208 rdn = (const char*)rdn_val->data;
1209 if (strcmp(rdn, "Deleted Objects") == 0) {
1211 * Set the originating_change_time to 29/12/9999 at 23:59:59
1212 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1214 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1216 m->originating_change_time = now;
1219 m->originating_change_time = now;
1221 m->originating_invocation_id = ac->our_invocation_id;
1222 m->originating_usn = ac->seq_num;
1223 m->local_usn = ac->seq_num;
1226 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1231 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1233 if (e->num_values != 0) {
1238 ldb_msg_remove_element(msg, e);
1241 /* fix meta data count */
1242 nmd.ctr.ctr1.count = ni;
1245 * sort meta data array
1247 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1248 if (ret != LDB_SUCCESS) {
1249 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1254 /* generated NDR encoded values */
1255 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1257 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1258 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1261 return LDB_ERR_OPERATIONS_ERROR;
1265 * add the autogenerated values
1267 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1268 if (ret != LDB_SUCCESS) {
1273 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1274 if (ret != LDB_SUCCESS) {
1279 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1280 if (ret != LDB_SUCCESS) {
1285 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1286 if (ret != LDB_SUCCESS) {
1291 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1292 if (ret != LDB_SUCCESS) {
1299 * sort the attributes by attid before storing the object
1301 replmd_ldb_message_sort(msg, ac->schema);
1304 * Assert that we do have an objectClass
1306 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1307 if (objectclass_el == NULL) {
1308 ldb_asprintf_errstring(ldb, __location__
1309 ": objectClass missing on %s\n",
1310 ldb_dn_get_linearized(msg->dn));
1312 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1314 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1315 REPL_URGENT_ON_CREATE);
1317 ac->is_urgent = is_urgent;
1318 ret = ldb_build_add_req(&down_req, ldb, ac,
1321 ac, replmd_op_callback,
1324 LDB_REQ_SET_LOCATION(down_req);
1325 if (ret != LDB_SUCCESS) {
1330 /* current partition control is needed by "replmd_op_callback" */
1331 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1332 ret = ldb_request_add_control(down_req,
1333 DSDB_CONTROL_CURRENT_PARTITION_OID,
1335 if (ret != LDB_SUCCESS) {
1341 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1342 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1343 if (ret != LDB_SUCCESS) {
1349 /* mark the control done */
1351 control->critical = 0;
1353 /* go on with the call chain */
1354 return ldb_next_request(module, down_req);
1359 * update the replPropertyMetaData for one element
1361 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1362 struct ldb_message *msg,
1363 struct ldb_message_element *el,
1364 struct ldb_message_element *old_el,
1365 struct replPropertyMetaDataBlob *omd,
1366 const struct dsdb_schema *schema,
1368 const struct GUID *our_invocation_id,
1371 struct ldb_request *req)
1374 const struct dsdb_attribute *a;
1375 struct replPropertyMetaData1 *md1;
1376 bool may_skip = false;
1379 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1381 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1382 /* allow this to make it possible for dbcheck
1383 to remove bad attributes */
1387 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1389 return LDB_ERR_OPERATIONS_ERROR;
1392 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1394 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1399 * if the attribute's value haven't changed, and this isn't
1400 * just a delete of everything then return LDB_SUCCESS Unless
1401 * we have the provision control or if the attribute is
1402 * interSiteTopologyGenerator as this page explain:
1403 * http://support.microsoft.com/kb/224815 this attribute is
1404 * periodicaly written by the DC responsible for the intersite
1405 * generation in a given site
1407 * Unchanged could be deleting or replacing an already-gone
1408 * thing with an unconstrained delete/empty replace or a
1409 * replace with the same value, but not an add with the same
1410 * value because that could be about adding a duplicate (which
1411 * is for someone else to error out on).
1413 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1414 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1417 } else if (old_el == NULL && el->num_values == 0) {
1418 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1420 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1423 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1424 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1426 * We intentionally skip the version bump when attempting to
1429 * The control is set by dbcheck and expunge-tombstones which
1430 * both attempt to be non-replicating. Otherwise, making an
1431 * alteration to the replication state would trigger a
1432 * broadcast of all expunged objects.
1437 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1439 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1443 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1444 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1446 * allow this to make it possible for dbcheck
1447 * to rebuild broken metadata
1453 for (i=0; i<omd->ctr.ctr1.count; i++) {
1455 * First check if we find it under the msDS-IntID,
1456 * then check if we find it under the OID and
1459 * This allows the administrator to simply re-write
1460 * the attributes and so restore replication, which is
1461 * likely what they will try to do.
1463 if (attid == omd->ctr.ctr1.array[i].attid) {
1467 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1472 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1473 /* linked attributes are not stored in
1474 replPropertyMetaData in FL above w2k, but we do
1475 raise the seqnum for the object */
1476 if (*seq_num == 0 &&
1477 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1478 return LDB_ERR_OPERATIONS_ERROR;
1483 if (i == omd->ctr.ctr1.count) {
1484 /* we need to add a new one */
1485 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1486 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1487 if (omd->ctr.ctr1.array == NULL) {
1489 return LDB_ERR_OPERATIONS_ERROR;
1491 omd->ctr.ctr1.count++;
1492 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1495 /* Get a new sequence number from the backend. We only do this
1496 * if we have a change that requires a new
1497 * replPropertyMetaData element
1499 if (*seq_num == 0) {
1500 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1501 if (ret != LDB_SUCCESS) {
1502 return LDB_ERR_OPERATIONS_ERROR;
1506 md1 = &omd->ctr.ctr1.array[i];
1509 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1510 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1513 if (rdn_val == NULL) {
1515 return LDB_ERR_OPERATIONS_ERROR;
1518 rdn = (const char*)rdn_val->data;
1519 if (strcmp(rdn, "Deleted Objects") == 0) {
1521 * Set the originating_change_time to 29/12/9999 at 23:59:59
1522 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1524 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1526 md1->originating_change_time = now;
1529 md1->originating_change_time = now;
1531 md1->originating_invocation_id = *our_invocation_id;
1532 md1->originating_usn = *seq_num;
1533 md1->local_usn = *seq_num;
1539 * Bump the replPropertyMetaData version on an attribute, and if it
1540 * has changed (or forced by leaving rdn_old NULL), update the value
1543 * This is important, as calling a modify operation may not change the
1544 * version number if the values appear unchanged, but a rename between
1545 * parents bumps this value.
1548 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1549 struct ldb_message *msg,
1550 const struct ldb_val *rdn_new,
1551 const struct ldb_val *rdn_old,
1552 struct replPropertyMetaDataBlob *omd,
1553 struct replmd_replicated_request *ar,
1557 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1558 const struct dsdb_attribute *rdn_attr =
1559 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1560 const char *attr_name = rdn_attr != NULL ?
1561 rdn_attr->lDAPDisplayName :
1563 struct ldb_message_element new_el = {
1564 .flags = LDB_FLAG_MOD_REPLACE,
1567 .values = discard_const_p(struct ldb_val, rdn_new)
1569 struct ldb_message_element old_el = {
1570 .flags = LDB_FLAG_MOD_REPLACE,
1572 .num_values = rdn_old ? 1 : 0,
1573 .values = discard_const_p(struct ldb_val, rdn_old)
1576 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1577 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1578 if (ret != LDB_SUCCESS) {
1579 return ldb_oom(ldb);
1583 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1584 omd, ar->schema, &ar->seq_num,
1585 &ar->our_invocation_id,
1586 now, is_schema_nc, ar->req);
1590 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1592 uint32_t count = omd.ctr.ctr1.count;
1595 for (i=0; i < count; i++) {
1596 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1597 if (max < m.local_usn) {
1605 * update the replPropertyMetaData object each time we modify an
1606 * object. This is needed for DRS replication, as the merge on the
1607 * client is based on this object
1609 static int replmd_update_rpmd(struct ldb_module *module,
1610 const struct dsdb_schema *schema,
1611 struct ldb_request *req,
1612 const char * const *rename_attrs,
1613 struct ldb_message *msg, uint64_t *seq_num,
1614 time_t t, bool is_schema_nc,
1615 bool *is_urgent, bool *rodc)
1617 const struct ldb_val *omd_value;
1618 enum ndr_err_code ndr_err;
1619 struct replPropertyMetaDataBlob omd;
1622 const struct GUID *our_invocation_id;
1624 const char * const *attrs = NULL;
1625 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1626 struct ldb_result *res;
1627 struct ldb_context *ldb;
1628 struct ldb_message_element *objectclass_el;
1629 enum urgent_situation situation;
1630 bool rmd_is_provided;
1631 bool rmd_is_just_resorted = false;
1632 const char *not_rename_attrs[4 + msg->num_elements];
1635 attrs = rename_attrs;
1637 for (i = 0; i < msg->num_elements; i++) {
1638 not_rename_attrs[i] = msg->elements[i].name;
1640 not_rename_attrs[i] = "replPropertyMetaData";
1641 not_rename_attrs[i+1] = "objectClass";
1642 not_rename_attrs[i+2] = "instanceType";
1643 not_rename_attrs[i+3] = NULL;
1644 attrs = not_rename_attrs;
1647 ldb = ldb_module_get_ctx(module);
1649 our_invocation_id = samdb_ntds_invocation_id(ldb);
1650 if (!our_invocation_id) {
1651 /* this happens during an initial vampire while
1652 updating the schema */
1653 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1657 unix_to_nt_time(&now, t);
1659 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1660 rmd_is_provided = true;
1661 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1662 rmd_is_just_resorted = true;
1665 rmd_is_provided = false;
1668 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1669 * otherwise we consider we are updating */
1670 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1671 situation = REPL_URGENT_ON_DELETE;
1672 } else if (rename_attrs) {
1673 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1675 situation = REPL_URGENT_ON_UPDATE;
1678 if (rmd_is_provided) {
1679 /* In this case the change_replmetadata control was supplied */
1680 /* We check that it's the only attribute that is provided
1681 * (it's a rare case so it's better to keep the code simplier)
1682 * We also check that the highest local_usn is bigger or the same as
1685 if( msg->num_elements != 1 ||
1686 strncmp(msg->elements[0].name,
1687 "replPropertyMetaData", 20) ) {
1688 DEBUG(0,(__location__ ": changereplmetada control called without "\
1689 "a specified replPropertyMetaData attribute or with others\n"));
1690 return LDB_ERR_OPERATIONS_ERROR;
1692 if (situation != REPL_URGENT_ON_UPDATE) {
1693 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1694 return LDB_ERR_OPERATIONS_ERROR;
1696 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1698 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1699 ldb_dn_get_linearized(msg->dn)));
1700 return LDB_ERR_OPERATIONS_ERROR;
1702 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1703 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1704 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1705 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1706 ldb_dn_get_linearized(msg->dn)));
1707 return LDB_ERR_OPERATIONS_ERROR;
1710 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1711 DSDB_FLAG_NEXT_MODULE |
1712 DSDB_SEARCH_SHOW_RECYCLED |
1713 DSDB_SEARCH_SHOW_EXTENDED_DN |
1714 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1715 DSDB_SEARCH_REVEAL_INTERNALS, req);
1717 if (ret != LDB_SUCCESS) {
1721 if (rmd_is_just_resorted == false) {
1722 *seq_num = find_max_local_usn(omd);
1724 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1727 * The test here now allows for a new
1728 * replPropertyMetaData with no change, if was
1729 * just dbcheck re-sorting the values.
1731 if (*seq_num <= db_seq) {
1732 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1733 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1734 (long long)*seq_num, (long long)db_seq));
1735 return LDB_ERR_OPERATIONS_ERROR;
1740 /* search for the existing replPropertyMetaDataBlob. We need
1741 * to use REVEAL and ask for DNs in storage format to support
1742 * the check for values being the same in
1743 * replmd_update_rpmd_element()
1745 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1746 DSDB_FLAG_NEXT_MODULE |
1747 DSDB_SEARCH_SHOW_RECYCLED |
1748 DSDB_SEARCH_SHOW_EXTENDED_DN |
1749 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1750 DSDB_SEARCH_REVEAL_INTERNALS, req);
1751 if (ret != LDB_SUCCESS) {
1755 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1757 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1758 ldb_dn_get_linearized(msg->dn)));
1759 return LDB_ERR_OPERATIONS_ERROR;
1762 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1763 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1764 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1765 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1766 ldb_dn_get_linearized(msg->dn)));
1767 return LDB_ERR_OPERATIONS_ERROR;
1770 if (omd.version != 1) {
1771 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1772 omd.version, ldb_dn_get_linearized(msg->dn)));
1773 return LDB_ERR_OPERATIONS_ERROR;
1776 for (i=0; i<msg->num_elements;) {
1777 struct ldb_message_element *el = &msg->elements[i];
1778 struct ldb_message_element *old_el;
1780 old_el = ldb_msg_find_element(res->msgs[0], el->name);
1781 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1782 &omd, schema, seq_num,
1786 if (ret != LDB_SUCCESS) {
1790 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1791 *is_urgent = replmd_check_urgent_attribute(el);
1794 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1799 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1801 if (el->num_values != 0) {
1806 ldb_msg_remove_element(msg, el);
1811 * Assert that we have an objectClass attribute - this is major
1812 * corruption if we don't have this!
1814 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1815 if (objectclass_el != NULL) {
1817 * Now check if this objectClass means we need to do urgent replication
1819 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1823 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1824 ldb_asprintf_errstring(ldb, __location__
1825 ": objectClass missing on %s\n",
1826 ldb_dn_get_linearized(msg->dn));
1827 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1831 * replmd_update_rpmd_element has done an update if the
1834 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1835 struct ldb_val *md_value;
1836 struct ldb_message_element *el;
1838 /*if we are RODC and this is a DRSR update then its ok*/
1839 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1840 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
1841 unsigned instanceType;
1843 ret = samdb_rodc(ldb, rodc);
1844 if (ret != LDB_SUCCESS) {
1845 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1847 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1848 return LDB_ERR_REFERRAL;
1851 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1852 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1853 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1854 "cannot change replicated attribute on partial replica");
1858 md_value = talloc(msg, struct ldb_val);
1859 if (md_value == NULL) {
1861 return LDB_ERR_OPERATIONS_ERROR;
1864 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1865 if (ret != LDB_SUCCESS) {
1866 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1870 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1871 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1872 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1873 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1874 ldb_dn_get_linearized(msg->dn)));
1875 return LDB_ERR_OPERATIONS_ERROR;
1878 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1879 if (ret != LDB_SUCCESS) {
1880 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1881 ldb_dn_get_linearized(msg->dn)));
1886 el->values = md_value;
1892 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1894 int ret = ndr_guid_compare(&pdn1->guid, &pdn2->guid);
1896 return data_blob_cmp(&pdn1->dsdb_dn->extra_part,
1897 &pdn2->dsdb_dn->extra_part);
1903 get a series of message element values as an array of DNs and GUIDs
1904 the result is sorted by GUID
1906 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1907 struct ldb_message_element *el, struct parsed_dn **pdn,
1908 const char *ldap_oid, struct ldb_request *parent)
1911 bool values_are_sorted = true;
1912 struct ldb_context *ldb = ldb_module_get_ctx(module);
1919 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1921 ldb_module_oom(module);
1922 return LDB_ERR_OPERATIONS_ERROR;
1925 for (i=0; i<el->num_values; i++) {
1926 struct ldb_val *v = &el->values[i];
1929 struct parsed_dn *p;
1933 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1934 if (p->dsdb_dn == NULL) {
1935 return LDB_ERR_INVALID_DN_SYNTAX;
1938 dn = p->dsdb_dn->dn;
1940 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
1941 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
1942 unlikely(GUID_all_zero(&p->guid))) {
1943 /* we got a DN without a GUID - go find the GUID */
1944 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
1945 if (ret != LDB_SUCCESS) {
1946 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1947 ldb_dn_get_linearized(dn));
1948 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1949 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1950 ldb_attr_cmp(el->name, "member") == 0) {
1951 return LDB_ERR_UNWILLING_TO_PERFORM;
1955 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
1956 if (ret != LDB_SUCCESS) {
1959 } else if (!NT_STATUS_IS_OK(status)) {
1960 return LDB_ERR_OPERATIONS_ERROR;
1962 if (i > 0 && values_are_sorted) {
1963 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
1965 values_are_sorted = false;
1968 /* keep a pointer to the original ldb_val */
1971 if (! values_are_sorted) {
1972 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1978 * Get a series of trusted message element values. The result is sorted by
1979 * GUID, even though the GUIDs might not be known. That works because we trust
1980 * the database to give us the elements like that if the
1981 * replmd_private->sorted_links flag is set.
1983 * We also ensure that the links are in the Functional Level 2003
1984 * linked attributes format.
1986 static int get_parsed_dns_trusted(struct ldb_module *module,
1987 struct replmd_private *replmd_private,
1988 TALLOC_CTX *mem_ctx,
1989 struct ldb_message_element *el,
1990 struct parsed_dn **pdn,
1991 const char *ldap_oid,
1992 struct ldb_request *parent)
2001 if (!replmd_private->sorted_links) {
2002 /* We need to sort the list. This is the slow old path we want
2005 ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2007 if (ret != LDB_SUCCESS) {
2011 /* Here we get a list of 'struct parsed_dns' without the parsing */
2012 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2015 ldb_module_oom(module);
2016 return LDB_ERR_OPERATIONS_ERROR;
2019 for (i = 0; i < el->num_values; i++) {
2020 (*pdn)[i].v = &el->values[i];
2025 * This upgrades links to FL2003 style, and sorts the result
2026 * if that was needed.
2028 * TODO: Add a database feature that asserts we have no FL2000
2029 * style links to avoid this check or add a feature that
2030 * uses a similar check to find sorted/unsorted links
2031 * for an on-the-fly upgrade.
2034 ret = replmd_check_upgrade_links(ldb_module_get_ctx(module),
2035 *pdn, el->num_values,
2038 if (ret != LDB_SUCCESS) {
2046 build a new extended DN, including all meta data fields
2048 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2049 RMD_ADDTIME = originating_add_time
2050 RMD_INVOCID = originating_invocation_id
2051 RMD_CHANGETIME = originating_change_time
2052 RMD_ORIGINATING_USN = originating_usn
2053 RMD_LOCAL_USN = local_usn
2054 RMD_VERSION = version
2056 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2057 const struct GUID *invocation_id, uint64_t seq_num,
2058 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
2060 struct ldb_dn *dn = dsdb_dn->dn;
2061 const char *tstring, *usn_string, *flags_string;
2062 struct ldb_val tval;
2064 struct ldb_val usnv, local_usnv;
2065 struct ldb_val vers, flagsv;
2068 const char *dnstring;
2070 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2072 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2074 return LDB_ERR_OPERATIONS_ERROR;
2076 tval = data_blob_string_const(tstring);
2078 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
2080 return LDB_ERR_OPERATIONS_ERROR;
2082 usnv = data_blob_string_const(usn_string);
2084 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2086 return LDB_ERR_OPERATIONS_ERROR;
2088 local_usnv = data_blob_string_const(usn_string);
2090 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2092 return LDB_ERR_OPERATIONS_ERROR;
2094 vers = data_blob_string_const(vstring);
2096 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2097 if (!NT_STATUS_IS_OK(status)) {
2098 return LDB_ERR_OPERATIONS_ERROR;
2101 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2102 if (!flags_string) {
2103 return LDB_ERR_OPERATIONS_ERROR;
2105 flagsv = data_blob_string_const(flags_string);
2107 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2108 if (ret != LDB_SUCCESS) return ret;
2109 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
2110 if (ret != LDB_SUCCESS) return ret;
2111 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2112 if (ret != LDB_SUCCESS) return ret;
2113 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2114 if (ret != LDB_SUCCESS) return ret;
2115 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2116 if (ret != LDB_SUCCESS) return ret;
2117 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2118 if (ret != LDB_SUCCESS) return ret;
2119 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2120 if (ret != LDB_SUCCESS) return ret;
2122 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2123 if (dnstring == NULL) {
2124 return LDB_ERR_OPERATIONS_ERROR;
2126 *v = data_blob_string_const(dnstring);
2131 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2132 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2133 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2134 uint32_t version, bool deleted);
2137 check if any links need upgrading from w2k format
2139 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2140 struct parsed_dn *dns, uint32_t count,
2141 struct ldb_message_element *el,
2142 const char *ldap_oid)
2145 const struct GUID *invocation_id = NULL;
2146 for (i=0; i<count; i++) {
2150 if (dns[i].dsdb_dn == NULL) {
2151 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2153 if (ret != LDB_SUCCESS) {
2154 return LDB_ERR_INVALID_DN_SYNTAX;
2158 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2159 &version, "RMD_VERSION");
2160 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2162 * We optimistically assume they are all the same; if
2163 * the first one is fixed, they are all fixed.
2165 * If the first one was *not* fixed and we find a
2166 * later one that is, that is an occasion to shout
2172 DEBUG(0, ("Mixed w2k and fixed format "
2173 "linked attributes\n"));
2177 if (invocation_id == NULL) {
2178 invocation_id = samdb_ntds_invocation_id(ldb);
2179 if (invocation_id == NULL) {
2180 return LDB_ERR_OPERATIONS_ERROR;
2185 /* it's an old one that needs upgrading */
2186 ret = replmd_update_la_val(el->values, dns[i].v,
2187 dns[i].dsdb_dn, dns[i].dsdb_dn,
2188 invocation_id, 1, 1, 0, 0, false);
2189 if (ret != LDB_SUCCESS) {
2195 * This sort() is critical for the operation of
2196 * get_parsed_dns_trusted() because callers of this function
2197 * expect a sorted list, and FL2000 style links are not
2198 * sorted. In particular, as well as the upgrade case,
2199 * get_parsed_dns_trusted() is called from
2200 * replmd_delete_remove_link() even in FL2000 mode
2202 * We do not normally pay the cost of the qsort() due to the
2203 * early return in the RMD_VERSION found case.
2205 TYPESAFE_QSORT(dns, count, parsed_dn_compare);
2210 update an extended DN, including all meta data fields
2212 see replmd_build_la_val for value names
2214 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2215 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2216 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2217 uint32_t version, bool deleted)
2219 struct ldb_dn *dn = dsdb_dn->dn;
2220 const char *tstring, *usn_string, *flags_string;
2221 struct ldb_val tval;
2223 struct ldb_val usnv, local_usnv;
2224 struct ldb_val vers, flagsv;
2225 const struct ldb_val *old_addtime;
2226 uint32_t old_version;
2229 const char *dnstring;
2231 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2233 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2235 return LDB_ERR_OPERATIONS_ERROR;
2237 tval = data_blob_string_const(tstring);
2239 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2241 return LDB_ERR_OPERATIONS_ERROR;
2243 usnv = data_blob_string_const(usn_string);
2245 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2247 return LDB_ERR_OPERATIONS_ERROR;
2249 local_usnv = data_blob_string_const(usn_string);
2251 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2252 if (!NT_STATUS_IS_OK(status)) {
2253 return LDB_ERR_OPERATIONS_ERROR;
2256 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2257 if (!flags_string) {
2258 return LDB_ERR_OPERATIONS_ERROR;
2260 flagsv = data_blob_string_const(flags_string);
2262 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2263 if (ret != LDB_SUCCESS) return ret;
2265 /* get the ADDTIME from the original */
2266 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2267 if (old_addtime == NULL) {
2268 old_addtime = &tval;
2270 if (dsdb_dn != old_dsdb_dn ||
2271 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2272 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2273 if (ret != LDB_SUCCESS) return ret;
2276 /* use our invocation id */
2277 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2278 if (ret != LDB_SUCCESS) return ret;
2280 /* changetime is the current time */
2281 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2282 if (ret != LDB_SUCCESS) return ret;
2284 /* update the USN */
2285 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2286 if (ret != LDB_SUCCESS) return ret;
2288 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2289 if (ret != LDB_SUCCESS) return ret;
2291 /* increase the version by 1 */
2292 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2293 if (NT_STATUS_IS_OK(status) && old_version >= version) {
2294 version = old_version+1;
2296 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2297 vers = data_blob_string_const(vstring);
2298 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2299 if (ret != LDB_SUCCESS) return ret;
2301 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2302 if (dnstring == NULL) {
2303 return LDB_ERR_OPERATIONS_ERROR;
2305 *v = data_blob_string_const(dnstring);
2311 handle adding a linked attribute
2313 static int replmd_modify_la_add(struct ldb_module *module,
2314 struct replmd_private *replmd_private,
2315 const struct dsdb_schema *schema,
2316 struct ldb_message *msg,
2317 struct ldb_message_element *el,
2318 struct ldb_message_element *old_el,
2319 const struct dsdb_attribute *schema_attr,
2322 struct ldb_dn *msg_dn,
2323 struct ldb_request *parent)
2326 struct parsed_dn *dns, *old_dns;
2327 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2329 struct ldb_val *new_values = NULL;
2330 unsigned old_num_values = old_el ? old_el->num_values : 0;
2331 unsigned num_values = 0;
2332 unsigned max_num_values;
2333 const struct GUID *invocation_id;
2334 struct ldb_context *ldb = ldb_module_get_ctx(module);
2336 unix_to_nt_time(&now, t);
2338 invocation_id = samdb_ntds_invocation_id(ldb);
2339 if (!invocation_id) {
2340 talloc_free(tmp_ctx);
2341 return LDB_ERR_OPERATIONS_ERROR;
2344 /* get the DNs to be added, fully parsed.
2346 * We need full parsing because they came off the wire and we don't
2347 * trust them, besides which we need their details to know where to put
2350 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2351 schema_attr->syntax->ldap_oid, parent);
2352 if (ret != LDB_SUCCESS) {
2353 talloc_free(tmp_ctx);
2357 /* get the existing DNs, lazily parsed */
2358 ret = get_parsed_dns_trusted(module, replmd_private,
2359 tmp_ctx, old_el, &old_dns,
2360 schema_attr->syntax->ldap_oid, parent);
2362 if (ret != LDB_SUCCESS) {
2363 talloc_free(tmp_ctx);
2367 max_num_values = old_num_values + el->num_values;
2368 if (max_num_values < old_num_values) {
2369 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2370 "old values: %u, new values: %u, sum: %u",
2371 old_num_values, el->num_values, max_num_values));
2372 talloc_free(tmp_ctx);
2373 return LDB_ERR_OPERATIONS_ERROR;
2376 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2378 if (new_values == NULL) {
2379 ldb_module_oom(module);
2380 talloc_free(tmp_ctx);
2381 return LDB_ERR_OPERATIONS_ERROR;
2385 * For each new value, find where it would go in the list. If there is
2386 * a matching GUID there, we update the existing value; otherwise we
2390 for (i = 0; i < el->num_values; i++) {
2391 struct parsed_dn *exact;
2392 struct parsed_dn *next;
2394 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2397 dns[i].dsdb_dn->extra_part, 0,
2399 schema_attr->syntax->ldap_oid,
2401 if (err != LDB_SUCCESS) {
2402 talloc_free(tmp_ctx);
2406 if (exact != NULL) {
2408 * We are trying to add one that exists, which is only
2409 * allowed if it was previously deleted.
2411 * When we do undelete a link we change it in place.
2412 * It will be copied across into the right spot in due
2416 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2418 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2419 struct GUID_txt_buf guid_str;
2420 ldb_asprintf_errstring(ldb,
2421 "Attribute %s already "
2422 "exists for target GUID %s",
2424 GUID_buf_string(&exact->guid,
2426 talloc_free(tmp_ctx);
2427 /* error codes for 'member' need to be
2429 if (ldb_attr_cmp(el->name, "member") == 0) {
2430 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2432 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2436 ret = replmd_update_la_val(new_values, exact->v,
2439 invocation_id, seq_num,
2440 seq_num, now, 0, false);
2441 if (ret != LDB_SUCCESS) {
2442 talloc_free(tmp_ctx);
2446 ret = replmd_add_backlink(module, replmd_private,
2453 if (ret != LDB_SUCCESS) {
2454 talloc_free(tmp_ctx);
2460 * Here we don't have an exact match.
2462 * If next is NULL, this one goes beyond the end of the
2463 * existing list, so we need to add all of those ones first.
2465 * If next is not NULL, we need to add all the ones before
2469 offset = old_num_values;
2471 /* next should have been parsed, but let's make sure */
2472 if (next->dsdb_dn == NULL) {
2473 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2474 schema_attr->syntax->ldap_oid);
2475 if (ret != LDB_SUCCESS) {
2479 offset = MIN(next - old_dns, old_num_values);
2482 /* put all the old ones before next on the list */
2483 for (; j < offset; j++) {
2484 new_values[num_values] = *old_dns[j].v;
2488 ret = replmd_add_backlink(module, replmd_private,
2493 /* Make the new linked attribute ldb_val. */
2494 ret = replmd_build_la_val(new_values, &new_values[num_values],
2495 dns[i].dsdb_dn, invocation_id,
2498 if (ret != LDB_SUCCESS) {
2499 talloc_free(tmp_ctx);
2503 if (ret != LDB_SUCCESS) {
2504 talloc_free(tmp_ctx);
2508 /* copy the rest of the old ones (if any) */
2509 for (; j < old_num_values; j++) {
2510 new_values[num_values] = *old_dns[j].v;
2514 talloc_steal(msg->elements, new_values);
2515 if (old_el != NULL) {
2516 talloc_steal(msg->elements, old_el->values);
2518 el->values = new_values;
2519 el->num_values = num_values;
2521 talloc_free(tmp_ctx);
2523 /* we now tell the backend to replace all existing values
2524 with the one we have constructed */
2525 el->flags = LDB_FLAG_MOD_REPLACE;
2532 handle deleting all active linked attributes
2534 static int replmd_modify_la_delete(struct ldb_module *module,
2535 struct replmd_private *replmd_private,
2536 const struct dsdb_schema *schema,
2537 struct ldb_message *msg,
2538 struct ldb_message_element *el,
2539 struct ldb_message_element *old_el,
2540 const struct dsdb_attribute *schema_attr,
2543 struct ldb_dn *msg_dn,
2544 struct ldb_request *parent)
2547 struct parsed_dn *dns, *old_dns;
2548 TALLOC_CTX *tmp_ctx = NULL;
2550 struct ldb_context *ldb = ldb_module_get_ctx(module);
2551 struct ldb_control *vanish_links_ctrl = NULL;
2552 bool vanish_links = false;
2553 unsigned int num_to_delete = el->num_values;
2555 const struct GUID *invocation_id;
2558 unix_to_nt_time(&now, t);
2560 invocation_id = samdb_ntds_invocation_id(ldb);
2561 if (!invocation_id) {
2562 return LDB_ERR_OPERATIONS_ERROR;
2565 if (old_el == NULL || old_el->num_values == 0) {
2566 /* there is nothing to delete... */
2567 if (num_to_delete == 0) {
2568 /* and we're deleting nothing, so that's OK */
2571 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2574 tmp_ctx = talloc_new(msg);
2575 if (tmp_ctx == NULL) {
2576 return LDB_ERR_OPERATIONS_ERROR;
2579 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2580 schema_attr->syntax->ldap_oid, parent);
2581 if (ret != LDB_SUCCESS) {
2582 talloc_free(tmp_ctx);
2586 ret = get_parsed_dns_trusted(module, replmd_private,
2587 tmp_ctx, old_el, &old_dns,
2588 schema_attr->syntax->ldap_oid, parent);
2590 if (ret != LDB_SUCCESS) {
2591 talloc_free(tmp_ctx);
2596 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2597 if (vanish_links_ctrl) {
2598 vanish_links = true;
2599 vanish_links_ctrl->critical = false;
2603 /* we empty out el->values here to avoid damage if we return early. */
2608 * If vanish links is set, we are actually removing members of
2609 * old_el->values; otherwise we are just marking them deleted.
2611 * There is a special case when no values are given: we remove them
2612 * all. When we have the vanish_links control we just have to remove
2613 * the backlinks and change our element to replace the existing values
2614 * with the empty list.
2617 if (num_to_delete == 0) {
2618 for (i = 0; i < old_el->num_values; i++) {
2619 struct parsed_dn *p = &old_dns[i];
2620 if (p->dsdb_dn == NULL) {
2621 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2622 schema_attr->syntax->ldap_oid);
2623 if (ret != LDB_SUCCESS) {
2627 ret = replmd_add_backlink(module, replmd_private,
2628 schema, msg_dn, &p->guid,
2631 if (ret != LDB_SUCCESS) {
2632 talloc_free(tmp_ctx);
2639 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2640 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2644 ret = replmd_update_la_val(old_el->values, p->v,
2645 p->dsdb_dn, p->dsdb_dn,
2646 invocation_id, seq_num,
2647 seq_num, now, 0, true);
2648 if (ret != LDB_SUCCESS) {
2649 talloc_free(tmp_ctx);
2655 el->flags = LDB_FLAG_MOD_REPLACE;
2656 talloc_free(tmp_ctx);
2662 for (i = 0; i < num_to_delete; i++) {
2663 struct parsed_dn *p = &dns[i];
2664 struct parsed_dn *exact = NULL;
2665 struct parsed_dn *next = NULL;
2666 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2669 p->dsdb_dn->extra_part, 0,
2671 schema_attr->syntax->ldap_oid,
2673 if (ret != LDB_SUCCESS) {
2674 talloc_free(tmp_ctx);
2677 if (exact == NULL) {
2678 struct GUID_txt_buf buf;
2679 ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2680 "exist for target GUID %s",
2682 GUID_buf_string(&p->guid, &buf));
2683 if (ldb_attr_cmp(el->name, "member") == 0) {
2684 talloc_free(tmp_ctx);
2685 return LDB_ERR_UNWILLING_TO_PERFORM;
2687 talloc_free(tmp_ctx);
2688 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2693 if (CHECK_DEBUGLVL(5)) {
2694 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2695 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2696 struct GUID_txt_buf buf;
2697 const char *guid_str = \
2698 GUID_buf_string(&p->guid, &buf);
2699 DEBUG(5, ("Deleting deleted linked "
2700 "attribute %s to %s, because "
2701 "vanish_links control is set\n",
2702 el->name, guid_str));
2706 /* remove the backlink */
2707 ret = replmd_add_backlink(module,
2714 if (ret != LDB_SUCCESS) {
2715 talloc_free(tmp_ctx);
2719 /* We flag the deletion and tidy it up later. */
2724 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2726 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2727 struct GUID_txt_buf buf;
2728 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2729 ldb_asprintf_errstring(ldb, "Attribute %s already "
2730 "deleted for target GUID %s",
2731 el->name, guid_str);
2732 if (ldb_attr_cmp(el->name, "member") == 0) {
2733 talloc_free(tmp_ctx);
2734 return LDB_ERR_UNWILLING_TO_PERFORM;
2736 talloc_free(tmp_ctx);
2737 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2741 ret = replmd_update_la_val(old_el->values, exact->v,
2742 exact->dsdb_dn, exact->dsdb_dn,
2743 invocation_id, seq_num, seq_num,
2745 if (ret != LDB_SUCCESS) {
2746 talloc_free(tmp_ctx);
2749 ret = replmd_add_backlink(module, replmd_private,
2754 if (ret != LDB_SUCCESS) {
2755 talloc_free(tmp_ctx);
2762 for (i = 0; i < old_el->num_values; i++) {
2763 if (old_dns[i].v != NULL) {
2764 old_el->values[j] = *old_dns[i].v;
2768 old_el->num_values = j;
2771 el->values = talloc_steal(msg->elements, old_el->values);
2772 el->num_values = old_el->num_values;
2774 talloc_free(tmp_ctx);
2776 /* we now tell the backend to replace all existing values
2777 with the one we have constructed */
2778 el->flags = LDB_FLAG_MOD_REPLACE;
2784 handle replacing a linked attribute
2786 static int replmd_modify_la_replace(struct ldb_module *module,
2787 struct replmd_private *replmd_private,
2788 const struct dsdb_schema *schema,
2789 struct ldb_message *msg,
2790 struct ldb_message_element *el,
2791 struct ldb_message_element *old_el,
2792 const struct dsdb_attribute *schema_attr,
2795 struct ldb_dn *msg_dn,
2796 struct ldb_request *parent)
2798 unsigned int i, old_i, new_i;
2799 struct parsed_dn *dns, *old_dns;
2800 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2802 const struct GUID *invocation_id;
2803 struct ldb_context *ldb = ldb_module_get_ctx(module);
2804 struct ldb_val *new_values = NULL;
2805 const char *ldap_oid = schema_attr->syntax->ldap_oid;
2806 unsigned int old_num_values;
2807 unsigned int repl_num_values;
2808 unsigned int max_num_values;
2811 unix_to_nt_time(&now, t);
2813 invocation_id = samdb_ntds_invocation_id(ldb);
2814 if (!invocation_id) {
2815 return LDB_ERR_OPERATIONS_ERROR;
2819 * The replace operation is unlike the replace and delete cases in that
2820 * we need to look at every existing link to see whether it is being
2821 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
2823 * As we are trying to combine two sorted lists, the algorithm we use
2824 * is akin to the merge phase of a merge sort. We interleave the two
2825 * lists, doing different things depending on which side the current
2828 * There are three main cases, with some sub-cases.
2830 * - a DN is in the old list but not the new one. It needs to be
2831 * marked as deleted (but left in the list).
2832 * - maybe it is already deleted, and we have less to do.
2834 * - a DN is in both lists. The old data gets replaced by the new,
2835 * and the list doesn't grow. The old link may have been marked as
2836 * deleted, in which case we undelete it.
2838 * - a DN is in the new list only. We add it in the right place.
2841 old_num_values = old_el ? old_el->num_values : 0;
2842 repl_num_values = el->num_values;
2843 max_num_values = old_num_values + repl_num_values;
2845 if (max_num_values == 0) {
2846 /* There is nothing to do! */
2850 ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
2851 if (ret != LDB_SUCCESS) {
2852 talloc_free(tmp_ctx);
2856 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
2858 if (ret != LDB_SUCCESS) {
2859 talloc_free(tmp_ctx);
2863 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2865 if (ret != LDB_SUCCESS) {
2866 talloc_free(tmp_ctx);
2870 new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
2871 if (new_values == NULL) {
2872 ldb_module_oom(module);
2873 talloc_free(tmp_ctx);
2874 return LDB_ERR_OPERATIONS_ERROR;
2879 for (i = 0; i < max_num_values; i++) {
2881 struct parsed_dn *old_p, *new_p;
2882 if (old_i < old_num_values && new_i < repl_num_values) {
2883 old_p = &old_dns[old_i];
2884 new_p = &dns[new_i];
2885 cmp = parsed_dn_compare(old_p, new_p);
2886 } else if (old_i < old_num_values) {
2887 /* the new list is empty, read the old list */
2888 old_p = &old_dns[old_i];
2891 } else if (new_i < repl_num_values) {
2892 /* the old list is empty, read new list */
2894 new_p = &dns[new_i];
2902 * An old ones that come before the next replacement
2903 * (if any). We mark it as deleted and add it to the
2906 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2907 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
2908 ret = replmd_update_la_val(new_values, old_p->v,
2914 if (ret != LDB_SUCCESS) {
2915 talloc_free(tmp_ctx);
2919 ret = replmd_add_backlink(module, replmd_private,
2922 &old_p->guid, false,
2925 if (ret != LDB_SUCCESS) {
2926 talloc_free(tmp_ctx);
2930 new_values[i] = *old_p->v;
2932 } else if (cmp == 0) {
2934 * We are overwriting one. If it was previously
2935 * deleted, we need to add a backlink.
2937 * Note that if any RMD_FLAGs in an extended new DN
2942 ret = replmd_update_la_val(new_values, old_p->v,
2948 if (ret != LDB_SUCCESS) {
2949 talloc_free(tmp_ctx);
2953 rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2954 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
2955 ret = replmd_add_backlink(module, replmd_private,
2961 if (ret != LDB_SUCCESS) {
2962 talloc_free(tmp_ctx);
2967 new_values[i] = *old_p->v;
2972 * Replacements that don't match an existing one. We
2973 * just add them to the final list.
2975 ret = replmd_build_la_val(new_values,
2981 if (ret != LDB_SUCCESS) {
2982 talloc_free(tmp_ctx);
2985 ret = replmd_add_backlink(module, replmd_private,
2991 if (ret != LDB_SUCCESS) {
2992 talloc_free(tmp_ctx);
2995 new_values[i] = *new_p->v;
2999 if (old_el != NULL) {
3000 talloc_steal(msg->elements, old_el->values);
3002 el->values = talloc_steal(msg->elements, new_values);
3004 talloc_free(tmp_ctx);
3006 el->flags = LDB_FLAG_MOD_REPLACE;
3013 handle linked attributes in modify requests
3015 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3016 struct replmd_private *replmd_private,
3017 struct ldb_message *msg,
3018 uint64_t seq_num, time_t t,
3019 struct ldb_request *parent)
3021 struct ldb_result *res;
3024 struct ldb_context *ldb = ldb_module_get_ctx(module);
3025 struct ldb_message *old_msg;
3027 const struct dsdb_schema *schema;
3029 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3031 * Nothing special is required for modifying or vanishing links
3032 * in fl2000 since they are just strings in a multi-valued
3035 struct ldb_control *ctrl = ldb_request_get_control(parent,
3036 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3038 ctrl->critical = false;
3046 * We should restrict this to the intersection of the list of
3047 * linked attributes in the schema and the list of attributes
3050 * This will help performance a little, as otherwise we have
3051 * to allocate the entire object value-by-value.
3053 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3054 DSDB_FLAG_NEXT_MODULE |
3055 DSDB_SEARCH_SHOW_RECYCLED |
3056 DSDB_SEARCH_REVEAL_INTERNALS |
3057 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3059 if (ret != LDB_SUCCESS) {
3062 schema = dsdb_get_schema(ldb, res);
3064 return LDB_ERR_OPERATIONS_ERROR;
3067 old_msg = res->msgs[0];
3069 for (i=0; i<msg->num_elements; i++) {
3070 struct ldb_message_element *el = &msg->elements[i];
3071 struct ldb_message_element *old_el, *new_el;
3072 const struct dsdb_attribute *schema_attr
3073 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3075 ldb_asprintf_errstring(ldb,
3076 "%s: attribute %s is not a valid attribute in schema",
3077 __FUNCTION__, el->name);
3078 return LDB_ERR_OBJECT_CLASS_VIOLATION;
3080 if (schema_attr->linkID == 0) {
3083 if ((schema_attr->linkID & 1) == 1) {
3084 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
3087 /* Odd is for the target. Illegal to modify */
3088 ldb_asprintf_errstring(ldb,
3089 "attribute %s must not be modified directly, it is a linked attribute", el->name);
3090 return LDB_ERR_UNWILLING_TO_PERFORM;
3092 old_el = ldb_msg_find_element(old_msg, el->name);
3093 switch (el->flags & LDB_FLAG_MOD_MASK) {
3094 case LDB_FLAG_MOD_REPLACE:
3095 ret = replmd_modify_la_replace(module, replmd_private,
3096 schema, msg, el, old_el,
3097 schema_attr, seq_num, t,
3101 case LDB_FLAG_MOD_DELETE:
3102 ret = replmd_modify_la_delete(module, replmd_private,
3103 schema, msg, el, old_el,
3104 schema_attr, seq_num, t,
3108 case LDB_FLAG_MOD_ADD:
3109 ret = replmd_modify_la_add(module, replmd_private,
3110 schema, msg, el, old_el,
3111 schema_attr, seq_num, t,
3116 ldb_asprintf_errstring(ldb,
3117 "invalid flags 0x%x for %s linked attribute",
3118 el->flags, el->name);
3119 return LDB_ERR_UNWILLING_TO_PERFORM;
3121 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3122 ldb_asprintf_errstring(ldb,
3123 "Attribute %s is single valued but more than one value has been supplied",
3125 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3127 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3132 if (ret != LDB_SUCCESS) {
3136 ldb_msg_remove_attr(old_msg, el->name);
3138 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3139 new_el->num_values = el->num_values;
3140 new_el->values = talloc_steal(msg->elements, el->values);
3142 /* TODO: this relises a bit too heavily on the exact
3143 behaviour of ldb_msg_find_element and
3144 ldb_msg_remove_element */
3145 old_el = ldb_msg_find_element(msg, el->name);
3147 ldb_msg_remove_element(msg, old_el);
3157 static int send_rodc_referral(struct ldb_request *req,
3158 struct ldb_context *ldb,
3161 char *referral = NULL;
3162 struct loadparm_context *lp_ctx = NULL;
3163 struct ldb_dn *fsmo_role_dn = NULL;
3164 struct ldb_dn *role_owner_dn = NULL;
3165 const char *domain = NULL;
3168 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3169 struct loadparm_context);
3171 werr = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3172 &fsmo_role_dn, &role_owner_dn);
3174 if (W_ERROR_IS_OK(werr)) {
3175 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3176 if (server_dn != NULL) {
3177 ldb_dn_remove_child_components(server_dn, 1);
3178 domain = samdb_dn_to_dnshostname(ldb, req,
3183 if (domain == NULL) {
3184 domain = lpcfg_dnsdomain(lp_ctx);
3187 referral = talloc_asprintf(req, "ldap://%s/%s",
3189 ldb_dn_get_linearized(dn));
3190 if (referral == NULL) {
3192 return LDB_ERR_OPERATIONS_ERROR;
3195 return ldb_module_send_referral(req, referral);
3199 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3201 struct ldb_context *ldb;
3202 struct replmd_replicated_request *ac;
3203 struct ldb_request *down_req;
3204 struct ldb_message *msg;
3205 time_t t = time(NULL);
3207 bool is_urgent = false, rodc = false;
3208 bool is_schema_nc = false;
3209 unsigned int functional_level;
3210 const struct ldb_message_element *guid_el = NULL;
3211 struct ldb_control *sd_propagation_control;
3212 struct replmd_private *replmd_private =
3213 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3215 /* do not manipulate our control entries */
3216 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3217 return ldb_next_request(module, req);
3220 sd_propagation_control = ldb_request_get_control(req,
3221 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3222 if (sd_propagation_control != NULL) {
3223 if (req->op.mod.message->num_elements != 1) {
3224 return ldb_module_operr(module);
3226 ret = strcmp(req->op.mod.message->elements[0].name,
3227 "nTSecurityDescriptor");
3229 return ldb_module_operr(module);
3232 return ldb_next_request(module, req);
3235 ldb = ldb_module_get_ctx(module);
3237 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3239 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3240 if (guid_el != NULL) {
3241 ldb_set_errstring(ldb,
3242 "replmd_modify: it's not allowed to change the objectGUID!");
3243 return LDB_ERR_CONSTRAINT_VIOLATION;
3246 ac = replmd_ctx_init(module, req);
3248 return ldb_module_oom(module);
3251 functional_level = dsdb_functional_level(ldb);
3253 /* we have to copy the message as the caller might have it as a const */
3254 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3258 return LDB_ERR_OPERATIONS_ERROR;
3261 ldb_msg_remove_attr(msg, "whenChanged");
3262 ldb_msg_remove_attr(msg, "uSNChanged");
3264 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3266 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3267 msg, &ac->seq_num, t, is_schema_nc,
3269 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3270 ret = send_rodc_referral(req, ldb, msg->dn);
3276 if (ret != LDB_SUCCESS) {
3281 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3282 msg, ac->seq_num, t, req);
3283 if (ret != LDB_SUCCESS) {
3289 * - replace the old object with the newly constructed one
3292 ac->is_urgent = is_urgent;
3294 ret = ldb_build_mod_req(&down_req, ldb, ac,
3297 ac, replmd_op_callback,
3299 LDB_REQ_SET_LOCATION(down_req);
3300 if (ret != LDB_SUCCESS) {
3305 /* current partition control is needed by "replmd_op_callback" */
3306 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3307 ret = ldb_request_add_control(down_req,
3308 DSDB_CONTROL_CURRENT_PARTITION_OID,
3310 if (ret != LDB_SUCCESS) {
3316 /* If we are in functional level 2000, then
3317 * replmd_modify_handle_linked_attribs will have done
3319 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3320 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3321 if (ret != LDB_SUCCESS) {
3327 talloc_steal(down_req, msg);
3329 /* we only change whenChanged and uSNChanged if the seq_num
3331 if (ac->seq_num != 0) {
3332 ret = add_time_element(msg, "whenChanged", t);
3333 if (ret != LDB_SUCCESS) {
3339 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3340 if (ret != LDB_SUCCESS) {
3347 /* go on with the call chain */
3348 return ldb_next_request(module, down_req);
3351 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3354 handle a rename request
3356 On a rename we need to do an extra ldb_modify which sets the
3357 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3359 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3361 struct ldb_context *ldb;
3362 struct replmd_replicated_request *ac;
3364 struct ldb_request *down_req;
3366 /* do not manipulate our control entries */
3367 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3368 return ldb_next_request(module, req);
3371 ldb = ldb_module_get_ctx(module);
3373 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3375 ac = replmd_ctx_init(module, req);
3377 return ldb_module_oom(module);
3380 ret = ldb_build_rename_req(&down_req, ldb, ac,
3381 ac->req->op.rename.olddn,
3382 ac->req->op.rename.newdn,
3384 ac, replmd_rename_callback,
3386 LDB_REQ_SET_LOCATION(down_req);
3387 if (ret != LDB_SUCCESS) {
3392 /* go on with the call chain */
3393 return ldb_next_request(module, down_req);
3396 /* After the rename is compleated, update the whenchanged etc */
3397 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3399 struct ldb_context *ldb;
3400 struct ldb_request *down_req;
3401 struct ldb_message *msg;
3402 const struct dsdb_attribute *rdn_attr;
3403 const char *rdn_name;
3404 const struct ldb_val *rdn_val;
3405 const char *attrs[5] = { NULL, };
3406 time_t t = time(NULL);
3408 bool is_urgent = false, rodc = false;
3410 struct replmd_replicated_request *ac =
3411 talloc_get_type(req->context, struct replmd_replicated_request);
3412 struct replmd_private *replmd_private =
3413 talloc_get_type(ldb_module_get_private(ac->module),
3414 struct replmd_private);
3416 ldb = ldb_module_get_ctx(ac->module);
3418 if (ares->error != LDB_SUCCESS) {
3419 return ldb_module_done(ac->req, ares->controls,
3420 ares->response, ares->error);
3423 if (ares->type != LDB_REPLY_DONE) {
3424 ldb_set_errstring(ldb,
3425 "invalid ldb_reply_type in callback");
3427 return ldb_module_done(ac->req, NULL, NULL,
3428 LDB_ERR_OPERATIONS_ERROR);
3432 * - replace the old object with the newly constructed one
3435 msg = ldb_msg_new(ac);
3438 return LDB_ERR_OPERATIONS_ERROR;
3441 msg->dn = ac->req->op.rename.newdn;
3443 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3445 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3446 if (rdn_name == NULL) {
3448 return ldb_module_done(ac->req, NULL, NULL,
3452 /* normalize the rdn attribute name */
3453 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3454 if (rdn_attr == NULL) {
3456 return ldb_module_done(ac->req, NULL, NULL,
3459 rdn_name = rdn_attr->lDAPDisplayName;
3461 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3462 if (rdn_val == NULL) {
3464 return ldb_module_done(ac->req, NULL, NULL,
3468 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3470 return ldb_module_done(ac->req, NULL, NULL,
3473 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3475 return ldb_module_done(ac->req, NULL, NULL,
3478 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3480 return ldb_module_done(ac->req, NULL, NULL,
3483 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3485 return ldb_module_done(ac->req, NULL, NULL,
3490 * here we let replmd_update_rpmd() only search for
3491 * the existing "replPropertyMetaData" and rdn_name attributes.
3493 * We do not want the existing "name" attribute as
3494 * the "name" attribute needs to get the version
3495 * updated on rename even if the rdn value hasn't changed.
3497 * This is the diff of the meta data, for a moved user
3498 * on a w2k8r2 server:
3501 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3502 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3503 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3504 * version : 0x00000001 (1)
3505 * reserved : 0x00000000 (0)
3506 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3507 * local_usn : 0x00000000000037a5 (14245)
3508 * array: struct replPropertyMetaData1
3509 * attid : DRSUAPI_ATTID_name (0x90001)
3510 * - version : 0x00000001 (1)
3511 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3512 * + version : 0x00000002 (2)
3513 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3514 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3515 * - originating_usn : 0x00000000000037a5 (14245)
3516 * - local_usn : 0x00000000000037a5 (14245)
3517 * + originating_usn : 0x0000000000003834 (14388)
3518 * + local_usn : 0x0000000000003834 (14388)
3519 * array: struct replPropertyMetaData1
3520 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3521 * version : 0x00000004 (4)
3523 attrs[0] = "replPropertyMetaData";
3524 attrs[1] = "objectClass";
3525 attrs[2] = "instanceType";
3526 attrs[3] = rdn_name;
3529 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3530 msg, &ac->seq_num, t,
3531 is_schema_nc, &is_urgent, &rodc);
3532 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3533 ret = send_rodc_referral(req, ldb, ac->req->op.rename.olddn);
3535 return ldb_module_done(req, NULL, NULL, ret);
3538 if (ret != LDB_SUCCESS) {
3540 return ldb_module_done(ac->req, NULL, NULL, ret);
3543 if (ac->seq_num == 0) {
3545 return ldb_module_done(ac->req, NULL, NULL,
3547 "internal error seq_num == 0"));
3549 ac->is_urgent = is_urgent;
3551 ret = ldb_build_mod_req(&down_req, ldb, ac,
3554 ac, replmd_op_callback,
3556 LDB_REQ_SET_LOCATION(down_req);
3557 if (ret != LDB_SUCCESS) {
3562 /* current partition control is needed by "replmd_op_callback" */
3563 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3564 ret = ldb_request_add_control(down_req,
3565 DSDB_CONTROL_CURRENT_PARTITION_OID,
3567 if (ret != LDB_SUCCESS) {
3573 talloc_steal(down_req, msg);
3575 ret = add_time_element(msg, "whenChanged", t);
3576 if (ret != LDB_SUCCESS) {
3582 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3583 if (ret != LDB_SUCCESS) {
3589 /* go on with the call chain - do the modify after the rename */
3590 return ldb_next_request(ac->module, down_req);
3594 * remove links from objects that point at this object when an object
3595 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3596 * RemoveObj which states that link removal due to the object being
3597 * deleted is NOT an originating update - they just go away!
3600 static int replmd_delete_remove_link(struct ldb_module *module,
3601 const struct dsdb_schema *schema,
3602 struct replmd_private *replmd_private,
3605 struct ldb_message_element *el,
3606 const struct dsdb_attribute *sa,
3607 struct ldb_request *parent)
3610 TALLOC_CTX *tmp_ctx = talloc_new(module);
3611 struct ldb_context *ldb = ldb_module_get_ctx(module);
3613 for (i=0; i<el->num_values; i++) {
3614 struct dsdb_dn *dsdb_dn;
3616 struct ldb_message *msg;
3617 const struct dsdb_attribute *target_attr;
3618 struct ldb_message_element *el2;
3620 struct ldb_val dn_val;
3621 uint32_t dsdb_flags = 0;
3622 const char *attrs[] = { NULL, NULL };
3623 struct ldb_result *link_res;
3624 struct ldb_message *link_msg;
3625 struct ldb_message_element *link_el;
3626 struct parsed_dn *link_dns;
3627 struct parsed_dn *p = NULL, *unused = NULL;
3629 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3633 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3635 talloc_free(tmp_ctx);
3636 return LDB_ERR_OPERATIONS_ERROR;
3639 /* remove the link */
3640 msg = ldb_msg_new(tmp_ctx);
3642 ldb_module_oom(module);
3643 talloc_free(tmp_ctx);
3644 return LDB_ERR_OPERATIONS_ERROR;
3648 msg->dn = dsdb_dn->dn;
3650 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3651 if (target_attr == NULL) {
3654 attrs[0] = target_attr->lDAPDisplayName;
3656 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName,
3657 LDB_FLAG_MOD_DELETE, &el2);
3658 if (ret != LDB_SUCCESS) {
3659 ldb_module_oom(module);
3660 talloc_free(tmp_ctx);
3661 return LDB_ERR_OPERATIONS_ERROR;
3664 ret = dsdb_module_search_dn(module, tmp_ctx, &link_res,
3666 DSDB_FLAG_NEXT_MODULE |
3667 DSDB_SEARCH_SHOW_EXTENDED_DN,
3670 if (ret != LDB_SUCCESS) {
3671 talloc_free(tmp_ctx);
3675 link_msg = link_res->msgs[0];
3676 link_el = ldb_msg_find_element(link_msg,
3677 target_attr->lDAPDisplayName);
3678 if (link_el == NULL) {
3679 talloc_free(tmp_ctx);
3680 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3684 * This call 'upgrades' the links in link_dns, but we
3685 * do not commit the result back into the database, so
3686 * this is safe to call in FL2000 or on databases that
3687 * have been run at that level in the past.
3689 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx,
3691 target_attr->syntax->ldap_oid, parent);
3692 if (ret != LDB_SUCCESS) {
3693 talloc_free(tmp_ctx);
3697 ret = parsed_dn_find(ldb, link_dns, link_el->num_values,
3701 target_attr->syntax->ldap_oid, false);
3702 if (ret != LDB_SUCCESS) {
3703 talloc_free(tmp_ctx);
3708 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3709 "Failed to find forward link on %s "
3710 "as %s to remove backlink %s on %s",
3711 ldb_dn_get_linearized(msg->dn),
3712 target_attr->lDAPDisplayName,
3713 sa->lDAPDisplayName,
3714 ldb_dn_get_linearized(dn));
3715 talloc_free(tmp_ctx);
3716 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3720 /* This needs to get the Binary DN, by first searching */
3721 dn_str = dsdb_dn_get_linearized(tmp_ctx,
3724 dn_val = data_blob_string_const(dn_str);
3725 el2->values = &dn_val;
3726 el2->num_values = 1;
3729 * Ensure that we tell the modification to vanish any linked
3730 * attributes (not simply mark them as isDeleted = TRUE)
3732 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3734 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3735 if (ret != LDB_SUCCESS) {
3736 talloc_free(tmp_ctx);
3740 talloc_free(tmp_ctx);
3746 handle update of replication meta data for deletion of objects
3748 This also handles the mapping of delete to a rename operation
3749 to allow deletes to be replicated.
3751 It also handles the incoming deleted objects, to ensure they are
3752 fully deleted here. In that case re_delete is true, and we do not
3753 use this as a signal to change the deleted state, just reinforce it.
3756 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3758 int ret = LDB_ERR_OTHER;
3759 bool retb, disallow_move_on_delete;
3760 struct ldb_dn *old_dn, *new_dn;
3761 const char *rdn_name;
3762 const struct ldb_val *rdn_value, *new_rdn_value;
3764 struct ldb_context *ldb = ldb_module_get_ctx(module);
3765 const struct dsdb_schema *schema;
3766 struct ldb_message *msg, *old_msg;
3767 struct ldb_message_element *el;
3768 TALLOC_CTX *tmp_ctx;
3769 struct ldb_result *res, *parent_res;
3770 static const char * const preserved_attrs[] = {
3771 /* yes, this really is a hard coded list. See MS-ADTS
3772 section 3.1.1.5.5.1.1 */
3775 "dNReferenceUpdate",
3786 "msDS-LastKnownRDN",
3792 "distinguishedName",
3796 "proxiedObjectName",
3798 "nTSecurityDescriptor",
3799 "replPropertyMetaData",
3801 "securityIdentifier",
3809 "userAccountControl",
3816 static const char * const all_attrs[] = {
3817 DSDB_SECRET_ATTRIBUTES,
3821 unsigned int i, el_count = 0;
3822 uint32_t dsdb_flags = 0;
3823 struct replmd_private *replmd_private;
3824 enum deletion_state deletion_state, next_deletion_state;
3826 if (ldb_dn_is_special(req->op.del.dn)) {
3827 return ldb_next_request(module, req);
3831 * We have to allow dbcheck to remove an object that
3832 * is beyond repair, and to do so totally. This could
3833 * mean we we can get a partial object from the other
3834 * DC, causing havoc, so dbcheck suggests
3835 * re-replication first. dbcheck sets both DBCHECK
3836 * and RELAX in this situation.
3838 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3839 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3840 /* really, really remove it */
3841 return ldb_next_request(module, req);
3844 tmp_ctx = talloc_new(ldb);
3847 return LDB_ERR_OPERATIONS_ERROR;
3850 schema = dsdb_get_schema(ldb, tmp_ctx);
3852 talloc_free(tmp_ctx);
3853 return LDB_ERR_OPERATIONS_ERROR;
3856 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3858 /* we need the complete msg off disk, so we can work out which
3859 attributes need to be removed */
3860 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3861 DSDB_FLAG_NEXT_MODULE |
3862 DSDB_SEARCH_SHOW_RECYCLED |
3863 DSDB_SEARCH_REVEAL_INTERNALS |
3864 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3865 if (ret != LDB_SUCCESS) {
3866 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3867 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3868 re_delete ? "re-delete" : "delete",
3869 ldb_dn_get_linearized(old_dn),
3870 ldb_errstring(ldb_module_get_ctx(module)));
3871 talloc_free(tmp_ctx);
3874 old_msg = res->msgs[0];
3876 replmd_deletion_state(module, old_msg,
3878 &next_deletion_state);
3880 /* This supports us noticing an incoming isDeleted and acting on it */
3882 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3883 next_deletion_state = deletion_state;
3886 if (next_deletion_state == OBJECT_REMOVED) {
3888 * We have to prevent objects being deleted, even if
3889 * the administrator really wants them gone, as
3890 * without the tombstone, we can get a partial object
3891 * from the other DC, causing havoc.
3893 * The only other valid case is when the 180 day
3894 * timeout has expired, when relax is specified.
3896 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3897 /* it is already deleted - really remove it this time */
3898 talloc_free(tmp_ctx);
3899 return ldb_next_request(module, req);
3902 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3903 "This check is to prevent corruption of the replicated state.",
3904 ldb_dn_get_linearized(old_msg->dn));
3905 return LDB_ERR_UNWILLING_TO_PERFORM;
3908 rdn_name = ldb_dn_get_rdn_name(old_dn);
3909 rdn_value = ldb_dn_get_rdn_val(old_dn);
3910 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3911 talloc_free(tmp_ctx);
3912 return ldb_operr(ldb);
3915 msg = ldb_msg_new(tmp_ctx);
3917 ldb_module_oom(module);
3918 talloc_free(tmp_ctx);
3919 return LDB_ERR_OPERATIONS_ERROR;
3924 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3925 disallow_move_on_delete =
3926 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3927 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3929 /* work out where we will be renaming this object to */
3930 if (!disallow_move_on_delete) {
3931 struct ldb_dn *deleted_objects_dn;
3932 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3933 &deleted_objects_dn);
3936 * We should not move objects if we can't find the
3937 * deleted objects DN. Not moving (or otherwise
3938 * harming) the Deleted Objects DN itself is handled
3941 if (re_delete && (ret != LDB_SUCCESS)) {
3942 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3943 if (new_dn == NULL) {
3944 ldb_module_oom(module);
3945 talloc_free(tmp_ctx);
3946 return LDB_ERR_OPERATIONS_ERROR;
3948 } else if (ret != LDB_SUCCESS) {
3949 /* this is probably an attempted delete on a partition
3950 * that doesn't allow delete operations, such as the
3951 * schema partition */
3952 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3953 ldb_dn_get_linearized(old_dn));
3954 talloc_free(tmp_ctx);
3955 return LDB_ERR_UNWILLING_TO_PERFORM;
3957 new_dn = deleted_objects_dn;
3960 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3961 if (new_dn == NULL) {
3962 ldb_module_oom(module);
3963 talloc_free(tmp_ctx);
3964 return LDB_ERR_OPERATIONS_ERROR;
3968 /* get the objects GUID from the search we just did */
3969 guid = samdb_result_guid(old_msg, "objectGUID");
3971 if (deletion_state == OBJECT_NOT_DELETED) {
3972 /* Add a formatted child */
3973 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3975 ldb_dn_escape_value(tmp_ctx, *rdn_value),
3976 GUID_string(tmp_ctx, &guid));
3978 ldb_asprintf_errstring(ldb, __location__
3979 ": Unable to add a formatted child to dn: %s",
3980 ldb_dn_get_linearized(new_dn));
3981 talloc_free(tmp_ctx);
3982 return LDB_ERR_OPERATIONS_ERROR;
3985 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
3986 if (ret != LDB_SUCCESS) {
3987 ldb_asprintf_errstring(ldb, __location__
3988 ": Failed to add isDeleted string to the msg");
3989 talloc_free(tmp_ctx);
3992 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3995 * No matter what has happened with other renames etc, try again to
3996 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
3999 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
4000 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
4002 ldb_asprintf_errstring(ldb, __location__
4003 ": Unable to add a prepare rdn of %s",
4004 ldb_dn_get_linearized(rdn));
4005 talloc_free(tmp_ctx);
4006 return LDB_ERR_OPERATIONS_ERROR;
4008 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
4010 retb = ldb_dn_add_child(new_dn, rdn);
4012 ldb_asprintf_errstring(ldb, __location__
4013 ": Unable to add rdn %s to base dn: %s",
4014 ldb_dn_get_linearized(rdn),
4015 ldb_dn_get_linearized(new_dn));
4016 talloc_free(tmp_ctx);
4017 return LDB_ERR_OPERATIONS_ERROR;
4022 now we need to modify the object in the following ways:
4024 - add isDeleted=TRUE
4025 - update rDN and name, with new rDN
4026 - remove linked attributes
4027 - remove objectCategory and sAMAccountType
4028 - remove attribs not on the preserved list
4029 - preserved if in above list, or is rDN
4030 - remove all linked attribs from this object
4031 - remove all links from other objects to this object
4032 - add lastKnownParent
4033 - update replPropertyMetaData?
4035 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4038 if (deletion_state == OBJECT_NOT_DELETED) {
4039 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4040 char *parent_dn_str = NULL;
4042 /* we need the storage form of the parent GUID */
4043 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
4045 DSDB_FLAG_NEXT_MODULE |
4046 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4047 DSDB_SEARCH_REVEAL_INTERNALS|
4048 DSDB_SEARCH_SHOW_RECYCLED, req);
4049 if (ret != LDB_SUCCESS) {
4050 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4051 "repmd_delete: Failed to %s %s, "
4052 "because we failed to find it's parent (%s): %s",
4053 re_delete ? "re-delete" : "delete",
4054 ldb_dn_get_linearized(old_dn),
4055 ldb_dn_get_linearized(parent_dn),
4056 ldb_errstring(ldb_module_get_ctx(module)));
4057 talloc_free(tmp_ctx);
4062 * Now we can use the DB version,
4063 * it will have the extended DN info in it
4065 parent_dn = parent_res->msgs[0]->dn;
4066 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4069 if (parent_dn_str == NULL) {
4070 talloc_free(tmp_ctx);
4071 return ldb_module_oom(module);
4074 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4076 if (ret != LDB_SUCCESS) {
4077 ldb_asprintf_errstring(ldb, __location__
4078 ": Failed to add lastKnownParent "
4079 "string when deleting %s",
4080 ldb_dn_get_linearized(old_dn));
4081 talloc_free(tmp_ctx);
4084 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4086 if (next_deletion_state == OBJECT_DELETED) {
4087 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4088 if (ret != LDB_SUCCESS) {
4089 ldb_asprintf_errstring(ldb, __location__
4090 ": Failed to add msDS-LastKnownRDN "
4091 "string when deleting %s",
4092 ldb_dn_get_linearized(old_dn));
4093 talloc_free(tmp_ctx);
4096 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
4100 switch (next_deletion_state) {
4102 case OBJECT_RECYCLED:
4103 case OBJECT_TOMBSTONE:
4106 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4107 * describes what must be removed from a tombstone
4110 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4111 * describes what must be removed from a recycled
4117 * we also mark it as recycled, meaning this object can't be
4118 * recovered (we are stripping its attributes).
4119 * This is done only if we have this schema object of course ...
4120 * This behavior is identical to the one of Windows 2008R2 which
4121 * always set the isRecycled attribute, even if the recycle-bin is
4122 * not activated and what ever the forest level is.
4124 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4125 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
4126 if (ret != LDB_SUCCESS) {
4127 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4128 ldb_module_oom(module);
4129 talloc_free(tmp_ctx);
4132 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4135 replmd_private = talloc_get_type(ldb_module_get_private(module),
4136 struct replmd_private);
4137 /* work out which of the old attributes we will be removing */
4138 for (i=0; i<old_msg->num_elements; i++) {
4139 const struct dsdb_attribute *sa;
4140 el = &old_msg->elements[i];
4141 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4143 talloc_free(tmp_ctx);
4144 return LDB_ERR_OPERATIONS_ERROR;
4146 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4147 /* don't remove the rDN */
4150 if (sa->linkID & 1) {
4152 we have a backlink in this object
4153 that needs to be removed. We're not
4154 allowed to remove it directly
4155 however, so we instead setup a
4156 modify to delete the corresponding
4159 ret = replmd_delete_remove_link(module, schema,
4163 if (ret != LDB_SUCCESS) {
4164 const char *old_dn_str
4165 = ldb_dn_get_linearized(old_dn);
4166 ldb_asprintf_errstring(ldb,
4168 ": Failed to remove backlink of "
4169 "%s when deleting %s: %s",
4172 ldb_errstring(ldb));
4173 talloc_free(tmp_ctx);
4174 return LDB_ERR_OPERATIONS_ERROR;
4176 /* now we continue, which means we
4177 won't remove this backlink
4181 } else if (sa->linkID == 0) {
4182 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4185 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4190 * Ensure that we tell the modification to vanish any linked
4191 * attributes (not simply mark them as isDeleted = TRUE)
4193 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4195 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4196 if (ret != LDB_SUCCESS) {
4197 talloc_free(tmp_ctx);
4198 ldb_module_oom(module);
4205 case OBJECT_DELETED:
4207 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4208 * describes what must be removed from a deleted
4212 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4213 if (ret != LDB_SUCCESS) {
4214 talloc_free(tmp_ctx);
4215 ldb_module_oom(module);
4219 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4220 if (ret != LDB_SUCCESS) {
4221 talloc_free(tmp_ctx);
4222 ldb_module_oom(module);
4232 if (deletion_state == OBJECT_NOT_DELETED) {
4233 const struct dsdb_attribute *sa;
4235 /* work out what the new rdn value is, for updating the
4236 rDN and name fields */
4237 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4238 if (new_rdn_value == NULL) {
4239 talloc_free(tmp_ctx);
4240 return ldb_operr(ldb);
4243 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4245 talloc_free(tmp_ctx);
4246 return LDB_ERR_OPERATIONS_ERROR;
4249 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4251 if (ret != LDB_SUCCESS) {
4252 talloc_free(tmp_ctx);
4255 el->flags = LDB_FLAG_MOD_REPLACE;
4257 el = ldb_msg_find_element(old_msg, "name");
4259 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4260 if (ret != LDB_SUCCESS) {
4261 talloc_free(tmp_ctx);
4264 el->flags = LDB_FLAG_MOD_REPLACE;
4269 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4274 * No matter what has happned with other renames, try again to
4275 * get this to be under the deleted DN.
4277 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4278 /* now rename onto the new DN */
4279 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4280 if (ret != LDB_SUCCESS){
4281 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4282 ldb_dn_get_linearized(old_dn),
4283 ldb_dn_get_linearized(new_dn),
4284 ldb_errstring(ldb)));
4285 talloc_free(tmp_ctx);
4291 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4292 if (ret != LDB_SUCCESS) {
4293 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4294 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4295 talloc_free(tmp_ctx);
4299 talloc_free(tmp_ctx);
4301 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4304 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4306 return replmd_delete_internals(module, req, false);
4310 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4315 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4317 int ret = LDB_ERR_OTHER;
4318 /* TODO: do some error mapping */
4320 /* Let the caller know the full WERROR */
4321 ar->objs->error = status;
4327 static struct replPropertyMetaData1 *
4328 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4329 enum drsuapi_DsAttributeId attid)
4332 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4334 for (i = 0; i < rpmd_ctr->count; i++) {
4335 if (rpmd_ctr->array[i].attid == attid) {
4336 return &rpmd_ctr->array[i];
4344 return true if an update is newer than an existing entry
4345 see section 5.11 of MS-ADTS
4347 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4348 const struct GUID *update_invocation_id,
4349 uint32_t current_version,
4350 uint32_t update_version,
4351 NTTIME current_change_time,
4352 NTTIME update_change_time)
4354 if (update_version != current_version) {
4355 return update_version > current_version;
4357 if (update_change_time != current_change_time) {
4358 return update_change_time > current_change_time;
4360 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4363 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4364 struct replPropertyMetaData1 *new_m)
4366 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4367 &new_m->originating_invocation_id,
4370 cur_m->originating_change_time,
4371 new_m->originating_change_time);
4374 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4375 struct replPropertyMetaData1 *cur_m,
4376 struct replPropertyMetaData1 *new_m)
4381 * If the new replPropertyMetaData entry for this attribute is
4382 * not provided (this happens in the case where we look for
4383 * ATTID_name, but the name was not changed), then the local
4384 * state is clearly still current, as the remote
4385 * server didn't send it due to being older the high watermark
4388 if (new_m == NULL) {
4392 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4394 * if we compare equal then do an
4395 * update. This is used when a client
4396 * asks for a FULL_SYNC, and can be
4397 * used to recover a corrupt
4400 * This call is a bit tricky, what we
4401 * are doing it turning the 'is_newer'
4402 * call into a 'not is older' by
4403 * swapping cur_m and new_m, and negating the
4406 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4409 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4419 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4421 const struct ldb_val *rdn_val;
4422 const char *rdn_name;
4423 struct ldb_dn *new_dn;
4425 rdn_val = ldb_dn_get_rdn_val(dn);
4426 rdn_name = ldb_dn_get_rdn_name(dn);
4427 if (!rdn_val || !rdn_name) {
4431 new_dn = ldb_dn_copy(mem_ctx, dn);
4436 if (!ldb_dn_remove_child_components(new_dn, 1)) {
4440 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4442 ldb_dn_escape_value(new_dn, *rdn_val),
4443 GUID_string(new_dn, guid))) {
4452 perform a modify operation which sets the rDN and name attributes to
4453 their current values. This has the effect of changing these
4454 attributes to have been last updated by the current DC. This is
4455 needed to ensure that renames performed as part of conflict
4456 resolution are propogated to other DCs
4458 static int replmd_name_modify(struct replmd_replicated_request *ar,
4459 struct ldb_request *req, struct ldb_dn *dn)
4461 struct ldb_message *msg;
4462 const char *rdn_name;
4463 const struct ldb_val *rdn_val;
4464 const struct dsdb_attribute *rdn_attr;
4467 msg = ldb_msg_new(req);
4473 rdn_name = ldb_dn_get_rdn_name(dn);
4474 if (rdn_name == NULL) {
4478 /* normalize the rdn attribute name */
4479 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4480 if (rdn_attr == NULL) {
4483 rdn_name = rdn_attr->lDAPDisplayName;
4485 rdn_val = ldb_dn_get_rdn_val(dn);
4486 if (rdn_val == NULL) {
4490 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4493 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4496 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4499 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4503 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4504 if (ret != LDB_SUCCESS) {
4505 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
4506 ldb_dn_get_linearized(dn),
4507 ldb_errstring(ldb_module_get_ctx(ar->module))));
4517 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
4518 ldb_dn_get_linearized(dn)));
4519 return LDB_ERR_OPERATIONS_ERROR;
4524 callback for conflict DN handling where we have renamed the incoming
4525 record. After renaming it, we need to ensure the change of name and
4526 rDN for the incoming record is seen as an originating update by this DC.
4528 This also handles updating lastKnownParent for entries sent to lostAndFound
4530 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4532 struct replmd_replicated_request *ar =
4533 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4534 struct ldb_dn *conflict_dn = NULL;
4537 if (ares->error != LDB_SUCCESS) {
4538 /* call the normal callback for everything except success */
4539 return replmd_op_callback(req, ares);
4542 switch (req->operation) {
4544 conflict_dn = req->op.add.message->dn;
4547 conflict_dn = req->op.mod.message->dn;
4550 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4553 /* perform a modify of the rDN and name of the record */
4554 ret = replmd_name_modify(ar, req, conflict_dn);
4555 if (ret != LDB_SUCCESS) {
4557 return replmd_op_callback(req, ares);
4560 if (ar->objs->objects[ar->index_current].last_known_parent) {
4561 struct ldb_message *msg = ldb_msg_new(req);
4563 ldb_module_oom(ar->module);
4564 return LDB_ERR_OPERATIONS_ERROR;
4567 msg->dn = req->op.add.message->dn;
4569 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4570 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4571 if (ret != LDB_SUCCESS) {
4572 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4573 ldb_module_oom(ar->module);
4576 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4578 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4579 if (ret != LDB_SUCCESS) {
4580 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4581 ldb_dn_get_linearized(msg->dn),
4582 ldb_errstring(ldb_module_get_ctx(ar->module))));
4588 return replmd_op_callback(req, ares);
4592 callback for replmd_replicated_apply_add()
4593 This copes with the creation of conflict records in the case where
4594 the DN exists, but with a different objectGUID
4596 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))
4598 struct ldb_dn *conflict_dn;
4599 struct replmd_replicated_request *ar =
4600 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4601 struct ldb_result *res;
4602 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4604 const struct ldb_val *omd_value;
4605 struct replPropertyMetaDataBlob omd, *rmd;
4606 enum ndr_err_code ndr_err;
4607 bool rename_incoming_record, rodc;
4608 struct replPropertyMetaData1 *rmd_name, *omd_name;
4609 struct ldb_message *msg;
4610 struct ldb_request *down_req = NULL;
4612 /* call the normal callback for success */
4613 if (ares->error == LDB_SUCCESS) {
4614 return callback(req, ares);
4618 * we have a conflict, and need to decide if we will keep the
4619 * new record or the old record
4622 msg = ar->objs->objects[ar->index_current].msg;
4623 conflict_dn = msg->dn;
4625 /* For failures other than conflicts, fail the whole operation here */
4626 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4627 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4628 ldb_dn_get_linearized(conflict_dn),
4629 ldb_errstring(ldb_module_get_ctx(ar->module)));
4631 return ldb_module_done(ar->req, NULL, NULL,
4632 LDB_ERR_OPERATIONS_ERROR);
4635 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4636 if (ret != LDB_SUCCESS) {
4637 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)));
4638 return ldb_module_done(ar->req, NULL, NULL,
4639 LDB_ERR_OPERATIONS_ERROR);
4645 * We are on an RODC, or were a GC for this
4646 * partition, so we have to fail this until
4647 * someone who owns the partition sorts it
4650 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4651 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
4652 " - We must fail the operation until a master for this partition resolves the conflict",
4653 ldb_dn_get_linearized(conflict_dn));
4658 * first we need the replPropertyMetaData attribute from the
4659 * local, conflicting record
4661 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4663 DSDB_FLAG_NEXT_MODULE |
4664 DSDB_SEARCH_SHOW_DELETED |
4665 DSDB_SEARCH_SHOW_RECYCLED, req);
4666 if (ret != LDB_SUCCESS) {
4667 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4668 ldb_dn_get_linearized(conflict_dn)));
4672 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4673 if (omd_value == NULL) {
4674 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4675 ldb_dn_get_linearized(conflict_dn)));
4679 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4680 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4681 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4682 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4683 ldb_dn_get_linearized(conflict_dn)));
4687 rmd = ar->objs->objects[ar->index_current].meta_data;
4690 * we decide which is newer based on the RPMD on the name
4691 * attribute. See [MS-DRSR] ResolveNameConflict.
4693 * We expect omd_name to be present, as this is from a local
4694 * search, but while rmd_name should have been given to us by
4695 * the remote server, if it is missing we just prefer the
4697 * replmd_replPropertyMetaData1_new_should_be_taken()
4699 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4700 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4702 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4703 ldb_dn_get_linearized(conflict_dn)));
4708 * Should we preserve the current record, and so rename the
4709 * incoming record to be a conflict?
4711 rename_incoming_record
4712 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4713 omd_name, rmd_name);
4715 if (rename_incoming_record) {
4717 struct ldb_dn *new_dn;
4719 guid = samdb_result_guid(msg, "objectGUID");
4720 if (GUID_all_zero(&guid)) {
4721 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4722 ldb_dn_get_linearized(conflict_dn)));
4725 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4726 if (new_dn == NULL) {
4727 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4728 ldb_dn_get_linearized(conflict_dn)));
4732 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4733 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4735 /* re-submit the request, but with the new DN */
4736 callback = replmd_op_name_modify_callback;
4739 /* we are renaming the existing record */
4741 struct ldb_dn *new_dn;
4743 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4744 if (GUID_all_zero(&guid)) {
4745 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4746 ldb_dn_get_linearized(conflict_dn)));
4750 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4751 if (new_dn == NULL) {
4752 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4753 ldb_dn_get_linearized(conflict_dn)));
4757 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4758 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4760 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4761 DSDB_FLAG_OWN_MODULE, req);
4762 if (ret != LDB_SUCCESS) {
4763 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4764 ldb_dn_get_linearized(conflict_dn),
4765 ldb_dn_get_linearized(new_dn),
4766 ldb_errstring(ldb_module_get_ctx(ar->module))));
4771 * now we need to ensure that the rename is seen as an
4772 * originating update. We do that with a modify.
4774 ret = replmd_name_modify(ar, req, new_dn);
4775 if (ret != LDB_SUCCESS) {
4779 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4780 ldb_dn_get_linearized(req->op.add.message->dn)));
4783 ret = ldb_build_add_req(&down_req,
4784 ldb_module_get_ctx(ar->module),
4791 if (ret != LDB_SUCCESS) {
4794 LDB_REQ_SET_LOCATION(down_req);
4796 /* current partition control needed by "repmd_op_callback" */
4797 ret = ldb_request_add_control(down_req,
4798 DSDB_CONTROL_CURRENT_PARTITION_OID,
4800 if (ret != LDB_SUCCESS) {
4801 return replmd_replicated_request_error(ar, ret);
4804 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4805 /* this tells the partition module to make it a
4806 partial replica if creating an NC */
4807 ret = ldb_request_add_control(down_req,
4808 DSDB_CONTROL_PARTIAL_REPLICA,
4810 if (ret != LDB_SUCCESS) {
4811 return replmd_replicated_request_error(ar, ret);
4816 * Finally we re-run the add, otherwise the new record won't
4817 * exist, as we are here because of that exact failure!
4819 return ldb_next_request(ar->module, down_req);
4822 /* on failure make the caller get the error. This means
4823 * replication will stop with an error, but there is not much
4826 return ldb_module_done(ar->req, NULL, NULL,
4831 callback for replmd_replicated_apply_add()
4832 This copes with the creation of conflict records in the case where
4833 the DN exists, but with a different objectGUID
4835 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4837 struct replmd_replicated_request *ar =
4838 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4840 if (ar->objs->objects[ar->index_current].last_known_parent) {
4841 /* This is like a conflict DN, where we put the object in LostAndFound
4842 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4843 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4846 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4850 this is called when a new object comes in over DRS
4852 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4854 struct ldb_context *ldb;
4855 struct ldb_request *change_req;
4856 enum ndr_err_code ndr_err;
4857 struct ldb_message *msg;
4858 struct replPropertyMetaDataBlob *md;
4859 struct ldb_val md_value;
4862 bool remote_isDeleted = false;
4865 time_t t = time(NULL);
4866 const struct ldb_val *rdn_val;
4867 struct replmd_private *replmd_private =
4868 talloc_get_type(ldb_module_get_private(ar->module),
4869 struct replmd_private);
4870 unix_to_nt_time(&now, t);
4872 ldb = ldb_module_get_ctx(ar->module);
4873 msg = ar->objs->objects[ar->index_current].msg;
4874 md = ar->objs->objects[ar->index_current].meta_data;
4875 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4877 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4878 if (ret != LDB_SUCCESS) {
4879 return replmd_replicated_request_error(ar, ret);
4882 ret = dsdb_msg_add_guid(msg,
4883 &ar->objs->objects[ar->index_current].object_guid,
4885 if (ret != LDB_SUCCESS) {
4886 return replmd_replicated_request_error(ar, ret);
4889 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4890 if (ret != LDB_SUCCESS) {
4891 return replmd_replicated_request_error(ar, ret);
4894 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4895 if (ret != LDB_SUCCESS) {
4896 return replmd_replicated_request_error(ar, ret);
4899 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4900 if (ret != LDB_SUCCESS) {
4901 return replmd_replicated_request_error(ar, ret);
4904 /* remove any message elements that have zero values */
4905 for (i=0; i<msg->num_elements; i++) {
4906 struct ldb_message_element *el = &msg->elements[i];
4908 if (el->num_values == 0) {
4909 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4910 ldb_asprintf_errstring(ldb, __location__
4911 ": empty objectClass sent on %s, aborting replication\n",
4912 ldb_dn_get_linearized(msg->dn));
4913 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4916 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4918 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4919 msg->num_elements--;
4926 struct GUID_txt_buf guid_txt;
4928 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4929 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4930 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4935 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4936 "isDeleted", false);
4939 * the meta data array is already sorted by the caller, except
4940 * for the RDN, which needs to be added.
4944 rdn_val = ldb_dn_get_rdn_val(msg->dn);
4945 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4946 md, ar, now, is_schema_nc);
4947 if (ret != LDB_SUCCESS) {
4948 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4949 return replmd_replicated_request_error(ar, ret);
4952 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4953 if (ret != LDB_SUCCESS) {
4954 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4955 return replmd_replicated_request_error(ar, ret);
4958 for (i=0; i < md->ctr.ctr1.count; i++) {
4959 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4961 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4962 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4963 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4964 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4965 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4967 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4968 if (ret != LDB_SUCCESS) {
4969 return replmd_replicated_request_error(ar, ret);
4972 replmd_ldb_message_sort(msg, ar->schema);
4974 if (!remote_isDeleted) {
4975 ret = dsdb_module_schedule_sd_propagation(ar->module,
4976 ar->objs->partition_dn,
4978 if (ret != LDB_SUCCESS) {
4979 return replmd_replicated_request_error(ar, ret);
4983 ar->isDeleted = remote_isDeleted;
4985 ret = ldb_build_add_req(&change_req,
4991 replmd_op_add_callback,
4993 LDB_REQ_SET_LOCATION(change_req);
4994 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4996 /* current partition control needed by "repmd_op_callback" */
4997 ret = ldb_request_add_control(change_req,
4998 DSDB_CONTROL_CURRENT_PARTITION_OID,
5000 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5002 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5003 /* this tells the partition module to make it a
5004 partial replica if creating an NC */
5005 ret = ldb_request_add_control(change_req,
5006 DSDB_CONTROL_PARTIAL_REPLICA,
5008 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5011 return ldb_next_request(ar->module, change_req);
5014 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
5015 struct ldb_reply *ares)
5017 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5018 struct replmd_replicated_request);
5022 return ldb_module_done(ar->req, NULL, NULL,
5023 LDB_ERR_OPERATIONS_ERROR);
5027 * The error NO_SUCH_OBJECT is not expected, unless the search
5028 * base is the partition DN, and that case doesn't happen here
5029 * because then we wouldn't get a parent_guid_value in any
5032 if (ares->error != LDB_SUCCESS) {
5033 return ldb_module_done(ar->req, ares->controls,
5034 ares->response, ares->error);
5037 switch (ares->type) {
5038 case LDB_REPLY_ENTRY:
5040 struct ldb_message *parent_msg = ares->message;
5041 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5042 struct ldb_dn *parent_dn;
5045 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
5046 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
5047 /* Per MS-DRSR 4.1.10.6.10
5048 * FindBestParentObject we need to move this
5049 * new object under a deleted object to
5051 struct ldb_dn *nc_root;
5053 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
5054 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
5055 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5056 "No suitable NC root found for %s. "
5057 "We need to move this object because parent object %s "
5058 "is deleted, but this object is not.",
5059 ldb_dn_get_linearized(msg->dn),
5060 ldb_dn_get_linearized(parent_msg->dn));
5061 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5062 } else if (ret != LDB_SUCCESS) {
5063 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5064 "Unable to find NC root for %s: %s. "
5065 "We need to move this object because parent object %s "
5066 "is deleted, but this object is not.",
5067 ldb_dn_get_linearized(msg->dn),
5068 ldb_errstring(ldb_module_get_ctx(ar->module)),
5069 ldb_dn_get_linearized(parent_msg->dn));
5070 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5073 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5075 DS_GUID_LOSTANDFOUND_CONTAINER,
5077 if (ret != LDB_SUCCESS) {
5078 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5079 "Unable to find LostAndFound Container for %s "
5080 "in partition %s: %s. "
5081 "We need to move this object because parent object %s "
5082 "is deleted, but this object is not.",
5083 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5084 ldb_errstring(ldb_module_get_ctx(ar->module)),
5085 ldb_dn_get_linearized(parent_msg->dn));
5086 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5088 ar->objs->objects[ar->index_current].last_known_parent
5089 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5093 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5096 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5098 comp_num = ldb_dn_get_comp_num(msg->dn);
5100 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5102 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5105 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5107 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5111 case LDB_REPLY_REFERRAL:
5112 /* we ignore referrals */
5115 case LDB_REPLY_DONE:
5117 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5118 struct GUID_txt_buf str_buf;
5119 if (ar->search_msg != NULL) {
5120 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5121 "No parent with GUID %s found for object locally known as %s",
5122 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5123 ldb_dn_get_linearized(ar->search_msg->dn));
5125 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5126 "No parent with GUID %s found for object remotely known as %s",
5127 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5128 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5132 * This error code is really important, as it
5133 * is the flag back to the callers to retry
5134 * this with DRSUAPI_DRS_GET_ANC, and so get
5135 * the parent objects before the child
5138 return ldb_module_done(ar->req, NULL, NULL,
5139 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5142 if (ar->search_msg != NULL) {
5143 ret = replmd_replicated_apply_merge(ar);
5145 ret = replmd_replicated_apply_add(ar);
5147 if (ret != LDB_SUCCESS) {
5148 return ldb_module_done(ar->req, NULL, NULL, ret);
5157 * Look for the parent object, so we put the new object in the right
5158 * place This is akin to NameObject in MS-DRSR - this routine and the
5159 * callbacks find the right parent name, and correct name for this
5163 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5165 struct ldb_context *ldb;
5169 struct ldb_request *search_req;
5170 static const char *attrs[] = {"isDeleted", NULL};
5171 struct GUID_txt_buf guid_str_buf;
5173 ldb = ldb_module_get_ctx(ar->module);
5175 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5176 if (ar->search_msg != NULL) {
5177 return replmd_replicated_apply_merge(ar);
5179 return replmd_replicated_apply_add(ar);
5183 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5186 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5187 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5189 ret = ldb_build_search_req(&search_req,
5192 ar->objs->partition_dn,
5198 replmd_replicated_apply_search_for_parent_callback,
5200 LDB_REQ_SET_LOCATION(search_req);
5202 ret = dsdb_request_add_controls(search_req,
5203 DSDB_SEARCH_SHOW_RECYCLED|
5204 DSDB_SEARCH_SHOW_DELETED|
5205 DSDB_SEARCH_SHOW_EXTENDED_DN);
5206 if (ret != LDB_SUCCESS) {
5210 return ldb_next_request(ar->module, search_req);
5214 handle renames that come in over DRS replication
5216 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5217 struct ldb_message *msg,
5218 struct ldb_request *parent,
5222 TALLOC_CTX *tmp_ctx = talloc_new(msg);
5223 struct ldb_result *res;
5224 struct ldb_dn *conflict_dn;
5225 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5226 const struct ldb_val *omd_value;
5227 struct replPropertyMetaDataBlob omd, *rmd;
5228 enum ndr_err_code ndr_err;
5229 bool rename_incoming_record, rodc;
5230 struct replPropertyMetaData1 *rmd_name, *omd_name;
5231 struct ldb_dn *new_dn;
5234 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5235 ldb_dn_get_linearized(ar->search_msg->dn),
5236 ldb_dn_get_linearized(msg->dn)));
5239 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5240 DSDB_FLAG_NEXT_MODULE, ar->req);
5241 if (ret == LDB_SUCCESS) {
5242 talloc_free(tmp_ctx);
5247 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5248 talloc_free(tmp_ctx);
5249 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5250 ldb_dn_get_linearized(ar->search_msg->dn),
5251 ldb_dn_get_linearized(msg->dn),
5252 ldb_errstring(ldb_module_get_ctx(ar->module)));
5256 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5257 if (ret != LDB_SUCCESS) {
5258 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5259 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5260 ldb_errstring(ldb_module_get_ctx(ar->module)));
5261 return LDB_ERR_OPERATIONS_ERROR;
5264 * we have a conflict, and need to decide if we will keep the
5265 * new record or the old record
5268 conflict_dn = msg->dn;
5272 * We are on an RODC, or were a GC for this
5273 * partition, so we have to fail this until
5274 * someone who owns the partition sorts it
5277 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5278 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5279 " - We must fail the operation until a master for this partition resolves the conflict",
5280 ldb_dn_get_linearized(conflict_dn));
5285 * first we need the replPropertyMetaData attribute from the
5288 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5290 DSDB_FLAG_NEXT_MODULE |
5291 DSDB_SEARCH_SHOW_DELETED |
5292 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5293 if (ret != LDB_SUCCESS) {
5294 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5295 ldb_dn_get_linearized(conflict_dn)));
5299 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5300 if (omd_value == NULL) {
5301 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5302 ldb_dn_get_linearized(conflict_dn)));
5306 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5307 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5308 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5309 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5310 ldb_dn_get_linearized(conflict_dn)));
5314 rmd = ar->objs->objects[ar->index_current].meta_data;
5317 * we decide which is newer based on the RPMD on the name
5318 * attribute. See [MS-DRSR] ResolveNameConflict.
5320 * We expect omd_name to be present, as this is from a local
5321 * search, but while rmd_name should have been given to us by
5322 * the remote server, if it is missing we just prefer the
5324 * replmd_replPropertyMetaData1_new_should_be_taken()
5326 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5327 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5329 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5330 ldb_dn_get_linearized(conflict_dn)));
5335 * Should we preserve the current record, and so rename the
5336 * incoming record to be a conflict?
5338 rename_incoming_record =
5339 !replmd_replPropertyMetaData1_new_should_be_taken(
5340 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5341 omd_name, rmd_name);
5343 if (rename_incoming_record) {
5345 new_dn = replmd_conflict_dn(msg, msg->dn,
5346 &ar->objs->objects[ar->index_current].object_guid);
5347 if (new_dn == NULL) {
5348 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5349 "Failed to form conflict DN for %s\n",
5350 ldb_dn_get_linearized(msg->dn));
5352 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5355 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5356 DSDB_FLAG_NEXT_MODULE, ar->req);
5357 if (ret != LDB_SUCCESS) {
5358 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5359 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5360 ldb_dn_get_linearized(conflict_dn),
5361 ldb_dn_get_linearized(ar->search_msg->dn),
5362 ldb_dn_get_linearized(new_dn),
5363 ldb_errstring(ldb_module_get_ctx(ar->module)));
5364 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5372 /* we are renaming the existing record */
5374 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5375 if (GUID_all_zero(&guid)) {
5376 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5377 ldb_dn_get_linearized(conflict_dn)));
5381 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5382 if (new_dn == NULL) {
5383 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5384 ldb_dn_get_linearized(conflict_dn)));
5388 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5389 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5391 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5392 DSDB_FLAG_OWN_MODULE, ar->req);
5393 if (ret != LDB_SUCCESS) {
5394 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5395 ldb_dn_get_linearized(conflict_dn),
5396 ldb_dn_get_linearized(new_dn),
5397 ldb_errstring(ldb_module_get_ctx(ar->module))));
5402 * now we need to ensure that the rename is seen as an
5403 * originating update. We do that with a modify.
5405 ret = replmd_name_modify(ar, ar->req, new_dn);
5406 if (ret != LDB_SUCCESS) {
5410 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5411 ldb_dn_get_linearized(ar->search_msg->dn),
5412 ldb_dn_get_linearized(msg->dn)));
5415 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5416 DSDB_FLAG_NEXT_MODULE, ar->req);
5417 if (ret != LDB_SUCCESS) {
5418 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5419 ldb_dn_get_linearized(ar->search_msg->dn),
5420 ldb_dn_get_linearized(msg->dn),
5421 ldb_errstring(ldb_module_get_ctx(ar->module))));
5427 * On failure make the caller get the error
5428 * This means replication will stop with an error,
5429 * but there is not much else we can do. In the
5430 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5434 talloc_free(tmp_ctx);
5439 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5441 struct ldb_context *ldb;
5442 struct ldb_request *change_req;
5443 enum ndr_err_code ndr_err;
5444 struct ldb_message *msg;
5445 struct replPropertyMetaDataBlob *rmd;
5446 struct replPropertyMetaDataBlob omd;
5447 const struct ldb_val *omd_value;
5448 struct replPropertyMetaDataBlob nmd;
5449 struct ldb_val nmd_value;
5450 struct GUID remote_parent_guid;
5453 unsigned int removed_attrs = 0;
5455 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5456 bool isDeleted = false;
5457 bool local_isDeleted = false;
5458 bool remote_isDeleted = false;
5459 bool take_remote_isDeleted = false;
5460 bool sd_updated = false;
5461 bool renamed = false;
5462 bool is_schema_nc = false;
5464 const struct ldb_val *old_rdn, *new_rdn;
5465 struct replmd_private *replmd_private =
5466 talloc_get_type(ldb_module_get_private(ar->module),
5467 struct replmd_private);
5469 time_t t = time(NULL);
5470 unix_to_nt_time(&now, t);
5472 ldb = ldb_module_get_ctx(ar->module);
5473 msg = ar->objs->objects[ar->index_current].msg;
5475 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5477 rmd = ar->objs->objects[ar->index_current].meta_data;
5481 /* find existing meta data */
5482 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5484 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5485 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5486 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5487 nt_status = ndr_map_error2ntstatus(ndr_err);
5488 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5491 if (omd.version != 1) {
5492 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5497 struct GUID_txt_buf guid_txt;
5499 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5500 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
5503 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5505 ndr_print_struct_string(s,
5506 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5507 "existing replPropertyMetaData",
5509 ndr_print_struct_string(s,
5510 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5511 "incoming replPropertyMetaData",
5516 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5517 "isDeleted", false);
5518 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5519 "isDeleted", false);
5522 * Fill in the remote_parent_guid with the GUID or an all-zero
5525 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5526 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5528 remote_parent_guid = GUID_zero();
5532 * To ensure we follow a complex rename chain around, we have
5533 * to confirm that the DN is the same (mostly to confirm the
5534 * RDN) and the parentGUID is the same.
5536 * This ensures we keep things under the correct parent, which
5537 * replmd_replicated_handle_rename() will do.
5540 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5541 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5545 * handle renames, even just by case that come in over
5546 * DRS. Changes in the parent DN don't hit us here,
5547 * because the search for a parent will clean up those
5550 * We also have already filtered out the case where
5551 * the peer has an older name to what we have (see
5552 * replmd_replicated_apply_search_callback())
5554 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5557 if (ret != LDB_SUCCESS) {
5558 ldb_debug(ldb, LDB_DEBUG_FATAL,
5559 "replmd_replicated_request rename %s => %s failed - %s\n",
5560 ldb_dn_get_linearized(ar->search_msg->dn),
5561 ldb_dn_get_linearized(msg->dn),
5562 ldb_errstring(ldb));
5563 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5566 if (renamed == true) {
5568 * Set the callback to one that will fix up the name
5569 * metadata on the new conflict DN
5571 callback = replmd_op_name_modify_callback;
5576 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5577 nmd.ctr.ctr1.array = talloc_array(ar,
5578 struct replPropertyMetaData1,
5579 nmd.ctr.ctr1.count);
5580 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5582 /* first copy the old meta data */
5583 for (i=0; i < omd.ctr.ctr1.count; i++) {
5584 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5589 /* now merge in the new meta data */
5590 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5593 for (j=0; j < ni; j++) {
5596 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5600 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5601 ar->objs->dsdb_repl_flags,
5602 &nmd.ctr.ctr1.array[j],
5603 &rmd->ctr.ctr1.array[i]);
5605 /* replace the entry */
5606 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5607 if (ar->seq_num == 0) {
5608 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5609 if (ret != LDB_SUCCESS) {
5610 return replmd_replicated_request_error(ar, ret);
5613 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5614 switch (nmd.ctr.ctr1.array[j].attid) {
5615 case DRSUAPI_ATTID_ntSecurityDescriptor:
5618 case DRSUAPI_ATTID_isDeleted:
5619 take_remote_isDeleted = true;
5628 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5629 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5630 msg->elements[i-removed_attrs].name,
5631 ldb_dn_get_linearized(msg->dn),
5632 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5635 /* we don't want to apply this change so remove the attribute */
5636 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5643 if (found) continue;
5645 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5646 if (ar->seq_num == 0) {
5647 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5648 if (ret != LDB_SUCCESS) {
5649 return replmd_replicated_request_error(ar, ret);
5652 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5653 switch (nmd.ctr.ctr1.array[ni].attid) {
5654 case DRSUAPI_ATTID_ntSecurityDescriptor:
5657 case DRSUAPI_ATTID_isDeleted:
5658 take_remote_isDeleted = true;
5667 * finally correct the size of the meta_data array
5669 nmd.ctr.ctr1.count = ni;
5671 new_rdn = ldb_dn_get_rdn_val(msg->dn);
5672 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5675 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5676 &nmd, ar, now, is_schema_nc);
5677 if (ret != LDB_SUCCESS) {
5678 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5679 return replmd_replicated_request_error(ar, ret);
5683 * sort the new meta data array
5685 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5686 if (ret != LDB_SUCCESS) {
5687 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5692 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
5695 * This also controls SD propagation below
5697 if (take_remote_isDeleted) {
5698 isDeleted = remote_isDeleted;
5700 isDeleted = local_isDeleted;
5703 ar->isDeleted = isDeleted;
5706 * check if some replicated attributes left, otherwise skip the ldb_modify() call
5708 if (msg->num_elements == 0) {
5709 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5712 return replmd_replicated_apply_isDeleted(ar);
5715 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5716 ar->index_current, msg->num_elements);
5722 if (sd_updated && !isDeleted) {
5723 ret = dsdb_module_schedule_sd_propagation(ar->module,
5724 ar->objs->partition_dn,
5726 if (ret != LDB_SUCCESS) {
5727 return ldb_operr(ldb);
5731 /* create the meta data value */
5732 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5733 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5734 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5735 nt_status = ndr_map_error2ntstatus(ndr_err);
5736 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5740 * when we know that we'll modify the record, add the whenChanged, uSNChanged
5741 * and replPopertyMetaData attributes
5743 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5744 if (ret != LDB_SUCCESS) {
5745 return replmd_replicated_request_error(ar, ret);
5747 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5748 if (ret != LDB_SUCCESS) {
5749 return replmd_replicated_request_error(ar, ret);
5751 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5752 if (ret != LDB_SUCCESS) {
5753 return replmd_replicated_request_error(ar, ret);
5756 replmd_ldb_message_sort(msg, ar->schema);
5758 /* we want to replace the old values */
5759 for (i=0; i < msg->num_elements; i++) {
5760 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5761 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5762 if (msg->elements[i].num_values == 0) {
5763 ldb_asprintf_errstring(ldb, __location__
5764 ": objectClass removed on %s, aborting replication\n",
5765 ldb_dn_get_linearized(msg->dn));
5766 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5772 struct GUID_txt_buf guid_txt;
5774 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5775 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5776 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5781 ret = ldb_build_mod_req(&change_req,
5789 LDB_REQ_SET_LOCATION(change_req);
5790 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5792 /* current partition control needed by "repmd_op_callback" */
5793 ret = ldb_request_add_control(change_req,
5794 DSDB_CONTROL_CURRENT_PARTITION_OID,
5796 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5798 return ldb_next_request(ar->module, change_req);
5801 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5802 struct ldb_reply *ares)
5804 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5805 struct replmd_replicated_request);
5809 return ldb_module_done(ar->req, NULL, NULL,
5810 LDB_ERR_OPERATIONS_ERROR);
5812 if (ares->error != LDB_SUCCESS &&
5813 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5814 return ldb_module_done(ar->req, ares->controls,
5815 ares->response, ares->error);
5818 switch (ares->type) {
5819 case LDB_REPLY_ENTRY:
5820 ar->search_msg = talloc_steal(ar, ares->message);
5823 case LDB_REPLY_REFERRAL:
5824 /* we ignore referrals */
5827 case LDB_REPLY_DONE:
5829 struct replPropertyMetaData1 *md_remote;
5830 struct replPropertyMetaData1 *md_local;
5832 struct replPropertyMetaDataBlob omd;
5833 const struct ldb_val *omd_value;
5834 struct replPropertyMetaDataBlob *rmd;
5835 struct ldb_message *msg;
5837 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5838 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5841 * This is the ADD case, find the appropriate parent,
5842 * as this object doesn't exist locally:
5844 if (ar->search_msg == NULL) {
5845 ret = replmd_replicated_apply_search_for_parent(ar);
5846 if (ret != LDB_SUCCESS) {
5847 return ldb_module_done(ar->req, NULL, NULL, ret);
5854 * Otherwise, in the MERGE case, work out if we are
5855 * attempting a rename, and if so find the parent the
5856 * newly renamed object wants to belong under (which
5857 * may not be the parent in it's attached string DN
5859 rmd = ar->objs->objects[ar->index_current].meta_data;
5863 /* find existing meta data */
5864 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5866 enum ndr_err_code ndr_err;
5867 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5868 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5869 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5870 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5871 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5874 if (omd.version != 1) {
5875 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5879 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5881 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5882 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5883 && GUID_all_zero(&ar->local_parent_guid)) {
5884 DEBUG(0, ("Refusing to replicate new version of %s "
5885 "as local object has an all-zero parentGUID attribute, "
5886 "despite not being an NC root\n",
5887 ldb_dn_get_linearized(ar->search_msg->dn)));
5888 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5892 * now we need to check for double renames. We could have a
5893 * local rename pending which our replication partner hasn't
5894 * received yet. We choose which one wins by looking at the
5895 * attribute stamps on the two objects, the newer one wins.
5897 * This also simply applies the correct algorithms for
5898 * determining if a change was made to name at all, or
5899 * if the object has just been renamed under the same
5902 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5903 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5905 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5906 ldb_dn_get_linearized(ar->search_msg->dn)));
5907 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5911 * if there is no name attribute given then we have to assume the
5912 * object we've received has the older name
5914 if (replmd_replPropertyMetaData1_new_should_be_taken(
5915 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5916 md_local, md_remote)) {
5917 struct GUID_txt_buf p_guid_local;
5918 struct GUID_txt_buf p_guid_remote;
5919 msg = ar->objs->objects[ar->index_current].msg;
5921 /* Merge on the existing object, with rename */
5923 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5924 "as incoming object changing to %s under %s\n",
5925 ldb_dn_get_linearized(ar->search_msg->dn),
5926 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5927 ldb_dn_get_linearized(msg->dn),
5928 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5930 ret = replmd_replicated_apply_search_for_parent(ar);
5932 struct GUID_txt_buf p_guid_local;
5933 struct GUID_txt_buf p_guid_remote;
5934 msg = ar->objs->objects[ar->index_current].msg;
5937 * Merge on the existing object, force no
5938 * rename (code below just to explain why in
5942 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5943 ldb_dn_get_linearized(msg->dn)) == 0) {
5944 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5945 GUID_equal(&ar->local_parent_guid,
5946 ar->objs->objects[ar->index_current].parent_guid)
5948 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5949 "despite incoming object changing parent to %s\n",
5950 ldb_dn_get_linearized(ar->search_msg->dn),
5951 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5952 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5956 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5957 " and rejecting older rename to %s under %s\n",
5958 ldb_dn_get_linearized(ar->search_msg->dn),
5959 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5960 ldb_dn_get_linearized(msg->dn),
5961 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5965 * This assignment ensures that the strcmp()
5966 * and GUID_equal() calls in
5967 * replmd_replicated_apply_merge() avoids the
5970 ar->objs->objects[ar->index_current].parent_guid =
5971 &ar->local_parent_guid;
5973 msg->dn = ar->search_msg->dn;
5974 ret = replmd_replicated_apply_merge(ar);
5976 if (ret != LDB_SUCCESS) {
5977 return ldb_module_done(ar->req, NULL, NULL, ret);
5986 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
5988 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
5990 struct ldb_context *ldb;
5994 struct ldb_request *search_req;
5995 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
5996 "parentGUID", "instanceType",
5997 "replPropertyMetaData", "nTSecurityDescriptor",
5998 "isDeleted", NULL };
5999 struct GUID_txt_buf guid_str_buf;
6001 if (ar->index_current >= ar->objs->num_objects) {
6002 /* done with it, go to next stage */
6003 return replmd_replicated_uptodate_vector(ar);
6006 ldb = ldb_module_get_ctx(ar->module);
6007 ar->search_msg = NULL;
6008 ar->isDeleted = false;
6010 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6013 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
6014 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6016 ret = ldb_build_search_req(&search_req,
6019 ar->objs->partition_dn,
6025 replmd_replicated_apply_search_callback,
6027 LDB_REQ_SET_LOCATION(search_req);
6029 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
6031 if (ret != LDB_SUCCESS) {
6035 return ldb_next_request(ar->module, search_req);
6039 * This is essentially a wrapper for replmd_replicated_apply_next()
6041 * This is needed to ensure that both codepaths call this handler.
6043 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
6045 struct ldb_dn *deleted_objects_dn;
6046 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
6047 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
6048 &deleted_objects_dn);
6049 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
6051 * Do a delete here again, so that if there is
6052 * anything local that conflicts with this
6053 * object being deleted, it is removed. This
6054 * includes links. See MS-DRSR 4.1.10.6.9
6057 * If the object is already deleted, and there
6058 * is no more work required, it doesn't do
6062 /* This has been updated to point to the DN we eventually did the modify on */
6064 struct ldb_request *del_req;
6065 struct ldb_result *res;
6067 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6069 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6073 res = talloc_zero(tmp_ctx, struct ldb_result);
6075 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6076 talloc_free(tmp_ctx);
6080 /* Build a delete request, which hopefully will artually turn into nothing */
6081 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6085 ldb_modify_default_callback,
6087 LDB_REQ_SET_LOCATION(del_req);
6088 if (ret != LDB_SUCCESS) {
6089 talloc_free(tmp_ctx);
6094 * This is the guts of the call, call back
6095 * into our delete code, but setting the
6096 * re_delete flag so we delete anything that
6097 * shouldn't be there on a deleted or recycled
6100 ret = replmd_delete_internals(ar->module, del_req, true);
6101 if (ret == LDB_SUCCESS) {
6102 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6105 talloc_free(tmp_ctx);
6106 if (ret != LDB_SUCCESS) {
6111 ar->index_current++;
6112 return replmd_replicated_apply_next(ar);
6115 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6116 struct ldb_reply *ares)
6118 struct ldb_context *ldb;
6119 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6120 struct replmd_replicated_request);
6121 ldb = ldb_module_get_ctx(ar->module);
6124 return ldb_module_done(ar->req, NULL, NULL,
6125 LDB_ERR_OPERATIONS_ERROR);
6127 if (ares->error != LDB_SUCCESS) {
6128 return ldb_module_done(ar->req, ares->controls,
6129 ares->response, ares->error);
6132 if (ares->type != LDB_REPLY_DONE) {
6133 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6134 return ldb_module_done(ar->req, NULL, NULL,
6135 LDB_ERR_OPERATIONS_ERROR);
6140 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6143 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6145 struct ldb_context *ldb;
6146 struct ldb_request *change_req;
6147 enum ndr_err_code ndr_err;
6148 struct ldb_message *msg;
6149 struct replUpToDateVectorBlob ouv;
6150 const struct ldb_val *ouv_value;
6151 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6152 struct replUpToDateVectorBlob nuv;
6153 struct ldb_val nuv_value;
6154 struct ldb_message_element *nuv_el = NULL;
6155 struct ldb_message_element *orf_el = NULL;
6156 struct repsFromToBlob nrf;
6157 struct ldb_val *nrf_value = NULL;
6158 struct ldb_message_element *nrf_el = NULL;
6162 time_t t = time(NULL);
6165 uint32_t instanceType;
6167 ldb = ldb_module_get_ctx(ar->module);
6168 ruv = ar->objs->uptodateness_vector;
6174 unix_to_nt_time(&now, t);
6176 if (ar->search_msg == NULL) {
6177 /* this happens for a REPL_OBJ call where we are
6178 creating the target object by replicating it. The
6179 subdomain join code does this for the partition DN
6181 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6182 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6185 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6186 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6187 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6188 ldb_dn_get_linearized(ar->search_msg->dn)));
6189 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6193 * first create the new replUpToDateVector
6195 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6197 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6198 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6199 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6200 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6201 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6204 if (ouv.version != 2) {
6205 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6210 * the new uptodateness vector will at least
6211 * contain 1 entry, one for the source_dsa
6213 * plus optional values from our old vector and the one from the source_dsa
6215 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6216 if (ruv) nuv.ctr.ctr2.count += ruv->count;
6217 nuv.ctr.ctr2.cursors = talloc_array(ar,
6218 struct drsuapi_DsReplicaCursor2,
6219 nuv.ctr.ctr2.count);
6220 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6222 /* first copy the old vector */
6223 for (i=0; i < ouv.ctr.ctr2.count; i++) {
6224 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6228 /* merge in the source_dsa vector is available */
6229 for (i=0; (ruv && i < ruv->count); i++) {
6232 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6233 &ar->our_invocation_id)) {
6237 for (j=0; j < ni; j++) {
6238 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6239 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6245 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6246 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6251 if (found) continue;
6253 /* if it's not there yet, add it */
6254 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6259 * finally correct the size of the cursors array
6261 nuv.ctr.ctr2.count = ni;
6266 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6269 * create the change ldb_message
6271 msg = ldb_msg_new(ar);
6272 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6273 msg->dn = ar->search_msg->dn;
6275 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6276 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6277 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6278 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6279 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6281 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6282 if (ret != LDB_SUCCESS) {
6283 return replmd_replicated_request_error(ar, ret);
6285 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6288 * now create the new repsFrom value from the given repsFromTo1 structure
6292 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6293 nrf.ctr.ctr1.last_attempt = now;
6294 nrf.ctr.ctr1.last_success = now;
6295 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6298 * first see if we already have a repsFrom value for the current source dsa
6299 * if so we'll later replace this value
6301 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6303 for (i=0; i < orf_el->num_values; i++) {
6304 struct repsFromToBlob *trf;
6306 trf = talloc(ar, struct repsFromToBlob);
6307 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6309 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6310 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6311 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6312 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6313 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6316 if (trf->version != 1) {
6317 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6321 * we compare the source dsa objectGUID not the invocation_id
6322 * because we want only one repsFrom value per source dsa
6323 * and when the invocation_id of the source dsa has changed we don't need
6324 * the old repsFrom with the old invocation_id
6326 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6327 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6333 nrf_value = &orf_el->values[i];
6338 * copy over all old values to the new ldb_message
6340 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6341 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6346 * if we haven't found an old repsFrom value for the current source dsa
6347 * we'll add a new value
6350 struct ldb_val zero_value;
6351 ZERO_STRUCT(zero_value);
6352 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6353 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6355 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6358 /* we now fill the value which is already attached to ldb_message */
6359 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6361 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6362 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6363 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6364 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6368 * the ldb_message_element for the attribute, has all the old values and the new one
6369 * so we'll replace the whole attribute with all values
6371 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6373 if (CHECK_DEBUGLVL(4)) {
6374 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
6375 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6379 /* prepare the ldb_modify() request */
6380 ret = ldb_build_mod_req(&change_req,
6386 replmd_replicated_uptodate_modify_callback,
6388 LDB_REQ_SET_LOCATION(change_req);
6389 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6391 return ldb_next_request(ar->module, change_req);
6394 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6395 struct ldb_reply *ares)
6397 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6398 struct replmd_replicated_request);
6402 return ldb_module_done(ar->req, NULL, NULL,
6403 LDB_ERR_OPERATIONS_ERROR);
6405 if (ares->error != LDB_SUCCESS &&
6406 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6407 return ldb_module_done(ar->req, ares->controls,
6408 ares->response, ares->error);
6411 switch (ares->type) {
6412 case LDB_REPLY_ENTRY:
6413 ar->search_msg = talloc_steal(ar, ares->message);
6416 case LDB_REPLY_REFERRAL:
6417 /* we ignore referrals */
6420 case LDB_REPLY_DONE:
6421 ret = replmd_replicated_uptodate_modify(ar);
6422 if (ret != LDB_SUCCESS) {
6423 return ldb_module_done(ar->req, NULL, NULL, ret);
6432 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6434 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6435 struct replmd_private *replmd_private =
6436 talloc_get_type_abort(ldb_module_get_private(ar->module),
6437 struct replmd_private);
6439 static const char *attrs[] = {
6440 "replUpToDateVector",
6445 struct ldb_request *search_req;
6447 ar->search_msg = NULL;
6450 * Let the caller know that we did an originating updates
6452 ar->objs->originating_updates = replmd_private->originating_updates;
6454 ret = ldb_build_search_req(&search_req,
6457 ar->objs->partition_dn,
6463 replmd_replicated_uptodate_search_callback,
6465 LDB_REQ_SET_LOCATION(search_req);
6466 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6468 return ldb_next_request(ar->module, search_req);
6473 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6475 struct ldb_context *ldb;
6476 struct dsdb_extended_replicated_objects *objs;
6477 struct replmd_replicated_request *ar;
6478 struct ldb_control **ctrls;
6481 struct replmd_private *replmd_private =
6482 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6484 ldb = ldb_module_get_ctx(module);
6486 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6488 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6490 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6491 return LDB_ERR_PROTOCOL_ERROR;
6494 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6495 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6496 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6497 return LDB_ERR_PROTOCOL_ERROR;
6500 ar = replmd_ctx_init(module, req);
6502 return LDB_ERR_OPERATIONS_ERROR;
6504 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6505 ar->apply_mode = true;
6507 ar->schema = dsdb_get_schema(ldb, ar);
6509 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6511 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6512 return LDB_ERR_CONSTRAINT_VIOLATION;
6515 ctrls = req->controls;
6517 if (req->controls) {
6518 req->controls = talloc_memdup(ar, req->controls,
6519 talloc_get_size(req->controls));
6520 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6523 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6524 if (ret != LDB_SUCCESS) {
6528 /* If this change contained linked attributes in the body
6529 * (rather than in the links section) we need to update
6530 * backlinks in linked_attributes */
6531 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6532 if (ret != LDB_SUCCESS) {
6536 ar->controls = req->controls;
6537 req->controls = ctrls;
6539 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
6541 /* save away the linked attributes for the end of the
6543 for (i=0; i<ar->objs->linked_attributes_count; i++) {
6544 struct la_entry *la_entry;
6546 if (replmd_private->la_ctx == NULL) {
6547 replmd_private->la_ctx = talloc_new(replmd_private);
6549 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6550 if (la_entry == NULL) {
6552 return LDB_ERR_OPERATIONS_ERROR;
6554 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6555 if (la_entry->la == NULL) {
6556 talloc_free(la_entry);
6558 return LDB_ERR_OPERATIONS_ERROR;
6560 *la_entry->la = ar->objs->linked_attributes[i];
6562 /* we need to steal the non-scalars so they stay
6563 around until the end of the transaction */
6564 talloc_steal(la_entry->la, la_entry->la->identifier);
6565 talloc_steal(la_entry->la, la_entry->la->value.blob);
6567 DLIST_ADD(replmd_private->la_list, la_entry);
6570 return replmd_replicated_apply_next(ar);
6574 process one linked attribute structure
6576 static int replmd_process_linked_attribute(struct ldb_module *module,
6577 struct replmd_private *replmd_private,
6578 struct la_entry *la_entry,
6579 struct ldb_request *parent)
6581 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6582 struct ldb_context *ldb = ldb_module_get_ctx(module);
6583 struct ldb_message *msg;
6584 struct ldb_message *target_msg = NULL;
6585 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6586 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
6588 const struct dsdb_attribute *attr;
6589 struct dsdb_dn *dsdb_dn;
6590 uint64_t seq_num = 0;
6591 struct ldb_message_element *old_el;
6593 time_t t = time(NULL);
6594 struct ldb_result *res;
6595 struct ldb_result *target_res;
6596 const char *attrs[4];
6597 const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
6598 struct parsed_dn *pdn_list, *pdn, *next;
6599 struct GUID guid = GUID_zero();
6601 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
6603 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
6604 enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
6607 linked_attributes[0]:
6608 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6610 identifier: struct drsuapi_DsReplicaObjectIdentifier
6611 __ndr_size : 0x0000003a (58)
6612 __ndr_size_sid : 0x00000000 (0)
6613 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6615 __ndr_size_dn : 0x00000000 (0)
6617 attid : DRSUAPI_ATTID_member (0x1F)
6618 value: struct drsuapi_DsAttributeValue
6619 __ndr_size : 0x0000007e (126)
6621 blob : DATA_BLOB length=126
6622 flags : 0x00000001 (1)
6623 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6624 originating_add_time : Wed Sep 2 22:20:01 2009 EST
6625 meta_data: struct drsuapi_DsReplicaMetaData
6626 version : 0x00000015 (21)
6627 originating_change_time : Wed Sep 2 23:39:07 2009 EST
6628 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6629 originating_usn : 0x000000000001e19c (123292)
6631 (for cases where the link is to a normal DN)
6632 &target: struct drsuapi_DsReplicaObjectIdentifier3
6633 __ndr_size : 0x0000007e (126)
6634 __ndr_size_sid : 0x0000001c (28)
6635 guid : 7639e594-db75-4086-b0d4-67890ae46031
6636 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
6637 __ndr_size_dn : 0x00000022 (34)
6638 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
6641 /* find the attribute being modified */
6642 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
6644 struct GUID_txt_buf guid_str;
6645 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
6647 GUID_buf_string(&la->identifier->guid,
6649 talloc_free(tmp_ctx);
6650 return LDB_ERR_OPERATIONS_ERROR;
6653 attrs[0] = attr->lDAPDisplayName;
6654 attrs[1] = "isDeleted";
6655 attrs[2] = "isRecycled";
6658 /* get the existing message from the db for the object with
6659 this GUID, returning attribute being modified. We will then
6660 use this msg as the basis for a modify call */
6661 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
6662 DSDB_FLAG_NEXT_MODULE |
6663 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6664 DSDB_SEARCH_SHOW_RECYCLED |
6665 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
6666 DSDB_SEARCH_REVEAL_INTERNALS,
6668 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
6669 if (ret != LDB_SUCCESS) {
6670 talloc_free(tmp_ctx);
6673 if (res->count != 1) {
6674 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
6675 GUID_string(tmp_ctx, &la->identifier->guid));
6676 talloc_free(tmp_ctx);
6677 return LDB_ERR_NO_SUCH_OBJECT;
6682 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6683 * ProcessLinkValue, because link updates are not applied to
6684 * recycled and tombstone objects. We don't have to delete
6685 * any existing link, that should have happened when the
6686 * object deletion was replicated or initiated.
6689 replmd_deletion_state(module, msg, &deletion_state, NULL);
6691 if (deletion_state >= OBJECT_RECYCLED) {
6692 talloc_free(tmp_ctx);
6696 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6697 if (old_el == NULL) {
6698 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
6699 if (ret != LDB_SUCCESS) {
6700 ldb_module_oom(module);
6701 talloc_free(tmp_ctx);
6702 return LDB_ERR_OPERATIONS_ERROR;
6705 old_el->flags = LDB_FLAG_MOD_REPLACE;
6708 /* parse the existing links */
6709 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
6710 attr->syntax->ldap_oid, parent);
6712 if (ret != LDB_SUCCESS) {
6713 talloc_free(tmp_ctx);
6717 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
6718 if (!W_ERROR_IS_OK(status)) {
6719 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
6720 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
6721 talloc_free(tmp_ctx);
6722 return LDB_ERR_OPERATIONS_ERROR;
6725 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
6726 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6728 * This strange behaviour (allowing a NULL/missing
6729 * GUID) originally comes from:
6731 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6732 * Author: Andrew Tridgell <tridge@samba.org>
6733 * Date: Mon Dec 21 21:21:55 2009 +1100
6735 * s4-drs: cope better with NULL GUIDS from DRS
6737 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
6738 * need to match by DN if possible when seeing if we should update an
6741 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6744 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6745 dsdb_dn->dn, attrs2,
6746 DSDB_FLAG_NEXT_MODULE |
6747 DSDB_SEARCH_SHOW_RECYCLED |
6748 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6749 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6751 } else if (!NT_STATUS_IS_OK(ntstatus)) {
6752 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
6754 ldb_dn_get_linearized(dsdb_dn->dn),
6755 ldb_dn_get_linearized(msg->dn));
6756 talloc_free(tmp_ctx);
6757 return LDB_ERR_OPERATIONS_ERROR;
6759 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6760 NULL, LDB_SCOPE_SUBTREE,
6762 DSDB_FLAG_NEXT_MODULE |
6763 DSDB_SEARCH_SHOW_RECYCLED |
6764 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6765 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6768 GUID_string(tmp_ctx, &guid));
6771 if (ret != LDB_SUCCESS) {
6772 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6773 GUID_string(tmp_ctx, &guid),
6774 ldb_errstring(ldb_module_get_ctx(module)));
6775 talloc_free(tmp_ctx);
6779 if (target_res->count == 0) {
6780 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6781 GUID_string(tmp_ctx, &guid),
6782 ldb_dn_get_linearized(dsdb_dn->dn)));
6783 } else if (target_res->count != 1) {
6784 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6785 GUID_string(tmp_ctx, &guid));
6786 talloc_free(tmp_ctx);
6787 return LDB_ERR_OPERATIONS_ERROR;
6789 target_msg = target_res->msgs[0];
6790 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6794 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6795 * ProcessLinkValue, because link updates are not applied to
6796 * recycled and tombstone objects. We don't have to delete
6797 * any existing link, that should have happened when the
6798 * object deletion was replicated or initiated.
6800 replmd_deletion_state(module, target_msg,
6801 &target_deletion_state, NULL);
6803 if (target_deletion_state >= OBJECT_RECYCLED) {
6804 talloc_free(tmp_ctx);
6808 /* see if this link already exists */
6809 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
6812 dsdb_dn->extra_part, 0,
6814 attr->syntax->ldap_oid,
6816 if (ret != LDB_SUCCESS) {
6817 talloc_free(tmp_ctx);
6823 /* see if this update is newer than what we have already */
6824 struct GUID invocation_id = GUID_zero();
6825 uint32_t version = 0;
6826 uint32_t originating_usn = 0;
6827 NTTIME change_time = 0;
6828 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6830 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6831 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6832 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6833 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6835 if (!replmd_update_is_newer(&invocation_id,
6836 &la->meta_data.originating_invocation_id,
6838 la->meta_data.version,
6840 la->meta_data.originating_change_time)) {
6841 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6842 old_el->name, ldb_dn_get_linearized(msg->dn),
6843 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6844 talloc_free(tmp_ctx);
6848 /* get a seq_num for this change */
6849 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6850 if (ret != LDB_SUCCESS) {
6851 talloc_free(tmp_ctx);
6855 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6856 /* remove the existing backlink */
6857 ret = replmd_add_backlink(module, replmd_private,
6862 if (ret != LDB_SUCCESS) {
6863 talloc_free(tmp_ctx);
6868 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6869 &la->meta_data.originating_invocation_id,
6870 la->meta_data.originating_usn, seq_num,
6871 la->meta_data.originating_change_time,
6872 la->meta_data.version,
6874 if (ret != LDB_SUCCESS) {
6875 talloc_free(tmp_ctx);
6880 /* add the new backlink */
6881 ret = replmd_add_backlink(module, replmd_private,
6886 if (ret != LDB_SUCCESS) {
6887 talloc_free(tmp_ctx);
6893 /* get a seq_num for this change */
6894 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6895 if (ret != LDB_SUCCESS) {
6896 talloc_free(tmp_ctx);
6900 * We know where the new one needs to be, from the *next
6901 * pointer into pdn_list.
6904 offset = old_el->num_values;
6906 if (next->dsdb_dn == NULL) {
6907 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
6908 attr->syntax->ldap_oid);
6909 if (ret != LDB_SUCCESS) {
6913 offset = next - pdn_list;
6914 if (offset > old_el->num_values) {
6915 talloc_free(tmp_ctx);
6916 return LDB_ERR_OPERATIONS_ERROR;
6920 old_el->values = talloc_realloc(msg->elements, old_el->values,
6921 struct ldb_val, old_el->num_values+1);
6922 if (!old_el->values) {
6923 ldb_module_oom(module);
6924 return LDB_ERR_OPERATIONS_ERROR;
6927 if (offset != old_el->num_values) {
6928 memmove(&old_el->values[offset + 1], &old_el->values[offset],
6929 (old_el->num_values - offset) * sizeof(old_el->values[0]));
6932 old_el->num_values++;
6934 ret = replmd_build_la_val(tmp_ctx, &old_el->values[offset], dsdb_dn,
6935 &la->meta_data.originating_invocation_id,
6936 la->meta_data.originating_usn, seq_num,
6937 la->meta_data.originating_change_time,
6938 la->meta_data.version,
6940 if (ret != LDB_SUCCESS) {
6941 talloc_free(tmp_ctx);
6946 ret = replmd_add_backlink(module, replmd_private,
6951 if (ret != LDB_SUCCESS) {
6952 talloc_free(tmp_ctx);
6958 /* we only change whenChanged and uSNChanged if the seq_num
6960 ret = add_time_element(msg, "whenChanged", t);
6961 if (ret != LDB_SUCCESS) {
6962 talloc_free(tmp_ctx);
6967 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
6968 if (ret != LDB_SUCCESS) {
6969 talloc_free(tmp_ctx);
6974 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6975 if (old_el == NULL) {
6976 talloc_free(tmp_ctx);
6977 return ldb_operr(ldb);
6980 ret = dsdb_check_single_valued_link(attr, old_el);
6981 if (ret != LDB_SUCCESS) {
6982 talloc_free(tmp_ctx);
6986 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
6988 ret = linked_attr_modify(module, msg, parent);
6989 if (ret != LDB_SUCCESS) {
6990 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
6992 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
6993 talloc_free(tmp_ctx);
6997 talloc_free(tmp_ctx);
7002 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
7004 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
7005 return replmd_extended_replicated_objects(module, req);
7008 return ldb_next_request(module, req);
7013 we hook into the transaction operations to allow us to
7014 perform the linked attribute updates at the end of the whole
7015 transaction. This allows a forward linked attribute to be created
7016 before the object is created. During a vampire, w2k8 sends us linked
7017 attributes before the objects they are part of.
7019 static int replmd_start_transaction(struct ldb_module *module)
7021 /* create our private structure for this transaction */
7022 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
7023 struct replmd_private);
7024 replmd_txn_cleanup(replmd_private);
7026 /* free any leftover mod_usn records from cancelled
7028 while (replmd_private->ncs) {
7029 struct nc_entry *e = replmd_private->ncs;
7030 DLIST_REMOVE(replmd_private->ncs, e);
7034 replmd_private->originating_updates = false;
7036 return ldb_next_start_trans(module);
7040 on prepare commit we loop over our queued la_context structures and
7043 static int replmd_prepare_commit(struct ldb_module *module)
7045 struct replmd_private *replmd_private =
7046 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7047 struct la_entry *la, *prev;
7051 * Walk the list of linked attributes from DRS replication.
7053 * We walk backwards, to do the first entry first, as we
7054 * added the entries with DLIST_ADD() which puts them at the
7057 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
7058 prev = DLIST_PREV(la);
7059 DLIST_REMOVE(replmd_private->la_list, la);
7060 ret = replmd_process_linked_attribute(module, replmd_private,
7062 if (ret != LDB_SUCCESS) {
7063 replmd_txn_cleanup(replmd_private);
7068 replmd_txn_cleanup(replmd_private);
7070 /* possibly change @REPLCHANGED */
7071 ret = replmd_notify_store(module, NULL);
7072 if (ret != LDB_SUCCESS) {
7076 return ldb_next_prepare_commit(module);
7079 static int replmd_del_transaction(struct ldb_module *module)
7081 struct replmd_private *replmd_private =
7082 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7083 replmd_txn_cleanup(replmd_private);
7085 return ldb_next_del_trans(module);
7089 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
7090 .name = "repl_meta_data",
7091 .init_context = replmd_init,
7093 .modify = replmd_modify,
7094 .rename = replmd_rename,
7095 .del = replmd_delete,
7096 .extended = replmd_extended,
7097 .start_transaction = replmd_start_transaction,
7098 .prepare_commit = replmd_prepare_commit,
7099 .del_transaction = replmd_del_transaction,
7102 int ldb_repl_meta_data_module_init(const char *version)
7104 LDB_MODULE_CHECK_VERSION(version);
7105 return ldb_register_module(&ldb_repl_meta_data_module_ops);