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 unlikely(GUID_all_zero(&p->guid))) {
2017 /* we got a DN without a GUID - go find the GUID */
2018 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
2019 if (ret != LDB_SUCCESS) {
2020 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
2021 ldb_dn_get_linearized(dn));
2022 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
2023 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
2024 ldb_attr_cmp(el->name, "member") == 0) {
2025 return LDB_ERR_UNWILLING_TO_PERFORM;
2029 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
2030 if (ret != LDB_SUCCESS) {
2033 } else if (!NT_STATUS_IS_OK(status)) {
2034 return LDB_ERR_OPERATIONS_ERROR;
2036 if (i > 0 && values_are_sorted) {
2037 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2039 values_are_sorted = false;
2042 /* keep a pointer to the original ldb_val */
2045 if (! values_are_sorted) {
2046 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2052 * Get a series of trusted message element values. The result is sorted by
2053 * GUID, even though the GUIDs might not be known. That works because we trust
2054 * the database to give us the elements like that if the
2055 * replmd_private->sorted_links flag is set.
2057 static int get_parsed_dns_trusted(struct ldb_module *module,
2058 struct replmd_private *replmd_private,
2059 TALLOC_CTX *mem_ctx,
2060 struct ldb_message_element *el,
2061 struct parsed_dn **pdn,
2062 const char *ldap_oid,
2063 struct ldb_request *parent)
2072 if (!replmd_private->sorted_links) {
2073 /* We need to sort the list. This is the slow old path we want
2076 return get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2079 /* Here we get a list of 'struct parsed_dns' without the parsing */
2080 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2083 ldb_module_oom(module);
2084 return LDB_ERR_OPERATIONS_ERROR;
2087 for (i = 0; i < el->num_values; i++) {
2088 (*pdn)[i].v = &el->values[i];
2095 build a new extended DN, including all meta data fields
2097 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2098 RMD_ADDTIME = originating_add_time
2099 RMD_INVOCID = originating_invocation_id
2100 RMD_CHANGETIME = originating_change_time
2101 RMD_ORIGINATING_USN = originating_usn
2102 RMD_LOCAL_USN = local_usn
2103 RMD_VERSION = version
2105 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2106 const struct GUID *invocation_id, uint64_t seq_num,
2107 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
2109 struct ldb_dn *dn = dsdb_dn->dn;
2110 const char *tstring, *usn_string, *flags_string;
2111 struct ldb_val tval;
2113 struct ldb_val usnv, local_usnv;
2114 struct ldb_val vers, flagsv;
2117 const char *dnstring;
2119 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2121 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2123 return LDB_ERR_OPERATIONS_ERROR;
2125 tval = data_blob_string_const(tstring);
2127 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
2129 return LDB_ERR_OPERATIONS_ERROR;
2131 usnv = data_blob_string_const(usn_string);
2133 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2135 return LDB_ERR_OPERATIONS_ERROR;
2137 local_usnv = data_blob_string_const(usn_string);
2139 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2141 return LDB_ERR_OPERATIONS_ERROR;
2143 vers = data_blob_string_const(vstring);
2145 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2146 if (!NT_STATUS_IS_OK(status)) {
2147 return LDB_ERR_OPERATIONS_ERROR;
2150 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2151 if (!flags_string) {
2152 return LDB_ERR_OPERATIONS_ERROR;
2154 flagsv = data_blob_string_const(flags_string);
2156 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2157 if (ret != LDB_SUCCESS) return ret;
2158 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
2159 if (ret != LDB_SUCCESS) return ret;
2160 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2161 if (ret != LDB_SUCCESS) return ret;
2162 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2163 if (ret != LDB_SUCCESS) return ret;
2164 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2165 if (ret != LDB_SUCCESS) return ret;
2166 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2167 if (ret != LDB_SUCCESS) return ret;
2168 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2169 if (ret != LDB_SUCCESS) return ret;
2171 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2172 if (dnstring == NULL) {
2173 return LDB_ERR_OPERATIONS_ERROR;
2175 *v = data_blob_string_const(dnstring);
2180 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2181 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2182 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2183 uint32_t version, bool deleted);
2186 check if any links need upgrading from w2k format
2188 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2189 struct parsed_dn *dns, uint32_t count,
2190 struct ldb_message_element *el,
2191 const struct GUID *invocation_id,
2192 const char *ldap_oid)
2195 for (i=0; i<count; i++) {
2199 if (dns[i].dsdb_dn == NULL) {
2200 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2202 if (ret != LDB_SUCCESS) {
2203 return LDB_ERR_INVALID_DN_SYNTAX;
2207 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2208 &version, "RMD_VERSION");
2209 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2211 * We optimistically assume they are all the same; if
2212 * the first one is fixed, they are all fixed.
2214 * If the first one was *not* fixed and we find a
2215 * later one that is, that is an occasion to shout
2221 DEBUG(0, ("Mixed w2k and fixed format "
2222 "linked attributes\n"));
2226 /* it's an old one that needs upgrading */
2227 ret = replmd_update_la_val(el->values, dns[i].v,
2228 dns[i].dsdb_dn, dns[i].dsdb_dn,
2229 invocation_id, 1, 1, 0, 0, false);
2230 if (ret != LDB_SUCCESS) {
2238 update an extended DN, including all meta data fields
2240 see replmd_build_la_val for value names
2242 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2243 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2244 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2245 uint32_t version, bool deleted)
2247 struct ldb_dn *dn = dsdb_dn->dn;
2248 const char *tstring, *usn_string, *flags_string;
2249 struct ldb_val tval;
2251 struct ldb_val usnv, local_usnv;
2252 struct ldb_val vers, flagsv;
2253 const struct ldb_val *old_addtime;
2254 uint32_t old_version;
2257 const char *dnstring;
2259 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2261 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2263 return LDB_ERR_OPERATIONS_ERROR;
2265 tval = data_blob_string_const(tstring);
2267 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2269 return LDB_ERR_OPERATIONS_ERROR;
2271 usnv = data_blob_string_const(usn_string);
2273 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2275 return LDB_ERR_OPERATIONS_ERROR;
2277 local_usnv = data_blob_string_const(usn_string);
2279 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2280 if (!NT_STATUS_IS_OK(status)) {
2281 return LDB_ERR_OPERATIONS_ERROR;
2284 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2285 if (!flags_string) {
2286 return LDB_ERR_OPERATIONS_ERROR;
2288 flagsv = data_blob_string_const(flags_string);
2290 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2291 if (ret != LDB_SUCCESS) return ret;
2293 /* get the ADDTIME from the original */
2294 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2295 if (old_addtime == NULL) {
2296 old_addtime = &tval;
2298 if (dsdb_dn != old_dsdb_dn ||
2299 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2300 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2301 if (ret != LDB_SUCCESS) return ret;
2304 /* use our invocation id */
2305 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2306 if (ret != LDB_SUCCESS) return ret;
2308 /* changetime is the current time */
2309 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2310 if (ret != LDB_SUCCESS) return ret;
2312 /* update the USN */
2313 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2314 if (ret != LDB_SUCCESS) return ret;
2316 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2317 if (ret != LDB_SUCCESS) return ret;
2319 /* increase the version by 1 */
2320 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2321 if (NT_STATUS_IS_OK(status) && old_version >= version) {
2322 version = old_version+1;
2324 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2325 vers = data_blob_string_const(vstring);
2326 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2327 if (ret != LDB_SUCCESS) return ret;
2329 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2330 if (dnstring == NULL) {
2331 return LDB_ERR_OPERATIONS_ERROR;
2333 *v = data_blob_string_const(dnstring);
2339 handle adding a linked attribute
2341 static int replmd_modify_la_add(struct ldb_module *module,
2342 struct replmd_private *replmd_private,
2343 const struct dsdb_schema *schema,
2344 struct ldb_message *msg,
2345 struct ldb_message_element *el,
2346 struct ldb_message_element *old_el,
2347 const struct dsdb_attribute *schema_attr,
2350 struct GUID *msg_guid,
2351 struct ldb_request *parent)
2354 struct parsed_dn *dns, *old_dns;
2355 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2357 struct ldb_val *new_values = NULL;
2358 unsigned old_num_values = old_el ? old_el->num_values : 0;
2359 unsigned num_values = 0;
2360 unsigned max_num_values;
2361 const struct GUID *invocation_id;
2362 struct ldb_context *ldb = ldb_module_get_ctx(module);
2365 unix_to_nt_time(&now, t);
2367 /* get the DNs to be added, fully parsed.
2369 * We need full parsing because they came off the wire and we don't
2370 * trust them, besides which we need their details to know where to put
2373 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2374 schema_attr->syntax->ldap_oid, parent);
2375 if (ret != LDB_SUCCESS) {
2376 talloc_free(tmp_ctx);
2380 /* get the existing DNs, lazily parsed */
2381 ret = get_parsed_dns_trusted(module, replmd_private,
2382 tmp_ctx, old_el, &old_dns,
2383 schema_attr->syntax->ldap_oid, parent);
2385 if (ret != LDB_SUCCESS) {
2386 talloc_free(tmp_ctx);
2390 invocation_id = samdb_ntds_invocation_id(ldb);
2391 if (!invocation_id) {
2392 talloc_free(tmp_ctx);
2393 return LDB_ERR_OPERATIONS_ERROR;
2396 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2397 old_el, invocation_id,
2398 schema_attr->syntax->ldap_oid);
2399 if (ret != LDB_SUCCESS) {
2400 talloc_free(tmp_ctx);
2404 max_num_values = old_num_values + el->num_values;
2405 if (max_num_values < old_num_values) {
2406 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2407 "old values: %u, new values: %u, sum: %u",
2408 old_num_values, el->num_values, max_num_values));
2409 talloc_free(tmp_ctx);
2410 return LDB_ERR_OPERATIONS_ERROR;
2413 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2415 if (new_values == NULL) {
2416 ldb_module_oom(module);
2417 talloc_free(tmp_ctx);
2418 return LDB_ERR_OPERATIONS_ERROR;
2422 * For each new value, find where it would go in the list. If there is
2423 * a matching GUID there, we update the existing value; otherwise we
2427 for (i = 0; i < el->num_values; i++) {
2428 struct parsed_dn *exact;
2429 struct parsed_dn *next;
2431 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2435 schema_attr->syntax->ldap_oid);
2436 if (err != LDB_SUCCESS) {
2437 talloc_free(tmp_ctx);
2441 if (exact != NULL) {
2443 * We are trying to add one that exists, which is only
2444 * allowed if it was previously deleted.
2446 * When we do undelete a link we change it in place.
2447 * It will be copied across into the right spot in due
2451 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2453 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2454 struct GUID_txt_buf guid_str;
2455 ldb_asprintf_errstring(ldb,
2456 "Attribute %s already "
2457 "exists for target GUID %s",
2459 GUID_buf_string(&exact->guid,
2461 talloc_free(tmp_ctx);
2462 /* error codes for 'member' need to be
2464 if (ldb_attr_cmp(el->name, "member") == 0) {
2465 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2467 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2471 ret = replmd_update_la_val(new_values, exact->v,
2474 invocation_id, seq_num,
2475 seq_num, now, 0, false);
2476 if (ret != LDB_SUCCESS) {
2477 talloc_free(tmp_ctx);
2481 ret = replmd_add_backlink(module, replmd_private,
2485 if (ret != LDB_SUCCESS) {
2486 talloc_free(tmp_ctx);
2492 * Here we don't have an exact match.
2494 * If next is NULL, this one goes beyond the end of the
2495 * existing list, so we need to add all of those ones first.
2497 * If next is not NULL, we need to add all the ones before
2501 offset = old_num_values;
2503 /* next should have been parsed, but let's make sure */
2504 if (next->dsdb_dn == NULL) {
2505 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2506 schema_attr->syntax->ldap_oid);
2507 if (ret != LDB_SUCCESS) {
2511 offset = MIN(next - old_dns, old_num_values);
2514 /* put all the old ones before next on the list */
2515 for (; j < offset; j++) {
2516 new_values[num_values] = *old_dns[j].v;
2520 ret = replmd_add_backlink(module, replmd_private,
2521 schema, msg_guid, &dns[i].guid,
2522 true, schema_attr, true);
2523 /* Make the new linked attribute ldb_val. */
2524 ret = replmd_build_la_val(new_values, &new_values[num_values],
2525 dns[i].dsdb_dn, invocation_id,
2528 if (ret != LDB_SUCCESS) {
2529 talloc_free(tmp_ctx);
2533 if (ret != LDB_SUCCESS) {
2534 talloc_free(tmp_ctx);
2538 /* copy the rest of the old ones (if any) */
2539 for (; j < old_num_values; j++) {
2540 new_values[num_values] = *old_dns[j].v;
2544 talloc_steal(msg->elements, new_values);
2545 if (old_el != NULL) {
2546 talloc_steal(msg->elements, old_el->values);
2548 el->values = new_values;
2549 el->num_values = num_values;
2551 talloc_free(tmp_ctx);
2553 /* we now tell the backend to replace all existing values
2554 with the one we have constructed */
2555 el->flags = LDB_FLAG_MOD_REPLACE;
2562 handle deleting all active linked attributes
2564 static int replmd_modify_la_delete(struct ldb_module *module,
2565 struct replmd_private *replmd_private,
2566 const struct dsdb_schema *schema,
2567 struct ldb_message *msg,
2568 struct ldb_message_element *el,
2569 struct ldb_message_element *old_el,
2570 const struct dsdb_attribute *schema_attr,
2573 struct GUID *msg_guid,
2574 struct ldb_request *parent)
2577 struct parsed_dn *dns, *old_dns;
2578 TALLOC_CTX *tmp_ctx = NULL;
2580 const struct GUID *invocation_id;
2581 struct ldb_context *ldb = ldb_module_get_ctx(module);
2582 struct ldb_control *vanish_links_ctrl = NULL;
2583 bool vanish_links = false;
2584 unsigned int num_to_delete = el->num_values;
2588 unix_to_nt_time(&now, t);
2590 if (old_el == NULL || old_el->num_values == 0) {
2591 /* there is nothing to delete... */
2592 if (num_to_delete == 0) {
2593 /* and we're deleting nothing, so that's OK */
2596 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2599 tmp_ctx = talloc_new(msg);
2600 if (tmp_ctx == NULL) {
2601 return LDB_ERR_OPERATIONS_ERROR;
2604 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2605 schema_attr->syntax->ldap_oid, parent);
2606 if (ret != LDB_SUCCESS) {
2607 talloc_free(tmp_ctx);
2611 ret = get_parsed_dns_trusted(module, replmd_private,
2612 tmp_ctx, old_el, &old_dns,
2613 schema_attr->syntax->ldap_oid, parent);
2615 if (ret != LDB_SUCCESS) {
2616 talloc_free(tmp_ctx);
2620 invocation_id = samdb_ntds_invocation_id(ldb);
2621 if (!invocation_id) {
2622 talloc_free(tmp_ctx);
2623 return LDB_ERR_OPERATIONS_ERROR;
2626 ret = replmd_check_upgrade_links(ldb, old_dns, old_el->num_values,
2627 old_el, invocation_id,
2628 schema_attr->syntax->ldap_oid);
2629 if (ret != LDB_SUCCESS) {
2630 talloc_free(tmp_ctx);
2635 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2636 if (vanish_links_ctrl) {
2637 vanish_links = true;
2638 vanish_links_ctrl->critical = false;
2642 /* we empty out el->values here to avoid damage if we return early. */
2647 * If vanish links is set, we are actually removing members of
2648 * old_el->values; otherwise we are just marking them deleted.
2650 * There is a special case when no values are given: we remove them
2651 * all. When we have the vanish_links control we just have to remove
2652 * the backlinks and change our element to replace the existing values
2653 * with the empty list.
2656 if (num_to_delete == 0) {
2657 for (i = 0; i < old_el->num_values; i++) {
2658 struct parsed_dn *p = &old_dns[i];
2659 if (p->dsdb_dn == NULL) {
2660 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2661 schema_attr->syntax->ldap_oid);
2662 if (ret != LDB_SUCCESS) {
2666 ret = replmd_add_backlink(module, replmd_private,
2667 schema, msg_guid, &p->guid,
2668 false, schema_attr, true);
2669 if (ret != LDB_SUCCESS) {
2670 talloc_free(tmp_ctx);
2677 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2678 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2682 ret = replmd_update_la_val(old_el->values, p->v,
2683 p->dsdb_dn, p->dsdb_dn,
2684 invocation_id, seq_num,
2685 seq_num, now, 0, true);
2686 if (ret != LDB_SUCCESS) {
2687 talloc_free(tmp_ctx);
2693 el->flags = LDB_FLAG_MOD_REPLACE;
2694 talloc_free(tmp_ctx);
2700 for (i = 0; i < num_to_delete; i++) {
2701 struct parsed_dn *p = &dns[i];
2702 struct parsed_dn *exact = NULL;
2703 struct parsed_dn *next = NULL;
2704 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2708 schema_attr->syntax->ldap_oid);
2709 if (ret != LDB_SUCCESS) {
2710 talloc_free(tmp_ctx);
2713 if (exact == NULL) {
2714 struct GUID_txt_buf buf;
2715 ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2716 "exist for target GUID %s",
2718 GUID_buf_string(&p->guid, &buf));
2719 if (ldb_attr_cmp(el->name, "member") == 0) {
2720 talloc_free(tmp_ctx);
2721 return LDB_ERR_UNWILLING_TO_PERFORM;
2723 talloc_free(tmp_ctx);
2724 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2729 if (CHECK_DEBUGLVL(5)) {
2730 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2731 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2732 struct GUID_txt_buf buf;
2733 const char *guid_str = \
2734 GUID_buf_string(&p->guid, &buf);
2735 DEBUG(5, ("Deleting deleted linked "
2736 "attribute %s to %s, because "
2737 "vanish_links control is set\n",
2738 el->name, guid_str));
2742 /* remove the backlink */
2743 ret = replmd_add_backlink(module,
2749 if (ret != LDB_SUCCESS) {
2750 talloc_free(tmp_ctx);
2754 /* We flag the deletion and tidy it up later. */
2759 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2761 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2762 struct GUID_txt_buf buf;
2763 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2764 ldb_asprintf_errstring(ldb, "Attribute %s already "
2765 "deleted for target GUID %s",
2766 el->name, guid_str);
2767 if (ldb_attr_cmp(el->name, "member") == 0) {
2768 talloc_free(tmp_ctx);
2769 return LDB_ERR_UNWILLING_TO_PERFORM;
2771 talloc_free(tmp_ctx);
2772 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2776 ret = replmd_update_la_val(old_el->values, exact->v,
2777 exact->dsdb_dn, exact->dsdb_dn,
2778 invocation_id, seq_num, seq_num,
2780 if (ret != LDB_SUCCESS) {
2781 talloc_free(tmp_ctx);
2784 ret = replmd_add_backlink(module, replmd_private,
2785 schema, msg_guid, &p->guid,
2786 false, schema_attr, true);
2787 if (ret != LDB_SUCCESS) {
2788 talloc_free(tmp_ctx);
2795 for (i = 0; i < old_el->num_values; i++) {
2796 if (old_dns[i].v != NULL) {
2797 old_el->values[j] = *old_dns[i].v;
2801 old_el->num_values = j;
2804 el->values = talloc_steal(msg->elements, old_el->values);
2805 el->num_values = old_el->num_values;
2807 talloc_free(tmp_ctx);
2809 /* we now tell the backend to replace all existing values
2810 with the one we have constructed */
2811 el->flags = LDB_FLAG_MOD_REPLACE;
2817 handle replacing a linked attribute
2819 static int replmd_modify_la_replace(struct ldb_module *module,
2820 struct replmd_private *replmd_private,
2821 const struct dsdb_schema *schema,
2822 struct ldb_message *msg,
2823 struct ldb_message_element *el,
2824 struct ldb_message_element *old_el,
2825 const struct dsdb_attribute *schema_attr,
2828 struct GUID *msg_guid,
2829 struct ldb_request *parent)
2831 unsigned int i, old_i, new_i;
2832 struct parsed_dn *dns, *old_dns;
2833 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2835 const struct GUID *invocation_id;
2836 struct ldb_context *ldb = ldb_module_get_ctx(module);
2837 struct ldb_val *new_values = NULL;
2838 const char *ldap_oid = schema_attr->syntax->ldap_oid;
2839 unsigned int old_num_values;
2840 unsigned int repl_num_values;
2841 unsigned int max_num_values;
2844 unix_to_nt_time(&now, t);
2847 * The replace operation is unlike the replace and delete cases in that
2848 * we need to look at every existing link to see whether it is being
2849 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
2851 * As we are trying to combine two sorted lists, the algorithm we use
2852 * is akin to the merge phase of a merge sort. We interleave the two
2853 * lists, doing different things depending on which side the current
2856 * There are three main cases, with some sub-cases.
2858 * - a DN is in the old list but not the new one. It needs to be
2859 * marked as deleted (but left in the list).
2860 * - maybe it is already deleted, and we have less to do.
2862 * - a DN is in both lists. The old data gets replaced by the new,
2863 * and the list doesn't grow. The old link may have been marked as
2864 * deleted, in which case we undelete it.
2866 * - a DN is in the new list only. We add it in the right place.
2869 old_num_values = old_el ? old_el->num_values : 0;
2870 repl_num_values = el->num_values;
2871 max_num_values = old_num_values + repl_num_values;
2873 if (max_num_values == 0) {
2874 /* There is nothing to do! */
2878 ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
2879 if (ret != LDB_SUCCESS) {
2880 talloc_free(tmp_ctx);
2884 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
2886 if (ret != LDB_SUCCESS) {
2887 talloc_free(tmp_ctx);
2891 invocation_id = samdb_ntds_invocation_id(ldb);
2892 if (!invocation_id) {
2893 return LDB_ERR_OPERATIONS_ERROR;
2896 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2897 old_el, invocation_id, ldap_oid);
2898 if (ret != LDB_SUCCESS) {
2899 talloc_free(tmp_ctx);
2903 new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
2904 if (new_values == NULL) {
2905 ldb_module_oom(module);
2906 talloc_free(tmp_ctx);
2907 return LDB_ERR_OPERATIONS_ERROR;
2912 for (i = 0; i < max_num_values; i++) {
2914 struct parsed_dn *old_p, *new_p;
2915 if (old_i < old_num_values && new_i < repl_num_values) {
2916 old_p = &old_dns[old_i];
2917 new_p = &dns[new_i];
2918 cmp = parsed_dn_compare(old_p, new_p);
2919 } else if (old_i < old_num_values) {
2920 /* the new list is empty, read the old list */
2921 old_p = &old_dns[old_i];
2924 } else if (new_i < repl_num_values) {
2925 /* the old list is empty, read new list */
2927 new_p = &dns[new_i];
2935 * An old ones that come before the next replacement
2936 * (if any). We mark it as deleted and add it to the
2939 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2940 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
2941 ret = replmd_update_la_val(new_values, old_p->v,
2947 if (ret != LDB_SUCCESS) {
2948 talloc_free(tmp_ctx);
2952 ret = replmd_add_backlink(module, replmd_private,
2954 &old_p->guid, false,
2956 if (ret != LDB_SUCCESS) {
2957 talloc_free(tmp_ctx);
2961 new_values[i] = *old_p->v;
2963 } else if (cmp == 0) {
2965 * We are overwriting one. If it was previously
2966 * deleted, we need to add a backlink.
2968 * Note that if any RMD_FLAGs in an extended new DN
2973 ret = replmd_update_la_val(new_values, old_p->v,
2979 if (ret != LDB_SUCCESS) {
2980 talloc_free(tmp_ctx);
2984 rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2985 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
2986 ret = replmd_add_backlink(module, replmd_private,
2990 if (ret != LDB_SUCCESS) {
2991 talloc_free(tmp_ctx);
2996 new_values[i] = *old_p->v;
3001 * Replacements that don't match an existing one. We
3002 * just add them to the final list.
3004 ret = replmd_build_la_val(new_values,
3010 if (ret != LDB_SUCCESS) {
3011 talloc_free(tmp_ctx);
3014 ret = replmd_add_backlink(module, replmd_private,
3018 if (ret != LDB_SUCCESS) {
3019 talloc_free(tmp_ctx);
3022 new_values[i] = *new_p->v;
3026 if (old_el != NULL) {
3027 talloc_steal(msg->elements, old_el->values);
3029 el->values = talloc_steal(msg->elements, new_values);
3031 talloc_free(tmp_ctx);
3033 el->flags = LDB_FLAG_MOD_REPLACE;
3040 handle linked attributes in modify requests
3042 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3043 struct replmd_private *replmd_private,
3044 struct ldb_message *msg,
3045 uint64_t seq_num, time_t t,
3046 struct ldb_request *parent)
3048 struct ldb_result *res;
3051 struct ldb_context *ldb = ldb_module_get_ctx(module);
3052 struct ldb_message *old_msg;
3054 const struct dsdb_schema *schema;
3055 struct GUID old_guid;
3057 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3059 * Nothing special is required for modifying or vanishing links
3060 * in fl2000 since they are just strings in a multi-valued
3063 struct ldb_control *ctrl = ldb_request_get_control(parent,
3064 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3066 ctrl->critical = false;
3074 * We should restrict this to the intersection of the list of
3075 * linked attributes in the schema and the list of attributes
3078 * This will help performance a little, as otherwise we have
3079 * to allocate the entire object value-by-value.
3081 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3082 DSDB_FLAG_NEXT_MODULE |
3083 DSDB_SEARCH_SHOW_RECYCLED |
3084 DSDB_SEARCH_REVEAL_INTERNALS |
3085 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3087 if (ret != LDB_SUCCESS) {
3090 schema = dsdb_get_schema(ldb, res);
3092 return LDB_ERR_OPERATIONS_ERROR;
3095 old_msg = res->msgs[0];
3097 old_guid = samdb_result_guid(old_msg, "objectGUID");
3099 for (i=0; i<msg->num_elements; i++) {
3100 struct ldb_message_element *el = &msg->elements[i];
3101 struct ldb_message_element *old_el, *new_el;
3102 const struct dsdb_attribute *schema_attr
3103 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3105 ldb_asprintf_errstring(ldb,
3106 "%s: attribute %s is not a valid attribute in schema",
3107 __FUNCTION__, el->name);
3108 return LDB_ERR_OBJECT_CLASS_VIOLATION;
3110 if (schema_attr->linkID == 0) {
3113 if ((schema_attr->linkID & 1) == 1) {
3114 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
3117 /* Odd is for the target. Illegal to modify */
3118 ldb_asprintf_errstring(ldb,
3119 "attribute %s must not be modified directly, it is a linked attribute", el->name);
3120 return LDB_ERR_UNWILLING_TO_PERFORM;
3122 old_el = ldb_msg_find_element(old_msg, el->name);
3123 switch (el->flags & LDB_FLAG_MOD_MASK) {
3124 case LDB_FLAG_MOD_REPLACE:
3125 ret = replmd_modify_la_replace(module, replmd_private,
3126 schema, msg, el, old_el,
3127 schema_attr, seq_num, t,
3130 case LDB_FLAG_MOD_DELETE:
3131 ret = replmd_modify_la_delete(module, replmd_private,
3132 schema, msg, el, old_el,
3133 schema_attr, seq_num, t,
3136 case LDB_FLAG_MOD_ADD:
3137 ret = replmd_modify_la_add(module, replmd_private,
3138 schema, msg, el, old_el,
3139 schema_attr, seq_num, t,
3143 ldb_asprintf_errstring(ldb,
3144 "invalid flags 0x%x for %s linked attribute",
3145 el->flags, el->name);
3146 return LDB_ERR_UNWILLING_TO_PERFORM;
3148 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3149 ldb_asprintf_errstring(ldb,
3150 "Attribute %s is single valued but more than one value has been supplied",
3152 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3154 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3159 if (ret != LDB_SUCCESS) {
3163 ldb_msg_remove_attr(old_msg, el->name);
3165 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3166 new_el->num_values = el->num_values;
3167 new_el->values = talloc_steal(msg->elements, el->values);
3169 /* TODO: this relises a bit too heavily on the exact
3170 behaviour of ldb_msg_find_element and
3171 ldb_msg_remove_element */
3172 old_el = ldb_msg_find_element(msg, el->name);
3174 ldb_msg_remove_element(msg, old_el);
3185 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3187 struct ldb_context *ldb;
3188 struct replmd_replicated_request *ac;
3189 struct ldb_request *down_req;
3190 struct ldb_message *msg;
3191 time_t t = time(NULL);
3193 bool is_urgent = false, rodc = false;
3194 bool is_schema_nc = false;
3195 unsigned int functional_level;
3196 const struct ldb_message_element *guid_el = NULL;
3197 struct ldb_control *sd_propagation_control;
3198 struct replmd_private *replmd_private =
3199 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3201 /* do not manipulate our control entries */
3202 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3203 return ldb_next_request(module, req);
3206 sd_propagation_control = ldb_request_get_control(req,
3207 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3208 if (sd_propagation_control != NULL) {
3209 if (req->op.mod.message->num_elements != 1) {
3210 return ldb_module_operr(module);
3212 ret = strcmp(req->op.mod.message->elements[0].name,
3213 "nTSecurityDescriptor");
3215 return ldb_module_operr(module);
3218 return ldb_next_request(module, req);
3221 ldb = ldb_module_get_ctx(module);
3223 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3225 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3226 if (guid_el != NULL) {
3227 ldb_set_errstring(ldb,
3228 "replmd_modify: it's not allowed to change the objectGUID!");
3229 return LDB_ERR_CONSTRAINT_VIOLATION;
3232 ac = replmd_ctx_init(module, req);
3234 return ldb_module_oom(module);
3237 functional_level = dsdb_functional_level(ldb);
3239 /* we have to copy the message as the caller might have it as a const */
3240 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3244 return LDB_ERR_OPERATIONS_ERROR;
3247 ldb_msg_remove_attr(msg, "whenChanged");
3248 ldb_msg_remove_attr(msg, "uSNChanged");
3250 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3252 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3253 msg, &ac->seq_num, t, is_schema_nc,
3255 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3256 struct loadparm_context *lp_ctx;
3259 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3260 struct loadparm_context);
3262 referral = talloc_asprintf(req,
3264 lpcfg_dnsdomain(lp_ctx),
3265 ldb_dn_get_linearized(msg->dn));
3266 ret = ldb_module_send_referral(req, referral);
3271 if (ret != LDB_SUCCESS) {
3276 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3277 msg, ac->seq_num, t, req);
3278 if (ret != LDB_SUCCESS) {
3284 * - replace the old object with the newly constructed one
3287 ac->is_urgent = is_urgent;
3289 ret = ldb_build_mod_req(&down_req, ldb, ac,
3292 ac, replmd_op_callback,
3294 LDB_REQ_SET_LOCATION(down_req);
3295 if (ret != LDB_SUCCESS) {
3300 /* current partition control is needed by "replmd_op_callback" */
3301 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3302 ret = ldb_request_add_control(down_req,
3303 DSDB_CONTROL_CURRENT_PARTITION_OID,
3305 if (ret != LDB_SUCCESS) {
3311 /* If we are in functional level 2000, then
3312 * replmd_modify_handle_linked_attribs will have done
3314 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3315 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3316 if (ret != LDB_SUCCESS) {
3322 talloc_steal(down_req, msg);
3324 /* we only change whenChanged and uSNChanged if the seq_num
3326 if (ac->seq_num != 0) {
3327 ret = add_time_element(msg, "whenChanged", t);
3328 if (ret != LDB_SUCCESS) {
3334 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3335 if (ret != LDB_SUCCESS) {
3342 /* go on with the call chain */
3343 return ldb_next_request(module, down_req);
3346 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3349 handle a rename request
3351 On a rename we need to do an extra ldb_modify which sets the
3352 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3354 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3356 struct ldb_context *ldb;
3357 struct replmd_replicated_request *ac;
3359 struct ldb_request *down_req;
3361 /* do not manipulate our control entries */
3362 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3363 return ldb_next_request(module, req);
3366 ldb = ldb_module_get_ctx(module);
3368 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3370 ac = replmd_ctx_init(module, req);
3372 return ldb_module_oom(module);
3375 ret = ldb_build_rename_req(&down_req, ldb, ac,
3376 ac->req->op.rename.olddn,
3377 ac->req->op.rename.newdn,
3379 ac, replmd_rename_callback,
3381 LDB_REQ_SET_LOCATION(down_req);
3382 if (ret != LDB_SUCCESS) {
3387 /* go on with the call chain */
3388 return ldb_next_request(module, down_req);
3391 /* After the rename is compleated, update the whenchanged etc */
3392 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3394 struct ldb_context *ldb;
3395 struct ldb_request *down_req;
3396 struct ldb_message *msg;
3397 const struct dsdb_attribute *rdn_attr;
3398 const char *rdn_name;
3399 const struct ldb_val *rdn_val;
3400 const char *attrs[5] = { NULL, };
3401 time_t t = time(NULL);
3403 bool is_urgent = false, rodc = false;
3405 struct replmd_replicated_request *ac =
3406 talloc_get_type(req->context, struct replmd_replicated_request);
3407 struct replmd_private *replmd_private =
3408 talloc_get_type(ldb_module_get_private(ac->module),
3409 struct replmd_private);
3411 ldb = ldb_module_get_ctx(ac->module);
3413 if (ares->error != LDB_SUCCESS) {
3414 return ldb_module_done(ac->req, ares->controls,
3415 ares->response, ares->error);
3418 if (ares->type != LDB_REPLY_DONE) {
3419 ldb_set_errstring(ldb,
3420 "invalid ldb_reply_type in callback");
3422 return ldb_module_done(ac->req, NULL, NULL,
3423 LDB_ERR_OPERATIONS_ERROR);
3427 * - replace the old object with the newly constructed one
3430 msg = ldb_msg_new(ac);
3433 return LDB_ERR_OPERATIONS_ERROR;
3436 msg->dn = ac->req->op.rename.newdn;
3438 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3440 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3441 if (rdn_name == NULL) {
3443 return ldb_module_done(ac->req, NULL, NULL,
3447 /* normalize the rdn attribute name */
3448 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3449 if (rdn_attr == NULL) {
3451 return ldb_module_done(ac->req, NULL, NULL,
3454 rdn_name = rdn_attr->lDAPDisplayName;
3456 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3457 if (rdn_val == NULL) {
3459 return ldb_module_done(ac->req, NULL, NULL,
3463 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3465 return ldb_module_done(ac->req, NULL, NULL,
3468 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3470 return ldb_module_done(ac->req, NULL, NULL,
3473 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3475 return ldb_module_done(ac->req, NULL, NULL,
3478 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3480 return ldb_module_done(ac->req, NULL, NULL,
3485 * here we let replmd_update_rpmd() only search for
3486 * the existing "replPropertyMetaData" and rdn_name attributes.
3488 * We do not want the existing "name" attribute as
3489 * the "name" attribute needs to get the version
3490 * updated on rename even if the rdn value hasn't changed.
3492 * This is the diff of the meta data, for a moved user
3493 * on a w2k8r2 server:
3496 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3497 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3498 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3499 * version : 0x00000001 (1)
3500 * reserved : 0x00000000 (0)
3501 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3502 * local_usn : 0x00000000000037a5 (14245)
3503 * array: struct replPropertyMetaData1
3504 * attid : DRSUAPI_ATTID_name (0x90001)
3505 * - version : 0x00000001 (1)
3506 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3507 * + version : 0x00000002 (2)
3508 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3509 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3510 * - originating_usn : 0x00000000000037a5 (14245)
3511 * - local_usn : 0x00000000000037a5 (14245)
3512 * + originating_usn : 0x0000000000003834 (14388)
3513 * + local_usn : 0x0000000000003834 (14388)
3514 * array: struct replPropertyMetaData1
3515 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3516 * version : 0x00000004 (4)
3518 attrs[0] = "replPropertyMetaData";
3519 attrs[1] = "objectClass";
3520 attrs[2] = "instanceType";
3521 attrs[3] = rdn_name;
3524 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3525 msg, &ac->seq_num, t,
3526 is_schema_nc, &is_urgent, &rodc);
3527 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3528 struct ldb_dn *olddn = ac->req->op.rename.olddn;
3529 struct loadparm_context *lp_ctx;
3532 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3533 struct loadparm_context);
3535 referral = talloc_asprintf(req,
3537 lpcfg_dnsdomain(lp_ctx),
3538 ldb_dn_get_linearized(olddn));
3539 ret = ldb_module_send_referral(req, referral);
3541 return ldb_module_done(req, NULL, NULL, ret);
3544 if (ret != LDB_SUCCESS) {
3546 return ldb_module_done(ac->req, NULL, NULL, ret);
3549 if (ac->seq_num == 0) {
3551 return ldb_module_done(ac->req, NULL, NULL,
3553 "internal error seq_num == 0"));
3555 ac->is_urgent = is_urgent;
3557 ret = ldb_build_mod_req(&down_req, ldb, ac,
3560 ac, replmd_op_callback,
3562 LDB_REQ_SET_LOCATION(down_req);
3563 if (ret != LDB_SUCCESS) {
3568 /* current partition control is needed by "replmd_op_callback" */
3569 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3570 ret = ldb_request_add_control(down_req,
3571 DSDB_CONTROL_CURRENT_PARTITION_OID,
3573 if (ret != LDB_SUCCESS) {
3579 talloc_steal(down_req, msg);
3581 ret = add_time_element(msg, "whenChanged", t);
3582 if (ret != LDB_SUCCESS) {
3588 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3589 if (ret != LDB_SUCCESS) {
3595 /* go on with the call chain - do the modify after the rename */
3596 return ldb_next_request(ac->module, down_req);
3600 * remove links from objects that point at this object when an object
3601 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3602 * RemoveObj which states that link removal due to the object being
3603 * deleted is NOT an originating update - they just go away!
3606 static int replmd_delete_remove_link(struct ldb_module *module,
3607 const struct dsdb_schema *schema,
3609 struct ldb_message_element *el,
3610 const struct dsdb_attribute *sa,
3611 struct ldb_request *parent)
3614 TALLOC_CTX *tmp_ctx = talloc_new(module);
3615 struct ldb_context *ldb = ldb_module_get_ctx(module);
3617 for (i=0; i<el->num_values; i++) {
3618 struct dsdb_dn *dsdb_dn;
3622 struct ldb_message *msg;
3623 const struct dsdb_attribute *target_attr;
3624 struct ldb_message_element *el2;
3625 struct ldb_val dn_val;
3626 uint32_t dsdb_flags = 0;
3628 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3632 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3634 talloc_free(tmp_ctx);
3635 return LDB_ERR_OPERATIONS_ERROR;
3638 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
3639 if (!NT_STATUS_IS_OK(status)) {
3640 talloc_free(tmp_ctx);
3641 return LDB_ERR_OPERATIONS_ERROR;
3644 /* remove the link */
3645 msg = ldb_msg_new(tmp_ctx);
3647 ldb_module_oom(module);
3648 talloc_free(tmp_ctx);
3649 return LDB_ERR_OPERATIONS_ERROR;
3653 msg->dn = dsdb_dn->dn;
3655 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3656 if (target_attr == NULL) {
3660 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
3661 if (ret != LDB_SUCCESS) {
3662 ldb_module_oom(module);
3663 talloc_free(tmp_ctx);
3664 return LDB_ERR_OPERATIONS_ERROR;
3666 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
3667 el2->values = &dn_val;
3668 el2->num_values = 1;
3671 * Ensure that we tell the modification to vanish any linked
3672 * attributes (not simply mark them as isDeleted = TRUE)
3674 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3676 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3677 if (ret != LDB_SUCCESS) {
3678 talloc_free(tmp_ctx);
3682 talloc_free(tmp_ctx);
3688 handle update of replication meta data for deletion of objects
3690 This also handles the mapping of delete to a rename operation
3691 to allow deletes to be replicated.
3693 It also handles the incoming deleted objects, to ensure they are
3694 fully deleted here. In that case re_delete is true, and we do not
3695 use this as a signal to change the deleted state, just reinforce it.
3698 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3700 int ret = LDB_ERR_OTHER;
3701 bool retb, disallow_move_on_delete;
3702 struct ldb_dn *old_dn, *new_dn;
3703 const char *rdn_name;
3704 const struct ldb_val *rdn_value, *new_rdn_value;
3706 struct ldb_context *ldb = ldb_module_get_ctx(module);
3707 const struct dsdb_schema *schema;
3708 struct ldb_message *msg, *old_msg;
3709 struct ldb_message_element *el;
3710 TALLOC_CTX *tmp_ctx;
3711 struct ldb_result *res, *parent_res;
3712 static const char * const preserved_attrs[] = {
3713 /* yes, this really is a hard coded list. See MS-ADTS
3714 section 3.1.1.5.5.1.1 */
3717 "dNReferenceUpdate",
3728 "msDS-LastKnownRDN",
3734 "distinguishedName",
3738 "proxiedObjectName",
3740 "nTSecurityDescriptor",
3741 "replPropertyMetaData",
3743 "securityIdentifier",
3751 "userAccountControl",
3758 static const char * const all_attrs[] = {
3759 DSDB_SECRET_ATTRIBUTES,
3763 unsigned int i, el_count = 0;
3764 uint32_t dsdb_flags = 0;
3765 enum deletion_state deletion_state, next_deletion_state;
3767 if (ldb_dn_is_special(req->op.del.dn)) {
3768 return ldb_next_request(module, req);
3772 * We have to allow dbcheck to remove an object that
3773 * is beyond repair, and to do so totally. This could
3774 * mean we we can get a partial object from the other
3775 * DC, causing havoc, so dbcheck suggests
3776 * re-replication first. dbcheck sets both DBCHECK
3777 * and RELAX in this situation.
3779 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3780 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3781 /* really, really remove it */
3782 return ldb_next_request(module, req);
3785 tmp_ctx = talloc_new(ldb);
3788 return LDB_ERR_OPERATIONS_ERROR;
3791 schema = dsdb_get_schema(ldb, tmp_ctx);
3793 talloc_free(tmp_ctx);
3794 return LDB_ERR_OPERATIONS_ERROR;
3797 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3799 /* we need the complete msg off disk, so we can work out which
3800 attributes need to be removed */
3801 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3802 DSDB_FLAG_NEXT_MODULE |
3803 DSDB_SEARCH_SHOW_RECYCLED |
3804 DSDB_SEARCH_REVEAL_INTERNALS |
3805 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3806 if (ret != LDB_SUCCESS) {
3807 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3808 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3809 re_delete ? "re-delete" : "delete",
3810 ldb_dn_get_linearized(old_dn),
3811 ldb_errstring(ldb_module_get_ctx(module)));
3812 talloc_free(tmp_ctx);
3815 old_msg = res->msgs[0];
3817 replmd_deletion_state(module, old_msg,
3819 &next_deletion_state);
3821 /* This supports us noticing an incoming isDeleted and acting on it */
3823 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3824 next_deletion_state = deletion_state;
3827 if (next_deletion_state == OBJECT_REMOVED) {
3829 * We have to prevent objects being deleted, even if
3830 * the administrator really wants them gone, as
3831 * without the tombstone, we can get a partial object
3832 * from the other DC, causing havoc.
3834 * The only other valid case is when the 180 day
3835 * timeout has expired, when relax is specified.
3837 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3838 /* it is already deleted - really remove it this time */
3839 talloc_free(tmp_ctx);
3840 return ldb_next_request(module, req);
3843 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3844 "This check is to prevent corruption of the replicated state.",
3845 ldb_dn_get_linearized(old_msg->dn));
3846 return LDB_ERR_UNWILLING_TO_PERFORM;
3849 rdn_name = ldb_dn_get_rdn_name(old_dn);
3850 rdn_value = ldb_dn_get_rdn_val(old_dn);
3851 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3852 talloc_free(tmp_ctx);
3853 return ldb_operr(ldb);
3856 msg = ldb_msg_new(tmp_ctx);
3858 ldb_module_oom(module);
3859 talloc_free(tmp_ctx);
3860 return LDB_ERR_OPERATIONS_ERROR;
3865 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3866 disallow_move_on_delete =
3867 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3868 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3870 /* work out where we will be renaming this object to */
3871 if (!disallow_move_on_delete) {
3872 struct ldb_dn *deleted_objects_dn;
3873 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3874 &deleted_objects_dn);
3877 * We should not move objects if we can't find the
3878 * deleted objects DN. Not moving (or otherwise
3879 * harming) the Deleted Objects DN itself is handled
3882 if (re_delete && (ret != LDB_SUCCESS)) {
3883 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3884 if (new_dn == NULL) {
3885 ldb_module_oom(module);
3886 talloc_free(tmp_ctx);
3887 return LDB_ERR_OPERATIONS_ERROR;
3889 } else if (ret != LDB_SUCCESS) {
3890 /* this is probably an attempted delete on a partition
3891 * that doesn't allow delete operations, such as the
3892 * schema partition */
3893 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3894 ldb_dn_get_linearized(old_dn));
3895 talloc_free(tmp_ctx);
3896 return LDB_ERR_UNWILLING_TO_PERFORM;
3898 new_dn = deleted_objects_dn;
3901 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3902 if (new_dn == NULL) {
3903 ldb_module_oom(module);
3904 talloc_free(tmp_ctx);
3905 return LDB_ERR_OPERATIONS_ERROR;
3909 if (deletion_state == OBJECT_NOT_DELETED) {
3910 /* get the objects GUID from the search we just did */
3911 guid = samdb_result_guid(old_msg, "objectGUID");
3913 /* Add a formatted child */
3914 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3916 ldb_dn_escape_value(tmp_ctx, *rdn_value),
3917 GUID_string(tmp_ctx, &guid));
3919 ldb_asprintf_errstring(ldb, __location__
3920 ": Unable to add a formatted child to dn: %s",
3921 ldb_dn_get_linearized(new_dn));
3922 talloc_free(tmp_ctx);
3923 return LDB_ERR_OPERATIONS_ERROR;
3926 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
3927 if (ret != LDB_SUCCESS) {
3928 ldb_asprintf_errstring(ldb, __location__
3929 ": Failed to add isDeleted string to the msg");
3930 talloc_free(tmp_ctx);
3933 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3936 * No matter what has happened with other renames etc, try again to
3937 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
3940 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
3941 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
3943 ldb_asprintf_errstring(ldb, __location__
3944 ": Unable to add a prepare rdn of %s",
3945 ldb_dn_get_linearized(rdn));
3946 talloc_free(tmp_ctx);
3947 return LDB_ERR_OPERATIONS_ERROR;
3949 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
3951 retb = ldb_dn_add_child(new_dn, rdn);
3953 ldb_asprintf_errstring(ldb, __location__
3954 ": Unable to add rdn %s to base dn: %s",
3955 ldb_dn_get_linearized(rdn),
3956 ldb_dn_get_linearized(new_dn));
3957 talloc_free(tmp_ctx);
3958 return LDB_ERR_OPERATIONS_ERROR;
3963 now we need to modify the object in the following ways:
3965 - add isDeleted=TRUE
3966 - update rDN and name, with new rDN
3967 - remove linked attributes
3968 - remove objectCategory and sAMAccountType
3969 - remove attribs not on the preserved list
3970 - preserved if in above list, or is rDN
3971 - remove all linked attribs from this object
3972 - remove all links from other objects to this object
3973 - add lastKnownParent
3974 - update replPropertyMetaData?
3976 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
3979 if (deletion_state == OBJECT_NOT_DELETED) {
3980 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3981 char *parent_dn_str = NULL;
3983 /* we need the storage form of the parent GUID */
3984 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
3986 DSDB_FLAG_NEXT_MODULE |
3987 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3988 DSDB_SEARCH_REVEAL_INTERNALS|
3989 DSDB_SEARCH_SHOW_RECYCLED, req);
3990 if (ret != LDB_SUCCESS) {
3991 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3992 "repmd_delete: Failed to %s %s, "
3993 "because we failed to find it's parent (%s): %s",
3994 re_delete ? "re-delete" : "delete",
3995 ldb_dn_get_linearized(old_dn),
3996 ldb_dn_get_linearized(parent_dn),
3997 ldb_errstring(ldb_module_get_ctx(module)));
3998 talloc_free(tmp_ctx);
4003 * Now we can use the DB version,
4004 * it will have the extended DN info in it
4006 parent_dn = parent_res->msgs[0]->dn;
4007 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4010 if (parent_dn_str == NULL) {
4011 talloc_free(tmp_ctx);
4012 return ldb_module_oom(module);
4015 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4017 if (ret != LDB_SUCCESS) {
4018 ldb_asprintf_errstring(ldb, __location__
4019 ": Failed to add lastKnownParent "
4020 "string when deleting %s",
4021 ldb_dn_get_linearized(old_dn));
4022 talloc_free(tmp_ctx);
4025 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4027 if (next_deletion_state == OBJECT_DELETED) {
4028 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4029 if (ret != LDB_SUCCESS) {
4030 ldb_asprintf_errstring(ldb, __location__
4031 ": Failed to add msDS-LastKnownRDN "
4032 "string when deleting %s",
4033 ldb_dn_get_linearized(old_dn));
4034 talloc_free(tmp_ctx);
4037 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
4041 switch (next_deletion_state) {
4043 case OBJECT_RECYCLED:
4044 case OBJECT_TOMBSTONE:
4047 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4048 * describes what must be removed from a tombstone
4051 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4052 * describes what must be removed from a recycled
4058 * we also mark it as recycled, meaning this object can't be
4059 * recovered (we are stripping its attributes).
4060 * This is done only if we have this schema object of course ...
4061 * This behavior is identical to the one of Windows 2008R2 which
4062 * always set the isRecycled attribute, even if the recycle-bin is
4063 * not activated and what ever the forest level is.
4065 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4066 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
4067 if (ret != LDB_SUCCESS) {
4068 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4069 ldb_module_oom(module);
4070 talloc_free(tmp_ctx);
4073 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4076 /* work out which of the old attributes we will be removing */
4077 for (i=0; i<old_msg->num_elements; i++) {
4078 const struct dsdb_attribute *sa;
4079 el = &old_msg->elements[i];
4080 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4082 talloc_free(tmp_ctx);
4083 return LDB_ERR_OPERATIONS_ERROR;
4085 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4086 /* don't remove the rDN */
4089 if (sa->linkID && (sa->linkID & 1)) {
4091 we have a backlink in this object
4092 that needs to be removed. We're not
4093 allowed to remove it directly
4094 however, so we instead setup a
4095 modify to delete the corresponding
4098 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
4099 if (ret != LDB_SUCCESS) {
4100 const char *old_dn_str
4101 = ldb_dn_get_linearized(old_dn);
4102 ldb_asprintf_errstring(ldb,
4104 ": Failed to remove backlink of "
4105 "%s when deleting %s: %s",
4108 ldb_errstring(ldb));
4109 talloc_free(tmp_ctx);
4110 return LDB_ERR_OPERATIONS_ERROR;
4112 /* now we continue, which means we
4113 won't remove this backlink
4119 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4122 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4127 * Ensure that we tell the modification to vanish any linked
4128 * attributes (not simply mark them as isDeleted = TRUE)
4130 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4132 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4133 if (ret != LDB_SUCCESS) {
4134 talloc_free(tmp_ctx);
4135 ldb_module_oom(module);
4142 case OBJECT_DELETED:
4144 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4145 * describes what must be removed from a deleted
4149 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4150 if (ret != LDB_SUCCESS) {
4151 talloc_free(tmp_ctx);
4152 ldb_module_oom(module);
4156 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4157 if (ret != LDB_SUCCESS) {
4158 talloc_free(tmp_ctx);
4159 ldb_module_oom(module);
4169 if (deletion_state == OBJECT_NOT_DELETED) {
4170 const struct dsdb_attribute *sa;
4172 /* work out what the new rdn value is, for updating the
4173 rDN and name fields */
4174 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4175 if (new_rdn_value == NULL) {
4176 talloc_free(tmp_ctx);
4177 return ldb_operr(ldb);
4180 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4182 talloc_free(tmp_ctx);
4183 return LDB_ERR_OPERATIONS_ERROR;
4186 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4188 if (ret != LDB_SUCCESS) {
4189 talloc_free(tmp_ctx);
4192 el->flags = LDB_FLAG_MOD_REPLACE;
4194 el = ldb_msg_find_element(old_msg, "name");
4196 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4197 if (ret != LDB_SUCCESS) {
4198 talloc_free(tmp_ctx);
4201 el->flags = LDB_FLAG_MOD_REPLACE;
4206 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4211 * No matter what has happned with other renames, try again to
4212 * get this to be under the deleted DN.
4214 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4215 /* now rename onto the new DN */
4216 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4217 if (ret != LDB_SUCCESS){
4218 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4219 ldb_dn_get_linearized(old_dn),
4220 ldb_dn_get_linearized(new_dn),
4221 ldb_errstring(ldb)));
4222 talloc_free(tmp_ctx);
4228 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4229 if (ret != LDB_SUCCESS) {
4230 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4231 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4232 talloc_free(tmp_ctx);
4236 talloc_free(tmp_ctx);
4238 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4241 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4243 return replmd_delete_internals(module, req, false);
4247 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4252 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4254 int ret = LDB_ERR_OTHER;
4255 /* TODO: do some error mapping */
4257 /* Let the caller know the full WERROR */
4258 ar->objs->error = status;
4264 static struct replPropertyMetaData1 *
4265 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4266 enum drsuapi_DsAttributeId attid)
4269 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4271 for (i = 0; i < rpmd_ctr->count; i++) {
4272 if (rpmd_ctr->array[i].attid == attid) {
4273 return &rpmd_ctr->array[i];
4281 return true if an update is newer than an existing entry
4282 see section 5.11 of MS-ADTS
4284 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4285 const struct GUID *update_invocation_id,
4286 uint32_t current_version,
4287 uint32_t update_version,
4288 NTTIME current_change_time,
4289 NTTIME update_change_time)
4291 if (update_version != current_version) {
4292 return update_version > current_version;
4294 if (update_change_time != current_change_time) {
4295 return update_change_time > current_change_time;
4297 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4300 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4301 struct replPropertyMetaData1 *new_m)
4303 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4304 &new_m->originating_invocation_id,
4307 cur_m->originating_change_time,
4308 new_m->originating_change_time);
4311 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4312 struct replPropertyMetaData1 *cur_m,
4313 struct replPropertyMetaData1 *new_m)
4318 * If the new replPropertyMetaData entry for this attribute is
4319 * not provided (this happens in the case where we look for
4320 * ATTID_name, but the name was not changed), then the local
4321 * state is clearly still current, as the remote
4322 * server didn't send it due to being older the high watermark
4325 if (new_m == NULL) {
4329 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4331 * if we compare equal then do an
4332 * update. This is used when a client
4333 * asks for a FULL_SYNC, and can be
4334 * used to recover a corrupt
4337 * This call is a bit tricky, what we
4338 * are doing it turning the 'is_newer'
4339 * call into a 'not is older' by
4340 * swapping cur_m and new_m, and negating the
4343 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4346 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4356 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4358 const struct ldb_val *rdn_val;
4359 const char *rdn_name;
4360 struct ldb_dn *new_dn;
4362 rdn_val = ldb_dn_get_rdn_val(dn);
4363 rdn_name = ldb_dn_get_rdn_name(dn);
4364 if (!rdn_val || !rdn_name) {
4368 new_dn = ldb_dn_copy(mem_ctx, dn);
4373 if (!ldb_dn_remove_child_components(new_dn, 1)) {
4377 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4379 ldb_dn_escape_value(new_dn, *rdn_val),
4380 GUID_string(new_dn, guid))) {
4389 perform a modify operation which sets the rDN and name attributes to
4390 their current values. This has the effect of changing these
4391 attributes to have been last updated by the current DC. This is
4392 needed to ensure that renames performed as part of conflict
4393 resolution are propogated to other DCs
4395 static int replmd_name_modify(struct replmd_replicated_request *ar,
4396 struct ldb_request *req, struct ldb_dn *dn)
4398 struct ldb_message *msg;
4399 const char *rdn_name;
4400 const struct ldb_val *rdn_val;
4401 const struct dsdb_attribute *rdn_attr;
4404 msg = ldb_msg_new(req);
4410 rdn_name = ldb_dn_get_rdn_name(dn);
4411 if (rdn_name == NULL) {
4415 /* normalize the rdn attribute name */
4416 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4417 if (rdn_attr == NULL) {
4420 rdn_name = rdn_attr->lDAPDisplayName;
4422 rdn_val = ldb_dn_get_rdn_val(dn);
4423 if (rdn_val == NULL) {
4427 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4430 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4433 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4436 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4440 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4441 if (ret != LDB_SUCCESS) {
4442 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
4443 ldb_dn_get_linearized(dn),
4444 ldb_errstring(ldb_module_get_ctx(ar->module))));
4454 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
4455 ldb_dn_get_linearized(dn)));
4456 return LDB_ERR_OPERATIONS_ERROR;
4461 callback for conflict DN handling where we have renamed the incoming
4462 record. After renaming it, we need to ensure the change of name and
4463 rDN for the incoming record is seen as an originating update by this DC.
4465 This also handles updating lastKnownParent for entries sent to lostAndFound
4467 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4469 struct replmd_replicated_request *ar =
4470 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4471 struct ldb_dn *conflict_dn = NULL;
4474 if (ares->error != LDB_SUCCESS) {
4475 /* call the normal callback for everything except success */
4476 return replmd_op_callback(req, ares);
4479 switch (req->operation) {
4481 conflict_dn = req->op.add.message->dn;
4484 conflict_dn = req->op.mod.message->dn;
4487 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4490 /* perform a modify of the rDN and name of the record */
4491 ret = replmd_name_modify(ar, req, conflict_dn);
4492 if (ret != LDB_SUCCESS) {
4494 return replmd_op_callback(req, ares);
4497 if (ar->objs->objects[ar->index_current].last_known_parent) {
4498 struct ldb_message *msg = ldb_msg_new(req);
4500 ldb_module_oom(ar->module);
4501 return LDB_ERR_OPERATIONS_ERROR;
4504 msg->dn = req->op.add.message->dn;
4506 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4507 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4508 if (ret != LDB_SUCCESS) {
4509 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4510 ldb_module_oom(ar->module);
4513 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4515 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4516 if (ret != LDB_SUCCESS) {
4517 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4518 ldb_dn_get_linearized(msg->dn),
4519 ldb_errstring(ldb_module_get_ctx(ar->module))));
4525 return replmd_op_callback(req, ares);
4529 callback for replmd_replicated_apply_add()
4530 This copes with the creation of conflict records in the case where
4531 the DN exists, but with a different objectGUID
4533 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))
4535 struct ldb_dn *conflict_dn;
4536 struct replmd_replicated_request *ar =
4537 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4538 struct ldb_result *res;
4539 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4541 const struct ldb_val *omd_value;
4542 struct replPropertyMetaDataBlob omd, *rmd;
4543 enum ndr_err_code ndr_err;
4544 bool rename_incoming_record, rodc;
4545 struct replPropertyMetaData1 *rmd_name, *omd_name;
4546 struct ldb_message *msg;
4547 struct ldb_request *down_req = NULL;
4549 /* call the normal callback for success */
4550 if (ares->error == LDB_SUCCESS) {
4551 return callback(req, ares);
4555 * we have a conflict, and need to decide if we will keep the
4556 * new record or the old record
4559 msg = ar->objs->objects[ar->index_current].msg;
4560 conflict_dn = msg->dn;
4562 /* For failures other than conflicts, fail the whole operation here */
4563 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4564 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4565 ldb_dn_get_linearized(conflict_dn),
4566 ldb_errstring(ldb_module_get_ctx(ar->module)));
4568 return ldb_module_done(ar->req, NULL, NULL,
4569 LDB_ERR_OPERATIONS_ERROR);
4572 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4573 if (ret != LDB_SUCCESS) {
4574 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)));
4575 return ldb_module_done(ar->req, NULL, NULL,
4576 LDB_ERR_OPERATIONS_ERROR);
4582 * We are on an RODC, or were a GC for this
4583 * partition, so we have to fail this until
4584 * someone who owns the partition sorts it
4587 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4588 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
4589 " - We must fail the operation until a master for this partition resolves the conflict",
4590 ldb_dn_get_linearized(conflict_dn));
4595 * first we need the replPropertyMetaData attribute from the
4596 * local, conflicting record
4598 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4600 DSDB_FLAG_NEXT_MODULE |
4601 DSDB_SEARCH_SHOW_DELETED |
4602 DSDB_SEARCH_SHOW_RECYCLED, req);
4603 if (ret != LDB_SUCCESS) {
4604 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4605 ldb_dn_get_linearized(conflict_dn)));
4609 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4610 if (omd_value == NULL) {
4611 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4612 ldb_dn_get_linearized(conflict_dn)));
4616 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4617 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4618 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4619 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4620 ldb_dn_get_linearized(conflict_dn)));
4624 rmd = ar->objs->objects[ar->index_current].meta_data;
4627 * we decide which is newer based on the RPMD on the name
4628 * attribute. See [MS-DRSR] ResolveNameConflict.
4630 * We expect omd_name to be present, as this is from a local
4631 * search, but while rmd_name should have been given to us by
4632 * the remote server, if it is missing we just prefer the
4634 * replmd_replPropertyMetaData1_new_should_be_taken()
4636 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4637 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4639 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4640 ldb_dn_get_linearized(conflict_dn)));
4645 * Should we preserve the current record, and so rename the
4646 * incoming record to be a conflict?
4648 rename_incoming_record
4649 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4650 omd_name, rmd_name);
4652 if (rename_incoming_record) {
4654 struct ldb_dn *new_dn;
4656 guid = samdb_result_guid(msg, "objectGUID");
4657 if (GUID_all_zero(&guid)) {
4658 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4659 ldb_dn_get_linearized(conflict_dn)));
4662 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4663 if (new_dn == NULL) {
4664 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4665 ldb_dn_get_linearized(conflict_dn)));
4669 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4670 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4672 /* re-submit the request, but with the new DN */
4673 callback = replmd_op_name_modify_callback;
4676 /* we are renaming the existing record */
4678 struct ldb_dn *new_dn;
4680 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4681 if (GUID_all_zero(&guid)) {
4682 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4683 ldb_dn_get_linearized(conflict_dn)));
4687 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4688 if (new_dn == NULL) {
4689 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4690 ldb_dn_get_linearized(conflict_dn)));
4694 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4695 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4697 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4698 DSDB_FLAG_OWN_MODULE, req);
4699 if (ret != LDB_SUCCESS) {
4700 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4701 ldb_dn_get_linearized(conflict_dn),
4702 ldb_dn_get_linearized(new_dn),
4703 ldb_errstring(ldb_module_get_ctx(ar->module))));
4708 * now we need to ensure that the rename is seen as an
4709 * originating update. We do that with a modify.
4711 ret = replmd_name_modify(ar, req, new_dn);
4712 if (ret != LDB_SUCCESS) {
4716 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4717 ldb_dn_get_linearized(req->op.add.message->dn)));
4720 ret = ldb_build_add_req(&down_req,
4721 ldb_module_get_ctx(ar->module),
4728 if (ret != LDB_SUCCESS) {
4731 LDB_REQ_SET_LOCATION(down_req);
4733 /* current partition control needed by "repmd_op_callback" */
4734 ret = ldb_request_add_control(down_req,
4735 DSDB_CONTROL_CURRENT_PARTITION_OID,
4737 if (ret != LDB_SUCCESS) {
4738 return replmd_replicated_request_error(ar, ret);
4741 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4742 /* this tells the partition module to make it a
4743 partial replica if creating an NC */
4744 ret = ldb_request_add_control(down_req,
4745 DSDB_CONTROL_PARTIAL_REPLICA,
4747 if (ret != LDB_SUCCESS) {
4748 return replmd_replicated_request_error(ar, ret);
4753 * Finally we re-run the add, otherwise the new record won't
4754 * exist, as we are here because of that exact failure!
4756 return ldb_next_request(ar->module, down_req);
4759 /* on failure make the caller get the error. This means
4760 * replication will stop with an error, but there is not much
4763 return ldb_module_done(ar->req, NULL, NULL,
4768 callback for replmd_replicated_apply_add()
4769 This copes with the creation of conflict records in the case where
4770 the DN exists, but with a different objectGUID
4772 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4774 struct replmd_replicated_request *ar =
4775 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4777 if (ar->objs->objects[ar->index_current].last_known_parent) {
4778 /* This is like a conflict DN, where we put the object in LostAndFound
4779 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4780 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4783 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4787 this is called when a new object comes in over DRS
4789 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4791 struct ldb_context *ldb;
4792 struct ldb_request *change_req;
4793 enum ndr_err_code ndr_err;
4794 struct ldb_message *msg;
4795 struct replPropertyMetaDataBlob *md;
4796 struct ldb_val md_value;
4799 bool remote_isDeleted = false;
4802 time_t t = time(NULL);
4803 const struct ldb_val *rdn_val;
4804 struct replmd_private *replmd_private =
4805 talloc_get_type(ldb_module_get_private(ar->module),
4806 struct replmd_private);
4807 unix_to_nt_time(&now, t);
4809 ldb = ldb_module_get_ctx(ar->module);
4810 msg = ar->objs->objects[ar->index_current].msg;
4811 md = ar->objs->objects[ar->index_current].meta_data;
4812 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4814 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4815 if (ret != LDB_SUCCESS) {
4816 return replmd_replicated_request_error(ar, ret);
4819 ret = dsdb_msg_add_guid(msg,
4820 &ar->objs->objects[ar->index_current].object_guid,
4822 if (ret != LDB_SUCCESS) {
4823 return replmd_replicated_request_error(ar, ret);
4826 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4827 if (ret != LDB_SUCCESS) {
4828 return replmd_replicated_request_error(ar, ret);
4831 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4832 if (ret != LDB_SUCCESS) {
4833 return replmd_replicated_request_error(ar, ret);
4836 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4837 if (ret != LDB_SUCCESS) {
4838 return replmd_replicated_request_error(ar, ret);
4841 /* remove any message elements that have zero values */
4842 for (i=0; i<msg->num_elements; i++) {
4843 struct ldb_message_element *el = &msg->elements[i];
4845 if (el->num_values == 0) {
4846 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4847 ldb_asprintf_errstring(ldb, __location__
4848 ": empty objectClass sent on %s, aborting replication\n",
4849 ldb_dn_get_linearized(msg->dn));
4850 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4853 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4855 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4856 msg->num_elements--;
4863 struct GUID_txt_buf guid_txt;
4865 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4866 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4867 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4872 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4873 "isDeleted", false);
4876 * the meta data array is already sorted by the caller, except
4877 * for the RDN, which needs to be added.
4881 rdn_val = ldb_dn_get_rdn_val(msg->dn);
4882 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4883 md, ar, now, is_schema_nc);
4884 if (ret != LDB_SUCCESS) {
4885 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4886 return replmd_replicated_request_error(ar, ret);
4889 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4890 if (ret != LDB_SUCCESS) {
4891 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4892 return replmd_replicated_request_error(ar, ret);
4895 for (i=0; i < md->ctr.ctr1.count; i++) {
4896 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4898 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4899 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4900 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4901 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4902 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4904 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4905 if (ret != LDB_SUCCESS) {
4906 return replmd_replicated_request_error(ar, ret);
4909 replmd_ldb_message_sort(msg, ar->schema);
4911 if (!remote_isDeleted) {
4912 ret = dsdb_module_schedule_sd_propagation(ar->module,
4913 ar->objs->partition_dn,
4915 if (ret != LDB_SUCCESS) {
4916 return replmd_replicated_request_error(ar, ret);
4920 ar->isDeleted = remote_isDeleted;
4922 ret = ldb_build_add_req(&change_req,
4928 replmd_op_add_callback,
4930 LDB_REQ_SET_LOCATION(change_req);
4931 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4933 /* current partition control needed by "repmd_op_callback" */
4934 ret = ldb_request_add_control(change_req,
4935 DSDB_CONTROL_CURRENT_PARTITION_OID,
4937 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4939 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4940 /* this tells the partition module to make it a
4941 partial replica if creating an NC */
4942 ret = ldb_request_add_control(change_req,
4943 DSDB_CONTROL_PARTIAL_REPLICA,
4945 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4948 return ldb_next_request(ar->module, change_req);
4951 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
4952 struct ldb_reply *ares)
4954 struct replmd_replicated_request *ar = talloc_get_type(req->context,
4955 struct replmd_replicated_request);
4959 return ldb_module_done(ar->req, NULL, NULL,
4960 LDB_ERR_OPERATIONS_ERROR);
4964 * The error NO_SUCH_OBJECT is not expected, unless the search
4965 * base is the partition DN, and that case doesn't happen here
4966 * because then we wouldn't get a parent_guid_value in any
4969 if (ares->error != LDB_SUCCESS) {
4970 return ldb_module_done(ar->req, ares->controls,
4971 ares->response, ares->error);
4974 switch (ares->type) {
4975 case LDB_REPLY_ENTRY:
4977 struct ldb_message *parent_msg = ares->message;
4978 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
4979 struct ldb_dn *parent_dn;
4982 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
4983 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
4984 /* Per MS-DRSR 4.1.10.6.10
4985 * FindBestParentObject we need to move this
4986 * new object under a deleted object to
4988 struct ldb_dn *nc_root;
4990 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
4991 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4992 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4993 "No suitable NC root found for %s. "
4994 "We need to move this object because parent object %s "
4995 "is deleted, but this object is not.",
4996 ldb_dn_get_linearized(msg->dn),
4997 ldb_dn_get_linearized(parent_msg->dn));
4998 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4999 } else if (ret != LDB_SUCCESS) {
5000 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5001 "Unable to find NC root for %s: %s. "
5002 "We need to move this object because parent object %s "
5003 "is deleted, but this object is not.",
5004 ldb_dn_get_linearized(msg->dn),
5005 ldb_errstring(ldb_module_get_ctx(ar->module)),
5006 ldb_dn_get_linearized(parent_msg->dn));
5007 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5010 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5012 DS_GUID_LOSTANDFOUND_CONTAINER,
5014 if (ret != LDB_SUCCESS) {
5015 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5016 "Unable to find LostAndFound Container for %s "
5017 "in partition %s: %s. "
5018 "We need to move this object because parent object %s "
5019 "is deleted, but this object is not.",
5020 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5021 ldb_errstring(ldb_module_get_ctx(ar->module)),
5022 ldb_dn_get_linearized(parent_msg->dn));
5023 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5025 ar->objs->objects[ar->index_current].last_known_parent
5026 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5030 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5033 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5035 comp_num = ldb_dn_get_comp_num(msg->dn);
5037 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5039 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5042 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5044 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5048 case LDB_REPLY_REFERRAL:
5049 /* we ignore referrals */
5052 case LDB_REPLY_DONE:
5054 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5055 struct GUID_txt_buf str_buf;
5056 if (ar->search_msg != NULL) {
5057 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5058 "No parent with GUID %s found for object locally known as %s",
5059 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5060 ldb_dn_get_linearized(ar->search_msg->dn));
5062 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5063 "No parent with GUID %s found for object remotely known as %s",
5064 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5065 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5069 * This error code is really important, as it
5070 * is the flag back to the callers to retry
5071 * this with DRSUAPI_DRS_GET_ANC, and so get
5072 * the parent objects before the child
5075 return ldb_module_done(ar->req, NULL, NULL,
5076 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5079 if (ar->search_msg != NULL) {
5080 ret = replmd_replicated_apply_merge(ar);
5082 ret = replmd_replicated_apply_add(ar);
5084 if (ret != LDB_SUCCESS) {
5085 return ldb_module_done(ar->req, NULL, NULL, ret);
5094 * Look for the parent object, so we put the new object in the right
5095 * place This is akin to NameObject in MS-DRSR - this routine and the
5096 * callbacks find the right parent name, and correct name for this
5100 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5102 struct ldb_context *ldb;
5106 struct ldb_request *search_req;
5107 static const char *attrs[] = {"isDeleted", NULL};
5108 struct GUID_txt_buf guid_str_buf;
5110 ldb = ldb_module_get_ctx(ar->module);
5112 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5113 if (ar->search_msg != NULL) {
5114 return replmd_replicated_apply_merge(ar);
5116 return replmd_replicated_apply_add(ar);
5120 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5123 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5124 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5126 ret = ldb_build_search_req(&search_req,
5129 ar->objs->partition_dn,
5135 replmd_replicated_apply_search_for_parent_callback,
5137 LDB_REQ_SET_LOCATION(search_req);
5139 ret = dsdb_request_add_controls(search_req,
5140 DSDB_SEARCH_SHOW_RECYCLED|
5141 DSDB_SEARCH_SHOW_DELETED|
5142 DSDB_SEARCH_SHOW_EXTENDED_DN);
5143 if (ret != LDB_SUCCESS) {
5147 return ldb_next_request(ar->module, search_req);
5151 handle renames that come in over DRS replication
5153 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5154 struct ldb_message *msg,
5155 struct ldb_request *parent,
5159 TALLOC_CTX *tmp_ctx = talloc_new(msg);
5160 struct ldb_result *res;
5161 struct ldb_dn *conflict_dn;
5162 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5163 const struct ldb_val *omd_value;
5164 struct replPropertyMetaDataBlob omd, *rmd;
5165 enum ndr_err_code ndr_err;
5166 bool rename_incoming_record, rodc;
5167 struct replPropertyMetaData1 *rmd_name, *omd_name;
5168 struct ldb_dn *new_dn;
5171 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5172 ldb_dn_get_linearized(ar->search_msg->dn),
5173 ldb_dn_get_linearized(msg->dn)));
5176 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5177 DSDB_FLAG_NEXT_MODULE, ar->req);
5178 if (ret == LDB_SUCCESS) {
5179 talloc_free(tmp_ctx);
5184 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5185 talloc_free(tmp_ctx);
5186 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5187 ldb_dn_get_linearized(ar->search_msg->dn),
5188 ldb_dn_get_linearized(msg->dn),
5189 ldb_errstring(ldb_module_get_ctx(ar->module)));
5193 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5194 if (ret != LDB_SUCCESS) {
5195 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5196 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5197 ldb_errstring(ldb_module_get_ctx(ar->module)));
5198 return LDB_ERR_OPERATIONS_ERROR;
5201 * we have a conflict, and need to decide if we will keep the
5202 * new record or the old record
5205 conflict_dn = msg->dn;
5209 * We are on an RODC, or were a GC for this
5210 * partition, so we have to fail this until
5211 * someone who owns the partition sorts it
5214 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5215 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5216 " - We must fail the operation until a master for this partition resolves the conflict",
5217 ldb_dn_get_linearized(conflict_dn));
5222 * first we need the replPropertyMetaData attribute from the
5225 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5227 DSDB_FLAG_NEXT_MODULE |
5228 DSDB_SEARCH_SHOW_DELETED |
5229 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5230 if (ret != LDB_SUCCESS) {
5231 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5232 ldb_dn_get_linearized(conflict_dn)));
5236 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5237 if (omd_value == NULL) {
5238 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5239 ldb_dn_get_linearized(conflict_dn)));
5243 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5244 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5245 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5246 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5247 ldb_dn_get_linearized(conflict_dn)));
5251 rmd = ar->objs->objects[ar->index_current].meta_data;
5254 * we decide which is newer based on the RPMD on the name
5255 * attribute. See [MS-DRSR] ResolveNameConflict.
5257 * We expect omd_name to be present, as this is from a local
5258 * search, but while rmd_name should have been given to us by
5259 * the remote server, if it is missing we just prefer the
5261 * replmd_replPropertyMetaData1_new_should_be_taken()
5263 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5264 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5266 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5267 ldb_dn_get_linearized(conflict_dn)));
5272 * Should we preserve the current record, and so rename the
5273 * incoming record to be a conflict?
5275 rename_incoming_record =
5276 !replmd_replPropertyMetaData1_new_should_be_taken(
5277 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5278 omd_name, rmd_name);
5280 if (rename_incoming_record) {
5282 new_dn = replmd_conflict_dn(msg, msg->dn,
5283 &ar->objs->objects[ar->index_current].object_guid);
5284 if (new_dn == NULL) {
5285 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5286 "Failed to form conflict DN for %s\n",
5287 ldb_dn_get_linearized(msg->dn));
5289 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5292 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5293 DSDB_FLAG_NEXT_MODULE, ar->req);
5294 if (ret != LDB_SUCCESS) {
5295 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5296 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5297 ldb_dn_get_linearized(conflict_dn),
5298 ldb_dn_get_linearized(ar->search_msg->dn),
5299 ldb_dn_get_linearized(new_dn),
5300 ldb_errstring(ldb_module_get_ctx(ar->module)));
5301 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5309 /* we are renaming the existing record */
5311 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5312 if (GUID_all_zero(&guid)) {
5313 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5314 ldb_dn_get_linearized(conflict_dn)));
5318 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5319 if (new_dn == NULL) {
5320 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5321 ldb_dn_get_linearized(conflict_dn)));
5325 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5326 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5328 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5329 DSDB_FLAG_OWN_MODULE, ar->req);
5330 if (ret != LDB_SUCCESS) {
5331 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5332 ldb_dn_get_linearized(conflict_dn),
5333 ldb_dn_get_linearized(new_dn),
5334 ldb_errstring(ldb_module_get_ctx(ar->module))));
5339 * now we need to ensure that the rename is seen as an
5340 * originating update. We do that with a modify.
5342 ret = replmd_name_modify(ar, ar->req, new_dn);
5343 if (ret != LDB_SUCCESS) {
5347 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5348 ldb_dn_get_linearized(ar->search_msg->dn),
5349 ldb_dn_get_linearized(msg->dn)));
5352 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5353 DSDB_FLAG_NEXT_MODULE, ar->req);
5354 if (ret != LDB_SUCCESS) {
5355 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5356 ldb_dn_get_linearized(ar->search_msg->dn),
5357 ldb_dn_get_linearized(msg->dn),
5358 ldb_errstring(ldb_module_get_ctx(ar->module))));
5364 * On failure make the caller get the error
5365 * This means replication will stop with an error,
5366 * but there is not much else we can do. In the
5367 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5371 talloc_free(tmp_ctx);
5376 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5378 struct ldb_context *ldb;
5379 struct ldb_request *change_req;
5380 enum ndr_err_code ndr_err;
5381 struct ldb_message *msg;
5382 struct replPropertyMetaDataBlob *rmd;
5383 struct replPropertyMetaDataBlob omd;
5384 const struct ldb_val *omd_value;
5385 struct replPropertyMetaDataBlob nmd;
5386 struct ldb_val nmd_value;
5387 struct GUID remote_parent_guid;
5390 unsigned int removed_attrs = 0;
5392 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5393 bool isDeleted = false;
5394 bool local_isDeleted = false;
5395 bool remote_isDeleted = false;
5396 bool take_remote_isDeleted = false;
5397 bool sd_updated = false;
5398 bool renamed = false;
5399 bool is_schema_nc = false;
5401 const struct ldb_val *old_rdn, *new_rdn;
5402 struct replmd_private *replmd_private =
5403 talloc_get_type(ldb_module_get_private(ar->module),
5404 struct replmd_private);
5406 time_t t = time(NULL);
5407 unix_to_nt_time(&now, t);
5409 ldb = ldb_module_get_ctx(ar->module);
5410 msg = ar->objs->objects[ar->index_current].msg;
5412 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5414 rmd = ar->objs->objects[ar->index_current].meta_data;
5418 /* find existing meta data */
5419 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5421 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5422 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5423 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5424 nt_status = ndr_map_error2ntstatus(ndr_err);
5425 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5428 if (omd.version != 1) {
5429 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5434 struct GUID_txt_buf guid_txt;
5436 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5437 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
5440 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5442 ndr_print_struct_string(s,
5443 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5444 "existing replPropertyMetaData",
5446 ndr_print_struct_string(s,
5447 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5448 "incoming replPropertyMetaData",
5453 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5454 "isDeleted", false);
5455 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5456 "isDeleted", false);
5459 * Fill in the remote_parent_guid with the GUID or an all-zero
5462 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5463 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5465 remote_parent_guid = GUID_zero();
5469 * To ensure we follow a complex rename chain around, we have
5470 * to confirm that the DN is the same (mostly to confirm the
5471 * RDN) and the parentGUID is the same.
5473 * This ensures we keep things under the correct parent, which
5474 * replmd_replicated_handle_rename() will do.
5477 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5478 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5482 * handle renames, even just by case that come in over
5483 * DRS. Changes in the parent DN don't hit us here,
5484 * because the search for a parent will clean up those
5487 * We also have already filtered out the case where
5488 * the peer has an older name to what we have (see
5489 * replmd_replicated_apply_search_callback())
5491 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5494 if (ret != LDB_SUCCESS) {
5495 ldb_debug(ldb, LDB_DEBUG_FATAL,
5496 "replmd_replicated_request rename %s => %s failed - %s\n",
5497 ldb_dn_get_linearized(ar->search_msg->dn),
5498 ldb_dn_get_linearized(msg->dn),
5499 ldb_errstring(ldb));
5500 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5503 if (renamed == true) {
5505 * Set the callback to one that will fix up the name
5506 * metadata on the new conflict DN
5508 callback = replmd_op_name_modify_callback;
5513 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5514 nmd.ctr.ctr1.array = talloc_array(ar,
5515 struct replPropertyMetaData1,
5516 nmd.ctr.ctr1.count);
5517 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5519 /* first copy the old meta data */
5520 for (i=0; i < omd.ctr.ctr1.count; i++) {
5521 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5526 /* now merge in the new meta data */
5527 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5530 for (j=0; j < ni; j++) {
5533 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5537 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5538 ar->objs->dsdb_repl_flags,
5539 &nmd.ctr.ctr1.array[j],
5540 &rmd->ctr.ctr1.array[i]);
5542 /* replace the entry */
5543 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5544 if (ar->seq_num == 0) {
5545 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5546 if (ret != LDB_SUCCESS) {
5547 return replmd_replicated_request_error(ar, ret);
5550 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5551 switch (nmd.ctr.ctr1.array[j].attid) {
5552 case DRSUAPI_ATTID_ntSecurityDescriptor:
5555 case DRSUAPI_ATTID_isDeleted:
5556 take_remote_isDeleted = true;
5565 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5566 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5567 msg->elements[i-removed_attrs].name,
5568 ldb_dn_get_linearized(msg->dn),
5569 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5572 /* we don't want to apply this change so remove the attribute */
5573 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5580 if (found) continue;
5582 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5583 if (ar->seq_num == 0) {
5584 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5585 if (ret != LDB_SUCCESS) {
5586 return replmd_replicated_request_error(ar, ret);
5589 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5590 switch (nmd.ctr.ctr1.array[ni].attid) {
5591 case DRSUAPI_ATTID_ntSecurityDescriptor:
5594 case DRSUAPI_ATTID_isDeleted:
5595 take_remote_isDeleted = true;
5604 * finally correct the size of the meta_data array
5606 nmd.ctr.ctr1.count = ni;
5608 new_rdn = ldb_dn_get_rdn_val(msg->dn);
5609 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5612 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5613 &nmd, ar, now, is_schema_nc);
5614 if (ret != LDB_SUCCESS) {
5615 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5616 return replmd_replicated_request_error(ar, ret);
5620 * sort the new meta data array
5622 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5623 if (ret != LDB_SUCCESS) {
5624 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5629 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
5632 * This also controls SD propagation below
5634 if (take_remote_isDeleted) {
5635 isDeleted = remote_isDeleted;
5637 isDeleted = local_isDeleted;
5640 ar->isDeleted = isDeleted;
5643 * check if some replicated attributes left, otherwise skip the ldb_modify() call
5645 if (msg->num_elements == 0) {
5646 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5649 return replmd_replicated_apply_isDeleted(ar);
5652 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5653 ar->index_current, msg->num_elements);
5659 if (sd_updated && !isDeleted) {
5660 ret = dsdb_module_schedule_sd_propagation(ar->module,
5661 ar->objs->partition_dn,
5663 if (ret != LDB_SUCCESS) {
5664 return ldb_operr(ldb);
5668 /* create the meta data value */
5669 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5670 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5671 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5672 nt_status = ndr_map_error2ntstatus(ndr_err);
5673 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5677 * when we know that we'll modify the record, add the whenChanged, uSNChanged
5678 * and replPopertyMetaData attributes
5680 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5681 if (ret != LDB_SUCCESS) {
5682 return replmd_replicated_request_error(ar, ret);
5684 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5685 if (ret != LDB_SUCCESS) {
5686 return replmd_replicated_request_error(ar, ret);
5688 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5689 if (ret != LDB_SUCCESS) {
5690 return replmd_replicated_request_error(ar, ret);
5693 replmd_ldb_message_sort(msg, ar->schema);
5695 /* we want to replace the old values */
5696 for (i=0; i < msg->num_elements; i++) {
5697 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5698 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5699 if (msg->elements[i].num_values == 0) {
5700 ldb_asprintf_errstring(ldb, __location__
5701 ": objectClass removed on %s, aborting replication\n",
5702 ldb_dn_get_linearized(msg->dn));
5703 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5709 struct GUID_txt_buf guid_txt;
5711 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5712 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5713 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5718 ret = ldb_build_mod_req(&change_req,
5726 LDB_REQ_SET_LOCATION(change_req);
5727 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5729 /* current partition control needed by "repmd_op_callback" */
5730 ret = ldb_request_add_control(change_req,
5731 DSDB_CONTROL_CURRENT_PARTITION_OID,
5733 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5735 return ldb_next_request(ar->module, change_req);
5738 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5739 struct ldb_reply *ares)
5741 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5742 struct replmd_replicated_request);
5746 return ldb_module_done(ar->req, NULL, NULL,
5747 LDB_ERR_OPERATIONS_ERROR);
5749 if (ares->error != LDB_SUCCESS &&
5750 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5751 return ldb_module_done(ar->req, ares->controls,
5752 ares->response, ares->error);
5755 switch (ares->type) {
5756 case LDB_REPLY_ENTRY:
5757 ar->search_msg = talloc_steal(ar, ares->message);
5760 case LDB_REPLY_REFERRAL:
5761 /* we ignore referrals */
5764 case LDB_REPLY_DONE:
5766 struct replPropertyMetaData1 *md_remote;
5767 struct replPropertyMetaData1 *md_local;
5769 struct replPropertyMetaDataBlob omd;
5770 const struct ldb_val *omd_value;
5771 struct replPropertyMetaDataBlob *rmd;
5772 struct ldb_message *msg;
5774 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5775 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5778 * This is the ADD case, find the appropriate parent,
5779 * as this object doesn't exist locally:
5781 if (ar->search_msg == NULL) {
5782 ret = replmd_replicated_apply_search_for_parent(ar);
5783 if (ret != LDB_SUCCESS) {
5784 return ldb_module_done(ar->req, NULL, NULL, ret);
5791 * Otherwise, in the MERGE case, work out if we are
5792 * attempting a rename, and if so find the parent the
5793 * newly renamed object wants to belong under (which
5794 * may not be the parent in it's attached string DN
5796 rmd = ar->objs->objects[ar->index_current].meta_data;
5800 /* find existing meta data */
5801 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5803 enum ndr_err_code ndr_err;
5804 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5805 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5806 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5807 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5808 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5811 if (omd.version != 1) {
5812 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5816 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5818 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5819 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5820 && GUID_all_zero(&ar->local_parent_guid)) {
5821 DEBUG(0, ("Refusing to replicate new version of %s "
5822 "as local object has an all-zero parentGUID attribute, "
5823 "despite not being an NC root\n",
5824 ldb_dn_get_linearized(ar->search_msg->dn)));
5825 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5829 * now we need to check for double renames. We could have a
5830 * local rename pending which our replication partner hasn't
5831 * received yet. We choose which one wins by looking at the
5832 * attribute stamps on the two objects, the newer one wins.
5834 * This also simply applies the correct algorithms for
5835 * determining if a change was made to name at all, or
5836 * if the object has just been renamed under the same
5839 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5840 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5842 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5843 ldb_dn_get_linearized(ar->search_msg->dn)));
5844 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5848 * if there is no name attribute given then we have to assume the
5849 * object we've received has the older name
5851 if (replmd_replPropertyMetaData1_new_should_be_taken(
5852 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5853 md_local, md_remote)) {
5854 struct GUID_txt_buf p_guid_local;
5855 struct GUID_txt_buf p_guid_remote;
5856 msg = ar->objs->objects[ar->index_current].msg;
5858 /* Merge on the existing object, with rename */
5860 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5861 "as incoming object changing to %s under %s\n",
5862 ldb_dn_get_linearized(ar->search_msg->dn),
5863 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5864 ldb_dn_get_linearized(msg->dn),
5865 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5867 ret = replmd_replicated_apply_search_for_parent(ar);
5869 struct GUID_txt_buf p_guid_local;
5870 struct GUID_txt_buf p_guid_remote;
5871 msg = ar->objs->objects[ar->index_current].msg;
5874 * Merge on the existing object, force no
5875 * rename (code below just to explain why in
5879 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5880 ldb_dn_get_linearized(msg->dn)) == 0) {
5881 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5882 GUID_equal(&ar->local_parent_guid,
5883 ar->objs->objects[ar->index_current].parent_guid)
5885 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5886 "despite incoming object changing parent to %s\n",
5887 ldb_dn_get_linearized(ar->search_msg->dn),
5888 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5889 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5893 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5894 " and rejecting older rename to %s under %s\n",
5895 ldb_dn_get_linearized(ar->search_msg->dn),
5896 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5897 ldb_dn_get_linearized(msg->dn),
5898 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5902 * This assignment ensures that the strcmp()
5903 * and GUID_equal() calls in
5904 * replmd_replicated_apply_merge() avoids the
5907 ar->objs->objects[ar->index_current].parent_guid =
5908 &ar->local_parent_guid;
5910 msg->dn = ar->search_msg->dn;
5911 ret = replmd_replicated_apply_merge(ar);
5913 if (ret != LDB_SUCCESS) {
5914 return ldb_module_done(ar->req, NULL, NULL, ret);
5923 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
5925 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
5927 struct ldb_context *ldb;
5931 struct ldb_request *search_req;
5932 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
5933 "parentGUID", "instanceType",
5934 "replPropertyMetaData", "nTSecurityDescriptor",
5935 "isDeleted", NULL };
5936 struct GUID_txt_buf guid_str_buf;
5938 if (ar->index_current >= ar->objs->num_objects) {
5939 /* done with it, go to next stage */
5940 return replmd_replicated_uptodate_vector(ar);
5943 ldb = ldb_module_get_ctx(ar->module);
5944 ar->search_msg = NULL;
5945 ar->isDeleted = false;
5947 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5950 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5951 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5953 ret = ldb_build_search_req(&search_req,
5956 ar->objs->partition_dn,
5962 replmd_replicated_apply_search_callback,
5964 LDB_REQ_SET_LOCATION(search_req);
5966 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
5968 if (ret != LDB_SUCCESS) {
5972 return ldb_next_request(ar->module, search_req);
5976 * This is essentially a wrapper for replmd_replicated_apply_next()
5978 * This is needed to ensure that both codepaths call this handler.
5980 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
5982 struct ldb_dn *deleted_objects_dn;
5983 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5984 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
5985 &deleted_objects_dn);
5986 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
5988 * Do a delete here again, so that if there is
5989 * anything local that conflicts with this
5990 * object being deleted, it is removed. This
5991 * includes links. See MS-DRSR 4.1.10.6.9
5994 * If the object is already deleted, and there
5995 * is no more work required, it doesn't do
5999 /* This has been updated to point to the DN we eventually did the modify on */
6001 struct ldb_request *del_req;
6002 struct ldb_result *res;
6004 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6006 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6010 res = talloc_zero(tmp_ctx, struct ldb_result);
6012 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6013 talloc_free(tmp_ctx);
6017 /* Build a delete request, which hopefully will artually turn into nothing */
6018 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6022 ldb_modify_default_callback,
6024 LDB_REQ_SET_LOCATION(del_req);
6025 if (ret != LDB_SUCCESS) {
6026 talloc_free(tmp_ctx);
6031 * This is the guts of the call, call back
6032 * into our delete code, but setting the
6033 * re_delete flag so we delete anything that
6034 * shouldn't be there on a deleted or recycled
6037 ret = replmd_delete_internals(ar->module, del_req, true);
6038 if (ret == LDB_SUCCESS) {
6039 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6042 talloc_free(tmp_ctx);
6043 if (ret != LDB_SUCCESS) {
6048 ar->index_current++;
6049 return replmd_replicated_apply_next(ar);
6052 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6053 struct ldb_reply *ares)
6055 struct ldb_context *ldb;
6056 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6057 struct replmd_replicated_request);
6058 ldb = ldb_module_get_ctx(ar->module);
6061 return ldb_module_done(ar->req, NULL, NULL,
6062 LDB_ERR_OPERATIONS_ERROR);
6064 if (ares->error != LDB_SUCCESS) {
6065 return ldb_module_done(ar->req, ares->controls,
6066 ares->response, ares->error);
6069 if (ares->type != LDB_REPLY_DONE) {
6070 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6071 return ldb_module_done(ar->req, NULL, NULL,
6072 LDB_ERR_OPERATIONS_ERROR);
6077 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6080 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6082 struct ldb_context *ldb;
6083 struct ldb_request *change_req;
6084 enum ndr_err_code ndr_err;
6085 struct ldb_message *msg;
6086 struct replUpToDateVectorBlob ouv;
6087 const struct ldb_val *ouv_value;
6088 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6089 struct replUpToDateVectorBlob nuv;
6090 struct ldb_val nuv_value;
6091 struct ldb_message_element *nuv_el = NULL;
6092 struct ldb_message_element *orf_el = NULL;
6093 struct repsFromToBlob nrf;
6094 struct ldb_val *nrf_value = NULL;
6095 struct ldb_message_element *nrf_el = NULL;
6099 time_t t = time(NULL);
6102 uint32_t instanceType;
6104 ldb = ldb_module_get_ctx(ar->module);
6105 ruv = ar->objs->uptodateness_vector;
6111 unix_to_nt_time(&now, t);
6113 if (ar->search_msg == NULL) {
6114 /* this happens for a REPL_OBJ call where we are
6115 creating the target object by replicating it. The
6116 subdomain join code does this for the partition DN
6118 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6119 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6122 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6123 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6124 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6125 ldb_dn_get_linearized(ar->search_msg->dn)));
6126 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6130 * first create the new replUpToDateVector
6132 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6134 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6135 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6136 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6137 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6138 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6141 if (ouv.version != 2) {
6142 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6147 * the new uptodateness vector will at least
6148 * contain 1 entry, one for the source_dsa
6150 * plus optional values from our old vector and the one from the source_dsa
6152 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6153 if (ruv) nuv.ctr.ctr2.count += ruv->count;
6154 nuv.ctr.ctr2.cursors = talloc_array(ar,
6155 struct drsuapi_DsReplicaCursor2,
6156 nuv.ctr.ctr2.count);
6157 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6159 /* first copy the old vector */
6160 for (i=0; i < ouv.ctr.ctr2.count; i++) {
6161 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6165 /* merge in the source_dsa vector is available */
6166 for (i=0; (ruv && i < ruv->count); i++) {
6169 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6170 &ar->our_invocation_id)) {
6174 for (j=0; j < ni; j++) {
6175 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6176 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6182 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6183 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6188 if (found) continue;
6190 /* if it's not there yet, add it */
6191 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6196 * finally correct the size of the cursors array
6198 nuv.ctr.ctr2.count = ni;
6203 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6206 * create the change ldb_message
6208 msg = ldb_msg_new(ar);
6209 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6210 msg->dn = ar->search_msg->dn;
6212 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6213 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6214 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6215 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6216 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6218 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6219 if (ret != LDB_SUCCESS) {
6220 return replmd_replicated_request_error(ar, ret);
6222 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6225 * now create the new repsFrom value from the given repsFromTo1 structure
6229 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6230 nrf.ctr.ctr1.last_attempt = now;
6231 nrf.ctr.ctr1.last_success = now;
6232 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6235 * first see if we already have a repsFrom value for the current source dsa
6236 * if so we'll later replace this value
6238 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6240 for (i=0; i < orf_el->num_values; i++) {
6241 struct repsFromToBlob *trf;
6243 trf = talloc(ar, struct repsFromToBlob);
6244 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6246 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6247 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6248 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6249 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6250 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6253 if (trf->version != 1) {
6254 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6258 * we compare the source dsa objectGUID not the invocation_id
6259 * because we want only one repsFrom value per source dsa
6260 * and when the invocation_id of the source dsa has changed we don't need
6261 * the old repsFrom with the old invocation_id
6263 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6264 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6270 nrf_value = &orf_el->values[i];
6275 * copy over all old values to the new ldb_message
6277 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6278 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6283 * if we haven't found an old repsFrom value for the current source dsa
6284 * we'll add a new value
6287 struct ldb_val zero_value;
6288 ZERO_STRUCT(zero_value);
6289 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6290 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6292 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6295 /* we now fill the value which is already attached to ldb_message */
6296 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6298 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6299 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6300 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6301 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6305 * the ldb_message_element for the attribute, has all the old values and the new one
6306 * so we'll replace the whole attribute with all values
6308 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6310 if (CHECK_DEBUGLVL(4)) {
6311 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
6312 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6316 /* prepare the ldb_modify() request */
6317 ret = ldb_build_mod_req(&change_req,
6323 replmd_replicated_uptodate_modify_callback,
6325 LDB_REQ_SET_LOCATION(change_req);
6326 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6328 return ldb_next_request(ar->module, change_req);
6331 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6332 struct ldb_reply *ares)
6334 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6335 struct replmd_replicated_request);
6339 return ldb_module_done(ar->req, NULL, NULL,
6340 LDB_ERR_OPERATIONS_ERROR);
6342 if (ares->error != LDB_SUCCESS &&
6343 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6344 return ldb_module_done(ar->req, ares->controls,
6345 ares->response, ares->error);
6348 switch (ares->type) {
6349 case LDB_REPLY_ENTRY:
6350 ar->search_msg = talloc_steal(ar, ares->message);
6353 case LDB_REPLY_REFERRAL:
6354 /* we ignore referrals */
6357 case LDB_REPLY_DONE:
6358 ret = replmd_replicated_uptodate_modify(ar);
6359 if (ret != LDB_SUCCESS) {
6360 return ldb_module_done(ar->req, NULL, NULL, ret);
6369 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6371 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6372 struct replmd_private *replmd_private =
6373 talloc_get_type_abort(ldb_module_get_private(ar->module),
6374 struct replmd_private);
6376 static const char *attrs[] = {
6377 "replUpToDateVector",
6382 struct ldb_request *search_req;
6384 ar->search_msg = NULL;
6387 * Let the caller know that we did an originating updates
6389 ar->objs->originating_updates = replmd_private->originating_updates;
6391 ret = ldb_build_search_req(&search_req,
6394 ar->objs->partition_dn,
6400 replmd_replicated_uptodate_search_callback,
6402 LDB_REQ_SET_LOCATION(search_req);
6403 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6405 return ldb_next_request(ar->module, search_req);
6410 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6412 struct ldb_context *ldb;
6413 struct dsdb_extended_replicated_objects *objs;
6414 struct replmd_replicated_request *ar;
6415 struct ldb_control **ctrls;
6418 struct replmd_private *replmd_private =
6419 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6421 ldb = ldb_module_get_ctx(module);
6423 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6425 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6427 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6428 return LDB_ERR_PROTOCOL_ERROR;
6431 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6432 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6433 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6434 return LDB_ERR_PROTOCOL_ERROR;
6437 ar = replmd_ctx_init(module, req);
6439 return LDB_ERR_OPERATIONS_ERROR;
6441 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6442 ar->apply_mode = true;
6444 ar->schema = dsdb_get_schema(ldb, ar);
6446 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6448 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6449 return LDB_ERR_CONSTRAINT_VIOLATION;
6452 ctrls = req->controls;
6454 if (req->controls) {
6455 req->controls = talloc_memdup(ar, req->controls,
6456 talloc_get_size(req->controls));
6457 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6460 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6461 if (ret != LDB_SUCCESS) {
6465 /* If this change contained linked attributes in the body
6466 * (rather than in the links section) we need to update
6467 * backlinks in linked_attributes */
6468 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6469 if (ret != LDB_SUCCESS) {
6473 ar->controls = req->controls;
6474 req->controls = ctrls;
6476 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
6478 /* save away the linked attributes for the end of the
6480 for (i=0; i<ar->objs->linked_attributes_count; i++) {
6481 struct la_entry *la_entry;
6483 if (replmd_private->la_ctx == NULL) {
6484 replmd_private->la_ctx = talloc_new(replmd_private);
6486 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6487 if (la_entry == NULL) {
6489 return LDB_ERR_OPERATIONS_ERROR;
6491 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6492 if (la_entry->la == NULL) {
6493 talloc_free(la_entry);
6495 return LDB_ERR_OPERATIONS_ERROR;
6497 *la_entry->la = ar->objs->linked_attributes[i];
6499 /* we need to steal the non-scalars so they stay
6500 around until the end of the transaction */
6501 talloc_steal(la_entry->la, la_entry->la->identifier);
6502 talloc_steal(la_entry->la, la_entry->la->value.blob);
6504 DLIST_ADD(replmd_private->la_list, la_entry);
6507 return replmd_replicated_apply_next(ar);
6511 process one linked attribute structure
6513 static int replmd_process_linked_attribute(struct ldb_module *module,
6514 struct replmd_private *replmd_private,
6515 struct la_entry *la_entry,
6516 struct ldb_request *parent)
6518 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6519 struct ldb_context *ldb = ldb_module_get_ctx(module);
6520 struct ldb_message *msg;
6521 struct ldb_message *target_msg = NULL;
6522 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6523 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
6525 const struct dsdb_attribute *attr;
6526 struct dsdb_dn *dsdb_dn;
6527 uint64_t seq_num = 0;
6528 struct ldb_message_element *old_el;
6530 time_t t = time(NULL);
6531 struct ldb_result *res;
6532 struct ldb_result *target_res;
6533 const char *attrs[4];
6534 const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
6535 struct parsed_dn *pdn_list, *pdn, *next;
6536 struct GUID guid = GUID_zero();
6538 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
6539 const struct GUID *our_invocation_id;
6541 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
6542 enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
6545 linked_attributes[0]:
6546 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6548 identifier: struct drsuapi_DsReplicaObjectIdentifier
6549 __ndr_size : 0x0000003a (58)
6550 __ndr_size_sid : 0x00000000 (0)
6551 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6553 __ndr_size_dn : 0x00000000 (0)
6555 attid : DRSUAPI_ATTID_member (0x1F)
6556 value: struct drsuapi_DsAttributeValue
6557 __ndr_size : 0x0000007e (126)
6559 blob : DATA_BLOB length=126
6560 flags : 0x00000001 (1)
6561 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6562 originating_add_time : Wed Sep 2 22:20:01 2009 EST
6563 meta_data: struct drsuapi_DsReplicaMetaData
6564 version : 0x00000015 (21)
6565 originating_change_time : Wed Sep 2 23:39:07 2009 EST
6566 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6567 originating_usn : 0x000000000001e19c (123292)
6569 (for cases where the link is to a normal DN)
6570 &target: struct drsuapi_DsReplicaObjectIdentifier3
6571 __ndr_size : 0x0000007e (126)
6572 __ndr_size_sid : 0x0000001c (28)
6573 guid : 7639e594-db75-4086-b0d4-67890ae46031
6574 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
6575 __ndr_size_dn : 0x00000022 (34)
6576 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
6579 /* find the attribute being modified */
6580 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
6582 struct GUID_txt_buf guid_str;
6583 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
6585 GUID_buf_string(&la->identifier->guid,
6587 talloc_free(tmp_ctx);
6588 return LDB_ERR_OPERATIONS_ERROR;
6591 attrs[0] = attr->lDAPDisplayName;
6592 attrs[1] = "isDeleted";
6593 attrs[2] = "isRecycled";
6596 /* get the existing message from the db for the object with
6597 this GUID, returning attribute being modified. We will then
6598 use this msg as the basis for a modify call */
6599 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
6600 DSDB_FLAG_NEXT_MODULE |
6601 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6602 DSDB_SEARCH_SHOW_RECYCLED |
6603 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
6604 DSDB_SEARCH_REVEAL_INTERNALS,
6606 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
6607 if (ret != LDB_SUCCESS) {
6608 talloc_free(tmp_ctx);
6611 if (res->count != 1) {
6612 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
6613 GUID_string(tmp_ctx, &la->identifier->guid));
6614 talloc_free(tmp_ctx);
6615 return LDB_ERR_NO_SUCH_OBJECT;
6620 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6621 * ProcessLinkValue, because link updates are not applied to
6622 * recycled and tombstone objects. We don't have to delete
6623 * any existing link, that should have happened when the
6624 * object deletion was replicated or initiated.
6627 replmd_deletion_state(module, msg, &deletion_state, NULL);
6629 if (deletion_state >= OBJECT_RECYCLED) {
6630 talloc_free(tmp_ctx);
6634 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6635 if (old_el == NULL) {
6636 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
6637 if (ret != LDB_SUCCESS) {
6638 ldb_module_oom(module);
6639 talloc_free(tmp_ctx);
6640 return LDB_ERR_OPERATIONS_ERROR;
6643 old_el->flags = LDB_FLAG_MOD_REPLACE;
6646 /* parse the existing links */
6647 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
6648 attr->syntax->ldap_oid, parent);
6650 if (ret != LDB_SUCCESS) {
6651 talloc_free(tmp_ctx);
6655 /* get our invocationId */
6656 our_invocation_id = samdb_ntds_invocation_id(ldb);
6657 if (!our_invocation_id) {
6658 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
6659 talloc_free(tmp_ctx);
6660 return LDB_ERR_OPERATIONS_ERROR;
6663 ret = replmd_check_upgrade_links(ldb, pdn_list, old_el->num_values,
6664 old_el, our_invocation_id,
6665 attr->syntax->ldap_oid);
6666 if (ret != LDB_SUCCESS) {
6667 talloc_free(tmp_ctx);
6671 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
6672 if (!W_ERROR_IS_OK(status)) {
6673 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
6674 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
6675 talloc_free(tmp_ctx);
6676 return LDB_ERR_OPERATIONS_ERROR;
6679 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
6680 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6682 * This strange behaviour (allowing a NULL/missing
6683 * GUID) originally comes from:
6685 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6686 * Author: Andrew Tridgell <tridge@samba.org>
6687 * Date: Mon Dec 21 21:21:55 2009 +1100
6689 * s4-drs: cope better with NULL GUIDS from DRS
6691 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
6692 * need to match by DN if possible when seeing if we should update an
6695 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6698 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6699 dsdb_dn->dn, attrs2,
6700 DSDB_FLAG_NEXT_MODULE |
6701 DSDB_SEARCH_SHOW_RECYCLED |
6702 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6703 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6705 } else if (!NT_STATUS_IS_OK(ntstatus)) {
6706 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
6708 ldb_dn_get_linearized(dsdb_dn->dn),
6709 ldb_dn_get_linearized(msg->dn));
6710 talloc_free(tmp_ctx);
6711 return LDB_ERR_OPERATIONS_ERROR;
6713 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6714 NULL, LDB_SCOPE_SUBTREE,
6716 DSDB_FLAG_NEXT_MODULE |
6717 DSDB_SEARCH_SHOW_RECYCLED |
6718 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6719 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6722 GUID_string(tmp_ctx, &guid));
6725 if (ret != LDB_SUCCESS) {
6726 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6727 GUID_string(tmp_ctx, &guid),
6728 ldb_errstring(ldb_module_get_ctx(module)));
6729 talloc_free(tmp_ctx);
6733 if (target_res->count == 0) {
6734 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6735 GUID_string(tmp_ctx, &guid),
6736 ldb_dn_get_linearized(dsdb_dn->dn)));
6737 } else if (target_res->count != 1) {
6738 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6739 GUID_string(tmp_ctx, &guid));
6740 talloc_free(tmp_ctx);
6741 return LDB_ERR_OPERATIONS_ERROR;
6743 target_msg = target_res->msgs[0];
6744 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6748 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6749 * ProcessLinkValue, because link updates are not applied to
6750 * recycled and tombstone objects. We don't have to delete
6751 * any existing link, that should have happened when the
6752 * object deletion was replicated or initiated.
6754 replmd_deletion_state(module, target_msg,
6755 &target_deletion_state, NULL);
6757 if (target_deletion_state >= OBJECT_RECYCLED) {
6758 talloc_free(tmp_ctx);
6762 /* see if this link already exists */
6763 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
6767 attr->syntax->ldap_oid);
6768 if (ret != LDB_SUCCESS) {
6769 talloc_free(tmp_ctx);
6775 /* see if this update is newer than what we have already */
6776 struct GUID invocation_id = GUID_zero();
6777 uint32_t version = 0;
6778 uint32_t originating_usn = 0;
6779 NTTIME change_time = 0;
6780 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6782 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6783 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6784 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6785 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6787 if (!replmd_update_is_newer(&invocation_id,
6788 &la->meta_data.originating_invocation_id,
6790 la->meta_data.version,
6792 la->meta_data.originating_change_time)) {
6793 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6794 old_el->name, ldb_dn_get_linearized(msg->dn),
6795 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6796 talloc_free(tmp_ctx);
6800 /* get a seq_num for this change */
6801 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6802 if (ret != LDB_SUCCESS) {
6803 talloc_free(tmp_ctx);
6807 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6808 /* remove the existing backlink */
6809 ret = replmd_add_backlink(module, replmd_private,
6810 schema, &la->identifier->guid,
6811 &guid, false, attr, true);
6812 if (ret != LDB_SUCCESS) {
6813 talloc_free(tmp_ctx);
6818 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6819 &la->meta_data.originating_invocation_id,
6820 la->meta_data.originating_usn, seq_num,
6821 la->meta_data.originating_change_time,
6822 la->meta_data.version,
6824 if (ret != LDB_SUCCESS) {
6825 talloc_free(tmp_ctx);
6830 /* add the new backlink */
6831 ret = replmd_add_backlink(module, replmd_private,
6832 schema, &la->identifier->guid,
6833 &guid, true, attr, true);
6834 if (ret != LDB_SUCCESS) {
6835 talloc_free(tmp_ctx);
6841 /* get a seq_num for this change */
6842 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6843 if (ret != LDB_SUCCESS) {
6844 talloc_free(tmp_ctx);
6848 * We know where the new one needs to be, from the *next
6849 * pointer into pdn_list.
6852 offset = old_el->num_values;
6854 if (next->dsdb_dn == NULL) {
6855 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
6856 attr->syntax->ldap_oid);
6857 if (ret != LDB_SUCCESS) {
6861 offset = next - pdn_list;
6862 if (offset > old_el->num_values) {
6863 talloc_free(tmp_ctx);
6864 return LDB_ERR_OPERATIONS_ERROR;
6868 old_el->values = talloc_realloc(msg->elements, old_el->values,
6869 struct ldb_val, old_el->num_values+1);
6870 if (!old_el->values) {
6871 ldb_module_oom(module);
6872 return LDB_ERR_OPERATIONS_ERROR;
6875 if (offset != old_el->num_values) {
6876 memmove(&old_el->values[offset + 1], &old_el->values[offset],
6877 (old_el->num_values - offset) * sizeof(old_el->values[0]));
6880 old_el->num_values++;
6882 ret = replmd_build_la_val(tmp_ctx, &old_el->values[offset], dsdb_dn,
6883 &la->meta_data.originating_invocation_id,
6884 la->meta_data.originating_usn, seq_num,
6885 la->meta_data.originating_change_time,
6886 la->meta_data.version,
6888 if (ret != LDB_SUCCESS) {
6889 talloc_free(tmp_ctx);
6894 ret = replmd_add_backlink(module, replmd_private,
6895 schema, &la->identifier->guid,
6896 &guid, true, attr, true);
6897 if (ret != LDB_SUCCESS) {
6898 talloc_free(tmp_ctx);
6904 /* we only change whenChanged and uSNChanged if the seq_num
6906 ret = add_time_element(msg, "whenChanged", t);
6907 if (ret != LDB_SUCCESS) {
6908 talloc_free(tmp_ctx);
6913 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
6914 if (ret != LDB_SUCCESS) {
6915 talloc_free(tmp_ctx);
6920 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6921 if (old_el == NULL) {
6922 talloc_free(tmp_ctx);
6923 return ldb_operr(ldb);
6926 ret = dsdb_check_single_valued_link(attr, old_el);
6927 if (ret != LDB_SUCCESS) {
6928 talloc_free(tmp_ctx);
6932 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
6934 ret = linked_attr_modify(module, msg, parent);
6935 if (ret != LDB_SUCCESS) {
6936 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
6938 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
6939 talloc_free(tmp_ctx);
6943 talloc_free(tmp_ctx);
6948 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
6950 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
6951 return replmd_extended_replicated_objects(module, req);
6954 return ldb_next_request(module, req);
6959 we hook into the transaction operations to allow us to
6960 perform the linked attribute updates at the end of the whole
6961 transaction. This allows a forward linked attribute to be created
6962 before the object is created. During a vampire, w2k8 sends us linked
6963 attributes before the objects they are part of.
6965 static int replmd_start_transaction(struct ldb_module *module)
6967 /* create our private structure for this transaction */
6968 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
6969 struct replmd_private);
6970 replmd_txn_cleanup(replmd_private);
6972 /* free any leftover mod_usn records from cancelled
6974 while (replmd_private->ncs) {
6975 struct nc_entry *e = replmd_private->ncs;
6976 DLIST_REMOVE(replmd_private->ncs, e);
6980 replmd_private->originating_updates = false;
6982 return ldb_next_start_trans(module);
6986 on prepare commit we loop over our queued la_context structures and
6989 static int replmd_prepare_commit(struct ldb_module *module)
6991 struct replmd_private *replmd_private =
6992 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6993 struct la_entry *la, *prev;
6994 struct la_backlink *bl;
6997 /* walk the list backwards, to do the first entry first, as we
6998 * added the entries with DLIST_ADD() which puts them at the
6999 * start of the list */
7000 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
7001 prev = DLIST_PREV(la);
7002 DLIST_REMOVE(replmd_private->la_list, la);
7003 ret = replmd_process_linked_attribute(module, replmd_private,
7005 if (ret != LDB_SUCCESS) {
7006 replmd_txn_cleanup(replmd_private);
7011 /* process our backlink list, creating and deleting backlinks
7013 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
7014 ret = replmd_process_backlink(module, bl, NULL);
7015 if (ret != LDB_SUCCESS) {
7016 replmd_txn_cleanup(replmd_private);
7021 replmd_txn_cleanup(replmd_private);
7023 /* possibly change @REPLCHANGED */
7024 ret = replmd_notify_store(module, NULL);
7025 if (ret != LDB_SUCCESS) {
7029 return ldb_next_prepare_commit(module);
7032 static int replmd_del_transaction(struct ldb_module *module)
7034 struct replmd_private *replmd_private =
7035 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7036 replmd_txn_cleanup(replmd_private);
7038 return ldb_next_del_trans(module);
7042 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
7043 .name = "repl_meta_data",
7044 .init_context = replmd_init,
7046 .modify = replmd_modify,
7047 .rename = replmd_rename,
7048 .del = replmd_delete,
7049 .extended = replmd_extended,
7050 .start_transaction = replmd_start_transaction,
7051 .prepare_commit = replmd_prepare_commit,
7052 .del_transaction = replmd_del_transaction,
7055 int ldb_repl_meta_data_module_init(const char *version)
7057 LDB_MODULE_CHECK_VERSION(version);
7058 return ldb_register_module(&ldb_repl_meta_data_module_ops);