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 "../libds/common/flags.h"
43 #include "librpc/gen_ndr/ndr_misc.h"
44 #include "librpc/gen_ndr/ndr_drsuapi.h"
45 #include "librpc/gen_ndr/ndr_drsblobs.h"
46 #include "param/param.h"
47 #include "libcli/security/security.h"
48 #include "lib/util/dlinklist.h"
49 #include "dsdb/samdb/ldb_modules/util.h"
50 #include "lib/util/binsearch.h"
51 #include "lib/util/tsort.h"
54 * It's 29/12/9999 at 23:59:59 UTC as specified in MS-ADTS 7.1.1.4.2
55 * Deleted Objects Container
57 static const NTTIME DELETED_OBJECT_CONTAINER_CHANGE_TIME = 2650466015990000000ULL;
59 struct replmd_private {
61 struct la_entry *la_list;
63 struct la_backlink *la_backlinks;
65 struct nc_entry *prev, *next;
68 uint64_t mod_usn_urgent;
70 struct ldb_dn *schema_dn;
71 bool originating_updates;
76 struct la_entry *next, *prev;
77 struct drsuapi_DsReplicaLinkedAttribute *la;
80 struct replmd_replicated_request {
81 struct ldb_module *module;
82 struct ldb_request *req;
84 const struct dsdb_schema *schema;
85 struct GUID our_invocation_id;
87 /* the controls we pass down */
88 struct ldb_control **controls;
90 /* details for the mode where we apply a bunch of inbound replication meessages */
92 uint32_t index_current;
93 struct dsdb_extended_replicated_objects *objs;
95 struct ldb_message *search_msg;
96 struct GUID local_parent_guid;
104 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
105 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
107 enum urgent_situation {
108 REPL_URGENT_ON_CREATE = 1,
109 REPL_URGENT_ON_UPDATE = 2,
110 REPL_URGENT_ON_DELETE = 4
113 enum deletion_state {
114 OBJECT_NOT_DELETED=1,
121 static void replmd_deletion_state(struct ldb_module *module,
122 const struct ldb_message *msg,
123 enum deletion_state *current_state,
124 enum deletion_state *next_state)
127 bool enabled = false;
130 *current_state = OBJECT_REMOVED;
131 if (next_state != NULL) {
132 *next_state = OBJECT_REMOVED;
137 ret = dsdb_recyclebin_enabled(module, &enabled);
138 if (ret != LDB_SUCCESS) {
142 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
144 *current_state = OBJECT_TOMBSTONE;
145 if (next_state != NULL) {
146 *next_state = OBJECT_REMOVED;
151 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
152 *current_state = OBJECT_RECYCLED;
153 if (next_state != NULL) {
154 *next_state = OBJECT_REMOVED;
159 *current_state = OBJECT_DELETED;
160 if (next_state != NULL) {
161 *next_state = OBJECT_RECYCLED;
166 *current_state = OBJECT_NOT_DELETED;
167 if (next_state == NULL) {
172 *next_state = OBJECT_DELETED;
174 *next_state = OBJECT_TOMBSTONE;
178 static const struct {
179 const char *update_name;
180 enum urgent_situation repl_situation;
181 } urgent_objects[] = {
182 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
183 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
184 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
185 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
186 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
187 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
191 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
192 static const char *urgent_attrs[] = {
195 "userAccountControl",
200 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
201 enum urgent_situation situation)
204 for (i=0; urgent_objects[i].update_name; i++) {
206 if ((situation & urgent_objects[i].repl_situation) == 0) {
210 for (j=0; j<objectclass_el->num_values; j++) {
211 const struct ldb_val *v = &objectclass_el->values[j];
212 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
220 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
222 if (ldb_attr_in_list(urgent_attrs, el->name)) {
229 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
232 initialise the module
233 allocate the private structure and build the list
234 of partition DNs for use by replmd_notify()
236 static int replmd_init(struct ldb_module *module)
238 struct replmd_private *replmd_private;
239 struct ldb_context *ldb = ldb_module_get_ctx(module);
241 replmd_private = talloc_zero(module, struct replmd_private);
242 if (replmd_private == NULL) {
244 return LDB_ERR_OPERATIONS_ERROR;
246 ldb_module_set_private(module, replmd_private);
248 replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
250 return ldb_next_init(module);
254 cleanup our per-transaction contexts
256 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
258 talloc_free(replmd_private->la_ctx);
259 replmd_private->la_list = NULL;
260 replmd_private->la_ctx = NULL;
262 talloc_free(replmd_private->bl_ctx);
263 replmd_private->la_backlinks = NULL;
264 replmd_private->bl_ctx = NULL;
269 struct la_backlink *next, *prev;
270 const char *attr_name;
271 struct GUID forward_guid, target_guid;
276 a ldb_modify request operating on modules below the
279 static int linked_attr_modify(struct ldb_module *module,
280 const struct ldb_message *message,
281 struct ldb_request *parent)
283 struct ldb_request *mod_req;
285 struct ldb_context *ldb = ldb_module_get_ctx(module);
286 TALLOC_CTX *tmp_ctx = talloc_new(module);
287 struct ldb_result *res;
289 res = talloc_zero(tmp_ctx, struct ldb_result);
291 talloc_free(tmp_ctx);
292 return ldb_oom(ldb_module_get_ctx(module));
295 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
299 ldb_modify_default_callback,
301 LDB_REQ_SET_LOCATION(mod_req);
302 if (ret != LDB_SUCCESS) {
303 talloc_free(tmp_ctx);
307 ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
309 if (ret != LDB_SUCCESS) {
313 /* Run the new request */
314 ret = ldb_next_request(module, mod_req);
316 if (ret == LDB_SUCCESS) {
317 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
320 talloc_free(tmp_ctx);
325 process a backlinks we accumulated during a transaction, adding and
326 deleting the backlinks from the target objects
328 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
330 struct ldb_dn *target_dn, *source_dn;
332 struct ldb_context *ldb = ldb_module_get_ctx(module);
333 struct ldb_message *msg;
334 TALLOC_CTX *tmp_ctx = talloc_new(bl);
340 - construct ldb_message
341 - either an add or a delete
343 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn, parent);
344 if (ret != LDB_SUCCESS) {
345 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
346 GUID_string(bl, &bl->target_guid)));
350 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn, parent);
351 if (ret != LDB_SUCCESS) {
352 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
353 GUID_string(bl, &bl->forward_guid));
354 talloc_free(tmp_ctx);
358 msg = ldb_msg_new(tmp_ctx);
360 ldb_module_oom(module);
361 talloc_free(tmp_ctx);
362 return LDB_ERR_OPERATIONS_ERROR;
365 /* construct a ldb_message for adding/deleting the backlink */
367 dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
369 ldb_module_oom(module);
370 talloc_free(tmp_ctx);
371 return LDB_ERR_OPERATIONS_ERROR;
373 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
374 if (ret != LDB_SUCCESS) {
375 talloc_free(tmp_ctx);
378 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
380 /* a backlink should never be single valued. Unfortunately the
381 exchange schema has a attribute
382 msExchBridgeheadedLocalConnectorsDNBL which is single
383 valued and a backlink. We need to cope with that by
384 ignoring the single value flag */
385 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
387 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
388 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
389 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
390 cope with possible corruption where the backlink has
391 already been removed */
392 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
393 ldb_dn_get_linearized(target_dn),
394 ldb_dn_get_linearized(source_dn),
395 ldb_errstring(ldb)));
397 } else if (ret != LDB_SUCCESS) {
398 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
399 bl->active?"add":"remove",
400 ldb_dn_get_linearized(source_dn),
401 ldb_dn_get_linearized(target_dn),
403 talloc_free(tmp_ctx);
406 talloc_free(tmp_ctx);
411 add a backlink to the list of backlinks to add/delete in the prepare
414 static int replmd_add_backlink(struct ldb_module *module,
415 struct replmd_private *replmd_private,
416 const struct dsdb_schema *schema,
417 struct GUID *forward_guid,
418 struct GUID *target_guid, bool active,
419 const struct dsdb_attribute *schema_attr,
422 const struct dsdb_attribute *target_attr;
423 struct la_backlink *bl;
425 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
428 * windows 2003 has a broken schema where the
429 * definition of msDS-IsDomainFor is missing (which is
430 * supposed to be the backlink of the
431 * msDS-HasDomainNCs attribute
436 /* see if its already in the list */
437 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
438 if (GUID_equal(forward_guid, &bl->forward_guid) &&
439 GUID_equal(target_guid, &bl->target_guid) &&
440 (target_attr->lDAPDisplayName == bl->attr_name ||
441 strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
447 /* we found an existing one */
448 if (bl->active == active) {
451 DLIST_REMOVE(replmd_private->la_backlinks, bl);
456 if (replmd_private->bl_ctx == NULL) {
457 replmd_private->bl_ctx = talloc_new(replmd_private);
458 if (replmd_private->bl_ctx == NULL) {
459 ldb_module_oom(module);
460 return LDB_ERR_OPERATIONS_ERROR;
465 bl = talloc(replmd_private->bl_ctx, struct la_backlink);
467 ldb_module_oom(module);
468 return LDB_ERR_OPERATIONS_ERROR;
471 /* Ensure the schema does not go away before the bl->attr_name is used */
472 if (!talloc_reference(bl, schema)) {
474 ldb_module_oom(module);
475 return LDB_ERR_OPERATIONS_ERROR;
478 bl->attr_name = target_attr->lDAPDisplayName;
479 bl->forward_guid = *forward_guid;
480 bl->target_guid = *target_guid;
483 /* the caller may ask for this backlink to be processed
486 int ret = replmd_process_backlink(module, bl, NULL);
491 DLIST_ADD(replmd_private->la_backlinks, bl);
498 * Callback for most write operations in this module:
500 * notify the repl task that a object has changed. The notifies are
501 * gathered up in the replmd_private structure then written to the
502 * @REPLCHANGED object in each partition during the prepare_commit
504 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
507 struct replmd_replicated_request *ac =
508 talloc_get_type_abort(req->context, struct replmd_replicated_request);
509 struct replmd_private *replmd_private =
510 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
511 struct nc_entry *modified_partition;
512 struct ldb_control *partition_ctrl;
513 const struct dsdb_control_current_partition *partition;
515 struct ldb_control **controls;
517 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
519 controls = ares->controls;
520 if (ldb_request_get_control(ac->req,
521 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
523 * Remove the current partition control from what we pass up
524 * the chain if it hasn't been requested manually.
526 controls = ldb_controls_except_specified(ares->controls, ares,
530 if (ares->error != LDB_SUCCESS) {
531 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
532 return ldb_module_done(ac->req, controls,
533 ares->response, ares->error);
536 if (ares->type != LDB_REPLY_DONE) {
537 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
538 return ldb_module_done(ac->req, NULL,
539 NULL, LDB_ERR_OPERATIONS_ERROR);
542 if (!partition_ctrl) {
543 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
544 return ldb_module_done(ac->req, NULL,
545 NULL, LDB_ERR_OPERATIONS_ERROR);
548 partition = talloc_get_type_abort(partition_ctrl->data,
549 struct dsdb_control_current_partition);
551 if (ac->seq_num > 0) {
552 for (modified_partition = replmd_private->ncs; modified_partition;
553 modified_partition = modified_partition->next) {
554 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
559 if (modified_partition == NULL) {
560 modified_partition = talloc_zero(replmd_private, struct nc_entry);
561 if (!modified_partition) {
562 ldb_oom(ldb_module_get_ctx(ac->module));
563 return ldb_module_done(ac->req, NULL,
564 NULL, LDB_ERR_OPERATIONS_ERROR);
566 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
567 if (!modified_partition->dn) {
568 ldb_oom(ldb_module_get_ctx(ac->module));
569 return ldb_module_done(ac->req, NULL,
570 NULL, LDB_ERR_OPERATIONS_ERROR);
572 DLIST_ADD(replmd_private->ncs, modified_partition);
575 if (ac->seq_num > modified_partition->mod_usn) {
576 modified_partition->mod_usn = ac->seq_num;
578 modified_partition->mod_usn_urgent = ac->seq_num;
581 if (!ac->apply_mode) {
582 replmd_private->originating_updates = true;
586 if (ac->apply_mode) {
587 ret = replmd_replicated_apply_isDeleted(ac);
588 if (ret != LDB_SUCCESS) {
589 return ldb_module_done(ac->req, NULL, NULL, ret);
593 /* free the partition control container here, for the
594 * common path. Other cases will have it cleaned up
595 * eventually with the ares */
596 talloc_free(partition_ctrl);
597 return ldb_module_done(ac->req, controls,
598 ares->response, LDB_SUCCESS);
604 * update a @REPLCHANGED record in each partition if there have been
605 * any writes of replicated data in the partition
607 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
609 struct replmd_private *replmd_private =
610 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
612 while (replmd_private->ncs) {
614 struct nc_entry *modified_partition = replmd_private->ncs;
616 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
617 modified_partition->mod_usn,
618 modified_partition->mod_usn_urgent, parent);
619 if (ret != LDB_SUCCESS) {
620 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
621 ldb_dn_get_linearized(modified_partition->dn)));
625 if (ldb_dn_compare(modified_partition->dn,
626 replmd_private->schema_dn) == 0) {
627 struct ldb_result *ext_res;
628 ret = dsdb_module_extended(module,
629 replmd_private->schema_dn,
631 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
633 DSDB_FLAG_NEXT_MODULE,
635 if (ret != LDB_SUCCESS) {
638 talloc_free(ext_res);
641 DLIST_REMOVE(replmd_private->ncs, modified_partition);
642 talloc_free(modified_partition);
650 created a replmd_replicated_request context
652 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
653 struct ldb_request *req)
655 struct ldb_context *ldb;
656 struct replmd_replicated_request *ac;
657 const struct GUID *our_invocation_id;
659 ldb = ldb_module_get_ctx(module);
661 ac = talloc_zero(req, struct replmd_replicated_request);
670 ac->schema = dsdb_get_schema(ldb, ac);
672 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
673 "replmd_modify: no dsdb_schema loaded");
674 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
679 /* get our invocationId */
680 our_invocation_id = samdb_ntds_invocation_id(ldb);
681 if (!our_invocation_id) {
682 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
683 "replmd_add: unable to find invocationId\n");
687 ac->our_invocation_id = *our_invocation_id;
693 add a time element to a record
695 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
697 struct ldb_message_element *el;
701 if (ldb_msg_find_element(msg, attr) != NULL) {
705 s = ldb_timestring(msg, t);
707 return LDB_ERR_OPERATIONS_ERROR;
710 ret = ldb_msg_add_string(msg, attr, s);
711 if (ret != LDB_SUCCESS) {
715 el = ldb_msg_find_element(msg, attr);
716 /* always set as replace. This works because on add ops, the flag
718 el->flags = LDB_FLAG_MOD_REPLACE;
724 add a uint64_t element to a record
726 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
727 const char *attr, uint64_t v)
729 struct ldb_message_element *el;
732 if (ldb_msg_find_element(msg, attr) != NULL) {
736 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
737 if (ret != LDB_SUCCESS) {
741 el = ldb_msg_find_element(msg, attr);
742 /* always set as replace. This works because on add ops, the flag
744 el->flags = LDB_FLAG_MOD_REPLACE;
749 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
750 const struct replPropertyMetaData1 *m2,
751 const uint32_t *rdn_attid)
754 * This assignment seems inoccous, but it is critical for the
755 * system, as we need to do the comparisons as a unsigned
756 * quantity, not signed (enums are signed integers)
758 uint32_t attid_1 = m1->attid;
759 uint32_t attid_2 = m2->attid;
761 if (attid_1 == attid_2) {
766 * See above regarding this being an unsigned comparison.
767 * Otherwise when the high bit is set on non-standard
768 * attributes, they would end up first, before objectClass
771 return attid_1 > attid_2 ? 1 : -1;
774 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
775 struct replPropertyMetaDataCtr1 *ctr1,
778 if (ctr1->count == 0) {
779 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
780 "No elements found in replPropertyMetaData for %s!\n",
781 ldb_dn_get_linearized(dn));
782 return LDB_ERR_CONSTRAINT_VIOLATION;
785 /* the objectClass attribute is value 0x00000000, so must be first */
786 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
787 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
788 "No objectClass found in replPropertyMetaData for %s!\n",
789 ldb_dn_get_linearized(dn));
790 return LDB_ERR_OBJECT_CLASS_VIOLATION;
796 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
797 struct replPropertyMetaDataCtr1 *ctr1,
800 /* Note this is O(n^2) for the almost-sorted case, which this is */
801 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
802 replmd_replPropertyMetaData1_attid_sort);
803 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
806 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
807 const struct ldb_message_element *e2,
808 const struct dsdb_schema *schema)
810 const struct dsdb_attribute *a1;
811 const struct dsdb_attribute *a2;
814 * TODO: make this faster by caching the dsdb_attribute pointer
815 * on the ldb_messag_element
818 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
819 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
822 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
826 return strcasecmp(e1->name, e2->name);
828 if (a1->attributeID_id == a2->attributeID_id) {
831 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
834 static void replmd_ldb_message_sort(struct ldb_message *msg,
835 const struct dsdb_schema *schema)
837 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
840 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
841 const struct GUID *invocation_id, uint64_t seq_num,
842 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
846 fix up linked attributes in replmd_add.
847 This involves setting up the right meta-data in extended DN
848 components, and creating backlinks to the object
850 static int replmd_add_fix_la(struct ldb_module *module,
851 struct replmd_private *replmd_private,
852 struct ldb_message_element *el,
853 uint64_t seq_num, const struct GUID *invocationId, NTTIME now,
854 struct GUID *guid, const struct dsdb_attribute *sa, struct ldb_request *parent)
857 TALLOC_CTX *tmp_ctx = talloc_new(el->values);
858 struct ldb_context *ldb = ldb_module_get_ctx(module);
860 /* We will take a reference to the schema in replmd_add_backlink */
861 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
863 for (i=0; i<el->num_values; i++) {
864 struct ldb_val *v = &el->values[i];
865 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
866 struct GUID target_guid;
870 if (dsdb_dn == NULL) {
871 talloc_free(tmp_ctx);
872 return LDB_ERR_INVALID_DN_SYNTAX;
875 /* note that the DN already has the extended
876 components from the extended_dn_store module */
877 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
878 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
879 ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
880 if (ret != LDB_SUCCESS) {
881 talloc_free(tmp_ctx);
884 ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
885 if (ret != LDB_SUCCESS) {
886 talloc_free(tmp_ctx);
891 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
892 seq_num, seq_num, now, 0, false);
893 if (ret != LDB_SUCCESS) {
894 talloc_free(tmp_ctx);
898 ret = replmd_add_backlink(module, replmd_private,
899 schema, guid, &target_guid, true, sa,
901 if (ret != LDB_SUCCESS) {
902 talloc_free(tmp_ctx);
907 talloc_free(tmp_ctx);
913 intercept add requests
915 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
917 struct ldb_context *ldb;
918 struct ldb_control *control;
919 struct replmd_replicated_request *ac;
920 enum ndr_err_code ndr_err;
921 struct ldb_request *down_req;
922 struct ldb_message *msg;
923 const DATA_BLOB *guid_blob;
925 struct replPropertyMetaDataBlob nmd;
926 struct ldb_val nmd_value;
929 * The use of a time_t here seems odd, but as the NTTIME
930 * elements are actually declared as NTTIME_1sec in the IDL,
931 * getting a higher resolution timestamp is not required.
933 time_t t = time(NULL);
938 unsigned int functional_level;
940 bool allow_add_guid = false;
941 bool remove_current_guid = false;
942 bool is_urgent = false;
943 bool is_schema_nc = false;
944 struct ldb_message_element *objectclass_el;
945 struct replmd_private *replmd_private =
946 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
948 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
949 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
951 allow_add_guid = true;
954 /* do not manipulate our control entries */
955 if (ldb_dn_is_special(req->op.add.message->dn)) {
956 return ldb_next_request(module, req);
959 ldb = ldb_module_get_ctx(module);
961 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
963 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
964 if (guid_blob != NULL) {
965 if (!allow_add_guid) {
966 ldb_set_errstring(ldb,
967 "replmd_add: it's not allowed to add an object with objectGUID!");
968 return LDB_ERR_UNWILLING_TO_PERFORM;
970 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
971 if (!NT_STATUS_IS_OK(status)) {
972 ldb_set_errstring(ldb,
973 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
974 return LDB_ERR_UNWILLING_TO_PERFORM;
976 /* we remove this attribute as it can be a string and
977 * will not be treated correctly and then we will re-add
978 * it later on in the good format */
979 remove_current_guid = true;
983 guid = GUID_random();
986 ac = replmd_ctx_init(module, req);
988 return ldb_module_oom(module);
991 functional_level = dsdb_functional_level(ldb);
993 /* Get a sequence number from the backend */
994 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
995 if (ret != LDB_SUCCESS) {
1000 /* we have to copy the message as the caller might have it as a const */
1001 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1005 return LDB_ERR_OPERATIONS_ERROR;
1008 /* generated times */
1009 unix_to_nt_time(&now, t);
1010 time_str = ldb_timestring(msg, t);
1014 return LDB_ERR_OPERATIONS_ERROR;
1016 if (remove_current_guid) {
1017 ldb_msg_remove_attr(msg,"objectGUID");
1021 * remove autogenerated attributes
1023 ldb_msg_remove_attr(msg, "whenCreated");
1024 ldb_msg_remove_attr(msg, "whenChanged");
1025 ldb_msg_remove_attr(msg, "uSNCreated");
1026 ldb_msg_remove_attr(msg, "uSNChanged");
1027 ldb_msg_remove_attr(msg, "replPropertyMetaData");
1030 * readd replicated attributes
1032 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1033 if (ret != LDB_SUCCESS) {
1039 /* build the replication meta_data */
1042 nmd.ctr.ctr1.count = msg->num_elements;
1043 nmd.ctr.ctr1.array = talloc_array(msg,
1044 struct replPropertyMetaData1,
1045 nmd.ctr.ctr1.count);
1046 if (!nmd.ctr.ctr1.array) {
1049 return LDB_ERR_OPERATIONS_ERROR;
1052 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1054 for (i=0; i < msg->num_elements;) {
1055 struct ldb_message_element *e = &msg->elements[i];
1056 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1057 const struct dsdb_attribute *sa;
1059 if (e->name[0] == '@') {
1064 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1066 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1067 "replmd_add: attribute '%s' not defined in schema\n",
1070 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1073 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1074 /* if the attribute is not replicated (0x00000001)
1075 * or constructed (0x00000004) it has no metadata
1081 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1082 ret = replmd_add_fix_la(module, replmd_private, e,
1084 &ac->our_invocation_id, now,
1086 if (ret != LDB_SUCCESS) {
1090 /* linked attributes are not stored in
1091 replPropertyMetaData in FL above w2k */
1096 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1098 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1099 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1102 if (rdn_val == NULL) {
1105 return LDB_ERR_OPERATIONS_ERROR;
1108 rdn = (const char*)rdn_val->data;
1109 if (strcmp(rdn, "Deleted Objects") == 0) {
1111 * Set the originating_change_time to 29/12/9999 at 23:59:59
1112 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1114 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1116 m->originating_change_time = now;
1119 m->originating_change_time = now;
1121 m->originating_invocation_id = ac->our_invocation_id;
1122 m->originating_usn = ac->seq_num;
1123 m->local_usn = ac->seq_num;
1126 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1131 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1133 if (e->num_values != 0) {
1138 ldb_msg_remove_element(msg, e);
1141 /* fix meta data count */
1142 nmd.ctr.ctr1.count = ni;
1145 * sort meta data array
1147 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1148 if (ret != LDB_SUCCESS) {
1149 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1154 /* generated NDR encoded values */
1155 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1157 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1158 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1161 return LDB_ERR_OPERATIONS_ERROR;
1165 * add the autogenerated values
1167 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1168 if (ret != LDB_SUCCESS) {
1173 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1174 if (ret != LDB_SUCCESS) {
1179 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1180 if (ret != LDB_SUCCESS) {
1185 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1186 if (ret != LDB_SUCCESS) {
1191 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1192 if (ret != LDB_SUCCESS) {
1199 * sort the attributes by attid before storing the object
1201 replmd_ldb_message_sort(msg, ac->schema);
1204 * Assert that we do have an objectClass
1206 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1207 if (objectclass_el == NULL) {
1208 ldb_asprintf_errstring(ldb, __location__
1209 ": objectClass missing on %s\n",
1210 ldb_dn_get_linearized(msg->dn));
1212 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1214 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1215 REPL_URGENT_ON_CREATE);
1217 ac->is_urgent = is_urgent;
1218 ret = ldb_build_add_req(&down_req, ldb, ac,
1221 ac, replmd_op_callback,
1224 LDB_REQ_SET_LOCATION(down_req);
1225 if (ret != LDB_SUCCESS) {
1230 /* current partition control is needed by "replmd_op_callback" */
1231 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1232 ret = ldb_request_add_control(down_req,
1233 DSDB_CONTROL_CURRENT_PARTITION_OID,
1235 if (ret != LDB_SUCCESS) {
1241 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1242 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1243 if (ret != LDB_SUCCESS) {
1249 /* mark the control done */
1251 control->critical = 0;
1253 /* go on with the call chain */
1254 return ldb_next_request(module, down_req);
1259 * update the replPropertyMetaData for one element
1261 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1262 struct ldb_message *msg,
1263 struct ldb_message_element *el,
1264 struct ldb_message_element *old_el,
1265 struct replPropertyMetaDataBlob *omd,
1266 const struct dsdb_schema *schema,
1268 const struct GUID *our_invocation_id,
1271 struct ldb_request *req)
1274 const struct dsdb_attribute *a;
1275 struct replPropertyMetaData1 *md1;
1276 bool may_skip = false;
1279 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1281 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1282 /* allow this to make it possible for dbcheck
1283 to remove bad attributes */
1287 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1289 return LDB_ERR_OPERATIONS_ERROR;
1292 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1294 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1299 * if the attribute's value haven't changed, and this isn't
1300 * just a delete of everything then return LDB_SUCCESS Unless
1301 * we have the provision control or if the attribute is
1302 * interSiteTopologyGenerator as this page explain:
1303 * http://support.microsoft.com/kb/224815 this attribute is
1304 * periodicaly written by the DC responsible for the intersite
1305 * generation in a given site
1307 * Unchanged could be deleting or replacing an already-gone
1308 * thing with an unconstrained delete/empty replace or a
1309 * replace with the same value, but not an add with the same
1310 * value because that could be about adding a duplicate (which
1311 * is for someone else to error out on).
1313 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1314 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1317 } else if (old_el == NULL && el->num_values == 0) {
1318 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1320 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1323 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1324 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1326 * We intentionally skip the version bump when attempting to
1329 * The control is set by dbcheck and expunge-tombstones which
1330 * both attempt to be non-replicating. Otherwise, making an
1331 * alteration to the replication state would trigger a
1332 * broadcast of all expunged objects.
1337 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1339 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1343 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1344 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1346 * allow this to make it possible for dbcheck
1347 * to rebuild broken metadata
1353 for (i=0; i<omd->ctr.ctr1.count; i++) {
1355 * First check if we find it under the msDS-IntID,
1356 * then check if we find it under the OID and
1359 * This allows the administrator to simply re-write
1360 * the attributes and so restore replication, which is
1361 * likely what they will try to do.
1363 if (attid == omd->ctr.ctr1.array[i].attid) {
1367 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1372 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1373 /* linked attributes are not stored in
1374 replPropertyMetaData in FL above w2k, but we do
1375 raise the seqnum for the object */
1376 if (*seq_num == 0 &&
1377 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1378 return LDB_ERR_OPERATIONS_ERROR;
1383 if (i == omd->ctr.ctr1.count) {
1384 /* we need to add a new one */
1385 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1386 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1387 if (omd->ctr.ctr1.array == NULL) {
1389 return LDB_ERR_OPERATIONS_ERROR;
1391 omd->ctr.ctr1.count++;
1392 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1395 /* Get a new sequence number from the backend. We only do this
1396 * if we have a change that requires a new
1397 * replPropertyMetaData element
1399 if (*seq_num == 0) {
1400 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1401 if (ret != LDB_SUCCESS) {
1402 return LDB_ERR_OPERATIONS_ERROR;
1406 md1 = &omd->ctr.ctr1.array[i];
1409 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1410 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1413 if (rdn_val == NULL) {
1415 return LDB_ERR_OPERATIONS_ERROR;
1418 rdn = (const char*)rdn_val->data;
1419 if (strcmp(rdn, "Deleted Objects") == 0) {
1421 * Set the originating_change_time to 29/12/9999 at 23:59:59
1422 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1424 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1426 md1->originating_change_time = now;
1429 md1->originating_change_time = now;
1431 md1->originating_invocation_id = *our_invocation_id;
1432 md1->originating_usn = *seq_num;
1433 md1->local_usn = *seq_num;
1439 * Bump the replPropertyMetaData version on an attribute, and if it
1440 * has changed (or forced by leaving rdn_old NULL), update the value
1443 * This is important, as calling a modify operation may not change the
1444 * version number if the values appear unchanged, but a rename between
1445 * parents bumps this value.
1448 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1449 struct ldb_message *msg,
1450 const struct ldb_val *rdn_new,
1451 const struct ldb_val *rdn_old,
1452 struct replPropertyMetaDataBlob *omd,
1453 struct replmd_replicated_request *ar,
1457 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1458 const struct dsdb_attribute *rdn_attr =
1459 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1460 const char *attr_name = rdn_attr != NULL ?
1461 rdn_attr->lDAPDisplayName :
1463 struct ldb_message_element new_el = {
1464 .flags = LDB_FLAG_MOD_REPLACE,
1467 .values = discard_const_p(struct ldb_val, rdn_new)
1469 struct ldb_message_element old_el = {
1470 .flags = LDB_FLAG_MOD_REPLACE,
1472 .num_values = rdn_old ? 1 : 0,
1473 .values = discard_const_p(struct ldb_val, rdn_old)
1476 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1477 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1478 if (ret != LDB_SUCCESS) {
1479 return ldb_oom(ldb);
1483 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1484 omd, ar->schema, &ar->seq_num,
1485 &ar->our_invocation_id,
1486 now, is_schema_nc, ar->req);
1490 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1492 uint32_t count = omd.ctr.ctr1.count;
1495 for (i=0; i < count; i++) {
1496 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1497 if (max < m.local_usn) {
1505 * update the replPropertyMetaData object each time we modify an
1506 * object. This is needed for DRS replication, as the merge on the
1507 * client is based on this object
1509 static int replmd_update_rpmd(struct ldb_module *module,
1510 const struct dsdb_schema *schema,
1511 struct ldb_request *req,
1512 const char * const *rename_attrs,
1513 struct ldb_message *msg, uint64_t *seq_num,
1514 time_t t, bool is_schema_nc,
1515 bool *is_urgent, bool *rodc)
1517 const struct ldb_val *omd_value;
1518 enum ndr_err_code ndr_err;
1519 struct replPropertyMetaDataBlob omd;
1522 const struct GUID *our_invocation_id;
1524 const char * const *attrs = NULL;
1525 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1526 struct ldb_result *res;
1527 struct ldb_context *ldb;
1528 struct ldb_message_element *objectclass_el;
1529 enum urgent_situation situation;
1530 bool rmd_is_provided;
1531 bool rmd_is_just_resorted = false;
1532 const char *not_rename_attrs[4 + msg->num_elements];
1535 attrs = rename_attrs;
1537 for (i = 0; i < msg->num_elements; i++) {
1538 not_rename_attrs[i] = msg->elements[i].name;
1540 not_rename_attrs[i] = "replPropertyMetaData";
1541 not_rename_attrs[i+1] = "objectClass";
1542 not_rename_attrs[i+2] = "instanceType";
1543 not_rename_attrs[i+3] = NULL;
1544 attrs = not_rename_attrs;
1547 ldb = ldb_module_get_ctx(module);
1549 our_invocation_id = samdb_ntds_invocation_id(ldb);
1550 if (!our_invocation_id) {
1551 /* this happens during an initial vampire while
1552 updating the schema */
1553 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1557 unix_to_nt_time(&now, t);
1559 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1560 rmd_is_provided = true;
1561 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1562 rmd_is_just_resorted = true;
1565 rmd_is_provided = false;
1568 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1569 * otherwise we consider we are updating */
1570 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1571 situation = REPL_URGENT_ON_DELETE;
1572 } else if (rename_attrs) {
1573 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1575 situation = REPL_URGENT_ON_UPDATE;
1578 if (rmd_is_provided) {
1579 /* In this case the change_replmetadata control was supplied */
1580 /* We check that it's the only attribute that is provided
1581 * (it's a rare case so it's better to keep the code simplier)
1582 * We also check that the highest local_usn is bigger or the same as
1585 if( msg->num_elements != 1 ||
1586 strncmp(msg->elements[0].name,
1587 "replPropertyMetaData", 20) ) {
1588 DEBUG(0,(__location__ ": changereplmetada control called without "\
1589 "a specified replPropertyMetaData attribute or with others\n"));
1590 return LDB_ERR_OPERATIONS_ERROR;
1592 if (situation != REPL_URGENT_ON_UPDATE) {
1593 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1594 return LDB_ERR_OPERATIONS_ERROR;
1596 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1598 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1599 ldb_dn_get_linearized(msg->dn)));
1600 return LDB_ERR_OPERATIONS_ERROR;
1602 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1603 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1604 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1605 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1606 ldb_dn_get_linearized(msg->dn)));
1607 return LDB_ERR_OPERATIONS_ERROR;
1610 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1611 DSDB_FLAG_NEXT_MODULE |
1612 DSDB_SEARCH_SHOW_RECYCLED |
1613 DSDB_SEARCH_SHOW_EXTENDED_DN |
1614 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1615 DSDB_SEARCH_REVEAL_INTERNALS, req);
1617 if (ret != LDB_SUCCESS) {
1621 if (rmd_is_just_resorted == false) {
1622 *seq_num = find_max_local_usn(omd);
1624 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1627 * The test here now allows for a new
1628 * replPropertyMetaData with no change, if was
1629 * just dbcheck re-sorting the values.
1631 if (*seq_num <= db_seq) {
1632 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1633 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1634 (long long)*seq_num, (long long)db_seq));
1635 return LDB_ERR_OPERATIONS_ERROR;
1640 /* search for the existing replPropertyMetaDataBlob. We need
1641 * to use REVEAL and ask for DNs in storage format to support
1642 * the check for values being the same in
1643 * replmd_update_rpmd_element()
1645 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1646 DSDB_FLAG_NEXT_MODULE |
1647 DSDB_SEARCH_SHOW_RECYCLED |
1648 DSDB_SEARCH_SHOW_EXTENDED_DN |
1649 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1650 DSDB_SEARCH_REVEAL_INTERNALS, req);
1651 if (ret != LDB_SUCCESS) {
1655 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1657 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1658 ldb_dn_get_linearized(msg->dn)));
1659 return LDB_ERR_OPERATIONS_ERROR;
1662 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1663 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1664 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1665 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1666 ldb_dn_get_linearized(msg->dn)));
1667 return LDB_ERR_OPERATIONS_ERROR;
1670 if (omd.version != 1) {
1671 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1672 omd.version, ldb_dn_get_linearized(msg->dn)));
1673 return LDB_ERR_OPERATIONS_ERROR;
1676 for (i=0; i<msg->num_elements;) {
1677 struct ldb_message_element *el = &msg->elements[i];
1678 struct ldb_message_element *old_el;
1680 old_el = ldb_msg_find_element(res->msgs[0], el->name);
1681 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1682 &omd, schema, seq_num,
1686 if (ret != LDB_SUCCESS) {
1690 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1691 *is_urgent = replmd_check_urgent_attribute(el);
1694 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1699 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1701 if (el->num_values != 0) {
1706 ldb_msg_remove_element(msg, el);
1711 * Assert that we have an objectClass attribute - this is major
1712 * corruption if we don't have this!
1714 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1715 if (objectclass_el != NULL) {
1717 * Now check if this objectClass means we need to do urgent replication
1719 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1723 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1724 ldb_asprintf_errstring(ldb, __location__
1725 ": objectClass missing on %s\n",
1726 ldb_dn_get_linearized(msg->dn));
1727 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1731 * replmd_update_rpmd_element has done an update if the
1734 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1735 struct ldb_val *md_value;
1736 struct ldb_message_element *el;
1738 /*if we are RODC and this is a DRSR update then its ok*/
1739 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1740 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
1741 unsigned instanceType;
1743 ret = samdb_rodc(ldb, rodc);
1744 if (ret != LDB_SUCCESS) {
1745 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1747 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1748 return LDB_ERR_REFERRAL;
1751 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1752 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1753 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1754 "cannot change replicated attribute on partial replica");
1758 md_value = talloc(msg, struct ldb_val);
1759 if (md_value == NULL) {
1761 return LDB_ERR_OPERATIONS_ERROR;
1764 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1765 if (ret != LDB_SUCCESS) {
1766 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1770 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1771 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1772 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1773 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1774 ldb_dn_get_linearized(msg->dn)));
1775 return LDB_ERR_OPERATIONS_ERROR;
1778 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1779 if (ret != LDB_SUCCESS) {
1780 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1781 ldb_dn_get_linearized(msg->dn)));
1786 el->values = md_value;
1793 struct dsdb_dn *dsdb_dn;
1798 struct compare_ctx {
1800 struct ldb_context *ldb;
1801 TALLOC_CTX *mem_ctx;
1802 const char *ldap_oid;
1804 const struct GUID *invocation_id;
1807 /* When a parsed_dn comes from the database, sometimes it is not really parsed. */
1809 static int really_parse_trusted_dn(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
1810 struct parsed_dn *pdn, const char *ldap_oid)
1813 struct dsdb_dn *dsdb_dn = dsdb_dn_parse_trusted(mem_ctx, ldb, pdn->v,
1815 if (dsdb_dn == NULL) {
1816 return LDB_ERR_INVALID_DN_SYNTAX;
1819 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &pdn->guid, "GUID");
1820 if (!NT_STATUS_IS_OK(status)) {
1821 return LDB_ERR_OPERATIONS_ERROR;
1823 pdn->dsdb_dn = dsdb_dn;
1828 * We choose, as the sort order, the same order as is used in DRS replication,
1829 * which is the memcmp() order of the NDR GUID, not that obtained from
1832 * This means that sorted links will be in the same order as a new DC would
1835 static int ndr_guid_compare(struct GUID *guid1, struct GUID *guid2)
1837 uint8_t v1_data[16];
1838 struct ldb_val v1 = data_blob_const(v1_data, sizeof(v1_data));
1839 uint8_t v2_data[16];
1840 struct ldb_val v2 = data_blob_const(v2_data, sizeof(v2_data));
1842 /* This can't fail */
1843 ndr_push_struct_into_fixed_blob(&v1, guid1,
1844 (ndr_push_flags_fn_t)ndr_push_GUID);
1845 /* This can't fail */
1846 ndr_push_struct_into_fixed_blob(&v2, guid2,
1847 (ndr_push_flags_fn_t)ndr_push_GUID);
1848 return data_blob_cmp(&v1, &v2);
1851 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1853 return ndr_guid_compare(&pdn1->guid, &pdn2->guid);
1856 static int la_guid_compare_with_trusted_dn(struct compare_ctx *ctx,
1857 struct parsed_dn *p)
1860 * This works like a standard compare function in its return values,
1861 * but has an extra trick to deal with errors: zero is returned and
1862 * ctx->err is set to the ldb error code.
1864 * That is, if (as is expected in most cases) you get a non-zero
1865 * result, you don't need to check for errors.
1867 * We assume the second argument refers to a DN is from the database
1868 * and has a GUID -- but this GUID might not have been parsed out yet.
1870 if (p->dsdb_dn == NULL) {
1871 int ret = really_parse_trusted_dn(ctx->mem_ctx, ctx->ldb, p,
1873 if (ret != LDB_SUCCESS) {
1878 return ndr_guid_compare(ctx->guid, &p->guid);
1883 static int parsed_dn_find(struct ldb_context *ldb, struct parsed_dn *pdn,
1886 struct ldb_dn *target_dn,
1887 struct parsed_dn **exact,
1888 struct parsed_dn **next,
1889 const char *ldap_oid)
1892 struct compare_ctx ctx;
1899 if (unlikely(GUID_all_zero(guid))) {
1901 * When updating a link using DRS, we sometimes get a NULL
1902 * GUID when a forward link has been deleted and its GUID has
1903 * for some reason been forgotten. The best we can do is try
1904 * and match by DN via a linear search. Note that this
1905 * probably only happens in the ADD case, in which we only
1906 * allow modification of link if it is already deleted, so
1907 * this seems very close to an elaborate NO-OP, but we are not
1908 * quite prepared to declare it so.
1910 * If the DN is not in our list, we have to add it to the
1911 * beginning of the list, where it would naturally sort.
1913 struct parsed_dn *p;
1914 if (target_dn == NULL) {
1915 /* We don't know the target DN, so we can't search for DN */
1916 DEBUG(1, ("parsed_dn_find has a NULL GUID for a linked "
1917 "attribute but we don't have a DN to compare "
1919 return LDB_ERR_OPERATIONS_ERROR;
1924 DEBUG(3, ("parsed_dn_find has a NULL GUID for a link to DN "
1925 "%s; searching through links for it",
1926 ldb_dn_get_linearized(target_dn)));
1928 for (i = 0; i < count; i++) {
1931 if (p->dsdb_dn == NULL) {
1932 int ret = really_parse_trusted_dn(pdn, ldb, p, ldap_oid);
1933 if (ret != LDB_SUCCESS) {
1934 return LDB_ERR_OPERATIONS_ERROR;
1938 cmp = ldb_dn_compare(p->dsdb_dn->dn, target_dn);
1945 * Here we have a null guid which doesn't match any existing
1946 * link. This is a bit unexpected because null guids occur
1947 * when a forward link has been deleted and we are replicating
1950 * The best thing to do is weep into the logs and add the
1951 * offending link to the beginning of the list which is
1952 * at least the correct sort position.
1954 DEBUG(1, ("parsed_dn_find has been given a NULL GUID for a "
1955 "link to unknown DN %s\n",
1956 ldb_dn_get_linearized(target_dn)));
1964 ctx.ldap_oid = ldap_oid;
1967 BINARY_ARRAY_SEARCH_GTE(pdn, count, &ctx, la_guid_compare_with_trusted_dn,
1977 get a series of message element values as an array of DNs and GUIDs
1978 the result is sorted by GUID
1980 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1981 struct ldb_message_element *el, struct parsed_dn **pdn,
1982 const char *ldap_oid, struct ldb_request *parent)
1985 bool values_are_sorted = true;
1986 struct ldb_context *ldb = ldb_module_get_ctx(module);
1993 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1995 ldb_module_oom(module);
1996 return LDB_ERR_OPERATIONS_ERROR;
1999 for (i=0; i<el->num_values; i++) {
2000 struct ldb_val *v = &el->values[i];
2003 struct parsed_dn *p;
2007 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
2008 if (p->dsdb_dn == NULL) {
2009 return LDB_ERR_INVALID_DN_SYNTAX;
2012 dn = p->dsdb_dn->dn;
2014 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
2015 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2016 /* we got a DN without a GUID - go find the GUID */
2017 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
2018 if (ret != LDB_SUCCESS) {
2019 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
2020 ldb_dn_get_linearized(dn));
2021 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
2022 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
2023 ldb_attr_cmp(el->name, "member") == 0) {
2024 return LDB_ERR_UNWILLING_TO_PERFORM;
2028 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
2029 if (ret != LDB_SUCCESS) {
2032 } else if (!NT_STATUS_IS_OK(status)) {
2033 return LDB_ERR_OPERATIONS_ERROR;
2035 if (i > 0 && values_are_sorted) {
2036 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2038 values_are_sorted = false;
2041 /* keep a pointer to the original ldb_val */
2044 if (! values_are_sorted) {
2045 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2051 * Get a series of trusted message element values. The result is sorted by
2052 * GUID, even though the GUIDs might not be known. That works because we trust
2053 * the database to give us the elements like that if the
2054 * replmd_private->sorted_links flag is set.
2056 static int get_parsed_dns_trusted(struct ldb_module *module,
2057 struct replmd_private *replmd_private,
2058 TALLOC_CTX *mem_ctx,
2059 struct ldb_message_element *el,
2060 struct parsed_dn **pdn,
2061 const char *ldap_oid,
2062 struct ldb_request *parent)
2071 if (!replmd_private->sorted_links) {
2072 /* We need to sort the list. This is the slow old path we want
2075 return get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2078 /* Here we get a list of 'struct parsed_dns' without the parsing */
2079 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2082 ldb_module_oom(module);
2083 return LDB_ERR_OPERATIONS_ERROR;
2086 for (i = 0; i < el->num_values; i++) {
2087 (*pdn)[i].v = &el->values[i];
2094 build a new extended DN, including all meta data fields
2096 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2097 RMD_ADDTIME = originating_add_time
2098 RMD_INVOCID = originating_invocation_id
2099 RMD_CHANGETIME = originating_change_time
2100 RMD_ORIGINATING_USN = originating_usn
2101 RMD_LOCAL_USN = local_usn
2102 RMD_VERSION = version
2104 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2105 const struct GUID *invocation_id, uint64_t seq_num,
2106 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
2108 struct ldb_dn *dn = dsdb_dn->dn;
2109 const char *tstring, *usn_string, *flags_string;
2110 struct ldb_val tval;
2112 struct ldb_val usnv, local_usnv;
2113 struct ldb_val vers, flagsv;
2116 const char *dnstring;
2118 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2120 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2122 return LDB_ERR_OPERATIONS_ERROR;
2124 tval = data_blob_string_const(tstring);
2126 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
2128 return LDB_ERR_OPERATIONS_ERROR;
2130 usnv = data_blob_string_const(usn_string);
2132 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2134 return LDB_ERR_OPERATIONS_ERROR;
2136 local_usnv = data_blob_string_const(usn_string);
2138 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2140 return LDB_ERR_OPERATIONS_ERROR;
2142 vers = data_blob_string_const(vstring);
2144 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2145 if (!NT_STATUS_IS_OK(status)) {
2146 return LDB_ERR_OPERATIONS_ERROR;
2149 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2150 if (!flags_string) {
2151 return LDB_ERR_OPERATIONS_ERROR;
2153 flagsv = data_blob_string_const(flags_string);
2155 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2156 if (ret != LDB_SUCCESS) return ret;
2157 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
2158 if (ret != LDB_SUCCESS) return ret;
2159 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2160 if (ret != LDB_SUCCESS) return ret;
2161 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2162 if (ret != LDB_SUCCESS) return ret;
2163 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2164 if (ret != LDB_SUCCESS) return ret;
2165 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2166 if (ret != LDB_SUCCESS) return ret;
2167 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2168 if (ret != LDB_SUCCESS) return ret;
2170 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2171 if (dnstring == NULL) {
2172 return LDB_ERR_OPERATIONS_ERROR;
2174 *v = data_blob_string_const(dnstring);
2179 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2180 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2181 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2182 uint32_t version, bool deleted);
2185 check if any links need upgrading from w2k format
2187 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2188 struct parsed_dn *dns, uint32_t count,
2189 struct ldb_message_element *el,
2190 const struct GUID *invocation_id,
2191 const char *ldap_oid)
2194 for (i=0; i<count; i++) {
2198 if (dns[i].dsdb_dn == NULL) {
2199 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2201 if (ret != LDB_SUCCESS) {
2202 return LDB_ERR_INVALID_DN_SYNTAX;
2206 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2207 &version, "RMD_VERSION");
2208 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2210 * We optimistically assume they are all the same; if
2211 * the first one is fixed, they are all fixed.
2213 * If the first one was *not* fixed and we find a
2214 * later one that is, that is an occasion to shout
2220 DEBUG(0, ("Mixed w2k and fixed format "
2221 "linked attributes\n"));
2225 /* it's an old one that needs upgrading */
2226 ret = replmd_update_la_val(el->values, dns[i].v,
2227 dns[i].dsdb_dn, dns[i].dsdb_dn,
2228 invocation_id, 1, 1, 0, 0, false);
2229 if (ret != LDB_SUCCESS) {
2237 update an extended DN, including all meta data fields
2239 see replmd_build_la_val for value names
2241 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2242 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2243 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2244 uint32_t version, bool deleted)
2246 struct ldb_dn *dn = dsdb_dn->dn;
2247 const char *tstring, *usn_string, *flags_string;
2248 struct ldb_val tval;
2250 struct ldb_val usnv, local_usnv;
2251 struct ldb_val vers, flagsv;
2252 const struct ldb_val *old_addtime;
2253 uint32_t old_version;
2256 const char *dnstring;
2258 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2260 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2262 return LDB_ERR_OPERATIONS_ERROR;
2264 tval = data_blob_string_const(tstring);
2266 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2268 return LDB_ERR_OPERATIONS_ERROR;
2270 usnv = data_blob_string_const(usn_string);
2272 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2274 return LDB_ERR_OPERATIONS_ERROR;
2276 local_usnv = data_blob_string_const(usn_string);
2278 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2279 if (!NT_STATUS_IS_OK(status)) {
2280 return LDB_ERR_OPERATIONS_ERROR;
2283 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2284 if (!flags_string) {
2285 return LDB_ERR_OPERATIONS_ERROR;
2287 flagsv = data_blob_string_const(flags_string);
2289 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2290 if (ret != LDB_SUCCESS) return ret;
2292 /* get the ADDTIME from the original */
2293 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2294 if (old_addtime == NULL) {
2295 old_addtime = &tval;
2297 if (dsdb_dn != old_dsdb_dn ||
2298 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2299 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2300 if (ret != LDB_SUCCESS) return ret;
2303 /* use our invocation id */
2304 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2305 if (ret != LDB_SUCCESS) return ret;
2307 /* changetime is the current time */
2308 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2309 if (ret != LDB_SUCCESS) return ret;
2311 /* update the USN */
2312 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2313 if (ret != LDB_SUCCESS) return ret;
2315 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2316 if (ret != LDB_SUCCESS) return ret;
2318 /* increase the version by 1 */
2319 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2320 if (NT_STATUS_IS_OK(status) && old_version >= version) {
2321 version = old_version+1;
2323 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2324 vers = data_blob_string_const(vstring);
2325 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2326 if (ret != LDB_SUCCESS) return ret;
2328 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2329 if (dnstring == NULL) {
2330 return LDB_ERR_OPERATIONS_ERROR;
2332 *v = data_blob_string_const(dnstring);
2338 handle adding a linked attribute
2340 static int replmd_modify_la_add(struct ldb_module *module,
2341 struct replmd_private *replmd_private,
2342 const struct dsdb_schema *schema,
2343 struct ldb_message *msg,
2344 struct ldb_message_element *el,
2345 struct ldb_message_element *old_el,
2346 const struct dsdb_attribute *schema_attr,
2349 struct GUID *msg_guid,
2350 struct ldb_request *parent)
2353 struct parsed_dn *dns, *old_dns;
2354 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2356 struct ldb_val *new_values = NULL;
2357 unsigned old_num_values = old_el ? old_el->num_values : 0;
2358 unsigned num_values = 0;
2359 unsigned max_num_values;
2360 const struct GUID *invocation_id;
2361 struct ldb_context *ldb = ldb_module_get_ctx(module);
2364 unix_to_nt_time(&now, t);
2366 /* get the DNs to be added, fully parsed.
2368 * We need full parsing because they came off the wire and we don't
2369 * trust them, besides which we need their details to know where to put
2372 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2373 schema_attr->syntax->ldap_oid, parent);
2374 if (ret != LDB_SUCCESS) {
2375 talloc_free(tmp_ctx);
2379 /* get the existing DNs, lazily parsed */
2380 ret = get_parsed_dns_trusted(module, replmd_private,
2381 tmp_ctx, old_el, &old_dns,
2382 schema_attr->syntax->ldap_oid, parent);
2384 if (ret != LDB_SUCCESS) {
2385 talloc_free(tmp_ctx);
2389 invocation_id = samdb_ntds_invocation_id(ldb);
2390 if (!invocation_id) {
2391 talloc_free(tmp_ctx);
2392 return LDB_ERR_OPERATIONS_ERROR;
2395 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2396 old_el, invocation_id,
2397 schema_attr->syntax->ldap_oid);
2398 if (ret != LDB_SUCCESS) {
2399 talloc_free(tmp_ctx);
2403 max_num_values = old_num_values + el->num_values;
2404 if (max_num_values < old_num_values) {
2405 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2406 "old values: %u, new values: %u, sum: %u",
2407 old_num_values, el->num_values, max_num_values));
2408 talloc_free(tmp_ctx);
2409 return LDB_ERR_OPERATIONS_ERROR;
2412 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2414 if (new_values == NULL) {
2415 ldb_module_oom(module);
2416 talloc_free(tmp_ctx);
2417 return LDB_ERR_OPERATIONS_ERROR;
2421 * For each new value, find where it would go in the list. If there is
2422 * a matching GUID there, we update the existing value; otherwise we
2426 for (i = 0; i < el->num_values; i++) {
2427 struct parsed_dn *exact;
2428 struct parsed_dn *next;
2430 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2434 schema_attr->syntax->ldap_oid);
2435 if (err != LDB_SUCCESS) {
2436 talloc_free(tmp_ctx);
2440 if (exact != NULL) {
2442 * We are trying to add one that exists, which is only
2443 * allowed if it was previously deleted.
2445 * When we do undelete a link we change it in place.
2446 * It will be copied across into the right spot in due
2450 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2452 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2453 struct GUID_txt_buf guid_str;
2454 ldb_asprintf_errstring(ldb,
2455 "Attribute %s already "
2456 "exists for target GUID %s",
2458 GUID_buf_string(&exact->guid,
2460 talloc_free(tmp_ctx);
2461 /* error codes for 'member' need to be
2463 if (ldb_attr_cmp(el->name, "member") == 0) {
2464 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2466 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2470 ret = replmd_update_la_val(new_values, exact->v,
2473 invocation_id, seq_num,
2474 seq_num, now, 0, false);
2475 if (ret != LDB_SUCCESS) {
2476 talloc_free(tmp_ctx);
2480 ret = replmd_add_backlink(module, replmd_private,
2484 if (ret != LDB_SUCCESS) {
2485 talloc_free(tmp_ctx);
2491 * Here we don't have an exact match.
2493 * If next is NULL, this one goes beyond the end of the
2494 * existing list, so we need to add all of those ones first.
2496 * If next is not NULL, we need to add all the ones before
2500 offset = old_num_values;
2502 /* next should have been parsed, but let's make sure */
2503 if (next->dsdb_dn == NULL) {
2504 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2505 schema_attr->syntax->ldap_oid);
2506 if (ret != LDB_SUCCESS) {
2510 offset = MIN(next - old_dns, old_num_values);
2513 /* put all the old ones before next on the list */
2514 for (; j < offset; j++) {
2515 new_values[num_values] = *old_dns[j].v;
2519 ret = replmd_add_backlink(module, replmd_private,
2520 schema, msg_guid, &dns[i].guid,
2521 true, schema_attr, true);
2522 /* Make the new linked attribute ldb_val. */
2523 ret = replmd_build_la_val(new_values, &new_values[num_values],
2524 dns[i].dsdb_dn, invocation_id,
2527 if (ret != LDB_SUCCESS) {
2528 talloc_free(tmp_ctx);
2532 if (ret != LDB_SUCCESS) {
2533 talloc_free(tmp_ctx);
2537 /* copy the rest of the old ones (if any) */
2538 for (; j < old_num_values; j++) {
2539 new_values[num_values] = *old_dns[j].v;
2543 talloc_steal(msg->elements, new_values);
2544 if (old_el != NULL) {
2545 talloc_steal(msg->elements, old_el->values);
2547 el->values = new_values;
2548 el->num_values = num_values;
2550 talloc_free(tmp_ctx);
2552 /* we now tell the backend to replace all existing values
2553 with the one we have constructed */
2554 el->flags = LDB_FLAG_MOD_REPLACE;
2561 handle deleting all active linked attributes
2563 static int replmd_modify_la_delete(struct ldb_module *module,
2564 struct replmd_private *replmd_private,
2565 const struct dsdb_schema *schema,
2566 struct ldb_message *msg,
2567 struct ldb_message_element *el,
2568 struct ldb_message_element *old_el,
2569 const struct dsdb_attribute *schema_attr,
2572 struct GUID *msg_guid,
2573 struct ldb_request *parent)
2576 struct parsed_dn *dns, *old_dns;
2577 TALLOC_CTX *tmp_ctx = NULL;
2579 const struct GUID *invocation_id;
2580 struct ldb_context *ldb = ldb_module_get_ctx(module);
2581 struct ldb_control *vanish_links_ctrl = NULL;
2582 bool vanish_links = false;
2583 unsigned int num_to_delete = el->num_values;
2587 unix_to_nt_time(&now, t);
2589 if (old_el == NULL || old_el->num_values == 0) {
2590 /* there is nothing to delete... */
2591 if (num_to_delete == 0) {
2592 /* and we're deleting nothing, so that's OK */
2595 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2598 tmp_ctx = talloc_new(msg);
2599 if (tmp_ctx == NULL) {
2600 return LDB_ERR_OPERATIONS_ERROR;
2603 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2604 schema_attr->syntax->ldap_oid, parent);
2605 if (ret != LDB_SUCCESS) {
2606 talloc_free(tmp_ctx);
2610 ret = get_parsed_dns_trusted(module, replmd_private,
2611 tmp_ctx, old_el, &old_dns,
2612 schema_attr->syntax->ldap_oid, parent);
2614 if (ret != LDB_SUCCESS) {
2615 talloc_free(tmp_ctx);
2619 invocation_id = samdb_ntds_invocation_id(ldb);
2620 if (!invocation_id) {
2621 talloc_free(tmp_ctx);
2622 return LDB_ERR_OPERATIONS_ERROR;
2625 ret = replmd_check_upgrade_links(ldb, old_dns, old_el->num_values,
2626 old_el, invocation_id,
2627 schema_attr->syntax->ldap_oid);
2628 if (ret != LDB_SUCCESS) {
2629 talloc_free(tmp_ctx);
2634 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2635 if (vanish_links_ctrl) {
2636 vanish_links = true;
2637 vanish_links_ctrl->critical = false;
2641 /* we empty out el->values here to avoid damage if we return early. */
2646 * If vanish links is set, we are actually removing members of
2647 * old_el->values; otherwise we are just marking them deleted.
2649 * There is a special case when no values are given: we remove them
2650 * all. When we have the vanish_links control we just have to remove
2651 * the backlinks and change our element to replace the existing values
2652 * with the empty list.
2655 if (num_to_delete == 0) {
2656 for (i = 0; i < old_el->num_values; i++) {
2657 struct parsed_dn *p = &old_dns[i];
2658 if (p->dsdb_dn == NULL) {
2659 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2660 schema_attr->syntax->ldap_oid);
2661 if (ret != LDB_SUCCESS) {
2665 ret = replmd_add_backlink(module, replmd_private,
2666 schema, msg_guid, &p->guid,
2667 false, schema_attr, true);
2668 if (ret != LDB_SUCCESS) {
2669 talloc_free(tmp_ctx);
2676 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2677 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2681 ret = replmd_update_la_val(old_el->values, p->v,
2682 p->dsdb_dn, p->dsdb_dn,
2683 invocation_id, seq_num,
2684 seq_num, now, 0, true);
2685 if (ret != LDB_SUCCESS) {
2686 talloc_free(tmp_ctx);
2692 el->flags = LDB_FLAG_MOD_REPLACE;
2693 talloc_free(tmp_ctx);
2699 for (i = 0; i < num_to_delete; i++) {
2700 struct parsed_dn *p = &dns[i];
2701 struct parsed_dn *exact = NULL;
2702 struct parsed_dn *next = NULL;
2703 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2707 schema_attr->syntax->ldap_oid);
2708 if (ret != LDB_SUCCESS) {
2709 talloc_free(tmp_ctx);
2712 if (exact == NULL) {
2713 struct GUID_txt_buf buf;
2714 ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2715 "exist for target GUID %s",
2717 GUID_buf_string(&p->guid, &buf));
2718 if (ldb_attr_cmp(el->name, "member") == 0) {
2719 talloc_free(tmp_ctx);
2720 return LDB_ERR_UNWILLING_TO_PERFORM;
2722 talloc_free(tmp_ctx);
2723 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2728 if (CHECK_DEBUGLVL(5)) {
2729 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2730 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2731 struct GUID_txt_buf buf;
2732 const char *guid_str = \
2733 GUID_buf_string(&p->guid, &buf);
2734 DEBUG(5, ("Deleting deleted linked "
2735 "attribute %s to %s, because "
2736 "vanish_links control is set\n",
2737 el->name, guid_str));
2741 /* remove the backlink */
2742 ret = replmd_add_backlink(module,
2748 if (ret != LDB_SUCCESS) {
2749 talloc_free(tmp_ctx);
2753 /* We flag the deletion and tidy it up later. */
2758 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2760 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2761 struct GUID_txt_buf buf;
2762 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2763 ldb_asprintf_errstring(ldb, "Attribute %s already "
2764 "deleted for target GUID %s",
2765 el->name, guid_str);
2766 if (ldb_attr_cmp(el->name, "member") == 0) {
2767 talloc_free(tmp_ctx);
2768 return LDB_ERR_UNWILLING_TO_PERFORM;
2770 talloc_free(tmp_ctx);
2771 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2775 ret = replmd_update_la_val(old_el->values, exact->v,
2776 exact->dsdb_dn, exact->dsdb_dn,
2777 invocation_id, seq_num, seq_num,
2779 if (ret != LDB_SUCCESS) {
2780 talloc_free(tmp_ctx);
2783 ret = replmd_add_backlink(module, replmd_private,
2784 schema, msg_guid, &p->guid,
2785 false, schema_attr, true);
2786 if (ret != LDB_SUCCESS) {
2787 talloc_free(tmp_ctx);
2794 for (i = 0; i < old_el->num_values; i++) {
2795 if (old_dns[i].v != NULL) {
2796 old_el->values[j] = *old_dns[i].v;
2800 old_el->num_values = j;
2803 el->values = talloc_steal(msg->elements, old_el->values);
2804 el->num_values = old_el->num_values;
2806 talloc_free(tmp_ctx);
2808 /* we now tell the backend to replace all existing values
2809 with the one we have constructed */
2810 el->flags = LDB_FLAG_MOD_REPLACE;
2816 handle replacing a linked attribute
2818 static int replmd_modify_la_replace(struct ldb_module *module,
2819 struct replmd_private *replmd_private,
2820 const struct dsdb_schema *schema,
2821 struct ldb_message *msg,
2822 struct ldb_message_element *el,
2823 struct ldb_message_element *old_el,
2824 const struct dsdb_attribute *schema_attr,
2827 struct GUID *msg_guid,
2828 struct ldb_request *parent)
2830 unsigned int i, old_i, new_i;
2831 struct parsed_dn *dns, *old_dns;
2832 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2834 const struct GUID *invocation_id;
2835 struct ldb_context *ldb = ldb_module_get_ctx(module);
2836 struct ldb_val *new_values = NULL;
2837 const char *ldap_oid = schema_attr->syntax->ldap_oid;
2838 unsigned int old_num_values;
2839 unsigned int repl_num_values;
2840 unsigned int max_num_values;
2843 unix_to_nt_time(&now, t);
2846 * The replace operation is unlike the replace and delete cases in that
2847 * we need to look at every existing link to see whether it is being
2848 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
2850 * As we are trying to combine two sorted lists, the algorithm we use
2851 * is akin to the merge phase of a merge sort. We interleave the two
2852 * lists, doing different things depending on which side the current
2855 * There are three main cases, with some sub-cases.
2857 * - a DN is in the old list but not the new one. It needs to be
2858 * marked as deleted (but left in the list).
2859 * - maybe it is already deleted, and we have less to do.
2861 * - a DN is in both lists. The old data gets replaced by the new,
2862 * and the list doesn't grow. The old link may have been marked as
2863 * deleted, in which case we undelete it.
2865 * - a DN is in the new list only. We add it in the right place.
2868 old_num_values = old_el ? old_el->num_values : 0;
2869 repl_num_values = el->num_values;
2870 max_num_values = old_num_values + repl_num_values;
2872 if (max_num_values == 0) {
2873 /* There is nothing to do! */
2877 ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
2878 if (ret != LDB_SUCCESS) {
2879 talloc_free(tmp_ctx);
2883 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
2885 if (ret != LDB_SUCCESS) {
2886 talloc_free(tmp_ctx);
2890 invocation_id = samdb_ntds_invocation_id(ldb);
2891 if (!invocation_id) {
2892 return LDB_ERR_OPERATIONS_ERROR;
2895 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2896 old_el, invocation_id, ldap_oid);
2897 if (ret != LDB_SUCCESS) {
2898 talloc_free(tmp_ctx);
2902 new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
2903 if (new_values == NULL) {
2904 ldb_module_oom(module);
2905 talloc_free(tmp_ctx);
2906 return LDB_ERR_OPERATIONS_ERROR;
2911 for (i = 0; i < max_num_values; i++) {
2913 struct parsed_dn *old_p, *new_p;
2914 if (old_i < old_num_values && new_i < repl_num_values) {
2915 old_p = &old_dns[old_i];
2916 new_p = &dns[new_i];
2917 cmp = parsed_dn_compare(old_p, new_p);
2918 } else if (old_i < old_num_values) {
2919 /* the new list is empty, read the old list */
2920 old_p = &old_dns[old_i];
2923 } else if (new_i < repl_num_values) {
2924 /* the old list is empty, read new list */
2926 new_p = &dns[new_i];
2934 * An old ones that come before the next replacement
2935 * (if any). We mark it as deleted and add it to the
2938 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2939 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
2940 ret = replmd_update_la_val(new_values, old_p->v,
2946 if (ret != LDB_SUCCESS) {
2947 talloc_free(tmp_ctx);
2951 ret = replmd_add_backlink(module, replmd_private,
2953 &old_p->guid, false,
2955 if (ret != LDB_SUCCESS) {
2956 talloc_free(tmp_ctx);
2960 new_values[i] = *old_p->v;
2962 } else if (cmp == 0) {
2964 * We are overwriting one. If it was previously
2965 * deleted, we need to add a backlink.
2967 * Note that if any RMD_FLAGs in an extended new DN
2972 ret = replmd_update_la_val(new_values, old_p->v,
2978 if (ret != LDB_SUCCESS) {
2979 talloc_free(tmp_ctx);
2983 rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2984 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
2985 ret = replmd_add_backlink(module, replmd_private,
2989 if (ret != LDB_SUCCESS) {
2990 talloc_free(tmp_ctx);
2995 new_values[i] = *old_p->v;
3000 * Replacements that don't match an existing one. We
3001 * just add them to the final list.
3003 ret = replmd_build_la_val(new_values,
3009 if (ret != LDB_SUCCESS) {
3010 talloc_free(tmp_ctx);
3013 ret = replmd_add_backlink(module, replmd_private,
3017 if (ret != LDB_SUCCESS) {
3018 talloc_free(tmp_ctx);
3021 new_values[i] = *new_p->v;
3025 if (old_el != NULL) {
3026 talloc_steal(msg->elements, old_el->values);
3028 el->values = talloc_steal(msg->elements, new_values);
3030 talloc_free(tmp_ctx);
3032 el->flags = LDB_FLAG_MOD_REPLACE;
3039 handle linked attributes in modify requests
3041 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3042 struct replmd_private *replmd_private,
3043 struct ldb_message *msg,
3044 uint64_t seq_num, time_t t,
3045 struct ldb_request *parent)
3047 struct ldb_result *res;
3050 struct ldb_context *ldb = ldb_module_get_ctx(module);
3051 struct ldb_message *old_msg;
3053 const struct dsdb_schema *schema;
3054 struct GUID old_guid;
3056 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3058 * Nothing special is required for modifying or vanishing links
3059 * in fl2000 since they are just strings in a multi-valued
3062 struct ldb_control *ctrl = ldb_request_get_control(parent,
3063 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3065 ctrl->critical = false;
3073 * We should restrict this to the intersection of the list of
3074 * linked attributes in the schema and the list of attributes
3077 * This will help performance a little, as otherwise we have
3078 * to allocate the entire object value-by-value.
3080 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3081 DSDB_FLAG_NEXT_MODULE |
3082 DSDB_SEARCH_SHOW_RECYCLED |
3083 DSDB_SEARCH_REVEAL_INTERNALS |
3084 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3086 if (ret != LDB_SUCCESS) {
3089 schema = dsdb_get_schema(ldb, res);
3091 return LDB_ERR_OPERATIONS_ERROR;
3094 old_msg = res->msgs[0];
3096 old_guid = samdb_result_guid(old_msg, "objectGUID");
3098 for (i=0; i<msg->num_elements; i++) {
3099 struct ldb_message_element *el = &msg->elements[i];
3100 struct ldb_message_element *old_el, *new_el;
3101 const struct dsdb_attribute *schema_attr
3102 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3104 ldb_asprintf_errstring(ldb,
3105 "%s: attribute %s is not a valid attribute in schema",
3106 __FUNCTION__, el->name);
3107 return LDB_ERR_OBJECT_CLASS_VIOLATION;
3109 if (schema_attr->linkID == 0) {
3112 if ((schema_attr->linkID & 1) == 1) {
3113 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
3116 /* Odd is for the target. Illegal to modify */
3117 ldb_asprintf_errstring(ldb,
3118 "attribute %s must not be modified directly, it is a linked attribute", el->name);
3119 return LDB_ERR_UNWILLING_TO_PERFORM;
3121 old_el = ldb_msg_find_element(old_msg, el->name);
3122 switch (el->flags & LDB_FLAG_MOD_MASK) {
3123 case LDB_FLAG_MOD_REPLACE:
3124 ret = replmd_modify_la_replace(module, replmd_private,
3125 schema, msg, el, old_el,
3126 schema_attr, seq_num, t,
3129 case LDB_FLAG_MOD_DELETE:
3130 ret = replmd_modify_la_delete(module, replmd_private,
3131 schema, msg, el, old_el,
3132 schema_attr, seq_num, t,
3135 case LDB_FLAG_MOD_ADD:
3136 ret = replmd_modify_la_add(module, replmd_private,
3137 schema, msg, el, old_el,
3138 schema_attr, seq_num, t,
3142 ldb_asprintf_errstring(ldb,
3143 "invalid flags 0x%x for %s linked attribute",
3144 el->flags, el->name);
3145 return LDB_ERR_UNWILLING_TO_PERFORM;
3147 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3148 ldb_asprintf_errstring(ldb,
3149 "Attribute %s is single valued but more than one value has been supplied",
3151 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3153 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3158 if (ret != LDB_SUCCESS) {
3162 ldb_msg_remove_attr(old_msg, el->name);
3164 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3165 new_el->num_values = el->num_values;
3166 new_el->values = talloc_steal(msg->elements, el->values);
3168 /* TODO: this relises a bit too heavily on the exact
3169 behaviour of ldb_msg_find_element and
3170 ldb_msg_remove_element */
3171 old_el = ldb_msg_find_element(msg, el->name);
3173 ldb_msg_remove_element(msg, old_el);
3184 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3186 struct ldb_context *ldb;
3187 struct replmd_replicated_request *ac;
3188 struct ldb_request *down_req;
3189 struct ldb_message *msg;
3190 time_t t = time(NULL);
3192 bool is_urgent = false, rodc = false;
3193 bool is_schema_nc = false;
3194 unsigned int functional_level;
3195 const struct ldb_message_element *guid_el = NULL;
3196 struct ldb_control *sd_propagation_control;
3197 struct replmd_private *replmd_private =
3198 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3200 /* do not manipulate our control entries */
3201 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3202 return ldb_next_request(module, req);
3205 sd_propagation_control = ldb_request_get_control(req,
3206 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3207 if (sd_propagation_control != NULL) {
3208 if (req->op.mod.message->num_elements != 1) {
3209 return ldb_module_operr(module);
3211 ret = strcmp(req->op.mod.message->elements[0].name,
3212 "nTSecurityDescriptor");
3214 return ldb_module_operr(module);
3217 return ldb_next_request(module, req);
3220 ldb = ldb_module_get_ctx(module);
3222 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3224 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3225 if (guid_el != NULL) {
3226 ldb_set_errstring(ldb,
3227 "replmd_modify: it's not allowed to change the objectGUID!");
3228 return LDB_ERR_CONSTRAINT_VIOLATION;
3231 ac = replmd_ctx_init(module, req);
3233 return ldb_module_oom(module);
3236 functional_level = dsdb_functional_level(ldb);
3238 /* we have to copy the message as the caller might have it as a const */
3239 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3243 return LDB_ERR_OPERATIONS_ERROR;
3246 ldb_msg_remove_attr(msg, "whenChanged");
3247 ldb_msg_remove_attr(msg, "uSNChanged");
3249 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3251 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3252 msg, &ac->seq_num, t, is_schema_nc,
3254 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3255 struct loadparm_context *lp_ctx;
3258 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3259 struct loadparm_context);
3261 referral = talloc_asprintf(req,
3263 lpcfg_dnsdomain(lp_ctx),
3264 ldb_dn_get_linearized(msg->dn));
3265 ret = ldb_module_send_referral(req, referral);
3270 if (ret != LDB_SUCCESS) {
3275 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3276 msg, ac->seq_num, t, req);
3277 if (ret != LDB_SUCCESS) {
3283 * - replace the old object with the newly constructed one
3286 ac->is_urgent = is_urgent;
3288 ret = ldb_build_mod_req(&down_req, ldb, ac,
3291 ac, replmd_op_callback,
3293 LDB_REQ_SET_LOCATION(down_req);
3294 if (ret != LDB_SUCCESS) {
3299 /* current partition control is needed by "replmd_op_callback" */
3300 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3301 ret = ldb_request_add_control(down_req,
3302 DSDB_CONTROL_CURRENT_PARTITION_OID,
3304 if (ret != LDB_SUCCESS) {
3310 /* If we are in functional level 2000, then
3311 * replmd_modify_handle_linked_attribs will have done
3313 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3314 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3315 if (ret != LDB_SUCCESS) {
3321 talloc_steal(down_req, msg);
3323 /* we only change whenChanged and uSNChanged if the seq_num
3325 if (ac->seq_num != 0) {
3326 ret = add_time_element(msg, "whenChanged", t);
3327 if (ret != LDB_SUCCESS) {
3333 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3334 if (ret != LDB_SUCCESS) {
3341 /* go on with the call chain */
3342 return ldb_next_request(module, down_req);
3345 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3348 handle a rename request
3350 On a rename we need to do an extra ldb_modify which sets the
3351 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3353 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3355 struct ldb_context *ldb;
3356 struct replmd_replicated_request *ac;
3358 struct ldb_request *down_req;
3360 /* do not manipulate our control entries */
3361 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3362 return ldb_next_request(module, req);
3365 ldb = ldb_module_get_ctx(module);
3367 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3369 ac = replmd_ctx_init(module, req);
3371 return ldb_module_oom(module);
3374 ret = ldb_build_rename_req(&down_req, ldb, ac,
3375 ac->req->op.rename.olddn,
3376 ac->req->op.rename.newdn,
3378 ac, replmd_rename_callback,
3380 LDB_REQ_SET_LOCATION(down_req);
3381 if (ret != LDB_SUCCESS) {
3386 /* go on with the call chain */
3387 return ldb_next_request(module, down_req);
3390 /* After the rename is compleated, update the whenchanged etc */
3391 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3393 struct ldb_context *ldb;
3394 struct ldb_request *down_req;
3395 struct ldb_message *msg;
3396 const struct dsdb_attribute *rdn_attr;
3397 const char *rdn_name;
3398 const struct ldb_val *rdn_val;
3399 const char *attrs[5] = { NULL, };
3400 time_t t = time(NULL);
3402 bool is_urgent = false, rodc = false;
3404 struct replmd_replicated_request *ac =
3405 talloc_get_type(req->context, struct replmd_replicated_request);
3406 struct replmd_private *replmd_private =
3407 talloc_get_type(ldb_module_get_private(ac->module),
3408 struct replmd_private);
3410 ldb = ldb_module_get_ctx(ac->module);
3412 if (ares->error != LDB_SUCCESS) {
3413 return ldb_module_done(ac->req, ares->controls,
3414 ares->response, ares->error);
3417 if (ares->type != LDB_REPLY_DONE) {
3418 ldb_set_errstring(ldb,
3419 "invalid ldb_reply_type in callback");
3421 return ldb_module_done(ac->req, NULL, NULL,
3422 LDB_ERR_OPERATIONS_ERROR);
3426 * - replace the old object with the newly constructed one
3429 msg = ldb_msg_new(ac);
3432 return LDB_ERR_OPERATIONS_ERROR;
3435 msg->dn = ac->req->op.rename.newdn;
3437 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3439 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3440 if (rdn_name == NULL) {
3442 return ldb_module_done(ac->req, NULL, NULL,
3446 /* normalize the rdn attribute name */
3447 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3448 if (rdn_attr == NULL) {
3450 return ldb_module_done(ac->req, NULL, NULL,
3453 rdn_name = rdn_attr->lDAPDisplayName;
3455 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3456 if (rdn_val == NULL) {
3458 return ldb_module_done(ac->req, NULL, NULL,
3462 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3464 return ldb_module_done(ac->req, NULL, NULL,
3467 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3469 return ldb_module_done(ac->req, NULL, NULL,
3472 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3474 return ldb_module_done(ac->req, NULL, NULL,
3477 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3479 return ldb_module_done(ac->req, NULL, NULL,
3484 * here we let replmd_update_rpmd() only search for
3485 * the existing "replPropertyMetaData" and rdn_name attributes.
3487 * We do not want the existing "name" attribute as
3488 * the "name" attribute needs to get the version
3489 * updated on rename even if the rdn value hasn't changed.
3491 * This is the diff of the meta data, for a moved user
3492 * on a w2k8r2 server:
3495 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3496 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3497 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3498 * version : 0x00000001 (1)
3499 * reserved : 0x00000000 (0)
3500 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3501 * local_usn : 0x00000000000037a5 (14245)
3502 * array: struct replPropertyMetaData1
3503 * attid : DRSUAPI_ATTID_name (0x90001)
3504 * - version : 0x00000001 (1)
3505 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3506 * + version : 0x00000002 (2)
3507 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3508 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3509 * - originating_usn : 0x00000000000037a5 (14245)
3510 * - local_usn : 0x00000000000037a5 (14245)
3511 * + originating_usn : 0x0000000000003834 (14388)
3512 * + local_usn : 0x0000000000003834 (14388)
3513 * array: struct replPropertyMetaData1
3514 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3515 * version : 0x00000004 (4)
3517 attrs[0] = "replPropertyMetaData";
3518 attrs[1] = "objectClass";
3519 attrs[2] = "instanceType";
3520 attrs[3] = rdn_name;
3523 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3524 msg, &ac->seq_num, t,
3525 is_schema_nc, &is_urgent, &rodc);
3526 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3527 struct ldb_dn *olddn = ac->req->op.rename.olddn;
3528 struct loadparm_context *lp_ctx;
3531 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3532 struct loadparm_context);
3534 referral = talloc_asprintf(req,
3536 lpcfg_dnsdomain(lp_ctx),
3537 ldb_dn_get_linearized(olddn));
3538 ret = ldb_module_send_referral(req, referral);
3540 return ldb_module_done(req, NULL, NULL, ret);
3543 if (ret != LDB_SUCCESS) {
3545 return ldb_module_done(ac->req, NULL, NULL, ret);
3548 if (ac->seq_num == 0) {
3550 return ldb_module_done(ac->req, NULL, NULL,
3552 "internal error seq_num == 0"));
3554 ac->is_urgent = is_urgent;
3556 ret = ldb_build_mod_req(&down_req, ldb, ac,
3559 ac, replmd_op_callback,
3561 LDB_REQ_SET_LOCATION(down_req);
3562 if (ret != LDB_SUCCESS) {
3567 /* current partition control is needed by "replmd_op_callback" */
3568 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3569 ret = ldb_request_add_control(down_req,
3570 DSDB_CONTROL_CURRENT_PARTITION_OID,
3572 if (ret != LDB_SUCCESS) {
3578 talloc_steal(down_req, msg);
3580 ret = add_time_element(msg, "whenChanged", t);
3581 if (ret != LDB_SUCCESS) {
3587 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3588 if (ret != LDB_SUCCESS) {
3594 /* go on with the call chain - do the modify after the rename */
3595 return ldb_next_request(ac->module, down_req);
3599 * remove links from objects that point at this object when an object
3600 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3601 * RemoveObj which states that link removal due to the object being
3602 * deleted is NOT an originating update - they just go away!
3605 static int replmd_delete_remove_link(struct ldb_module *module,
3606 const struct dsdb_schema *schema,
3608 struct ldb_message_element *el,
3609 const struct dsdb_attribute *sa,
3610 struct ldb_request *parent)
3613 TALLOC_CTX *tmp_ctx = talloc_new(module);
3614 struct ldb_context *ldb = ldb_module_get_ctx(module);
3616 for (i=0; i<el->num_values; i++) {
3617 struct dsdb_dn *dsdb_dn;
3621 struct ldb_message *msg;
3622 const struct dsdb_attribute *target_attr;
3623 struct ldb_message_element *el2;
3624 struct ldb_val dn_val;
3625 uint32_t dsdb_flags = 0;
3627 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3631 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3633 talloc_free(tmp_ctx);
3634 return LDB_ERR_OPERATIONS_ERROR;
3637 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
3638 if (!NT_STATUS_IS_OK(status)) {
3639 talloc_free(tmp_ctx);
3640 return LDB_ERR_OPERATIONS_ERROR;
3643 /* remove the link */
3644 msg = ldb_msg_new(tmp_ctx);
3646 ldb_module_oom(module);
3647 talloc_free(tmp_ctx);
3648 return LDB_ERR_OPERATIONS_ERROR;
3652 msg->dn = dsdb_dn->dn;
3654 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3655 if (target_attr == NULL) {
3659 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
3660 if (ret != LDB_SUCCESS) {
3661 ldb_module_oom(module);
3662 talloc_free(tmp_ctx);
3663 return LDB_ERR_OPERATIONS_ERROR;
3665 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
3666 el2->values = &dn_val;
3667 el2->num_values = 1;
3670 * Ensure that we tell the modification to vanish any linked
3671 * attributes (not simply mark them as isDeleted = TRUE)
3673 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3675 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3676 if (ret != LDB_SUCCESS) {
3677 talloc_free(tmp_ctx);
3681 talloc_free(tmp_ctx);
3687 handle update of replication meta data for deletion of objects
3689 This also handles the mapping of delete to a rename operation
3690 to allow deletes to be replicated.
3692 It also handles the incoming deleted objects, to ensure they are
3693 fully deleted here. In that case re_delete is true, and we do not
3694 use this as a signal to change the deleted state, just reinforce it.
3697 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3699 int ret = LDB_ERR_OTHER;
3700 bool retb, disallow_move_on_delete;
3701 struct ldb_dn *old_dn, *new_dn;
3702 const char *rdn_name;
3703 const struct ldb_val *rdn_value, *new_rdn_value;
3705 struct ldb_context *ldb = ldb_module_get_ctx(module);
3706 const struct dsdb_schema *schema;
3707 struct ldb_message *msg, *old_msg;
3708 struct ldb_message_element *el;
3709 TALLOC_CTX *tmp_ctx;
3710 struct ldb_result *res, *parent_res;
3711 static const char * const preserved_attrs[] = {
3712 /* yes, this really is a hard coded list. See MS-ADTS
3713 section 3.1.1.5.5.1.1 */
3716 "dNReferenceUpdate",
3727 "msDS-LastKnownRDN",
3733 "distinguishedName",
3737 "proxiedObjectName",
3739 "nTSecurityDescriptor",
3740 "replPropertyMetaData",
3742 "securityIdentifier",
3750 "userAccountControl",
3757 static const char * const all_attrs[] = {
3758 DSDB_SECRET_ATTRIBUTES,
3762 unsigned int i, el_count = 0;
3763 uint32_t dsdb_flags = 0;
3764 enum deletion_state deletion_state, next_deletion_state;
3766 if (ldb_dn_is_special(req->op.del.dn)) {
3767 return ldb_next_request(module, req);
3771 * We have to allow dbcheck to remove an object that
3772 * is beyond repair, and to do so totally. This could
3773 * mean we we can get a partial object from the other
3774 * DC, causing havoc, so dbcheck suggests
3775 * re-replication first. dbcheck sets both DBCHECK
3776 * and RELAX in this situation.
3778 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3779 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3780 /* really, really remove it */
3781 return ldb_next_request(module, req);
3784 tmp_ctx = talloc_new(ldb);
3787 return LDB_ERR_OPERATIONS_ERROR;
3790 schema = dsdb_get_schema(ldb, tmp_ctx);
3792 talloc_free(tmp_ctx);
3793 return LDB_ERR_OPERATIONS_ERROR;
3796 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3798 /* we need the complete msg off disk, so we can work out which
3799 attributes need to be removed */
3800 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3801 DSDB_FLAG_NEXT_MODULE |
3802 DSDB_SEARCH_SHOW_RECYCLED |
3803 DSDB_SEARCH_REVEAL_INTERNALS |
3804 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3805 if (ret != LDB_SUCCESS) {
3806 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3807 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3808 re_delete ? "re-delete" : "delete",
3809 ldb_dn_get_linearized(old_dn),
3810 ldb_errstring(ldb_module_get_ctx(module)));
3811 talloc_free(tmp_ctx);
3814 old_msg = res->msgs[0];
3816 replmd_deletion_state(module, old_msg,
3818 &next_deletion_state);
3820 /* This supports us noticing an incoming isDeleted and acting on it */
3822 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3823 next_deletion_state = deletion_state;
3826 if (next_deletion_state == OBJECT_REMOVED) {
3828 * We have to prevent objects being deleted, even if
3829 * the administrator really wants them gone, as
3830 * without the tombstone, we can get a partial object
3831 * from the other DC, causing havoc.
3833 * The only other valid case is when the 180 day
3834 * timeout has expired, when relax is specified.
3836 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3837 /* it is already deleted - really remove it this time */
3838 talloc_free(tmp_ctx);
3839 return ldb_next_request(module, req);
3842 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3843 "This check is to prevent corruption of the replicated state.",
3844 ldb_dn_get_linearized(old_msg->dn));
3845 return LDB_ERR_UNWILLING_TO_PERFORM;
3848 rdn_name = ldb_dn_get_rdn_name(old_dn);
3849 rdn_value = ldb_dn_get_rdn_val(old_dn);
3850 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3851 talloc_free(tmp_ctx);
3852 return ldb_operr(ldb);
3855 msg = ldb_msg_new(tmp_ctx);
3857 ldb_module_oom(module);
3858 talloc_free(tmp_ctx);
3859 return LDB_ERR_OPERATIONS_ERROR;
3864 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3865 disallow_move_on_delete =
3866 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3867 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3869 /* work out where we will be renaming this object to */
3870 if (!disallow_move_on_delete) {
3871 struct ldb_dn *deleted_objects_dn;
3872 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3873 &deleted_objects_dn);
3876 * We should not move objects if we can't find the
3877 * deleted objects DN. Not moving (or otherwise
3878 * harming) the Deleted Objects DN itself is handled
3881 if (re_delete && (ret != LDB_SUCCESS)) {
3882 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3883 if (new_dn == NULL) {
3884 ldb_module_oom(module);
3885 talloc_free(tmp_ctx);
3886 return LDB_ERR_OPERATIONS_ERROR;
3888 } else if (ret != LDB_SUCCESS) {
3889 /* this is probably an attempted delete on a partition
3890 * that doesn't allow delete operations, such as the
3891 * schema partition */
3892 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3893 ldb_dn_get_linearized(old_dn));
3894 talloc_free(tmp_ctx);
3895 return LDB_ERR_UNWILLING_TO_PERFORM;
3897 new_dn = deleted_objects_dn;
3900 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3901 if (new_dn == NULL) {
3902 ldb_module_oom(module);
3903 talloc_free(tmp_ctx);
3904 return LDB_ERR_OPERATIONS_ERROR;
3908 if (deletion_state == OBJECT_NOT_DELETED) {
3909 /* get the objects GUID from the search we just did */
3910 guid = samdb_result_guid(old_msg, "objectGUID");
3912 /* Add a formatted child */
3913 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3915 ldb_dn_escape_value(tmp_ctx, *rdn_value),
3916 GUID_string(tmp_ctx, &guid));
3918 ldb_asprintf_errstring(ldb, __location__
3919 ": Unable to add a formatted child to dn: %s",
3920 ldb_dn_get_linearized(new_dn));
3921 talloc_free(tmp_ctx);
3922 return LDB_ERR_OPERATIONS_ERROR;
3925 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
3926 if (ret != LDB_SUCCESS) {
3927 ldb_asprintf_errstring(ldb, __location__
3928 ": Failed to add isDeleted string to the msg");
3929 talloc_free(tmp_ctx);
3932 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3935 * No matter what has happened with other renames etc, try again to
3936 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
3939 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
3940 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
3942 ldb_asprintf_errstring(ldb, __location__
3943 ": Unable to add a prepare rdn of %s",
3944 ldb_dn_get_linearized(rdn));
3945 talloc_free(tmp_ctx);
3946 return LDB_ERR_OPERATIONS_ERROR;
3948 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
3950 retb = ldb_dn_add_child(new_dn, rdn);
3952 ldb_asprintf_errstring(ldb, __location__
3953 ": Unable to add rdn %s to base dn: %s",
3954 ldb_dn_get_linearized(rdn),
3955 ldb_dn_get_linearized(new_dn));
3956 talloc_free(tmp_ctx);
3957 return LDB_ERR_OPERATIONS_ERROR;
3962 now we need to modify the object in the following ways:
3964 - add isDeleted=TRUE
3965 - update rDN and name, with new rDN
3966 - remove linked attributes
3967 - remove objectCategory and sAMAccountType
3968 - remove attribs not on the preserved list
3969 - preserved if in above list, or is rDN
3970 - remove all linked attribs from this object
3971 - remove all links from other objects to this object
3972 - add lastKnownParent
3973 - update replPropertyMetaData?
3975 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
3978 if (deletion_state == OBJECT_NOT_DELETED) {
3979 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3980 char *parent_dn_str = NULL;
3982 /* we need the storage form of the parent GUID */
3983 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
3985 DSDB_FLAG_NEXT_MODULE |
3986 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3987 DSDB_SEARCH_REVEAL_INTERNALS|
3988 DSDB_SEARCH_SHOW_RECYCLED, req);
3989 if (ret != LDB_SUCCESS) {
3990 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3991 "repmd_delete: Failed to %s %s, "
3992 "because we failed to find it's parent (%s): %s",
3993 re_delete ? "re-delete" : "delete",
3994 ldb_dn_get_linearized(old_dn),
3995 ldb_dn_get_linearized(parent_dn),
3996 ldb_errstring(ldb_module_get_ctx(module)));
3997 talloc_free(tmp_ctx);
4002 * Now we can use the DB version,
4003 * it will have the extended DN info in it
4005 parent_dn = parent_res->msgs[0]->dn;
4006 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4009 if (parent_dn_str == NULL) {
4010 talloc_free(tmp_ctx);
4011 return ldb_module_oom(module);
4014 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4016 if (ret != LDB_SUCCESS) {
4017 ldb_asprintf_errstring(ldb, __location__
4018 ": Failed to add lastKnownParent "
4019 "string when deleting %s",
4020 ldb_dn_get_linearized(old_dn));
4021 talloc_free(tmp_ctx);
4024 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4026 if (next_deletion_state == OBJECT_DELETED) {
4027 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4028 if (ret != LDB_SUCCESS) {
4029 ldb_asprintf_errstring(ldb, __location__
4030 ": Failed to add msDS-LastKnownRDN "
4031 "string when deleting %s",
4032 ldb_dn_get_linearized(old_dn));
4033 talloc_free(tmp_ctx);
4036 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
4040 switch (next_deletion_state) {
4042 case OBJECT_RECYCLED:
4043 case OBJECT_TOMBSTONE:
4046 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4047 * describes what must be removed from a tombstone
4050 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4051 * describes what must be removed from a recycled
4057 * we also mark it as recycled, meaning this object can't be
4058 * recovered (we are stripping its attributes).
4059 * This is done only if we have this schema object of course ...
4060 * This behavior is identical to the one of Windows 2008R2 which
4061 * always set the isRecycled attribute, even if the recycle-bin is
4062 * not activated and what ever the forest level is.
4064 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4065 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
4066 if (ret != LDB_SUCCESS) {
4067 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4068 ldb_module_oom(module);
4069 talloc_free(tmp_ctx);
4072 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4075 /* work out which of the old attributes we will be removing */
4076 for (i=0; i<old_msg->num_elements; i++) {
4077 const struct dsdb_attribute *sa;
4078 el = &old_msg->elements[i];
4079 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4081 talloc_free(tmp_ctx);
4082 return LDB_ERR_OPERATIONS_ERROR;
4084 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4085 /* don't remove the rDN */
4088 if (sa->linkID && (sa->linkID & 1)) {
4090 we have a backlink in this object
4091 that needs to be removed. We're not
4092 allowed to remove it directly
4093 however, so we instead setup a
4094 modify to delete the corresponding
4097 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
4098 if (ret != LDB_SUCCESS) {
4099 const char *old_dn_str
4100 = ldb_dn_get_linearized(old_dn);
4101 ldb_asprintf_errstring(ldb,
4103 ": Failed to remove backlink of "
4104 "%s when deleting %s: %s",
4107 ldb_errstring(ldb));
4108 talloc_free(tmp_ctx);
4109 return LDB_ERR_OPERATIONS_ERROR;
4111 /* now we continue, which means we
4112 won't remove this backlink
4118 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4121 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4126 * Ensure that we tell the modification to vanish any linked
4127 * attributes (not simply mark them as isDeleted = TRUE)
4129 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4131 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4132 if (ret != LDB_SUCCESS) {
4133 talloc_free(tmp_ctx);
4134 ldb_module_oom(module);
4141 case OBJECT_DELETED:
4143 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4144 * describes what must be removed from a deleted
4148 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4149 if (ret != LDB_SUCCESS) {
4150 talloc_free(tmp_ctx);
4151 ldb_module_oom(module);
4155 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4156 if (ret != LDB_SUCCESS) {
4157 talloc_free(tmp_ctx);
4158 ldb_module_oom(module);
4168 if (deletion_state == OBJECT_NOT_DELETED) {
4169 const struct dsdb_attribute *sa;
4171 /* work out what the new rdn value is, for updating the
4172 rDN and name fields */
4173 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4174 if (new_rdn_value == NULL) {
4175 talloc_free(tmp_ctx);
4176 return ldb_operr(ldb);
4179 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4181 talloc_free(tmp_ctx);
4182 return LDB_ERR_OPERATIONS_ERROR;
4185 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4187 if (ret != LDB_SUCCESS) {
4188 talloc_free(tmp_ctx);
4191 el->flags = LDB_FLAG_MOD_REPLACE;
4193 el = ldb_msg_find_element(old_msg, "name");
4195 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4196 if (ret != LDB_SUCCESS) {
4197 talloc_free(tmp_ctx);
4200 el->flags = LDB_FLAG_MOD_REPLACE;
4205 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4210 * No matter what has happned with other renames, try again to
4211 * get this to be under the deleted DN.
4213 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4214 /* now rename onto the new DN */
4215 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4216 if (ret != LDB_SUCCESS){
4217 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4218 ldb_dn_get_linearized(old_dn),
4219 ldb_dn_get_linearized(new_dn),
4220 ldb_errstring(ldb)));
4221 talloc_free(tmp_ctx);
4227 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4228 if (ret != LDB_SUCCESS) {
4229 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4230 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4231 talloc_free(tmp_ctx);
4235 talloc_free(tmp_ctx);
4237 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4240 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4242 return replmd_delete_internals(module, req, false);
4246 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4251 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4253 int ret = LDB_ERR_OTHER;
4254 /* TODO: do some error mapping */
4256 /* Let the caller know the full WERROR */
4257 ar->objs->error = status;
4263 static struct replPropertyMetaData1 *
4264 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4265 enum drsuapi_DsAttributeId attid)
4268 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4270 for (i = 0; i < rpmd_ctr->count; i++) {
4271 if (rpmd_ctr->array[i].attid == attid) {
4272 return &rpmd_ctr->array[i];
4280 return true if an update is newer than an existing entry
4281 see section 5.11 of MS-ADTS
4283 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4284 const struct GUID *update_invocation_id,
4285 uint32_t current_version,
4286 uint32_t update_version,
4287 NTTIME current_change_time,
4288 NTTIME update_change_time)
4290 if (update_version != current_version) {
4291 return update_version > current_version;
4293 if (update_change_time != current_change_time) {
4294 return update_change_time > current_change_time;
4296 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4299 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4300 struct replPropertyMetaData1 *new_m)
4302 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4303 &new_m->originating_invocation_id,
4306 cur_m->originating_change_time,
4307 new_m->originating_change_time);
4310 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4311 struct replPropertyMetaData1 *cur_m,
4312 struct replPropertyMetaData1 *new_m)
4317 * If the new replPropertyMetaData entry for this attribute is
4318 * not provided (this happens in the case where we look for
4319 * ATTID_name, but the name was not changed), then the local
4320 * state is clearly still current, as the remote
4321 * server didn't send it due to being older the high watermark
4324 if (new_m == NULL) {
4328 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4330 * if we compare equal then do an
4331 * update. This is used when a client
4332 * asks for a FULL_SYNC, and can be
4333 * used to recover a corrupt
4336 * This call is a bit tricky, what we
4337 * are doing it turning the 'is_newer'
4338 * call into a 'not is older' by
4339 * swapping cur_m and new_m, and negating the
4342 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4345 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4355 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4357 const struct ldb_val *rdn_val;
4358 const char *rdn_name;
4359 struct ldb_dn *new_dn;
4361 rdn_val = ldb_dn_get_rdn_val(dn);
4362 rdn_name = ldb_dn_get_rdn_name(dn);
4363 if (!rdn_val || !rdn_name) {
4367 new_dn = ldb_dn_copy(mem_ctx, dn);
4372 if (!ldb_dn_remove_child_components(new_dn, 1)) {
4376 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4378 ldb_dn_escape_value(new_dn, *rdn_val),
4379 GUID_string(new_dn, guid))) {
4388 perform a modify operation which sets the rDN and name attributes to
4389 their current values. This has the effect of changing these
4390 attributes to have been last updated by the current DC. This is
4391 needed to ensure that renames performed as part of conflict
4392 resolution are propogated to other DCs
4394 static int replmd_name_modify(struct replmd_replicated_request *ar,
4395 struct ldb_request *req, struct ldb_dn *dn)
4397 struct ldb_message *msg;
4398 const char *rdn_name;
4399 const struct ldb_val *rdn_val;
4400 const struct dsdb_attribute *rdn_attr;
4403 msg = ldb_msg_new(req);
4409 rdn_name = ldb_dn_get_rdn_name(dn);
4410 if (rdn_name == NULL) {
4414 /* normalize the rdn attribute name */
4415 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4416 if (rdn_attr == NULL) {
4419 rdn_name = rdn_attr->lDAPDisplayName;
4421 rdn_val = ldb_dn_get_rdn_val(dn);
4422 if (rdn_val == NULL) {
4426 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4429 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4432 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4435 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4439 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4440 if (ret != LDB_SUCCESS) {
4441 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
4442 ldb_dn_get_linearized(dn),
4443 ldb_errstring(ldb_module_get_ctx(ar->module))));
4453 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
4454 ldb_dn_get_linearized(dn)));
4455 return LDB_ERR_OPERATIONS_ERROR;
4460 callback for conflict DN handling where we have renamed the incoming
4461 record. After renaming it, we need to ensure the change of name and
4462 rDN for the incoming record is seen as an originating update by this DC.
4464 This also handles updating lastKnownParent for entries sent to lostAndFound
4466 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4468 struct replmd_replicated_request *ar =
4469 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4470 struct ldb_dn *conflict_dn = NULL;
4473 if (ares->error != LDB_SUCCESS) {
4474 /* call the normal callback for everything except success */
4475 return replmd_op_callback(req, ares);
4478 switch (req->operation) {
4480 conflict_dn = req->op.add.message->dn;
4483 conflict_dn = req->op.mod.message->dn;
4486 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4489 /* perform a modify of the rDN and name of the record */
4490 ret = replmd_name_modify(ar, req, conflict_dn);
4491 if (ret != LDB_SUCCESS) {
4493 return replmd_op_callback(req, ares);
4496 if (ar->objs->objects[ar->index_current].last_known_parent) {
4497 struct ldb_message *msg = ldb_msg_new(req);
4499 ldb_module_oom(ar->module);
4500 return LDB_ERR_OPERATIONS_ERROR;
4503 msg->dn = req->op.add.message->dn;
4505 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4506 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4507 if (ret != LDB_SUCCESS) {
4508 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4509 ldb_module_oom(ar->module);
4512 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4514 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4515 if (ret != LDB_SUCCESS) {
4516 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4517 ldb_dn_get_linearized(msg->dn),
4518 ldb_errstring(ldb_module_get_ctx(ar->module))));
4524 return replmd_op_callback(req, ares);
4528 callback for replmd_replicated_apply_add()
4529 This copes with the creation of conflict records in the case where
4530 the DN exists, but with a different objectGUID
4532 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))
4534 struct ldb_dn *conflict_dn;
4535 struct replmd_replicated_request *ar =
4536 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4537 struct ldb_result *res;
4538 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4540 const struct ldb_val *omd_value;
4541 struct replPropertyMetaDataBlob omd, *rmd;
4542 enum ndr_err_code ndr_err;
4543 bool rename_incoming_record, rodc;
4544 struct replPropertyMetaData1 *rmd_name, *omd_name;
4545 struct ldb_message *msg;
4546 struct ldb_request *down_req = NULL;
4548 /* call the normal callback for success */
4549 if (ares->error == LDB_SUCCESS) {
4550 return callback(req, ares);
4554 * we have a conflict, and need to decide if we will keep the
4555 * new record or the old record
4558 msg = ar->objs->objects[ar->index_current].msg;
4559 conflict_dn = msg->dn;
4561 /* For failures other than conflicts, fail the whole operation here */
4562 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4563 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4564 ldb_dn_get_linearized(conflict_dn),
4565 ldb_errstring(ldb_module_get_ctx(ar->module)));
4567 return ldb_module_done(ar->req, NULL, NULL,
4568 LDB_ERR_OPERATIONS_ERROR);
4571 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4572 if (ret != LDB_SUCCESS) {
4573 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)));
4574 return ldb_module_done(ar->req, NULL, NULL,
4575 LDB_ERR_OPERATIONS_ERROR);
4581 * We are on an RODC, or were a GC for this
4582 * partition, so we have to fail this until
4583 * someone who owns the partition sorts it
4586 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4587 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
4588 " - We must fail the operation until a master for this partition resolves the conflict",
4589 ldb_dn_get_linearized(conflict_dn));
4594 * first we need the replPropertyMetaData attribute from the
4595 * local, conflicting record
4597 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4599 DSDB_FLAG_NEXT_MODULE |
4600 DSDB_SEARCH_SHOW_DELETED |
4601 DSDB_SEARCH_SHOW_RECYCLED, req);
4602 if (ret != LDB_SUCCESS) {
4603 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4604 ldb_dn_get_linearized(conflict_dn)));
4608 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4609 if (omd_value == NULL) {
4610 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4611 ldb_dn_get_linearized(conflict_dn)));
4615 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4616 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4617 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4618 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4619 ldb_dn_get_linearized(conflict_dn)));
4623 rmd = ar->objs->objects[ar->index_current].meta_data;
4626 * we decide which is newer based on the RPMD on the name
4627 * attribute. See [MS-DRSR] ResolveNameConflict.
4629 * We expect omd_name to be present, as this is from a local
4630 * search, but while rmd_name should have been given to us by
4631 * the remote server, if it is missing we just prefer the
4633 * replmd_replPropertyMetaData1_new_should_be_taken()
4635 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4636 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4638 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4639 ldb_dn_get_linearized(conflict_dn)));
4644 * Should we preserve the current record, and so rename the
4645 * incoming record to be a conflict?
4647 rename_incoming_record
4648 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4649 omd_name, rmd_name);
4651 if (rename_incoming_record) {
4653 struct ldb_dn *new_dn;
4655 guid = samdb_result_guid(msg, "objectGUID");
4656 if (GUID_all_zero(&guid)) {
4657 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4658 ldb_dn_get_linearized(conflict_dn)));
4661 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4662 if (new_dn == NULL) {
4663 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4664 ldb_dn_get_linearized(conflict_dn)));
4668 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4669 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4671 /* re-submit the request, but with the new DN */
4672 callback = replmd_op_name_modify_callback;
4675 /* we are renaming the existing record */
4677 struct ldb_dn *new_dn;
4679 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4680 if (GUID_all_zero(&guid)) {
4681 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4682 ldb_dn_get_linearized(conflict_dn)));
4686 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4687 if (new_dn == NULL) {
4688 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4689 ldb_dn_get_linearized(conflict_dn)));
4693 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4694 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4696 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4697 DSDB_FLAG_OWN_MODULE, req);
4698 if (ret != LDB_SUCCESS) {
4699 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4700 ldb_dn_get_linearized(conflict_dn),
4701 ldb_dn_get_linearized(new_dn),
4702 ldb_errstring(ldb_module_get_ctx(ar->module))));
4707 * now we need to ensure that the rename is seen as an
4708 * originating update. We do that with a modify.
4710 ret = replmd_name_modify(ar, req, new_dn);
4711 if (ret != LDB_SUCCESS) {
4715 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4716 ldb_dn_get_linearized(req->op.add.message->dn)));
4719 ret = ldb_build_add_req(&down_req,
4720 ldb_module_get_ctx(ar->module),
4727 if (ret != LDB_SUCCESS) {
4730 LDB_REQ_SET_LOCATION(down_req);
4732 /* current partition control needed by "repmd_op_callback" */
4733 ret = ldb_request_add_control(down_req,
4734 DSDB_CONTROL_CURRENT_PARTITION_OID,
4736 if (ret != LDB_SUCCESS) {
4737 return replmd_replicated_request_error(ar, ret);
4740 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4741 /* this tells the partition module to make it a
4742 partial replica if creating an NC */
4743 ret = ldb_request_add_control(down_req,
4744 DSDB_CONTROL_PARTIAL_REPLICA,
4746 if (ret != LDB_SUCCESS) {
4747 return replmd_replicated_request_error(ar, ret);
4752 * Finally we re-run the add, otherwise the new record won't
4753 * exist, as we are here because of that exact failure!
4755 return ldb_next_request(ar->module, down_req);
4758 /* on failure make the caller get the error. This means
4759 * replication will stop with an error, but there is not much
4762 return ldb_module_done(ar->req, NULL, NULL,
4767 callback for replmd_replicated_apply_add()
4768 This copes with the creation of conflict records in the case where
4769 the DN exists, but with a different objectGUID
4771 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4773 struct replmd_replicated_request *ar =
4774 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4776 if (ar->objs->objects[ar->index_current].last_known_parent) {
4777 /* This is like a conflict DN, where we put the object in LostAndFound
4778 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4779 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4782 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4786 this is called when a new object comes in over DRS
4788 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4790 struct ldb_context *ldb;
4791 struct ldb_request *change_req;
4792 enum ndr_err_code ndr_err;
4793 struct ldb_message *msg;
4794 struct replPropertyMetaDataBlob *md;
4795 struct ldb_val md_value;
4798 bool remote_isDeleted = false;
4801 time_t t = time(NULL);
4802 const struct ldb_val *rdn_val;
4803 struct replmd_private *replmd_private =
4804 talloc_get_type(ldb_module_get_private(ar->module),
4805 struct replmd_private);
4806 unix_to_nt_time(&now, t);
4808 ldb = ldb_module_get_ctx(ar->module);
4809 msg = ar->objs->objects[ar->index_current].msg;
4810 md = ar->objs->objects[ar->index_current].meta_data;
4811 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4813 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4814 if (ret != LDB_SUCCESS) {
4815 return replmd_replicated_request_error(ar, ret);
4818 ret = dsdb_msg_add_guid(msg,
4819 &ar->objs->objects[ar->index_current].object_guid,
4821 if (ret != LDB_SUCCESS) {
4822 return replmd_replicated_request_error(ar, ret);
4825 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4826 if (ret != LDB_SUCCESS) {
4827 return replmd_replicated_request_error(ar, ret);
4830 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4831 if (ret != LDB_SUCCESS) {
4832 return replmd_replicated_request_error(ar, ret);
4835 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4836 if (ret != LDB_SUCCESS) {
4837 return replmd_replicated_request_error(ar, ret);
4840 /* remove any message elements that have zero values */
4841 for (i=0; i<msg->num_elements; i++) {
4842 struct ldb_message_element *el = &msg->elements[i];
4844 if (el->num_values == 0) {
4845 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4846 ldb_asprintf_errstring(ldb, __location__
4847 ": empty objectClass sent on %s, aborting replication\n",
4848 ldb_dn_get_linearized(msg->dn));
4849 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4852 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4854 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4855 msg->num_elements--;
4862 struct GUID_txt_buf guid_txt;
4864 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4865 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4866 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4871 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4872 "isDeleted", false);
4875 * the meta data array is already sorted by the caller, except
4876 * for the RDN, which needs to be added.
4880 rdn_val = ldb_dn_get_rdn_val(msg->dn);
4881 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4882 md, ar, now, is_schema_nc);
4883 if (ret != LDB_SUCCESS) {
4884 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4885 return replmd_replicated_request_error(ar, ret);
4888 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4889 if (ret != LDB_SUCCESS) {
4890 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4891 return replmd_replicated_request_error(ar, ret);
4894 for (i=0; i < md->ctr.ctr1.count; i++) {
4895 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4897 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4898 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4899 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4900 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4901 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4903 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4904 if (ret != LDB_SUCCESS) {
4905 return replmd_replicated_request_error(ar, ret);
4908 replmd_ldb_message_sort(msg, ar->schema);
4910 if (!remote_isDeleted) {
4911 ret = dsdb_module_schedule_sd_propagation(ar->module,
4912 ar->objs->partition_dn,
4914 if (ret != LDB_SUCCESS) {
4915 return replmd_replicated_request_error(ar, ret);
4919 ar->isDeleted = remote_isDeleted;
4921 ret = ldb_build_add_req(&change_req,
4927 replmd_op_add_callback,
4929 LDB_REQ_SET_LOCATION(change_req);
4930 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4932 /* current partition control needed by "repmd_op_callback" */
4933 ret = ldb_request_add_control(change_req,
4934 DSDB_CONTROL_CURRENT_PARTITION_OID,
4936 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4938 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4939 /* this tells the partition module to make it a
4940 partial replica if creating an NC */
4941 ret = ldb_request_add_control(change_req,
4942 DSDB_CONTROL_PARTIAL_REPLICA,
4944 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4947 return ldb_next_request(ar->module, change_req);
4950 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
4951 struct ldb_reply *ares)
4953 struct replmd_replicated_request *ar = talloc_get_type(req->context,
4954 struct replmd_replicated_request);
4958 return ldb_module_done(ar->req, NULL, NULL,
4959 LDB_ERR_OPERATIONS_ERROR);
4963 * The error NO_SUCH_OBJECT is not expected, unless the search
4964 * base is the partition DN, and that case doesn't happen here
4965 * because then we wouldn't get a parent_guid_value in any
4968 if (ares->error != LDB_SUCCESS) {
4969 return ldb_module_done(ar->req, ares->controls,
4970 ares->response, ares->error);
4973 switch (ares->type) {
4974 case LDB_REPLY_ENTRY:
4976 struct ldb_message *parent_msg = ares->message;
4977 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
4978 struct ldb_dn *parent_dn;
4981 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
4982 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
4983 /* Per MS-DRSR 4.1.10.6.10
4984 * FindBestParentObject we need to move this
4985 * new object under a deleted object to
4987 struct ldb_dn *nc_root;
4989 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
4990 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4991 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4992 "No suitable NC root found for %s. "
4993 "We need to move this object because parent object %s "
4994 "is deleted, but this object is not.",
4995 ldb_dn_get_linearized(msg->dn),
4996 ldb_dn_get_linearized(parent_msg->dn));
4997 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4998 } else if (ret != LDB_SUCCESS) {
4999 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5000 "Unable to find NC root for %s: %s. "
5001 "We need to move this object because parent object %s "
5002 "is deleted, but this object is not.",
5003 ldb_dn_get_linearized(msg->dn),
5004 ldb_errstring(ldb_module_get_ctx(ar->module)),
5005 ldb_dn_get_linearized(parent_msg->dn));
5006 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5009 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5011 DS_GUID_LOSTANDFOUND_CONTAINER,
5013 if (ret != LDB_SUCCESS) {
5014 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5015 "Unable to find LostAndFound Container for %s "
5016 "in partition %s: %s. "
5017 "We need to move this object because parent object %s "
5018 "is deleted, but this object is not.",
5019 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5020 ldb_errstring(ldb_module_get_ctx(ar->module)),
5021 ldb_dn_get_linearized(parent_msg->dn));
5022 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5024 ar->objs->objects[ar->index_current].last_known_parent
5025 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5029 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5032 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5034 comp_num = ldb_dn_get_comp_num(msg->dn);
5036 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5038 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5041 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5043 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5047 case LDB_REPLY_REFERRAL:
5048 /* we ignore referrals */
5051 case LDB_REPLY_DONE:
5053 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5054 struct GUID_txt_buf str_buf;
5055 if (ar->search_msg != NULL) {
5056 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5057 "No parent with GUID %s found for object locally known as %s",
5058 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5059 ldb_dn_get_linearized(ar->search_msg->dn));
5061 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5062 "No parent with GUID %s found for object remotely known as %s",
5063 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5064 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5068 * This error code is really important, as it
5069 * is the flag back to the callers to retry
5070 * this with DRSUAPI_DRS_GET_ANC, and so get
5071 * the parent objects before the child
5074 return ldb_module_done(ar->req, NULL, NULL,
5075 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5078 if (ar->search_msg != NULL) {
5079 ret = replmd_replicated_apply_merge(ar);
5081 ret = replmd_replicated_apply_add(ar);
5083 if (ret != LDB_SUCCESS) {
5084 return ldb_module_done(ar->req, NULL, NULL, ret);
5093 * Look for the parent object, so we put the new object in the right
5094 * place This is akin to NameObject in MS-DRSR - this routine and the
5095 * callbacks find the right parent name, and correct name for this
5099 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5101 struct ldb_context *ldb;
5105 struct ldb_request *search_req;
5106 static const char *attrs[] = {"isDeleted", NULL};
5107 struct GUID_txt_buf guid_str_buf;
5109 ldb = ldb_module_get_ctx(ar->module);
5111 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5112 if (ar->search_msg != NULL) {
5113 return replmd_replicated_apply_merge(ar);
5115 return replmd_replicated_apply_add(ar);
5119 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5122 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5123 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5125 ret = ldb_build_search_req(&search_req,
5128 ar->objs->partition_dn,
5134 replmd_replicated_apply_search_for_parent_callback,
5136 LDB_REQ_SET_LOCATION(search_req);
5138 ret = dsdb_request_add_controls(search_req,
5139 DSDB_SEARCH_SHOW_RECYCLED|
5140 DSDB_SEARCH_SHOW_DELETED|
5141 DSDB_SEARCH_SHOW_EXTENDED_DN);
5142 if (ret != LDB_SUCCESS) {
5146 return ldb_next_request(ar->module, search_req);
5150 handle renames that come in over DRS replication
5152 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5153 struct ldb_message *msg,
5154 struct ldb_request *parent,
5158 TALLOC_CTX *tmp_ctx = talloc_new(msg);
5159 struct ldb_result *res;
5160 struct ldb_dn *conflict_dn;
5161 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5162 const struct ldb_val *omd_value;
5163 struct replPropertyMetaDataBlob omd, *rmd;
5164 enum ndr_err_code ndr_err;
5165 bool rename_incoming_record, rodc;
5166 struct replPropertyMetaData1 *rmd_name, *omd_name;
5167 struct ldb_dn *new_dn;
5170 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5171 ldb_dn_get_linearized(ar->search_msg->dn),
5172 ldb_dn_get_linearized(msg->dn)));
5175 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5176 DSDB_FLAG_NEXT_MODULE, ar->req);
5177 if (ret == LDB_SUCCESS) {
5178 talloc_free(tmp_ctx);
5183 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5184 talloc_free(tmp_ctx);
5185 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5186 ldb_dn_get_linearized(ar->search_msg->dn),
5187 ldb_dn_get_linearized(msg->dn),
5188 ldb_errstring(ldb_module_get_ctx(ar->module)));
5192 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5193 if (ret != LDB_SUCCESS) {
5194 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5195 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5196 ldb_errstring(ldb_module_get_ctx(ar->module)));
5197 return LDB_ERR_OPERATIONS_ERROR;
5200 * we have a conflict, and need to decide if we will keep the
5201 * new record or the old record
5204 conflict_dn = msg->dn;
5208 * We are on an RODC, or were a GC for this
5209 * partition, so we have to fail this until
5210 * someone who owns the partition sorts it
5213 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5214 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5215 " - We must fail the operation until a master for this partition resolves the conflict",
5216 ldb_dn_get_linearized(conflict_dn));
5221 * first we need the replPropertyMetaData attribute from the
5224 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5226 DSDB_FLAG_NEXT_MODULE |
5227 DSDB_SEARCH_SHOW_DELETED |
5228 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5229 if (ret != LDB_SUCCESS) {
5230 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5231 ldb_dn_get_linearized(conflict_dn)));
5235 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5236 if (omd_value == NULL) {
5237 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5238 ldb_dn_get_linearized(conflict_dn)));
5242 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5243 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5244 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5245 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5246 ldb_dn_get_linearized(conflict_dn)));
5250 rmd = ar->objs->objects[ar->index_current].meta_data;
5253 * we decide which is newer based on the RPMD on the name
5254 * attribute. See [MS-DRSR] ResolveNameConflict.
5256 * We expect omd_name to be present, as this is from a local
5257 * search, but while rmd_name should have been given to us by
5258 * the remote server, if it is missing we just prefer the
5260 * replmd_replPropertyMetaData1_new_should_be_taken()
5262 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5263 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5265 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5266 ldb_dn_get_linearized(conflict_dn)));
5271 * Should we preserve the current record, and so rename the
5272 * incoming record to be a conflict?
5274 rename_incoming_record =
5275 !replmd_replPropertyMetaData1_new_should_be_taken(
5276 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5277 omd_name, rmd_name);
5279 if (rename_incoming_record) {
5281 new_dn = replmd_conflict_dn(msg, msg->dn,
5282 &ar->objs->objects[ar->index_current].object_guid);
5283 if (new_dn == NULL) {
5284 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5285 "Failed to form conflict DN for %s\n",
5286 ldb_dn_get_linearized(msg->dn));
5288 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5291 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5292 DSDB_FLAG_NEXT_MODULE, ar->req);
5293 if (ret != LDB_SUCCESS) {
5294 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5295 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5296 ldb_dn_get_linearized(conflict_dn),
5297 ldb_dn_get_linearized(ar->search_msg->dn),
5298 ldb_dn_get_linearized(new_dn),
5299 ldb_errstring(ldb_module_get_ctx(ar->module)));
5300 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5308 /* we are renaming the existing record */
5310 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5311 if (GUID_all_zero(&guid)) {
5312 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5313 ldb_dn_get_linearized(conflict_dn)));
5317 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5318 if (new_dn == NULL) {
5319 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5320 ldb_dn_get_linearized(conflict_dn)));
5324 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5325 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5327 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5328 DSDB_FLAG_OWN_MODULE, ar->req);
5329 if (ret != LDB_SUCCESS) {
5330 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5331 ldb_dn_get_linearized(conflict_dn),
5332 ldb_dn_get_linearized(new_dn),
5333 ldb_errstring(ldb_module_get_ctx(ar->module))));
5338 * now we need to ensure that the rename is seen as an
5339 * originating update. We do that with a modify.
5341 ret = replmd_name_modify(ar, ar->req, new_dn);
5342 if (ret != LDB_SUCCESS) {
5346 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5347 ldb_dn_get_linearized(ar->search_msg->dn),
5348 ldb_dn_get_linearized(msg->dn)));
5351 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5352 DSDB_FLAG_NEXT_MODULE, ar->req);
5353 if (ret != LDB_SUCCESS) {
5354 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5355 ldb_dn_get_linearized(ar->search_msg->dn),
5356 ldb_dn_get_linearized(msg->dn),
5357 ldb_errstring(ldb_module_get_ctx(ar->module))));
5363 * On failure make the caller get the error
5364 * This means replication will stop with an error,
5365 * but there is not much else we can do. In the
5366 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5370 talloc_free(tmp_ctx);
5375 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5377 struct ldb_context *ldb;
5378 struct ldb_request *change_req;
5379 enum ndr_err_code ndr_err;
5380 struct ldb_message *msg;
5381 struct replPropertyMetaDataBlob *rmd;
5382 struct replPropertyMetaDataBlob omd;
5383 const struct ldb_val *omd_value;
5384 struct replPropertyMetaDataBlob nmd;
5385 struct ldb_val nmd_value;
5386 struct GUID remote_parent_guid;
5389 unsigned int removed_attrs = 0;
5391 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5392 bool isDeleted = false;
5393 bool local_isDeleted = false;
5394 bool remote_isDeleted = false;
5395 bool take_remote_isDeleted = false;
5396 bool sd_updated = false;
5397 bool renamed = false;
5398 bool is_schema_nc = false;
5400 const struct ldb_val *old_rdn, *new_rdn;
5401 struct replmd_private *replmd_private =
5402 talloc_get_type(ldb_module_get_private(ar->module),
5403 struct replmd_private);
5405 time_t t = time(NULL);
5406 unix_to_nt_time(&now, t);
5408 ldb = ldb_module_get_ctx(ar->module);
5409 msg = ar->objs->objects[ar->index_current].msg;
5411 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5413 rmd = ar->objs->objects[ar->index_current].meta_data;
5417 /* find existing meta data */
5418 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5420 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5421 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5422 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5423 nt_status = ndr_map_error2ntstatus(ndr_err);
5424 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5427 if (omd.version != 1) {
5428 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5433 struct GUID_txt_buf guid_txt;
5435 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5436 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
5439 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5441 ndr_print_struct_string(s,
5442 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5443 "existing replPropertyMetaData",
5445 ndr_print_struct_string(s,
5446 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5447 "incoming replPropertyMetaData",
5452 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5453 "isDeleted", false);
5454 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5455 "isDeleted", false);
5458 * Fill in the remote_parent_guid with the GUID or an all-zero
5461 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5462 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5464 remote_parent_guid = GUID_zero();
5468 * To ensure we follow a complex rename chain around, we have
5469 * to confirm that the DN is the same (mostly to confirm the
5470 * RDN) and the parentGUID is the same.
5472 * This ensures we keep things under the correct parent, which
5473 * replmd_replicated_handle_rename() will do.
5476 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5477 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5481 * handle renames, even just by case that come in over
5482 * DRS. Changes in the parent DN don't hit us here,
5483 * because the search for a parent will clean up those
5486 * We also have already filtered out the case where
5487 * the peer has an older name to what we have (see
5488 * replmd_replicated_apply_search_callback())
5490 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5493 if (ret != LDB_SUCCESS) {
5494 ldb_debug(ldb, LDB_DEBUG_FATAL,
5495 "replmd_replicated_request rename %s => %s failed - %s\n",
5496 ldb_dn_get_linearized(ar->search_msg->dn),
5497 ldb_dn_get_linearized(msg->dn),
5498 ldb_errstring(ldb));
5499 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5502 if (renamed == true) {
5504 * Set the callback to one that will fix up the name
5505 * metadata on the new conflict DN
5507 callback = replmd_op_name_modify_callback;
5512 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5513 nmd.ctr.ctr1.array = talloc_array(ar,
5514 struct replPropertyMetaData1,
5515 nmd.ctr.ctr1.count);
5516 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5518 /* first copy the old meta data */
5519 for (i=0; i < omd.ctr.ctr1.count; i++) {
5520 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5525 /* now merge in the new meta data */
5526 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5529 for (j=0; j < ni; j++) {
5532 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5536 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5537 ar->objs->dsdb_repl_flags,
5538 &nmd.ctr.ctr1.array[j],
5539 &rmd->ctr.ctr1.array[i]);
5541 /* replace the entry */
5542 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5543 if (ar->seq_num == 0) {
5544 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5545 if (ret != LDB_SUCCESS) {
5546 return replmd_replicated_request_error(ar, ret);
5549 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5550 switch (nmd.ctr.ctr1.array[j].attid) {
5551 case DRSUAPI_ATTID_ntSecurityDescriptor:
5554 case DRSUAPI_ATTID_isDeleted:
5555 take_remote_isDeleted = true;
5564 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5565 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5566 msg->elements[i-removed_attrs].name,
5567 ldb_dn_get_linearized(msg->dn),
5568 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5571 /* we don't want to apply this change so remove the attribute */
5572 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5579 if (found) continue;
5581 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5582 if (ar->seq_num == 0) {
5583 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5584 if (ret != LDB_SUCCESS) {
5585 return replmd_replicated_request_error(ar, ret);
5588 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5589 switch (nmd.ctr.ctr1.array[ni].attid) {
5590 case DRSUAPI_ATTID_ntSecurityDescriptor:
5593 case DRSUAPI_ATTID_isDeleted:
5594 take_remote_isDeleted = true;
5603 * finally correct the size of the meta_data array
5605 nmd.ctr.ctr1.count = ni;
5607 new_rdn = ldb_dn_get_rdn_val(msg->dn);
5608 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5611 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5612 &nmd, ar, now, is_schema_nc);
5613 if (ret != LDB_SUCCESS) {
5614 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5615 return replmd_replicated_request_error(ar, ret);
5619 * sort the new meta data array
5621 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5622 if (ret != LDB_SUCCESS) {
5623 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5628 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
5631 * This also controls SD propagation below
5633 if (take_remote_isDeleted) {
5634 isDeleted = remote_isDeleted;
5636 isDeleted = local_isDeleted;
5639 ar->isDeleted = isDeleted;
5642 * check if some replicated attributes left, otherwise skip the ldb_modify() call
5644 if (msg->num_elements == 0) {
5645 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5648 return replmd_replicated_apply_isDeleted(ar);
5651 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5652 ar->index_current, msg->num_elements);
5658 if (sd_updated && !isDeleted) {
5659 ret = dsdb_module_schedule_sd_propagation(ar->module,
5660 ar->objs->partition_dn,
5662 if (ret != LDB_SUCCESS) {
5663 return ldb_operr(ldb);
5667 /* create the meta data value */
5668 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5669 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5670 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5671 nt_status = ndr_map_error2ntstatus(ndr_err);
5672 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5676 * when we know that we'll modify the record, add the whenChanged, uSNChanged
5677 * and replPopertyMetaData attributes
5679 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5680 if (ret != LDB_SUCCESS) {
5681 return replmd_replicated_request_error(ar, ret);
5683 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5684 if (ret != LDB_SUCCESS) {
5685 return replmd_replicated_request_error(ar, ret);
5687 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5688 if (ret != LDB_SUCCESS) {
5689 return replmd_replicated_request_error(ar, ret);
5692 replmd_ldb_message_sort(msg, ar->schema);
5694 /* we want to replace the old values */
5695 for (i=0; i < msg->num_elements; i++) {
5696 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5697 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5698 if (msg->elements[i].num_values == 0) {
5699 ldb_asprintf_errstring(ldb, __location__
5700 ": objectClass removed on %s, aborting replication\n",
5701 ldb_dn_get_linearized(msg->dn));
5702 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5708 struct GUID_txt_buf guid_txt;
5710 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5711 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5712 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5717 ret = ldb_build_mod_req(&change_req,
5725 LDB_REQ_SET_LOCATION(change_req);
5726 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5728 /* current partition control needed by "repmd_op_callback" */
5729 ret = ldb_request_add_control(change_req,
5730 DSDB_CONTROL_CURRENT_PARTITION_OID,
5732 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5734 return ldb_next_request(ar->module, change_req);
5737 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5738 struct ldb_reply *ares)
5740 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5741 struct replmd_replicated_request);
5745 return ldb_module_done(ar->req, NULL, NULL,
5746 LDB_ERR_OPERATIONS_ERROR);
5748 if (ares->error != LDB_SUCCESS &&
5749 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5750 return ldb_module_done(ar->req, ares->controls,
5751 ares->response, ares->error);
5754 switch (ares->type) {
5755 case LDB_REPLY_ENTRY:
5756 ar->search_msg = talloc_steal(ar, ares->message);
5759 case LDB_REPLY_REFERRAL:
5760 /* we ignore referrals */
5763 case LDB_REPLY_DONE:
5765 struct replPropertyMetaData1 *md_remote;
5766 struct replPropertyMetaData1 *md_local;
5768 struct replPropertyMetaDataBlob omd;
5769 const struct ldb_val *omd_value;
5770 struct replPropertyMetaDataBlob *rmd;
5771 struct ldb_message *msg;
5773 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5774 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5777 * This is the ADD case, find the appropriate parent,
5778 * as this object doesn't exist locally:
5780 if (ar->search_msg == NULL) {
5781 ret = replmd_replicated_apply_search_for_parent(ar);
5782 if (ret != LDB_SUCCESS) {
5783 return ldb_module_done(ar->req, NULL, NULL, ret);
5790 * Otherwise, in the MERGE case, work out if we are
5791 * attempting a rename, and if so find the parent the
5792 * newly renamed object wants to belong under (which
5793 * may not be the parent in it's attached string DN
5795 rmd = ar->objs->objects[ar->index_current].meta_data;
5799 /* find existing meta data */
5800 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5802 enum ndr_err_code ndr_err;
5803 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5804 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5805 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5806 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5807 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5810 if (omd.version != 1) {
5811 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5815 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5817 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5818 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5819 && GUID_all_zero(&ar->local_parent_guid)) {
5820 DEBUG(0, ("Refusing to replicate new version of %s "
5821 "as local object has an all-zero parentGUID attribute, "
5822 "despite not being an NC root\n",
5823 ldb_dn_get_linearized(ar->search_msg->dn)));
5824 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5828 * now we need to check for double renames. We could have a
5829 * local rename pending which our replication partner hasn't
5830 * received yet. We choose which one wins by looking at the
5831 * attribute stamps on the two objects, the newer one wins.
5833 * This also simply applies the correct algorithms for
5834 * determining if a change was made to name at all, or
5835 * if the object has just been renamed under the same
5838 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5839 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5841 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5842 ldb_dn_get_linearized(ar->search_msg->dn)));
5843 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5847 * if there is no name attribute given then we have to assume the
5848 * object we've received has the older name
5850 if (replmd_replPropertyMetaData1_new_should_be_taken(
5851 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5852 md_local, md_remote)) {
5853 struct GUID_txt_buf p_guid_local;
5854 struct GUID_txt_buf p_guid_remote;
5855 msg = ar->objs->objects[ar->index_current].msg;
5857 /* Merge on the existing object, with rename */
5859 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5860 "as incoming object changing to %s under %s\n",
5861 ldb_dn_get_linearized(ar->search_msg->dn),
5862 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5863 ldb_dn_get_linearized(msg->dn),
5864 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5866 ret = replmd_replicated_apply_search_for_parent(ar);
5868 struct GUID_txt_buf p_guid_local;
5869 struct GUID_txt_buf p_guid_remote;
5870 msg = ar->objs->objects[ar->index_current].msg;
5873 * Merge on the existing object, force no
5874 * rename (code below just to explain why in
5878 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5879 ldb_dn_get_linearized(msg->dn)) == 0) {
5880 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5881 GUID_equal(&ar->local_parent_guid,
5882 ar->objs->objects[ar->index_current].parent_guid)
5884 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5885 "despite incoming object changing parent to %s\n",
5886 ldb_dn_get_linearized(ar->search_msg->dn),
5887 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5888 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5892 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5893 " and rejecting older rename to %s under %s\n",
5894 ldb_dn_get_linearized(ar->search_msg->dn),
5895 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5896 ldb_dn_get_linearized(msg->dn),
5897 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5901 * This assignment ensures that the strcmp()
5902 * and GUID_equal() calls in
5903 * replmd_replicated_apply_merge() avoids the
5906 ar->objs->objects[ar->index_current].parent_guid =
5907 &ar->local_parent_guid;
5909 msg->dn = ar->search_msg->dn;
5910 ret = replmd_replicated_apply_merge(ar);
5912 if (ret != LDB_SUCCESS) {
5913 return ldb_module_done(ar->req, NULL, NULL, ret);
5922 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
5924 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
5926 struct ldb_context *ldb;
5930 struct ldb_request *search_req;
5931 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
5932 "parentGUID", "instanceType",
5933 "replPropertyMetaData", "nTSecurityDescriptor",
5934 "isDeleted", NULL };
5935 struct GUID_txt_buf guid_str_buf;
5937 if (ar->index_current >= ar->objs->num_objects) {
5938 /* done with it, go to next stage */
5939 return replmd_replicated_uptodate_vector(ar);
5942 ldb = ldb_module_get_ctx(ar->module);
5943 ar->search_msg = NULL;
5944 ar->isDeleted = false;
5946 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5949 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5950 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5952 ret = ldb_build_search_req(&search_req,
5955 ar->objs->partition_dn,
5961 replmd_replicated_apply_search_callback,
5963 LDB_REQ_SET_LOCATION(search_req);
5965 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
5967 if (ret != LDB_SUCCESS) {
5971 return ldb_next_request(ar->module, search_req);
5975 * This is essentially a wrapper for replmd_replicated_apply_next()
5977 * This is needed to ensure that both codepaths call this handler.
5979 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
5981 struct ldb_dn *deleted_objects_dn;
5982 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5983 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
5984 &deleted_objects_dn);
5985 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
5987 * Do a delete here again, so that if there is
5988 * anything local that conflicts with this
5989 * object being deleted, it is removed. This
5990 * includes links. See MS-DRSR 4.1.10.6.9
5993 * If the object is already deleted, and there
5994 * is no more work required, it doesn't do
5998 /* This has been updated to point to the DN we eventually did the modify on */
6000 struct ldb_request *del_req;
6001 struct ldb_result *res;
6003 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6005 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6009 res = talloc_zero(tmp_ctx, struct ldb_result);
6011 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6012 talloc_free(tmp_ctx);
6016 /* Build a delete request, which hopefully will artually turn into nothing */
6017 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6021 ldb_modify_default_callback,
6023 LDB_REQ_SET_LOCATION(del_req);
6024 if (ret != LDB_SUCCESS) {
6025 talloc_free(tmp_ctx);
6030 * This is the guts of the call, call back
6031 * into our delete code, but setting the
6032 * re_delete flag so we delete anything that
6033 * shouldn't be there on a deleted or recycled
6036 ret = replmd_delete_internals(ar->module, del_req, true);
6037 if (ret == LDB_SUCCESS) {
6038 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6041 talloc_free(tmp_ctx);
6042 if (ret != LDB_SUCCESS) {
6047 ar->index_current++;
6048 return replmd_replicated_apply_next(ar);
6051 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6052 struct ldb_reply *ares)
6054 struct ldb_context *ldb;
6055 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6056 struct replmd_replicated_request);
6057 ldb = ldb_module_get_ctx(ar->module);
6060 return ldb_module_done(ar->req, NULL, NULL,
6061 LDB_ERR_OPERATIONS_ERROR);
6063 if (ares->error != LDB_SUCCESS) {
6064 return ldb_module_done(ar->req, ares->controls,
6065 ares->response, ares->error);
6068 if (ares->type != LDB_REPLY_DONE) {
6069 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6070 return ldb_module_done(ar->req, NULL, NULL,
6071 LDB_ERR_OPERATIONS_ERROR);
6076 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6079 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6081 struct ldb_context *ldb;
6082 struct ldb_request *change_req;
6083 enum ndr_err_code ndr_err;
6084 struct ldb_message *msg;
6085 struct replUpToDateVectorBlob ouv;
6086 const struct ldb_val *ouv_value;
6087 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6088 struct replUpToDateVectorBlob nuv;
6089 struct ldb_val nuv_value;
6090 struct ldb_message_element *nuv_el = NULL;
6091 struct ldb_message_element *orf_el = NULL;
6092 struct repsFromToBlob nrf;
6093 struct ldb_val *nrf_value = NULL;
6094 struct ldb_message_element *nrf_el = NULL;
6098 time_t t = time(NULL);
6101 uint32_t instanceType;
6103 ldb = ldb_module_get_ctx(ar->module);
6104 ruv = ar->objs->uptodateness_vector;
6110 unix_to_nt_time(&now, t);
6112 if (ar->search_msg == NULL) {
6113 /* this happens for a REPL_OBJ call where we are
6114 creating the target object by replicating it. The
6115 subdomain join code does this for the partition DN
6117 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6118 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6121 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6122 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6123 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6124 ldb_dn_get_linearized(ar->search_msg->dn)));
6125 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6129 * first create the new replUpToDateVector
6131 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6133 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6134 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6135 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6136 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6137 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6140 if (ouv.version != 2) {
6141 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6146 * the new uptodateness vector will at least
6147 * contain 1 entry, one for the source_dsa
6149 * plus optional values from our old vector and the one from the source_dsa
6151 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6152 if (ruv) nuv.ctr.ctr2.count += ruv->count;
6153 nuv.ctr.ctr2.cursors = talloc_array(ar,
6154 struct drsuapi_DsReplicaCursor2,
6155 nuv.ctr.ctr2.count);
6156 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6158 /* first copy the old vector */
6159 for (i=0; i < ouv.ctr.ctr2.count; i++) {
6160 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6164 /* merge in the source_dsa vector is available */
6165 for (i=0; (ruv && i < ruv->count); i++) {
6168 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6169 &ar->our_invocation_id)) {
6173 for (j=0; j < ni; j++) {
6174 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6175 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6181 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6182 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6187 if (found) continue;
6189 /* if it's not there yet, add it */
6190 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6195 * finally correct the size of the cursors array
6197 nuv.ctr.ctr2.count = ni;
6202 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6205 * create the change ldb_message
6207 msg = ldb_msg_new(ar);
6208 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6209 msg->dn = ar->search_msg->dn;
6211 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6212 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6213 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6214 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6215 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6217 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6218 if (ret != LDB_SUCCESS) {
6219 return replmd_replicated_request_error(ar, ret);
6221 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6224 * now create the new repsFrom value from the given repsFromTo1 structure
6228 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6229 nrf.ctr.ctr1.last_attempt = now;
6230 nrf.ctr.ctr1.last_success = now;
6231 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6234 * first see if we already have a repsFrom value for the current source dsa
6235 * if so we'll later replace this value
6237 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6239 for (i=0; i < orf_el->num_values; i++) {
6240 struct repsFromToBlob *trf;
6242 trf = talloc(ar, struct repsFromToBlob);
6243 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6245 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6246 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6247 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6248 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6249 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6252 if (trf->version != 1) {
6253 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6257 * we compare the source dsa objectGUID not the invocation_id
6258 * because we want only one repsFrom value per source dsa
6259 * and when the invocation_id of the source dsa has changed we don't need
6260 * the old repsFrom with the old invocation_id
6262 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6263 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6269 nrf_value = &orf_el->values[i];
6274 * copy over all old values to the new ldb_message
6276 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6277 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6282 * if we haven't found an old repsFrom value for the current source dsa
6283 * we'll add a new value
6286 struct ldb_val zero_value;
6287 ZERO_STRUCT(zero_value);
6288 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6289 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6291 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6294 /* we now fill the value which is already attached to ldb_message */
6295 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6297 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6298 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6299 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6300 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6304 * the ldb_message_element for the attribute, has all the old values and the new one
6305 * so we'll replace the whole attribute with all values
6307 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6309 if (CHECK_DEBUGLVL(4)) {
6310 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
6311 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6315 /* prepare the ldb_modify() request */
6316 ret = ldb_build_mod_req(&change_req,
6322 replmd_replicated_uptodate_modify_callback,
6324 LDB_REQ_SET_LOCATION(change_req);
6325 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6327 return ldb_next_request(ar->module, change_req);
6330 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6331 struct ldb_reply *ares)
6333 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6334 struct replmd_replicated_request);
6338 return ldb_module_done(ar->req, NULL, NULL,
6339 LDB_ERR_OPERATIONS_ERROR);
6341 if (ares->error != LDB_SUCCESS &&
6342 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6343 return ldb_module_done(ar->req, ares->controls,
6344 ares->response, ares->error);
6347 switch (ares->type) {
6348 case LDB_REPLY_ENTRY:
6349 ar->search_msg = talloc_steal(ar, ares->message);
6352 case LDB_REPLY_REFERRAL:
6353 /* we ignore referrals */
6356 case LDB_REPLY_DONE:
6357 ret = replmd_replicated_uptodate_modify(ar);
6358 if (ret != LDB_SUCCESS) {
6359 return ldb_module_done(ar->req, NULL, NULL, ret);
6368 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6370 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6371 struct replmd_private *replmd_private =
6372 talloc_get_type_abort(ldb_module_get_private(ar->module),
6373 struct replmd_private);
6375 static const char *attrs[] = {
6376 "replUpToDateVector",
6381 struct ldb_request *search_req;
6383 ar->search_msg = NULL;
6386 * Let the caller know that we did an originating updates
6388 ar->objs->originating_updates = replmd_private->originating_updates;
6390 ret = ldb_build_search_req(&search_req,
6393 ar->objs->partition_dn,
6399 replmd_replicated_uptodate_search_callback,
6401 LDB_REQ_SET_LOCATION(search_req);
6402 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6404 return ldb_next_request(ar->module, search_req);
6409 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6411 struct ldb_context *ldb;
6412 struct dsdb_extended_replicated_objects *objs;
6413 struct replmd_replicated_request *ar;
6414 struct ldb_control **ctrls;
6417 struct replmd_private *replmd_private =
6418 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6420 ldb = ldb_module_get_ctx(module);
6422 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6424 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6426 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6427 return LDB_ERR_PROTOCOL_ERROR;
6430 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6431 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6432 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6433 return LDB_ERR_PROTOCOL_ERROR;
6436 ar = replmd_ctx_init(module, req);
6438 return LDB_ERR_OPERATIONS_ERROR;
6440 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6441 ar->apply_mode = true;
6443 ar->schema = dsdb_get_schema(ldb, ar);
6445 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6447 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6448 return LDB_ERR_CONSTRAINT_VIOLATION;
6451 ctrls = req->controls;
6453 if (req->controls) {
6454 req->controls = talloc_memdup(ar, req->controls,
6455 talloc_get_size(req->controls));
6456 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6459 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6460 if (ret != LDB_SUCCESS) {
6464 /* If this change contained linked attributes in the body
6465 * (rather than in the links section) we need to update
6466 * backlinks in linked_attributes */
6467 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6468 if (ret != LDB_SUCCESS) {
6472 ar->controls = req->controls;
6473 req->controls = ctrls;
6475 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
6477 /* save away the linked attributes for the end of the
6479 for (i=0; i<ar->objs->linked_attributes_count; i++) {
6480 struct la_entry *la_entry;
6482 if (replmd_private->la_ctx == NULL) {
6483 replmd_private->la_ctx = talloc_new(replmd_private);
6485 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6486 if (la_entry == NULL) {
6488 return LDB_ERR_OPERATIONS_ERROR;
6490 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6491 if (la_entry->la == NULL) {
6492 talloc_free(la_entry);
6494 return LDB_ERR_OPERATIONS_ERROR;
6496 *la_entry->la = ar->objs->linked_attributes[i];
6498 /* we need to steal the non-scalars so they stay
6499 around until the end of the transaction */
6500 talloc_steal(la_entry->la, la_entry->la->identifier);
6501 talloc_steal(la_entry->la, la_entry->la->value.blob);
6503 DLIST_ADD(replmd_private->la_list, la_entry);
6506 return replmd_replicated_apply_next(ar);
6510 process one linked attribute structure
6512 static int replmd_process_linked_attribute(struct ldb_module *module,
6513 struct replmd_private *replmd_private,
6514 struct la_entry *la_entry,
6515 struct ldb_request *parent)
6517 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6518 struct ldb_context *ldb = ldb_module_get_ctx(module);
6519 struct ldb_message *msg;
6520 struct ldb_message *target_msg = NULL;
6521 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6522 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
6524 const struct dsdb_attribute *attr;
6525 struct dsdb_dn *dsdb_dn;
6526 uint64_t seq_num = 0;
6527 struct ldb_message_element *old_el;
6529 time_t t = time(NULL);
6530 struct ldb_result *res;
6531 struct ldb_result *target_res;
6532 const char *attrs[4];
6533 const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
6534 struct parsed_dn *pdn_list, *pdn, *next;
6535 struct GUID guid = GUID_zero();
6537 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
6538 const struct GUID *our_invocation_id;
6540 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
6541 enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
6544 linked_attributes[0]:
6545 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6547 identifier: struct drsuapi_DsReplicaObjectIdentifier
6548 __ndr_size : 0x0000003a (58)
6549 __ndr_size_sid : 0x00000000 (0)
6550 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6552 __ndr_size_dn : 0x00000000 (0)
6554 attid : DRSUAPI_ATTID_member (0x1F)
6555 value: struct drsuapi_DsAttributeValue
6556 __ndr_size : 0x0000007e (126)
6558 blob : DATA_BLOB length=126
6559 flags : 0x00000001 (1)
6560 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6561 originating_add_time : Wed Sep 2 22:20:01 2009 EST
6562 meta_data: struct drsuapi_DsReplicaMetaData
6563 version : 0x00000015 (21)
6564 originating_change_time : Wed Sep 2 23:39:07 2009 EST
6565 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6566 originating_usn : 0x000000000001e19c (123292)
6568 (for cases where the link is to a normal DN)
6569 &target: struct drsuapi_DsReplicaObjectIdentifier3
6570 __ndr_size : 0x0000007e (126)
6571 __ndr_size_sid : 0x0000001c (28)
6572 guid : 7639e594-db75-4086-b0d4-67890ae46031
6573 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
6574 __ndr_size_dn : 0x00000022 (34)
6575 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
6578 /* find the attribute being modified */
6579 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
6581 struct GUID_txt_buf guid_str;
6582 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
6584 GUID_buf_string(&la->identifier->guid,
6586 talloc_free(tmp_ctx);
6587 return LDB_ERR_OPERATIONS_ERROR;
6590 attrs[0] = attr->lDAPDisplayName;
6591 attrs[1] = "isDeleted";
6592 attrs[2] = "isRecycled";
6595 /* get the existing message from the db for the object with
6596 this GUID, returning attribute being modified. We will then
6597 use this msg as the basis for a modify call */
6598 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
6599 DSDB_FLAG_NEXT_MODULE |
6600 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6601 DSDB_SEARCH_SHOW_RECYCLED |
6602 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
6603 DSDB_SEARCH_REVEAL_INTERNALS,
6605 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
6606 if (ret != LDB_SUCCESS) {
6607 talloc_free(tmp_ctx);
6610 if (res->count != 1) {
6611 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
6612 GUID_string(tmp_ctx, &la->identifier->guid));
6613 talloc_free(tmp_ctx);
6614 return LDB_ERR_NO_SUCH_OBJECT;
6619 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6620 * ProcessLinkValue, because link updates are not applied to
6621 * recycled and tombstone objects. We don't have to delete
6622 * any existing link, that should have happened when the
6623 * object deletion was replicated or initiated.
6626 replmd_deletion_state(module, msg, &deletion_state, NULL);
6628 if (deletion_state >= OBJECT_RECYCLED) {
6629 talloc_free(tmp_ctx);
6633 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6634 if (old_el == NULL) {
6635 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
6636 if (ret != LDB_SUCCESS) {
6637 ldb_module_oom(module);
6638 talloc_free(tmp_ctx);
6639 return LDB_ERR_OPERATIONS_ERROR;
6642 old_el->flags = LDB_FLAG_MOD_REPLACE;
6645 /* parse the existing links */
6646 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
6647 attr->syntax->ldap_oid, parent);
6649 if (ret != LDB_SUCCESS) {
6650 talloc_free(tmp_ctx);
6654 /* get our invocationId */
6655 our_invocation_id = samdb_ntds_invocation_id(ldb);
6656 if (!our_invocation_id) {
6657 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
6658 talloc_free(tmp_ctx);
6659 return LDB_ERR_OPERATIONS_ERROR;
6662 ret = replmd_check_upgrade_links(ldb, pdn_list, old_el->num_values,
6663 old_el, our_invocation_id,
6664 attr->syntax->ldap_oid);
6665 if (ret != LDB_SUCCESS) {
6666 talloc_free(tmp_ctx);
6670 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
6671 if (!W_ERROR_IS_OK(status)) {
6672 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
6673 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
6674 talloc_free(tmp_ctx);
6675 return LDB_ERR_OPERATIONS_ERROR;
6678 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
6679 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6681 * This strange behaviour (allowing a NULL/missing
6682 * GUID) originally comes from:
6684 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6685 * Author: Andrew Tridgell <tridge@samba.org>
6686 * Date: Mon Dec 21 21:21:55 2009 +1100
6688 * s4-drs: cope better with NULL GUIDS from DRS
6690 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
6691 * need to match by DN if possible when seeing if we should update an
6694 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6697 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6698 dsdb_dn->dn, attrs2,
6699 DSDB_FLAG_NEXT_MODULE |
6700 DSDB_SEARCH_SHOW_RECYCLED |
6701 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6702 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6704 } else if (!NT_STATUS_IS_OK(ntstatus)) {
6705 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
6707 ldb_dn_get_linearized(dsdb_dn->dn),
6708 ldb_dn_get_linearized(msg->dn));
6709 talloc_free(tmp_ctx);
6710 return LDB_ERR_OPERATIONS_ERROR;
6712 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6713 NULL, LDB_SCOPE_SUBTREE,
6715 DSDB_FLAG_NEXT_MODULE |
6716 DSDB_SEARCH_SHOW_RECYCLED |
6717 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6718 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6721 GUID_string(tmp_ctx, &guid));
6724 if (ret != LDB_SUCCESS) {
6725 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6726 GUID_string(tmp_ctx, &guid),
6727 ldb_errstring(ldb_module_get_ctx(module)));
6728 talloc_free(tmp_ctx);
6732 if (target_res->count == 0) {
6733 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6734 GUID_string(tmp_ctx, &guid),
6735 ldb_dn_get_linearized(dsdb_dn->dn)));
6736 } else if (target_res->count != 1) {
6737 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6738 GUID_string(tmp_ctx, &guid));
6739 talloc_free(tmp_ctx);
6740 return LDB_ERR_OPERATIONS_ERROR;
6742 target_msg = target_res->msgs[0];
6743 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6747 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6748 * ProcessLinkValue, because link updates are not applied to
6749 * recycled and tombstone objects. We don't have to delete
6750 * any existing link, that should have happened when the
6751 * object deletion was replicated or initiated.
6753 replmd_deletion_state(module, target_msg,
6754 &target_deletion_state, NULL);
6756 if (target_deletion_state >= OBJECT_RECYCLED) {
6757 talloc_free(tmp_ctx);
6761 /* see if this link already exists */
6762 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
6766 attr->syntax->ldap_oid);
6767 if (ret != LDB_SUCCESS) {
6768 talloc_free(tmp_ctx);
6774 /* see if this update is newer than what we have already */
6775 struct GUID invocation_id = GUID_zero();
6776 uint32_t version = 0;
6777 uint32_t originating_usn = 0;
6778 NTTIME change_time = 0;
6779 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6781 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6782 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6783 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6784 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6786 if (!replmd_update_is_newer(&invocation_id,
6787 &la->meta_data.originating_invocation_id,
6789 la->meta_data.version,
6791 la->meta_data.originating_change_time)) {
6792 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6793 old_el->name, ldb_dn_get_linearized(msg->dn),
6794 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6795 talloc_free(tmp_ctx);
6799 /* get a seq_num for this change */
6800 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6801 if (ret != LDB_SUCCESS) {
6802 talloc_free(tmp_ctx);
6806 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6807 /* remove the existing backlink */
6808 ret = replmd_add_backlink(module, replmd_private,
6809 schema, &la->identifier->guid,
6810 &guid, false, attr, true);
6811 if (ret != LDB_SUCCESS) {
6812 talloc_free(tmp_ctx);
6817 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6818 &la->meta_data.originating_invocation_id,
6819 la->meta_data.originating_usn, seq_num,
6820 la->meta_data.originating_change_time,
6821 la->meta_data.version,
6823 if (ret != LDB_SUCCESS) {
6824 talloc_free(tmp_ctx);
6829 /* add the new backlink */
6830 ret = replmd_add_backlink(module, replmd_private,
6831 schema, &la->identifier->guid,
6832 &guid, true, attr, true);
6833 if (ret != LDB_SUCCESS) {
6834 talloc_free(tmp_ctx);
6840 /* get a seq_num for this change */
6841 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6842 if (ret != LDB_SUCCESS) {
6843 talloc_free(tmp_ctx);
6847 * We know where the new one needs to be, from the *next
6848 * pointer into pdn_list.
6851 offset = old_el->num_values;
6853 if (next->dsdb_dn == NULL) {
6854 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
6855 attr->syntax->ldap_oid);
6856 if (ret != LDB_SUCCESS) {
6860 offset = next - pdn_list;
6861 if (offset > old_el->num_values) {
6862 talloc_free(tmp_ctx);
6863 return LDB_ERR_OPERATIONS_ERROR;
6867 old_el->values = talloc_realloc(msg->elements, old_el->values,
6868 struct ldb_val, old_el->num_values+1);
6869 if (!old_el->values) {
6870 ldb_module_oom(module);
6871 return LDB_ERR_OPERATIONS_ERROR;
6874 if (offset != old_el->num_values) {
6875 memmove(&old_el->values[offset + 1], &old_el->values[offset],
6876 (old_el->num_values - offset) * sizeof(old_el->values[0]));
6879 old_el->num_values++;
6881 ret = replmd_build_la_val(tmp_ctx, &old_el->values[offset], dsdb_dn,
6882 &la->meta_data.originating_invocation_id,
6883 la->meta_data.originating_usn, seq_num,
6884 la->meta_data.originating_change_time,
6885 la->meta_data.version,
6887 if (ret != LDB_SUCCESS) {
6888 talloc_free(tmp_ctx);
6893 ret = replmd_add_backlink(module, replmd_private,
6894 schema, &la->identifier->guid,
6895 &guid, true, attr, true);
6896 if (ret != LDB_SUCCESS) {
6897 talloc_free(tmp_ctx);
6903 /* we only change whenChanged and uSNChanged if the seq_num
6905 ret = add_time_element(msg, "whenChanged", t);
6906 if (ret != LDB_SUCCESS) {
6907 talloc_free(tmp_ctx);
6912 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
6913 if (ret != LDB_SUCCESS) {
6914 talloc_free(tmp_ctx);
6919 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6920 if (old_el == NULL) {
6921 talloc_free(tmp_ctx);
6922 return ldb_operr(ldb);
6925 ret = dsdb_check_single_valued_link(attr, old_el);
6926 if (ret != LDB_SUCCESS) {
6927 talloc_free(tmp_ctx);
6931 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
6933 ret = linked_attr_modify(module, msg, parent);
6934 if (ret != LDB_SUCCESS) {
6935 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
6937 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
6938 talloc_free(tmp_ctx);
6942 talloc_free(tmp_ctx);
6947 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
6949 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
6950 return replmd_extended_replicated_objects(module, req);
6953 return ldb_next_request(module, req);
6958 we hook into the transaction operations to allow us to
6959 perform the linked attribute updates at the end of the whole
6960 transaction. This allows a forward linked attribute to be created
6961 before the object is created. During a vampire, w2k8 sends us linked
6962 attributes before the objects they are part of.
6964 static int replmd_start_transaction(struct ldb_module *module)
6966 /* create our private structure for this transaction */
6967 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
6968 struct replmd_private);
6969 replmd_txn_cleanup(replmd_private);
6971 /* free any leftover mod_usn records from cancelled
6973 while (replmd_private->ncs) {
6974 struct nc_entry *e = replmd_private->ncs;
6975 DLIST_REMOVE(replmd_private->ncs, e);
6979 replmd_private->originating_updates = false;
6981 return ldb_next_start_trans(module);
6985 on prepare commit we loop over our queued la_context structures and
6988 static int replmd_prepare_commit(struct ldb_module *module)
6990 struct replmd_private *replmd_private =
6991 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6992 struct la_entry *la, *prev;
6993 struct la_backlink *bl;
6996 /* walk the list backwards, to do the first entry first, as we
6997 * added the entries with DLIST_ADD() which puts them at the
6998 * start of the list */
6999 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
7000 prev = DLIST_PREV(la);
7001 DLIST_REMOVE(replmd_private->la_list, la);
7002 ret = replmd_process_linked_attribute(module, replmd_private,
7004 if (ret != LDB_SUCCESS) {
7005 replmd_txn_cleanup(replmd_private);
7010 /* process our backlink list, creating and deleting backlinks
7012 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
7013 ret = replmd_process_backlink(module, bl, NULL);
7014 if (ret != LDB_SUCCESS) {
7015 replmd_txn_cleanup(replmd_private);
7020 replmd_txn_cleanup(replmd_private);
7022 /* possibly change @REPLCHANGED */
7023 ret = replmd_notify_store(module, NULL);
7024 if (ret != LDB_SUCCESS) {
7028 return ldb_next_prepare_commit(module);
7031 static int replmd_del_transaction(struct ldb_module *module)
7033 struct replmd_private *replmd_private =
7034 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7035 replmd_txn_cleanup(replmd_private);
7037 return ldb_next_del_trans(module);
7041 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
7042 .name = "repl_meta_data",
7043 .init_context = replmd_init,
7045 .modify = replmd_modify,
7046 .rename = replmd_rename,
7047 .del = replmd_delete,
7048 .extended = replmd_extended,
7049 .start_transaction = replmd_start_transaction,
7050 .prepare_commit = replmd_prepare_commit,
7051 .del_transaction = replmd_del_transaction,
7054 int ldb_repl_meta_data_module_init(const char *version)
7056 LDB_MODULE_CHECK_VERSION(version);
7057 return ldb_register_module(&ldb_repl_meta_data_module_ops);