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;
1827 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1829 return GUID_compare(&pdn1->guid, &pdn2->guid);
1832 static int la_guid_compare_with_trusted_dn(struct compare_ctx *ctx,
1833 struct parsed_dn *p)
1836 * This works like a standard compare function in its return values,
1837 * but has an extra trick to deal with errors: zero is returned and
1838 * ctx->err is set to the ldb error code.
1840 * That is, if (as is expected in most cases) you get a non-zero
1841 * result, you don't need to check for errors.
1843 * We assume the second argument refers to a DN is from the database
1844 * and has a GUID -- but this GUID might not have been parsed out yet.
1848 if (GUID_all_zero(&p->guid)) {
1850 if (p->dsdb_dn == NULL) {
1851 p->dsdb_dn = dsdb_dn_parse_trusted(ctx->mem_ctx, ctx->ldb, p->v,
1853 if (p->dsdb_dn == NULL) {
1854 ctx->err = LDB_ERR_INVALID_DN_SYNTAX;
1859 status = dsdb_get_extended_dn_guid(p->dsdb_dn->dn, &p->guid, "GUID");
1860 if (!NT_STATUS_IS_OK(status)) {
1861 ctx->err = LDB_ERR_OPERATIONS_ERROR;
1866 return GUID_compare(ctx->guid, &p->guid);
1871 static int parsed_dn_find(struct ldb_context *ldb, struct parsed_dn *pdn,
1874 struct ldb_dn *target_dn,
1875 struct parsed_dn **exact,
1876 struct parsed_dn **next,
1877 const char *ldap_oid)
1880 struct compare_ctx ctx;
1887 if (unlikely(GUID_all_zero(guid))) {
1889 * When updating a link using DRS, we sometimes get a NULL
1890 * GUID when a forward link has been deleted and its GUID has
1891 * for some reason been forgotten. The best we can do is try
1892 * and match by DN via a linear search. Note that this
1893 * probably only happens in the ADD case, in which we only
1894 * allow modification of link if it is already deleted, so
1895 * this seems very close to an elaborate NO-OP, but we are not
1896 * quite prepared to declare it so.
1898 * If the DN is not in our list, we have to add it to the
1899 * beginning of the list, where it would naturally sort.
1901 struct parsed_dn *p;
1902 if (target_dn == NULL) {
1903 /* We don't know the target DN, so we can't search for DN */
1904 DEBUG(1, ("parsed_dn_find has a NULL GUID for a linked "
1905 "attribute but we don't have a DN to compare "
1907 return LDB_ERR_OPERATIONS_ERROR;
1912 DEBUG(3, ("parsed_dn_find has a NULL GUID for a link to DN "
1913 "%s; searching through links for it",
1914 ldb_dn_get_linearized(target_dn)));
1916 for (i = 0; i < count; i++) {
1919 if (p->dsdb_dn == NULL) {
1920 p->dsdb_dn = dsdb_dn_parse_trusted(pdn, ldb,
1922 if (p->dsdb_dn == NULL) {
1923 return LDB_ERR_OPERATIONS_ERROR;
1926 cmp = ldb_dn_compare(p->dsdb_dn->dn, target_dn);
1928 dsdb_get_extended_dn_guid(p->dsdb_dn->dn,
1935 * Here we have a null guid which doesn't match any existing
1936 * link. This is a bit unexpected because null guids occur
1937 * when a forward link has been deleted and we are replicating
1940 * The best thing to do is weep into the logs and add the
1941 * offending link to the beginning of the list which is
1942 * at least the correct sort position.
1944 DEBUG(1, ("parsed_dn_find has been given a NULL GUID for a "
1945 "link to unknown DN %s\n",
1946 ldb_dn_get_linearized(target_dn)));
1954 ctx.ldap_oid = ldap_oid;
1957 BINARY_ARRAY_SEARCH_GTE(pdn, count, &ctx, la_guid_compare_with_trusted_dn,
1967 get a series of message element values as an array of DNs and GUIDs
1968 the result is sorted by GUID
1970 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1971 struct ldb_message_element *el, struct parsed_dn **pdn,
1972 const char *ldap_oid, struct ldb_request *parent)
1975 bool values_are_sorted = true;
1976 struct ldb_context *ldb = ldb_module_get_ctx(module);
1983 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1985 ldb_module_oom(module);
1986 return LDB_ERR_OPERATIONS_ERROR;
1989 for (i=0; i<el->num_values; i++) {
1990 struct ldb_val *v = &el->values[i];
1993 struct parsed_dn *p;
1997 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1998 if (p->dsdb_dn == NULL) {
1999 return LDB_ERR_INVALID_DN_SYNTAX;
2002 dn = p->dsdb_dn->dn;
2004 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
2005 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2006 /* we got a DN without a GUID - go find the GUID */
2007 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
2008 if (ret != LDB_SUCCESS) {
2009 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
2010 ldb_dn_get_linearized(dn));
2011 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
2012 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
2013 ldb_attr_cmp(el->name, "member") == 0) {
2014 return LDB_ERR_UNWILLING_TO_PERFORM;
2018 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
2019 if (ret != LDB_SUCCESS) {
2022 } else if (!NT_STATUS_IS_OK(status)) {
2023 return LDB_ERR_OPERATIONS_ERROR;
2025 if (i > 0 && values_are_sorted) {
2026 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2028 values_are_sorted = false;
2031 /* keep a pointer to the original ldb_val */
2034 if (! values_are_sorted) {
2035 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2041 * Get a series of trusted message element values. The result is sorted by
2042 * GUID, even though the GUIDs might not be known. That works because we trust
2043 * the database to give us the elements like that if the
2044 * replmd_private->sorted_links flag is set.
2046 static int get_parsed_dns_trusted(struct ldb_module *module,
2047 struct replmd_private *replmd_private,
2048 TALLOC_CTX *mem_ctx,
2049 struct ldb_message_element *el,
2050 struct parsed_dn **pdn,
2051 const char *ldap_oid,
2052 struct ldb_request *parent)
2061 if (!replmd_private->sorted_links) {
2062 /* We need to sort the list. This is the slow old path we want
2065 return get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2068 /* Here we get a list of 'struct parsed_dns' without the parsing */
2069 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2072 ldb_module_oom(module);
2073 return LDB_ERR_OPERATIONS_ERROR;
2076 for (i = 0; i < el->num_values; i++) {
2077 (*pdn)[i].v = &el->values[i];
2084 build a new extended DN, including all meta data fields
2086 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2087 RMD_ADDTIME = originating_add_time
2088 RMD_INVOCID = originating_invocation_id
2089 RMD_CHANGETIME = originating_change_time
2090 RMD_ORIGINATING_USN = originating_usn
2091 RMD_LOCAL_USN = local_usn
2092 RMD_VERSION = version
2094 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2095 const struct GUID *invocation_id, uint64_t seq_num,
2096 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
2098 struct ldb_dn *dn = dsdb_dn->dn;
2099 const char *tstring, *usn_string, *flags_string;
2100 struct ldb_val tval;
2102 struct ldb_val usnv, local_usnv;
2103 struct ldb_val vers, flagsv;
2106 const char *dnstring;
2108 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2110 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2112 return LDB_ERR_OPERATIONS_ERROR;
2114 tval = data_blob_string_const(tstring);
2116 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
2118 return LDB_ERR_OPERATIONS_ERROR;
2120 usnv = data_blob_string_const(usn_string);
2122 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2124 return LDB_ERR_OPERATIONS_ERROR;
2126 local_usnv = data_blob_string_const(usn_string);
2128 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2130 return LDB_ERR_OPERATIONS_ERROR;
2132 vers = data_blob_string_const(vstring);
2134 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2135 if (!NT_STATUS_IS_OK(status)) {
2136 return LDB_ERR_OPERATIONS_ERROR;
2139 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2140 if (!flags_string) {
2141 return LDB_ERR_OPERATIONS_ERROR;
2143 flagsv = data_blob_string_const(flags_string);
2145 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2146 if (ret != LDB_SUCCESS) return ret;
2147 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
2148 if (ret != LDB_SUCCESS) return ret;
2149 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2150 if (ret != LDB_SUCCESS) return ret;
2151 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2152 if (ret != LDB_SUCCESS) return ret;
2153 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2154 if (ret != LDB_SUCCESS) return ret;
2155 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2156 if (ret != LDB_SUCCESS) return ret;
2157 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2158 if (ret != LDB_SUCCESS) return ret;
2160 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2161 if (dnstring == NULL) {
2162 return LDB_ERR_OPERATIONS_ERROR;
2164 *v = data_blob_string_const(dnstring);
2169 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2170 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2171 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2172 uint32_t version, bool deleted);
2175 check if any links need upgrading from w2k format
2177 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2178 struct parsed_dn *dns, uint32_t count,
2179 struct ldb_message_element *el,
2180 const struct GUID *invocation_id,
2181 const char *ldap_oid)
2184 for (i=0; i<count; i++) {
2188 if (dns[i].dsdb_dn == NULL) {
2189 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2191 if (ret != LDB_SUCCESS) {
2192 return LDB_ERR_INVALID_DN_SYNTAX;
2196 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2197 &version, "RMD_VERSION");
2198 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2200 * We optimistically assume they are all the same; if
2201 * the first one is fixed, they are all fixed.
2203 * If the first one was *not* fixed and we find a
2204 * later one that is, that is an occasion to shout
2210 DEBUG(0, ("Mixed w2k and fixed format "
2211 "linked attributes\n"));
2215 /* it's an old one that needs upgrading */
2216 ret = replmd_update_la_val(el->values, dns[i].v,
2217 dns[i].dsdb_dn, dns[i].dsdb_dn,
2218 invocation_id, 1, 1, 0, 0, false);
2219 if (ret != LDB_SUCCESS) {
2227 update an extended DN, including all meta data fields
2229 see replmd_build_la_val for value names
2231 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2232 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2233 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2234 uint32_t version, bool deleted)
2236 struct ldb_dn *dn = dsdb_dn->dn;
2237 const char *tstring, *usn_string, *flags_string;
2238 struct ldb_val tval;
2240 struct ldb_val usnv, local_usnv;
2241 struct ldb_val vers, flagsv;
2242 const struct ldb_val *old_addtime;
2243 uint32_t old_version;
2246 const char *dnstring;
2248 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2250 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2252 return LDB_ERR_OPERATIONS_ERROR;
2254 tval = data_blob_string_const(tstring);
2256 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2258 return LDB_ERR_OPERATIONS_ERROR;
2260 usnv = data_blob_string_const(usn_string);
2262 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2264 return LDB_ERR_OPERATIONS_ERROR;
2266 local_usnv = data_blob_string_const(usn_string);
2268 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2269 if (!NT_STATUS_IS_OK(status)) {
2270 return LDB_ERR_OPERATIONS_ERROR;
2273 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2274 if (!flags_string) {
2275 return LDB_ERR_OPERATIONS_ERROR;
2277 flagsv = data_blob_string_const(flags_string);
2279 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2280 if (ret != LDB_SUCCESS) return ret;
2282 /* get the ADDTIME from the original */
2283 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2284 if (old_addtime == NULL) {
2285 old_addtime = &tval;
2287 if (dsdb_dn != old_dsdb_dn ||
2288 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2289 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2290 if (ret != LDB_SUCCESS) return ret;
2293 /* use our invocation id */
2294 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2295 if (ret != LDB_SUCCESS) return ret;
2297 /* changetime is the current time */
2298 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2299 if (ret != LDB_SUCCESS) return ret;
2301 /* update the USN */
2302 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2303 if (ret != LDB_SUCCESS) return ret;
2305 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2306 if (ret != LDB_SUCCESS) return ret;
2308 /* increase the version by 1 */
2309 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2310 if (NT_STATUS_IS_OK(status) && old_version >= version) {
2311 version = old_version+1;
2313 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2314 vers = data_blob_string_const(vstring);
2315 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2316 if (ret != LDB_SUCCESS) return ret;
2318 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2319 if (dnstring == NULL) {
2320 return LDB_ERR_OPERATIONS_ERROR;
2322 *v = data_blob_string_const(dnstring);
2328 handle adding a linked attribute
2330 static int replmd_modify_la_add(struct ldb_module *module,
2331 struct replmd_private *replmd_private,
2332 const struct dsdb_schema *schema,
2333 struct ldb_message *msg,
2334 struct ldb_message_element *el,
2335 struct ldb_message_element *old_el,
2336 const struct dsdb_attribute *schema_attr,
2339 struct GUID *msg_guid,
2340 struct ldb_request *parent)
2343 struct parsed_dn *dns, *old_dns;
2344 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2346 struct ldb_val *new_values = NULL;
2347 unsigned int num_new_values = 0;
2348 unsigned old_num_values = old_el?old_el->num_values:0;
2349 const struct GUID *invocation_id;
2350 struct ldb_context *ldb = ldb_module_get_ctx(module);
2353 unix_to_nt_time(&now, t);
2355 /* get the DNs to be added, fully parsed.
2357 * We need full parsing because they came off the wire and we don't
2358 * trust them, besides which we need their details to know where to put
2361 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2362 schema_attr->syntax->ldap_oid, parent);
2363 if (ret != LDB_SUCCESS) {
2364 talloc_free(tmp_ctx);
2368 /* get the existing DNs, lazily parsed */
2369 ret = get_parsed_dns_trusted(module, replmd_private,
2370 tmp_ctx, old_el, &old_dns,
2371 schema_attr->syntax->ldap_oid, parent);
2373 if (ret != LDB_SUCCESS) {
2374 talloc_free(tmp_ctx);
2378 invocation_id = samdb_ntds_invocation_id(ldb);
2379 if (!invocation_id) {
2380 talloc_free(tmp_ctx);
2381 return LDB_ERR_OPERATIONS_ERROR;
2384 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2385 old_el, invocation_id,
2386 schema_attr->syntax->ldap_oid);
2387 if (ret != LDB_SUCCESS) {
2388 talloc_free(tmp_ctx);
2392 /* for each new value, see if it exists already with the same GUID */
2393 for (i=0; i<el->num_values; i++) {
2394 struct parsed_dn *p;
2395 struct parsed_dn *next;
2396 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2400 schema_attr->syntax->ldap_oid);
2401 if (err != LDB_SUCCESS) {
2402 talloc_free(tmp_ctx);
2406 /* this is a new linked attribute value */
2407 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
2408 if (new_values == NULL) {
2409 ldb_module_oom(module);
2410 talloc_free(tmp_ctx);
2411 return LDB_ERR_OPERATIONS_ERROR;
2413 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2414 invocation_id, seq_num, seq_num, now, 0, false);
2415 if (ret != LDB_SUCCESS) {
2416 talloc_free(tmp_ctx);
2421 /* this is only allowed if the GUID was
2422 previously deleted. */
2423 uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2424 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2425 struct GUID_txt_buf guid_str;
2426 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
2427 el->name, GUID_buf_string(&p->guid, &guid_str));
2428 talloc_free(tmp_ctx);
2429 /* error codes for 'member' need to be
2431 if (ldb_attr_cmp(el->name, "member") == 0) {
2432 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2434 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2437 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
2438 invocation_id, seq_num, seq_num, now, 0, false);
2439 if (ret != LDB_SUCCESS) {
2440 talloc_free(tmp_ctx);
2445 ret = replmd_add_backlink(module, replmd_private,
2446 schema, msg_guid, &dns[i].guid,
2447 true, schema_attr, true);
2448 if (ret != LDB_SUCCESS) {
2449 talloc_free(tmp_ctx);
2454 /* add the new ones on to the end of the old values, constructing a new el->values */
2455 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2457 old_num_values+num_new_values);
2458 if (el->values == NULL) {
2459 ldb_module_oom(module);
2460 return LDB_ERR_OPERATIONS_ERROR;
2463 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
2464 el->num_values = old_num_values + num_new_values;
2466 talloc_steal(msg->elements, el->values);
2467 talloc_steal(el->values, new_values);
2469 talloc_free(tmp_ctx);
2471 /* we now tell the backend to replace all existing values
2472 with the one we have constructed */
2473 el->flags = LDB_FLAG_MOD_REPLACE;
2480 handle deleting all active linked attributes
2482 static int replmd_modify_la_delete(struct ldb_module *module,
2483 struct replmd_private *replmd_private,
2484 const struct dsdb_schema *schema,
2485 struct ldb_message *msg,
2486 struct ldb_message_element *el,
2487 struct ldb_message_element *old_el,
2488 const struct dsdb_attribute *schema_attr,
2491 struct GUID *msg_guid,
2492 struct ldb_request *parent)
2495 struct parsed_dn *dns, *old_dns;
2496 TALLOC_CTX *tmp_ctx = NULL;
2498 const struct GUID *invocation_id;
2499 struct ldb_context *ldb = ldb_module_get_ctx(module);
2500 struct ldb_control *vanish_links_ctrl = NULL;
2501 bool vanish_links = false;
2502 unsigned int num_to_delete = el->num_values;
2505 unix_to_nt_time(&now, t);
2507 /* check if there is nothing to delete */
2508 if ((!old_el || old_el->num_values == 0) &&
2509 el->num_values == 0) {
2513 if (!old_el || old_el->num_values == 0) {
2514 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2517 tmp_ctx = talloc_new(msg);
2518 if (tmp_ctx == NULL) {
2519 return LDB_ERR_OPERATIONS_ERROR;
2522 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2523 if (ret != LDB_SUCCESS) {
2524 talloc_free(tmp_ctx);
2528 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2529 if (ret != LDB_SUCCESS) {
2530 talloc_free(tmp_ctx);
2534 invocation_id = samdb_ntds_invocation_id(ldb);
2535 if (!invocation_id) {
2536 talloc_free(tmp_ctx);
2537 return LDB_ERR_OPERATIONS_ERROR;
2540 ret = replmd_check_upgrade_links(ldb, old_dns, old_el->num_values,
2541 old_el, invocation_id,
2542 schema_attr->syntax->ldap_oid);
2543 if (ret != LDB_SUCCESS) {
2544 talloc_free(tmp_ctx);
2549 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2550 if (vanish_links_ctrl) {
2551 vanish_links = true;
2552 vanish_links_ctrl->critical = false;
2559 /* see if we are being asked to delete any links that
2560 don't exist or are already deleted */
2561 for (i=0; i < num_to_delete; i++) {
2562 struct parsed_dn *p = &dns[i];
2563 struct parsed_dn *p2;
2564 struct parsed_dn *next = NULL;
2566 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2570 schema_attr->syntax->ldap_oid);
2571 if (ret != LDB_SUCCESS) {
2572 talloc_free(tmp_ctx);
2577 struct GUID_txt_buf buf;
2578 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
2579 el->name, GUID_buf_string(&p->guid, &buf));
2580 if (ldb_attr_cmp(el->name, "member") == 0) {
2581 talloc_free(tmp_ctx);
2582 return LDB_ERR_UNWILLING_TO_PERFORM;
2584 talloc_free(tmp_ctx);
2585 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2588 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
2589 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2590 struct GUID_txt_buf buf;
2591 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2593 DEBUG(0, ("Deleting deleted linked attribute %s to %s, "
2594 "because vanish_links control is set\n",
2595 el->name, guid_str));
2598 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
2599 el->name, guid_str);
2600 if (ldb_attr_cmp(el->name, "member") == 0) {
2601 talloc_free(tmp_ctx);
2602 return LDB_ERR_UNWILLING_TO_PERFORM;
2604 talloc_free(tmp_ctx);
2605 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2611 if (num_to_delete == old_el->num_values || num_to_delete == 0) {
2612 el->flags = LDB_FLAG_MOD_REPLACE;
2614 for (i = 0; i < old_el->num_values; i++) {
2615 ret = replmd_add_backlink(module,
2621 if (ret != LDB_SUCCESS) {
2622 talloc_free(tmp_ctx);
2626 talloc_free(tmp_ctx);
2629 unsigned int num_values = 0;
2631 struct parsed_dn *exact = NULL, *next = NULL;
2633 for (i = 0; i < old_el->num_values; i++) {
2634 ret = parsed_dn_find(ldb, dns, num_to_delete,
2638 schema_attr->syntax->ldap_oid);
2639 if (ret != LDB_SUCCESS) {
2640 talloc_free(tmp_ctx);
2644 if (exact != NULL) {
2645 /* The element is in the delete list.
2647 ret = replmd_add_backlink(module,
2655 if (ret != LDB_SUCCESS) {
2656 talloc_free(tmp_ctx);
2659 old_dns[i].v->length = 0;
2664 for (i = 0; i < old_el->num_values; i++) {
2665 if (old_el->values[i].length != 0) {
2666 old_el->values[j] = old_el->values[i];
2668 if (j == num_values) {
2673 old_el->num_values = num_values;
2677 /* for each new value, see if it exists already with the same GUID
2678 if it is not already deleted and matches the delete list then delete it
2680 for (i=0; i<old_el->num_values; i++) {
2681 struct parsed_dn *p = &old_dns[i];
2682 struct parsed_dn *exact = NULL, *next = NULL;
2685 if (num_to_delete != 0) {
2686 ret = parsed_dn_find(ldb, dns, num_to_delete,
2690 schema_attr->syntax->ldap_oid);
2691 if (ret != LDB_SUCCESS) {
2692 talloc_free(tmp_ctx);
2695 if (exact == NULL) {
2700 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2701 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2703 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
2704 invocation_id, seq_num, seq_num, now, 0, true);
2705 if (ret != LDB_SUCCESS) {
2706 talloc_free(tmp_ctx);
2709 ret = replmd_add_backlink(module, replmd_private,
2710 schema, msg_guid, &p->guid,
2711 false, schema_attr, true);
2712 if (ret != LDB_SUCCESS) {
2713 talloc_free(tmp_ctx);
2718 el->values = talloc_steal(msg->elements, old_el->values);
2719 el->num_values = old_el->num_values;
2721 talloc_free(tmp_ctx);
2723 /* we now tell the backend to replace all existing values
2724 with the one we have constructed */
2725 el->flags = LDB_FLAG_MOD_REPLACE;
2731 handle replacing a linked attribute
2733 static int replmd_modify_la_replace(struct ldb_module *module,
2734 struct replmd_private *replmd_private,
2735 const struct dsdb_schema *schema,
2736 struct ldb_message *msg,
2737 struct ldb_message_element *el,
2738 struct ldb_message_element *old_el,
2739 const struct dsdb_attribute *schema_attr,
2742 struct GUID *msg_guid,
2743 struct ldb_request *parent)
2746 struct parsed_dn *dns, *old_dns;
2747 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2749 const struct GUID *invocation_id;
2750 struct ldb_context *ldb = ldb_module_get_ctx(module);
2751 struct ldb_val *new_values = NULL;
2752 unsigned int num_new_values = 0;
2753 unsigned int old_num_values = old_el?old_el->num_values:0;
2756 unix_to_nt_time(&now, t);
2758 /* check if there is nothing to replace */
2759 if ((!old_el || old_el->num_values == 0) &&
2760 el->num_values == 0) {
2764 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2765 if (ret != LDB_SUCCESS) {
2766 talloc_free(tmp_ctx);
2770 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2771 if (ret != LDB_SUCCESS) {
2772 talloc_free(tmp_ctx);
2776 invocation_id = samdb_ntds_invocation_id(ldb);
2777 if (!invocation_id) {
2778 return LDB_ERR_OPERATIONS_ERROR;
2781 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2782 old_el, invocation_id,
2783 schema_attr->syntax->ldap_oid);
2784 if (ret != LDB_SUCCESS) {
2785 talloc_free(tmp_ctx);
2789 /* mark all the old ones as deleted */
2790 for (i=0; i<old_num_values; i++) {
2791 struct parsed_dn *old_p = &old_dns[i];
2792 struct parsed_dn *exact = NULL, *next = NULL;
2793 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2795 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2797 ret = replmd_add_backlink(module, replmd_private,
2798 schema, msg_guid, &old_dns[i].guid,
2799 false, schema_attr, false);
2800 if (ret != LDB_SUCCESS) {
2801 talloc_free(tmp_ctx);
2805 ret = parsed_dn_find(ldb, dns, el->num_values,
2809 schema_attr->syntax->ldap_oid);
2810 if (ret != LDB_SUCCESS) {
2811 talloc_free(tmp_ctx);
2815 /* we don't delete it if we are re-adding it */
2819 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2820 invocation_id, seq_num, seq_num, now, 0, true);
2821 if (ret != LDB_SUCCESS) {
2822 talloc_free(tmp_ctx);
2827 /* for each new value, either update its meta-data, or add it
2830 for (i=0; i<el->num_values; i++) {
2831 struct parsed_dn *p = &dns[i];
2832 struct parsed_dn *old_p = NULL, *next = NULL;
2835 ret = parsed_dn_find(ldb, old_dns, old_num_values,
2839 schema_attr->syntax->ldap_oid);
2840 if (ret != LDB_SUCCESS) {
2841 talloc_free(tmp_ctx);
2846 if (old_p != NULL) {
2847 /* update in place */
2848 ret = replmd_update_la_val(old_el->values, old_p->v, p->dsdb_dn,
2849 old_p->dsdb_dn, invocation_id,
2850 seq_num, seq_num, now, 0, false);
2851 if (ret != LDB_SUCCESS) {
2852 talloc_free(tmp_ctx);
2857 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2859 if (new_values == NULL) {
2860 ldb_module_oom(module);
2861 talloc_free(tmp_ctx);
2862 return LDB_ERR_OPERATIONS_ERROR;
2864 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2865 invocation_id, seq_num, seq_num, now, 0, false);
2866 if (ret != LDB_SUCCESS) {
2867 talloc_free(tmp_ctx);
2873 ret = replmd_add_backlink(module, replmd_private,
2874 schema, msg_guid, &dns[i].guid,
2875 true, schema_attr, false);
2876 if (ret != LDB_SUCCESS) {
2877 talloc_free(tmp_ctx);
2882 /* add the new values to the end of old_el */
2883 if (num_new_values != 0) {
2884 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2885 struct ldb_val, old_num_values+num_new_values);
2886 if (el->values == NULL) {
2887 ldb_module_oom(module);
2888 return LDB_ERR_OPERATIONS_ERROR;
2890 memcpy(&el->values[old_num_values], &new_values[0],
2891 sizeof(struct ldb_val)*num_new_values);
2892 el->num_values = old_num_values + num_new_values;
2893 talloc_steal(msg->elements, new_values);
2895 el->values = old_el->values;
2896 el->num_values = old_el->num_values;
2897 talloc_steal(msg->elements, el->values);
2900 talloc_free(tmp_ctx);
2902 /* we now tell the backend to replace all existing values
2903 with the one we have constructed */
2904 el->flags = LDB_FLAG_MOD_REPLACE;
2911 handle linked attributes in modify requests
2913 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2914 struct replmd_private *replmd_private,
2915 struct ldb_message *msg,
2916 uint64_t seq_num, time_t t,
2917 struct ldb_request *parent)
2919 struct ldb_result *res;
2922 struct ldb_context *ldb = ldb_module_get_ctx(module);
2923 struct ldb_message *old_msg;
2925 const struct dsdb_schema *schema;
2926 struct GUID old_guid;
2928 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2930 * Nothing special is required for modifying or vanishing links
2931 * in fl2000 since they are just strings in a multi-valued
2934 struct ldb_control *ctrl = ldb_request_get_control(parent,
2935 DSDB_CONTROL_REPLMD_VANISH_LINKS);
2937 ctrl->critical = false;
2945 * We should restrict this to the intersection of the list of
2946 * linked attributes in the schema and the list of attributes
2949 * This will help performance a little, as otherwise we have
2950 * to allocate the entire object value-by-value.
2952 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2953 DSDB_FLAG_NEXT_MODULE |
2954 DSDB_SEARCH_SHOW_RECYCLED |
2955 DSDB_SEARCH_REVEAL_INTERNALS |
2956 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2958 if (ret != LDB_SUCCESS) {
2961 schema = dsdb_get_schema(ldb, res);
2963 return LDB_ERR_OPERATIONS_ERROR;
2966 old_msg = res->msgs[0];
2968 old_guid = samdb_result_guid(old_msg, "objectGUID");
2970 for (i=0; i<msg->num_elements; i++) {
2971 struct ldb_message_element *el = &msg->elements[i];
2972 struct ldb_message_element *old_el, *new_el;
2973 const struct dsdb_attribute *schema_attr
2974 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2976 ldb_asprintf_errstring(ldb,
2977 "%s: attribute %s is not a valid attribute in schema",
2978 __FUNCTION__, el->name);
2979 return LDB_ERR_OBJECT_CLASS_VIOLATION;
2981 if (schema_attr->linkID == 0) {
2984 if ((schema_attr->linkID & 1) == 1) {
2985 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
2988 /* Odd is for the target. Illegal to modify */
2989 ldb_asprintf_errstring(ldb,
2990 "attribute %s must not be modified directly, it is a linked attribute", el->name);
2991 return LDB_ERR_UNWILLING_TO_PERFORM;
2993 old_el = ldb_msg_find_element(old_msg, el->name);
2994 switch (el->flags & LDB_FLAG_MOD_MASK) {
2995 case LDB_FLAG_MOD_REPLACE:
2996 ret = replmd_modify_la_replace(module, replmd_private,
2997 schema, msg, el, old_el,
2998 schema_attr, seq_num, t,
3001 case LDB_FLAG_MOD_DELETE:
3002 ret = replmd_modify_la_delete(module, replmd_private,
3003 schema, msg, el, old_el,
3004 schema_attr, seq_num, t,
3007 case LDB_FLAG_MOD_ADD:
3008 ret = replmd_modify_la_add(module, replmd_private,
3009 schema, msg, el, old_el,
3010 schema_attr, seq_num, t,
3014 ldb_asprintf_errstring(ldb,
3015 "invalid flags 0x%x for %s linked attribute",
3016 el->flags, el->name);
3017 return LDB_ERR_UNWILLING_TO_PERFORM;
3019 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3020 ldb_asprintf_errstring(ldb,
3021 "Attribute %s is single valued but more than one value has been supplied",
3023 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3025 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3030 if (ret != LDB_SUCCESS) {
3034 ldb_msg_remove_attr(old_msg, el->name);
3036 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3037 new_el->num_values = el->num_values;
3038 new_el->values = talloc_steal(msg->elements, el->values);
3040 /* TODO: this relises a bit too heavily on the exact
3041 behaviour of ldb_msg_find_element and
3042 ldb_msg_remove_element */
3043 old_el = ldb_msg_find_element(msg, el->name);
3045 ldb_msg_remove_element(msg, old_el);
3056 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3058 struct ldb_context *ldb;
3059 struct replmd_replicated_request *ac;
3060 struct ldb_request *down_req;
3061 struct ldb_message *msg;
3062 time_t t = time(NULL);
3064 bool is_urgent = false, rodc = false;
3065 bool is_schema_nc = false;
3066 unsigned int functional_level;
3067 const struct ldb_message_element *guid_el = NULL;
3068 struct ldb_control *sd_propagation_control;
3069 struct replmd_private *replmd_private =
3070 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3072 /* do not manipulate our control entries */
3073 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3074 return ldb_next_request(module, req);
3077 sd_propagation_control = ldb_request_get_control(req,
3078 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3079 if (sd_propagation_control != NULL) {
3080 if (req->op.mod.message->num_elements != 1) {
3081 return ldb_module_operr(module);
3083 ret = strcmp(req->op.mod.message->elements[0].name,
3084 "nTSecurityDescriptor");
3086 return ldb_module_operr(module);
3089 return ldb_next_request(module, req);
3092 ldb = ldb_module_get_ctx(module);
3094 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3096 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3097 if (guid_el != NULL) {
3098 ldb_set_errstring(ldb,
3099 "replmd_modify: it's not allowed to change the objectGUID!");
3100 return LDB_ERR_CONSTRAINT_VIOLATION;
3103 ac = replmd_ctx_init(module, req);
3105 return ldb_module_oom(module);
3108 functional_level = dsdb_functional_level(ldb);
3110 /* we have to copy the message as the caller might have it as a const */
3111 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3115 return LDB_ERR_OPERATIONS_ERROR;
3118 ldb_msg_remove_attr(msg, "whenChanged");
3119 ldb_msg_remove_attr(msg, "uSNChanged");
3121 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3123 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3124 msg, &ac->seq_num, t, is_schema_nc,
3126 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3127 struct loadparm_context *lp_ctx;
3130 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3131 struct loadparm_context);
3133 referral = talloc_asprintf(req,
3135 lpcfg_dnsdomain(lp_ctx),
3136 ldb_dn_get_linearized(msg->dn));
3137 ret = ldb_module_send_referral(req, referral);
3142 if (ret != LDB_SUCCESS) {
3147 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3148 msg, ac->seq_num, t, req);
3149 if (ret != LDB_SUCCESS) {
3155 * - replace the old object with the newly constructed one
3158 ac->is_urgent = is_urgent;
3160 ret = ldb_build_mod_req(&down_req, ldb, ac,
3163 ac, replmd_op_callback,
3165 LDB_REQ_SET_LOCATION(down_req);
3166 if (ret != LDB_SUCCESS) {
3171 /* current partition control is needed by "replmd_op_callback" */
3172 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3173 ret = ldb_request_add_control(down_req,
3174 DSDB_CONTROL_CURRENT_PARTITION_OID,
3176 if (ret != LDB_SUCCESS) {
3182 /* If we are in functional level 2000, then
3183 * replmd_modify_handle_linked_attribs will have done
3185 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3186 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3187 if (ret != LDB_SUCCESS) {
3193 talloc_steal(down_req, msg);
3195 /* we only change whenChanged and uSNChanged if the seq_num
3197 if (ac->seq_num != 0) {
3198 ret = add_time_element(msg, "whenChanged", t);
3199 if (ret != LDB_SUCCESS) {
3205 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3206 if (ret != LDB_SUCCESS) {
3213 /* go on with the call chain */
3214 return ldb_next_request(module, down_req);
3217 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3220 handle a rename request
3222 On a rename we need to do an extra ldb_modify which sets the
3223 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3225 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3227 struct ldb_context *ldb;
3228 struct replmd_replicated_request *ac;
3230 struct ldb_request *down_req;
3232 /* do not manipulate our control entries */
3233 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3234 return ldb_next_request(module, req);
3237 ldb = ldb_module_get_ctx(module);
3239 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3241 ac = replmd_ctx_init(module, req);
3243 return ldb_module_oom(module);
3246 ret = ldb_build_rename_req(&down_req, ldb, ac,
3247 ac->req->op.rename.olddn,
3248 ac->req->op.rename.newdn,
3250 ac, replmd_rename_callback,
3252 LDB_REQ_SET_LOCATION(down_req);
3253 if (ret != LDB_SUCCESS) {
3258 /* go on with the call chain */
3259 return ldb_next_request(module, down_req);
3262 /* After the rename is compleated, update the whenchanged etc */
3263 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3265 struct ldb_context *ldb;
3266 struct ldb_request *down_req;
3267 struct ldb_message *msg;
3268 const struct dsdb_attribute *rdn_attr;
3269 const char *rdn_name;
3270 const struct ldb_val *rdn_val;
3271 const char *attrs[5] = { NULL, };
3272 time_t t = time(NULL);
3274 bool is_urgent = false, rodc = false;
3276 struct replmd_replicated_request *ac =
3277 talloc_get_type(req->context, struct replmd_replicated_request);
3278 struct replmd_private *replmd_private =
3279 talloc_get_type(ldb_module_get_private(ac->module),
3280 struct replmd_private);
3282 ldb = ldb_module_get_ctx(ac->module);
3284 if (ares->error != LDB_SUCCESS) {
3285 return ldb_module_done(ac->req, ares->controls,
3286 ares->response, ares->error);
3289 if (ares->type != LDB_REPLY_DONE) {
3290 ldb_set_errstring(ldb,
3291 "invalid ldb_reply_type in callback");
3293 return ldb_module_done(ac->req, NULL, NULL,
3294 LDB_ERR_OPERATIONS_ERROR);
3298 * - replace the old object with the newly constructed one
3301 msg = ldb_msg_new(ac);
3304 return LDB_ERR_OPERATIONS_ERROR;
3307 msg->dn = ac->req->op.rename.newdn;
3309 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3311 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3312 if (rdn_name == NULL) {
3314 return ldb_module_done(ac->req, NULL, NULL,
3318 /* normalize the rdn attribute name */
3319 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3320 if (rdn_attr == NULL) {
3322 return ldb_module_done(ac->req, NULL, NULL,
3325 rdn_name = rdn_attr->lDAPDisplayName;
3327 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3328 if (rdn_val == NULL) {
3330 return ldb_module_done(ac->req, NULL, NULL,
3334 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3336 return ldb_module_done(ac->req, NULL, NULL,
3339 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3341 return ldb_module_done(ac->req, NULL, NULL,
3344 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3346 return ldb_module_done(ac->req, NULL, NULL,
3349 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3351 return ldb_module_done(ac->req, NULL, NULL,
3356 * here we let replmd_update_rpmd() only search for
3357 * the existing "replPropertyMetaData" and rdn_name attributes.
3359 * We do not want the existing "name" attribute as
3360 * the "name" attribute needs to get the version
3361 * updated on rename even if the rdn value hasn't changed.
3363 * This is the diff of the meta data, for a moved user
3364 * on a w2k8r2 server:
3367 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3368 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3369 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3370 * version : 0x00000001 (1)
3371 * reserved : 0x00000000 (0)
3372 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3373 * local_usn : 0x00000000000037a5 (14245)
3374 * array: struct replPropertyMetaData1
3375 * attid : DRSUAPI_ATTID_name (0x90001)
3376 * - version : 0x00000001 (1)
3377 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3378 * + version : 0x00000002 (2)
3379 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3380 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3381 * - originating_usn : 0x00000000000037a5 (14245)
3382 * - local_usn : 0x00000000000037a5 (14245)
3383 * + originating_usn : 0x0000000000003834 (14388)
3384 * + local_usn : 0x0000000000003834 (14388)
3385 * array: struct replPropertyMetaData1
3386 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3387 * version : 0x00000004 (4)
3389 attrs[0] = "replPropertyMetaData";
3390 attrs[1] = "objectClass";
3391 attrs[2] = "instanceType";
3392 attrs[3] = rdn_name;
3395 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3396 msg, &ac->seq_num, t,
3397 is_schema_nc, &is_urgent, &rodc);
3398 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3399 struct ldb_dn *olddn = ac->req->op.rename.olddn;
3400 struct loadparm_context *lp_ctx;
3403 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3404 struct loadparm_context);
3406 referral = talloc_asprintf(req,
3408 lpcfg_dnsdomain(lp_ctx),
3409 ldb_dn_get_linearized(olddn));
3410 ret = ldb_module_send_referral(req, referral);
3412 return ldb_module_done(req, NULL, NULL, ret);
3415 if (ret != LDB_SUCCESS) {
3417 return ldb_module_done(ac->req, NULL, NULL, ret);
3420 if (ac->seq_num == 0) {
3422 return ldb_module_done(ac->req, NULL, NULL,
3424 "internal error seq_num == 0"));
3426 ac->is_urgent = is_urgent;
3428 ret = ldb_build_mod_req(&down_req, ldb, ac,
3431 ac, replmd_op_callback,
3433 LDB_REQ_SET_LOCATION(down_req);
3434 if (ret != LDB_SUCCESS) {
3439 /* current partition control is needed by "replmd_op_callback" */
3440 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3441 ret = ldb_request_add_control(down_req,
3442 DSDB_CONTROL_CURRENT_PARTITION_OID,
3444 if (ret != LDB_SUCCESS) {
3450 talloc_steal(down_req, msg);
3452 ret = add_time_element(msg, "whenChanged", t);
3453 if (ret != LDB_SUCCESS) {
3459 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3460 if (ret != LDB_SUCCESS) {
3466 /* go on with the call chain - do the modify after the rename */
3467 return ldb_next_request(ac->module, down_req);
3471 * remove links from objects that point at this object when an object
3472 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3473 * RemoveObj which states that link removal due to the object being
3474 * deleted is NOT an originating update - they just go away!
3477 static int replmd_delete_remove_link(struct ldb_module *module,
3478 const struct dsdb_schema *schema,
3480 struct ldb_message_element *el,
3481 const struct dsdb_attribute *sa,
3482 struct ldb_request *parent)
3485 TALLOC_CTX *tmp_ctx = talloc_new(module);
3486 struct ldb_context *ldb = ldb_module_get_ctx(module);
3488 for (i=0; i<el->num_values; i++) {
3489 struct dsdb_dn *dsdb_dn;
3493 struct ldb_message *msg;
3494 const struct dsdb_attribute *target_attr;
3495 struct ldb_message_element *el2;
3496 struct ldb_val dn_val;
3497 uint32_t dsdb_flags = 0;
3499 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3503 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3505 talloc_free(tmp_ctx);
3506 return LDB_ERR_OPERATIONS_ERROR;
3509 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
3510 if (!NT_STATUS_IS_OK(status)) {
3511 talloc_free(tmp_ctx);
3512 return LDB_ERR_OPERATIONS_ERROR;
3515 /* remove the link */
3516 msg = ldb_msg_new(tmp_ctx);
3518 ldb_module_oom(module);
3519 talloc_free(tmp_ctx);
3520 return LDB_ERR_OPERATIONS_ERROR;
3524 msg->dn = dsdb_dn->dn;
3526 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3527 if (target_attr == NULL) {
3531 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
3532 if (ret != LDB_SUCCESS) {
3533 ldb_module_oom(module);
3534 talloc_free(tmp_ctx);
3535 return LDB_ERR_OPERATIONS_ERROR;
3537 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
3538 el2->values = &dn_val;
3539 el2->num_values = 1;
3542 * Ensure that we tell the modification to vanish any linked
3543 * attributes (not simply mark them as isDeleted = TRUE)
3545 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3547 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3548 if (ret != LDB_SUCCESS) {
3549 talloc_free(tmp_ctx);
3553 talloc_free(tmp_ctx);
3559 handle update of replication meta data for deletion of objects
3561 This also handles the mapping of delete to a rename operation
3562 to allow deletes to be replicated.
3564 It also handles the incoming deleted objects, to ensure they are
3565 fully deleted here. In that case re_delete is true, and we do not
3566 use this as a signal to change the deleted state, just reinforce it.
3569 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3571 int ret = LDB_ERR_OTHER;
3572 bool retb, disallow_move_on_delete;
3573 struct ldb_dn *old_dn, *new_dn;
3574 const char *rdn_name;
3575 const struct ldb_val *rdn_value, *new_rdn_value;
3577 struct ldb_context *ldb = ldb_module_get_ctx(module);
3578 const struct dsdb_schema *schema;
3579 struct ldb_message *msg, *old_msg;
3580 struct ldb_message_element *el;
3581 TALLOC_CTX *tmp_ctx;
3582 struct ldb_result *res, *parent_res;
3583 static const char * const preserved_attrs[] = {
3584 /* yes, this really is a hard coded list. See MS-ADTS
3585 section 3.1.1.5.5.1.1 */
3588 "dNReferenceUpdate",
3599 "msDS-LastKnownRDN",
3605 "distinguishedName",
3609 "proxiedObjectName",
3611 "nTSecurityDescriptor",
3612 "replPropertyMetaData",
3614 "securityIdentifier",
3622 "userAccountControl",
3629 static const char * const all_attrs[] = {
3630 DSDB_SECRET_ATTRIBUTES,
3634 unsigned int i, el_count = 0;
3635 uint32_t dsdb_flags = 0;
3636 enum deletion_state deletion_state, next_deletion_state;
3638 if (ldb_dn_is_special(req->op.del.dn)) {
3639 return ldb_next_request(module, req);
3643 * We have to allow dbcheck to remove an object that
3644 * is beyond repair, and to do so totally. This could
3645 * mean we we can get a partial object from the other
3646 * DC, causing havoc, so dbcheck suggests
3647 * re-replication first. dbcheck sets both DBCHECK
3648 * and RELAX in this situation.
3650 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3651 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3652 /* really, really remove it */
3653 return ldb_next_request(module, req);
3656 tmp_ctx = talloc_new(ldb);
3659 return LDB_ERR_OPERATIONS_ERROR;
3662 schema = dsdb_get_schema(ldb, tmp_ctx);
3664 talloc_free(tmp_ctx);
3665 return LDB_ERR_OPERATIONS_ERROR;
3668 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3670 /* we need the complete msg off disk, so we can work out which
3671 attributes need to be removed */
3672 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3673 DSDB_FLAG_NEXT_MODULE |
3674 DSDB_SEARCH_SHOW_RECYCLED |
3675 DSDB_SEARCH_REVEAL_INTERNALS |
3676 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3677 if (ret != LDB_SUCCESS) {
3678 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3679 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3680 re_delete ? "re-delete" : "delete",
3681 ldb_dn_get_linearized(old_dn),
3682 ldb_errstring(ldb_module_get_ctx(module)));
3683 talloc_free(tmp_ctx);
3686 old_msg = res->msgs[0];
3688 replmd_deletion_state(module, old_msg,
3690 &next_deletion_state);
3692 /* This supports us noticing an incoming isDeleted and acting on it */
3694 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3695 next_deletion_state = deletion_state;
3698 if (next_deletion_state == OBJECT_REMOVED) {
3700 * We have to prevent objects being deleted, even if
3701 * the administrator really wants them gone, as
3702 * without the tombstone, we can get a partial object
3703 * from the other DC, causing havoc.
3705 * The only other valid case is when the 180 day
3706 * timeout has expired, when relax is specified.
3708 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3709 /* it is already deleted - really remove it this time */
3710 talloc_free(tmp_ctx);
3711 return ldb_next_request(module, req);
3714 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3715 "This check is to prevent corruption of the replicated state.",
3716 ldb_dn_get_linearized(old_msg->dn));
3717 return LDB_ERR_UNWILLING_TO_PERFORM;
3720 rdn_name = ldb_dn_get_rdn_name(old_dn);
3721 rdn_value = ldb_dn_get_rdn_val(old_dn);
3722 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3723 talloc_free(tmp_ctx);
3724 return ldb_operr(ldb);
3727 msg = ldb_msg_new(tmp_ctx);
3729 ldb_module_oom(module);
3730 talloc_free(tmp_ctx);
3731 return LDB_ERR_OPERATIONS_ERROR;
3736 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3737 disallow_move_on_delete =
3738 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3739 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3741 /* work out where we will be renaming this object to */
3742 if (!disallow_move_on_delete) {
3743 struct ldb_dn *deleted_objects_dn;
3744 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3745 &deleted_objects_dn);
3748 * We should not move objects if we can't find the
3749 * deleted objects DN. Not moving (or otherwise
3750 * harming) the Deleted Objects DN itself is handled
3753 if (re_delete && (ret != LDB_SUCCESS)) {
3754 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3755 if (new_dn == NULL) {
3756 ldb_module_oom(module);
3757 talloc_free(tmp_ctx);
3758 return LDB_ERR_OPERATIONS_ERROR;
3760 } else if (ret != LDB_SUCCESS) {
3761 /* this is probably an attempted delete on a partition
3762 * that doesn't allow delete operations, such as the
3763 * schema partition */
3764 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3765 ldb_dn_get_linearized(old_dn));
3766 talloc_free(tmp_ctx);
3767 return LDB_ERR_UNWILLING_TO_PERFORM;
3769 new_dn = deleted_objects_dn;
3772 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3773 if (new_dn == NULL) {
3774 ldb_module_oom(module);
3775 talloc_free(tmp_ctx);
3776 return LDB_ERR_OPERATIONS_ERROR;
3780 if (deletion_state == OBJECT_NOT_DELETED) {
3781 /* get the objects GUID from the search we just did */
3782 guid = samdb_result_guid(old_msg, "objectGUID");
3784 /* Add a formatted child */
3785 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3787 ldb_dn_escape_value(tmp_ctx, *rdn_value),
3788 GUID_string(tmp_ctx, &guid));
3790 ldb_asprintf_errstring(ldb, __location__
3791 ": Unable to add a formatted child to dn: %s",
3792 ldb_dn_get_linearized(new_dn));
3793 talloc_free(tmp_ctx);
3794 return LDB_ERR_OPERATIONS_ERROR;
3797 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
3798 if (ret != LDB_SUCCESS) {
3799 ldb_asprintf_errstring(ldb, __location__
3800 ": Failed to add isDeleted string to the msg");
3801 talloc_free(tmp_ctx);
3804 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3807 * No matter what has happened with other renames etc, try again to
3808 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
3811 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
3812 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
3814 ldb_asprintf_errstring(ldb, __location__
3815 ": Unable to add a prepare rdn of %s",
3816 ldb_dn_get_linearized(rdn));
3817 talloc_free(tmp_ctx);
3818 return LDB_ERR_OPERATIONS_ERROR;
3820 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
3822 retb = ldb_dn_add_child(new_dn, rdn);
3824 ldb_asprintf_errstring(ldb, __location__
3825 ": Unable to add rdn %s to base dn: %s",
3826 ldb_dn_get_linearized(rdn),
3827 ldb_dn_get_linearized(new_dn));
3828 talloc_free(tmp_ctx);
3829 return LDB_ERR_OPERATIONS_ERROR;
3834 now we need to modify the object in the following ways:
3836 - add isDeleted=TRUE
3837 - update rDN and name, with new rDN
3838 - remove linked attributes
3839 - remove objectCategory and sAMAccountType
3840 - remove attribs not on the preserved list
3841 - preserved if in above list, or is rDN
3842 - remove all linked attribs from this object
3843 - remove all links from other objects to this object
3844 - add lastKnownParent
3845 - update replPropertyMetaData?
3847 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
3850 if (deletion_state == OBJECT_NOT_DELETED) {
3851 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3852 char *parent_dn_str = NULL;
3854 /* we need the storage form of the parent GUID */
3855 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
3857 DSDB_FLAG_NEXT_MODULE |
3858 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3859 DSDB_SEARCH_REVEAL_INTERNALS|
3860 DSDB_SEARCH_SHOW_RECYCLED, req);
3861 if (ret != LDB_SUCCESS) {
3862 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3863 "repmd_delete: Failed to %s %s, "
3864 "because we failed to find it's parent (%s): %s",
3865 re_delete ? "re-delete" : "delete",
3866 ldb_dn_get_linearized(old_dn),
3867 ldb_dn_get_linearized(parent_dn),
3868 ldb_errstring(ldb_module_get_ctx(module)));
3869 talloc_free(tmp_ctx);
3874 * Now we can use the DB version,
3875 * it will have the extended DN info in it
3877 parent_dn = parent_res->msgs[0]->dn;
3878 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
3881 if (parent_dn_str == NULL) {
3882 talloc_free(tmp_ctx);
3883 return ldb_module_oom(module);
3886 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3888 if (ret != LDB_SUCCESS) {
3889 ldb_asprintf_errstring(ldb, __location__
3890 ": Failed to add lastKnownParent "
3891 "string when deleting %s",
3892 ldb_dn_get_linearized(old_dn));
3893 talloc_free(tmp_ctx);
3896 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3898 if (next_deletion_state == OBJECT_DELETED) {
3899 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
3900 if (ret != LDB_SUCCESS) {
3901 ldb_asprintf_errstring(ldb, __location__
3902 ": Failed to add msDS-LastKnownRDN "
3903 "string when deleting %s",
3904 ldb_dn_get_linearized(old_dn));
3905 talloc_free(tmp_ctx);
3908 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
3912 switch (next_deletion_state) {
3914 case OBJECT_RECYCLED:
3915 case OBJECT_TOMBSTONE:
3918 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
3919 * describes what must be removed from a tombstone
3922 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
3923 * describes what must be removed from a recycled
3929 * we also mark it as recycled, meaning this object can't be
3930 * recovered (we are stripping its attributes).
3931 * This is done only if we have this schema object of course ...
3932 * This behavior is identical to the one of Windows 2008R2 which
3933 * always set the isRecycled attribute, even if the recycle-bin is
3934 * not activated and what ever the forest level is.
3936 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
3937 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
3938 if (ret != LDB_SUCCESS) {
3939 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
3940 ldb_module_oom(module);
3941 talloc_free(tmp_ctx);
3944 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3947 /* work out which of the old attributes we will be removing */
3948 for (i=0; i<old_msg->num_elements; i++) {
3949 const struct dsdb_attribute *sa;
3950 el = &old_msg->elements[i];
3951 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3953 talloc_free(tmp_ctx);
3954 return LDB_ERR_OPERATIONS_ERROR;
3956 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
3957 /* don't remove the rDN */
3960 if (sa->linkID && (sa->linkID & 1)) {
3962 we have a backlink in this object
3963 that needs to be removed. We're not
3964 allowed to remove it directly
3965 however, so we instead setup a
3966 modify to delete the corresponding
3969 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
3970 if (ret != LDB_SUCCESS) {
3971 const char *old_dn_str
3972 = ldb_dn_get_linearized(old_dn);
3973 ldb_asprintf_errstring(ldb,
3975 ": Failed to remove backlink of "
3976 "%s when deleting %s: %s",
3979 ldb_errstring(ldb));
3980 talloc_free(tmp_ctx);
3981 return LDB_ERR_OPERATIONS_ERROR;
3983 /* now we continue, which means we
3984 won't remove this backlink
3990 if (ldb_attr_in_list(preserved_attrs, el->name)) {
3993 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
3998 * Ensure that we tell the modification to vanish any linked
3999 * attributes (not simply mark them as isDeleted = TRUE)
4001 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4003 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4004 if (ret != LDB_SUCCESS) {
4005 talloc_free(tmp_ctx);
4006 ldb_module_oom(module);
4013 case OBJECT_DELETED:
4015 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4016 * describes what must be removed from a deleted
4020 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4021 if (ret != LDB_SUCCESS) {
4022 talloc_free(tmp_ctx);
4023 ldb_module_oom(module);
4027 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4028 if (ret != LDB_SUCCESS) {
4029 talloc_free(tmp_ctx);
4030 ldb_module_oom(module);
4040 if (deletion_state == OBJECT_NOT_DELETED) {
4041 const struct dsdb_attribute *sa;
4043 /* work out what the new rdn value is, for updating the
4044 rDN and name fields */
4045 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4046 if (new_rdn_value == NULL) {
4047 talloc_free(tmp_ctx);
4048 return ldb_operr(ldb);
4051 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4053 talloc_free(tmp_ctx);
4054 return LDB_ERR_OPERATIONS_ERROR;
4057 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4059 if (ret != LDB_SUCCESS) {
4060 talloc_free(tmp_ctx);
4063 el->flags = LDB_FLAG_MOD_REPLACE;
4065 el = ldb_msg_find_element(old_msg, "name");
4067 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4068 if (ret != LDB_SUCCESS) {
4069 talloc_free(tmp_ctx);
4072 el->flags = LDB_FLAG_MOD_REPLACE;
4077 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4082 * No matter what has happned with other renames, try again to
4083 * get this to be under the deleted DN.
4085 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4086 /* now rename onto the new DN */
4087 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4088 if (ret != LDB_SUCCESS){
4089 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4090 ldb_dn_get_linearized(old_dn),
4091 ldb_dn_get_linearized(new_dn),
4092 ldb_errstring(ldb)));
4093 talloc_free(tmp_ctx);
4099 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4100 if (ret != LDB_SUCCESS) {
4101 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4102 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4103 talloc_free(tmp_ctx);
4107 talloc_free(tmp_ctx);
4109 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4112 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4114 return replmd_delete_internals(module, req, false);
4118 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4123 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4125 int ret = LDB_ERR_OTHER;
4126 /* TODO: do some error mapping */
4128 /* Let the caller know the full WERROR */
4129 ar->objs->error = status;
4135 static struct replPropertyMetaData1 *
4136 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4137 enum drsuapi_DsAttributeId attid)
4140 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4142 for (i = 0; i < rpmd_ctr->count; i++) {
4143 if (rpmd_ctr->array[i].attid == attid) {
4144 return &rpmd_ctr->array[i];
4152 return true if an update is newer than an existing entry
4153 see section 5.11 of MS-ADTS
4155 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4156 const struct GUID *update_invocation_id,
4157 uint32_t current_version,
4158 uint32_t update_version,
4159 NTTIME current_change_time,
4160 NTTIME update_change_time)
4162 if (update_version != current_version) {
4163 return update_version > current_version;
4165 if (update_change_time != current_change_time) {
4166 return update_change_time > current_change_time;
4168 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4171 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4172 struct replPropertyMetaData1 *new_m)
4174 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4175 &new_m->originating_invocation_id,
4178 cur_m->originating_change_time,
4179 new_m->originating_change_time);
4182 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4183 struct replPropertyMetaData1 *cur_m,
4184 struct replPropertyMetaData1 *new_m)
4189 * If the new replPropertyMetaData entry for this attribute is
4190 * not provided (this happens in the case where we look for
4191 * ATTID_name, but the name was not changed), then the local
4192 * state is clearly still current, as the remote
4193 * server didn't send it due to being older the high watermark
4196 if (new_m == NULL) {
4200 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4202 * if we compare equal then do an
4203 * update. This is used when a client
4204 * asks for a FULL_SYNC, and can be
4205 * used to recover a corrupt
4208 * This call is a bit tricky, what we
4209 * are doing it turning the 'is_newer'
4210 * call into a 'not is older' by
4211 * swapping cur_m and new_m, and negating the
4214 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4217 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4227 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4229 const struct ldb_val *rdn_val;
4230 const char *rdn_name;
4231 struct ldb_dn *new_dn;
4233 rdn_val = ldb_dn_get_rdn_val(dn);
4234 rdn_name = ldb_dn_get_rdn_name(dn);
4235 if (!rdn_val || !rdn_name) {
4239 new_dn = ldb_dn_copy(mem_ctx, dn);
4244 if (!ldb_dn_remove_child_components(new_dn, 1)) {
4248 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4250 ldb_dn_escape_value(new_dn, *rdn_val),
4251 GUID_string(new_dn, guid))) {
4260 perform a modify operation which sets the rDN and name attributes to
4261 their current values. This has the effect of changing these
4262 attributes to have been last updated by the current DC. This is
4263 needed to ensure that renames performed as part of conflict
4264 resolution are propogated to other DCs
4266 static int replmd_name_modify(struct replmd_replicated_request *ar,
4267 struct ldb_request *req, struct ldb_dn *dn)
4269 struct ldb_message *msg;
4270 const char *rdn_name;
4271 const struct ldb_val *rdn_val;
4272 const struct dsdb_attribute *rdn_attr;
4275 msg = ldb_msg_new(req);
4281 rdn_name = ldb_dn_get_rdn_name(dn);
4282 if (rdn_name == NULL) {
4286 /* normalize the rdn attribute name */
4287 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4288 if (rdn_attr == NULL) {
4291 rdn_name = rdn_attr->lDAPDisplayName;
4293 rdn_val = ldb_dn_get_rdn_val(dn);
4294 if (rdn_val == NULL) {
4298 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4301 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4304 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4307 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4311 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4312 if (ret != LDB_SUCCESS) {
4313 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
4314 ldb_dn_get_linearized(dn),
4315 ldb_errstring(ldb_module_get_ctx(ar->module))));
4325 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
4326 ldb_dn_get_linearized(dn)));
4327 return LDB_ERR_OPERATIONS_ERROR;
4332 callback for conflict DN handling where we have renamed the incoming
4333 record. After renaming it, we need to ensure the change of name and
4334 rDN for the incoming record is seen as an originating update by this DC.
4336 This also handles updating lastKnownParent for entries sent to lostAndFound
4338 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4340 struct replmd_replicated_request *ar =
4341 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4342 struct ldb_dn *conflict_dn = NULL;
4345 if (ares->error != LDB_SUCCESS) {
4346 /* call the normal callback for everything except success */
4347 return replmd_op_callback(req, ares);
4350 switch (req->operation) {
4352 conflict_dn = req->op.add.message->dn;
4355 conflict_dn = req->op.mod.message->dn;
4358 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4361 /* perform a modify of the rDN and name of the record */
4362 ret = replmd_name_modify(ar, req, conflict_dn);
4363 if (ret != LDB_SUCCESS) {
4365 return replmd_op_callback(req, ares);
4368 if (ar->objs->objects[ar->index_current].last_known_parent) {
4369 struct ldb_message *msg = ldb_msg_new(req);
4371 ldb_module_oom(ar->module);
4372 return LDB_ERR_OPERATIONS_ERROR;
4375 msg->dn = req->op.add.message->dn;
4377 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4378 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4379 if (ret != LDB_SUCCESS) {
4380 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4381 ldb_module_oom(ar->module);
4384 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4386 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4387 if (ret != LDB_SUCCESS) {
4388 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4389 ldb_dn_get_linearized(msg->dn),
4390 ldb_errstring(ldb_module_get_ctx(ar->module))));
4396 return replmd_op_callback(req, ares);
4400 callback for replmd_replicated_apply_add()
4401 This copes with the creation of conflict records in the case where
4402 the DN exists, but with a different objectGUID
4404 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))
4406 struct ldb_dn *conflict_dn;
4407 struct replmd_replicated_request *ar =
4408 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4409 struct ldb_result *res;
4410 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4412 const struct ldb_val *omd_value;
4413 struct replPropertyMetaDataBlob omd, *rmd;
4414 enum ndr_err_code ndr_err;
4415 bool rename_incoming_record, rodc;
4416 struct replPropertyMetaData1 *rmd_name, *omd_name;
4417 struct ldb_message *msg;
4418 struct ldb_request *down_req = NULL;
4420 /* call the normal callback for success */
4421 if (ares->error == LDB_SUCCESS) {
4422 return callback(req, ares);
4426 * we have a conflict, and need to decide if we will keep the
4427 * new record or the old record
4430 msg = ar->objs->objects[ar->index_current].msg;
4431 conflict_dn = msg->dn;
4433 /* For failures other than conflicts, fail the whole operation here */
4434 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4435 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4436 ldb_dn_get_linearized(conflict_dn),
4437 ldb_errstring(ldb_module_get_ctx(ar->module)));
4439 return ldb_module_done(ar->req, NULL, NULL,
4440 LDB_ERR_OPERATIONS_ERROR);
4443 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4444 if (ret != LDB_SUCCESS) {
4445 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)));
4446 return ldb_module_done(ar->req, NULL, NULL,
4447 LDB_ERR_OPERATIONS_ERROR);
4453 * We are on an RODC, or were a GC for this
4454 * partition, so we have to fail this until
4455 * someone who owns the partition sorts it
4458 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4459 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
4460 " - We must fail the operation until a master for this partition resolves the conflict",
4461 ldb_dn_get_linearized(conflict_dn));
4466 * first we need the replPropertyMetaData attribute from the
4467 * local, conflicting record
4469 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4471 DSDB_FLAG_NEXT_MODULE |
4472 DSDB_SEARCH_SHOW_DELETED |
4473 DSDB_SEARCH_SHOW_RECYCLED, req);
4474 if (ret != LDB_SUCCESS) {
4475 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4476 ldb_dn_get_linearized(conflict_dn)));
4480 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4481 if (omd_value == NULL) {
4482 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4483 ldb_dn_get_linearized(conflict_dn)));
4487 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4488 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4489 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4490 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4491 ldb_dn_get_linearized(conflict_dn)));
4495 rmd = ar->objs->objects[ar->index_current].meta_data;
4498 * we decide which is newer based on the RPMD on the name
4499 * attribute. See [MS-DRSR] ResolveNameConflict.
4501 * We expect omd_name to be present, as this is from a local
4502 * search, but while rmd_name should have been given to us by
4503 * the remote server, if it is missing we just prefer the
4505 * replmd_replPropertyMetaData1_new_should_be_taken()
4507 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4508 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4510 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4511 ldb_dn_get_linearized(conflict_dn)));
4516 * Should we preserve the current record, and so rename the
4517 * incoming record to be a conflict?
4519 rename_incoming_record
4520 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4521 omd_name, rmd_name);
4523 if (rename_incoming_record) {
4525 struct ldb_dn *new_dn;
4527 guid = samdb_result_guid(msg, "objectGUID");
4528 if (GUID_all_zero(&guid)) {
4529 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4530 ldb_dn_get_linearized(conflict_dn)));
4533 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4534 if (new_dn == NULL) {
4535 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4536 ldb_dn_get_linearized(conflict_dn)));
4540 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4541 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4543 /* re-submit the request, but with the new DN */
4544 callback = replmd_op_name_modify_callback;
4547 /* we are renaming the existing record */
4549 struct ldb_dn *new_dn;
4551 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4552 if (GUID_all_zero(&guid)) {
4553 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4554 ldb_dn_get_linearized(conflict_dn)));
4558 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4559 if (new_dn == NULL) {
4560 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4561 ldb_dn_get_linearized(conflict_dn)));
4565 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4566 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4568 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4569 DSDB_FLAG_OWN_MODULE, req);
4570 if (ret != LDB_SUCCESS) {
4571 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4572 ldb_dn_get_linearized(conflict_dn),
4573 ldb_dn_get_linearized(new_dn),
4574 ldb_errstring(ldb_module_get_ctx(ar->module))));
4579 * now we need to ensure that the rename is seen as an
4580 * originating update. We do that with a modify.
4582 ret = replmd_name_modify(ar, req, new_dn);
4583 if (ret != LDB_SUCCESS) {
4587 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4588 ldb_dn_get_linearized(req->op.add.message->dn)));
4591 ret = ldb_build_add_req(&down_req,
4592 ldb_module_get_ctx(ar->module),
4599 if (ret != LDB_SUCCESS) {
4602 LDB_REQ_SET_LOCATION(down_req);
4604 /* current partition control needed by "repmd_op_callback" */
4605 ret = ldb_request_add_control(down_req,
4606 DSDB_CONTROL_CURRENT_PARTITION_OID,
4608 if (ret != LDB_SUCCESS) {
4609 return replmd_replicated_request_error(ar, ret);
4612 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4613 /* this tells the partition module to make it a
4614 partial replica if creating an NC */
4615 ret = ldb_request_add_control(down_req,
4616 DSDB_CONTROL_PARTIAL_REPLICA,
4618 if (ret != LDB_SUCCESS) {
4619 return replmd_replicated_request_error(ar, ret);
4624 * Finally we re-run the add, otherwise the new record won't
4625 * exist, as we are here because of that exact failure!
4627 return ldb_next_request(ar->module, down_req);
4630 /* on failure make the caller get the error. This means
4631 * replication will stop with an error, but there is not much
4634 return ldb_module_done(ar->req, NULL, NULL,
4639 callback for replmd_replicated_apply_add()
4640 This copes with the creation of conflict records in the case where
4641 the DN exists, but with a different objectGUID
4643 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4645 struct replmd_replicated_request *ar =
4646 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4648 if (ar->objs->objects[ar->index_current].last_known_parent) {
4649 /* This is like a conflict DN, where we put the object in LostAndFound
4650 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4651 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4654 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4658 this is called when a new object comes in over DRS
4660 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4662 struct ldb_context *ldb;
4663 struct ldb_request *change_req;
4664 enum ndr_err_code ndr_err;
4665 struct ldb_message *msg;
4666 struct replPropertyMetaDataBlob *md;
4667 struct ldb_val md_value;
4670 bool remote_isDeleted = false;
4673 time_t t = time(NULL);
4674 const struct ldb_val *rdn_val;
4675 struct replmd_private *replmd_private =
4676 talloc_get_type(ldb_module_get_private(ar->module),
4677 struct replmd_private);
4678 unix_to_nt_time(&now, t);
4680 ldb = ldb_module_get_ctx(ar->module);
4681 msg = ar->objs->objects[ar->index_current].msg;
4682 md = ar->objs->objects[ar->index_current].meta_data;
4683 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4685 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4686 if (ret != LDB_SUCCESS) {
4687 return replmd_replicated_request_error(ar, ret);
4690 ret = dsdb_msg_add_guid(msg,
4691 &ar->objs->objects[ar->index_current].object_guid,
4693 if (ret != LDB_SUCCESS) {
4694 return replmd_replicated_request_error(ar, ret);
4697 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4698 if (ret != LDB_SUCCESS) {
4699 return replmd_replicated_request_error(ar, ret);
4702 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4703 if (ret != LDB_SUCCESS) {
4704 return replmd_replicated_request_error(ar, ret);
4707 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4708 if (ret != LDB_SUCCESS) {
4709 return replmd_replicated_request_error(ar, ret);
4712 /* remove any message elements that have zero values */
4713 for (i=0; i<msg->num_elements; i++) {
4714 struct ldb_message_element *el = &msg->elements[i];
4716 if (el->num_values == 0) {
4717 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4718 ldb_asprintf_errstring(ldb, __location__
4719 ": empty objectClass sent on %s, aborting replication\n",
4720 ldb_dn_get_linearized(msg->dn));
4721 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4724 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4726 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4727 msg->num_elements--;
4734 struct GUID_txt_buf guid_txt;
4736 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4737 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4738 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4743 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4744 "isDeleted", false);
4747 * the meta data array is already sorted by the caller, except
4748 * for the RDN, which needs to be added.
4752 rdn_val = ldb_dn_get_rdn_val(msg->dn);
4753 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4754 md, ar, now, is_schema_nc);
4755 if (ret != LDB_SUCCESS) {
4756 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4757 return replmd_replicated_request_error(ar, ret);
4760 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4761 if (ret != LDB_SUCCESS) {
4762 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4763 return replmd_replicated_request_error(ar, ret);
4766 for (i=0; i < md->ctr.ctr1.count; i++) {
4767 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4769 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4770 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4771 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4772 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4773 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4775 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4776 if (ret != LDB_SUCCESS) {
4777 return replmd_replicated_request_error(ar, ret);
4780 replmd_ldb_message_sort(msg, ar->schema);
4782 if (!remote_isDeleted) {
4783 ret = dsdb_module_schedule_sd_propagation(ar->module,
4784 ar->objs->partition_dn,
4786 if (ret != LDB_SUCCESS) {
4787 return replmd_replicated_request_error(ar, ret);
4791 ar->isDeleted = remote_isDeleted;
4793 ret = ldb_build_add_req(&change_req,
4799 replmd_op_add_callback,
4801 LDB_REQ_SET_LOCATION(change_req);
4802 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4804 /* current partition control needed by "repmd_op_callback" */
4805 ret = ldb_request_add_control(change_req,
4806 DSDB_CONTROL_CURRENT_PARTITION_OID,
4808 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4810 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4811 /* this tells the partition module to make it a
4812 partial replica if creating an NC */
4813 ret = ldb_request_add_control(change_req,
4814 DSDB_CONTROL_PARTIAL_REPLICA,
4816 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4819 return ldb_next_request(ar->module, change_req);
4822 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
4823 struct ldb_reply *ares)
4825 struct replmd_replicated_request *ar = talloc_get_type(req->context,
4826 struct replmd_replicated_request);
4830 return ldb_module_done(ar->req, NULL, NULL,
4831 LDB_ERR_OPERATIONS_ERROR);
4835 * The error NO_SUCH_OBJECT is not expected, unless the search
4836 * base is the partition DN, and that case doesn't happen here
4837 * because then we wouldn't get a parent_guid_value in any
4840 if (ares->error != LDB_SUCCESS) {
4841 return ldb_module_done(ar->req, ares->controls,
4842 ares->response, ares->error);
4845 switch (ares->type) {
4846 case LDB_REPLY_ENTRY:
4848 struct ldb_message *parent_msg = ares->message;
4849 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
4850 struct ldb_dn *parent_dn;
4853 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
4854 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
4855 /* Per MS-DRSR 4.1.10.6.10
4856 * FindBestParentObject we need to move this
4857 * new object under a deleted object to
4859 struct ldb_dn *nc_root;
4861 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
4862 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4863 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4864 "No suitable NC root found for %s. "
4865 "We need to move this object because parent object %s "
4866 "is deleted, but this object is not.",
4867 ldb_dn_get_linearized(msg->dn),
4868 ldb_dn_get_linearized(parent_msg->dn));
4869 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4870 } else if (ret != LDB_SUCCESS) {
4871 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4872 "Unable to find NC root for %s: %s. "
4873 "We need to move this object because parent object %s "
4874 "is deleted, but this object is not.",
4875 ldb_dn_get_linearized(msg->dn),
4876 ldb_errstring(ldb_module_get_ctx(ar->module)),
4877 ldb_dn_get_linearized(parent_msg->dn));
4878 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4881 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
4883 DS_GUID_LOSTANDFOUND_CONTAINER,
4885 if (ret != LDB_SUCCESS) {
4886 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4887 "Unable to find LostAndFound Container for %s "
4888 "in partition %s: %s. "
4889 "We need to move this object because parent object %s "
4890 "is deleted, but this object is not.",
4891 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
4892 ldb_errstring(ldb_module_get_ctx(ar->module)),
4893 ldb_dn_get_linearized(parent_msg->dn));
4894 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4896 ar->objs->objects[ar->index_current].last_known_parent
4897 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4901 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4904 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
4906 comp_num = ldb_dn_get_comp_num(msg->dn);
4908 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
4910 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4913 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
4915 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4919 case LDB_REPLY_REFERRAL:
4920 /* we ignore referrals */
4923 case LDB_REPLY_DONE:
4925 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
4926 struct GUID_txt_buf str_buf;
4927 if (ar->search_msg != NULL) {
4928 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4929 "No parent with GUID %s found for object locally known as %s",
4930 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4931 ldb_dn_get_linearized(ar->search_msg->dn));
4933 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4934 "No parent with GUID %s found for object remotely known as %s",
4935 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4936 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
4940 * This error code is really important, as it
4941 * is the flag back to the callers to retry
4942 * this with DRSUAPI_DRS_GET_ANC, and so get
4943 * the parent objects before the child
4946 return ldb_module_done(ar->req, NULL, NULL,
4947 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
4950 if (ar->search_msg != NULL) {
4951 ret = replmd_replicated_apply_merge(ar);
4953 ret = replmd_replicated_apply_add(ar);
4955 if (ret != LDB_SUCCESS) {
4956 return ldb_module_done(ar->req, NULL, NULL, ret);
4965 * Look for the parent object, so we put the new object in the right
4966 * place This is akin to NameObject in MS-DRSR - this routine and the
4967 * callbacks find the right parent name, and correct name for this
4971 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
4973 struct ldb_context *ldb;
4977 struct ldb_request *search_req;
4978 static const char *attrs[] = {"isDeleted", NULL};
4979 struct GUID_txt_buf guid_str_buf;
4981 ldb = ldb_module_get_ctx(ar->module);
4983 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
4984 if (ar->search_msg != NULL) {
4985 return replmd_replicated_apply_merge(ar);
4987 return replmd_replicated_apply_add(ar);
4991 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
4994 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
4995 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
4997 ret = ldb_build_search_req(&search_req,
5000 ar->objs->partition_dn,
5006 replmd_replicated_apply_search_for_parent_callback,
5008 LDB_REQ_SET_LOCATION(search_req);
5010 ret = dsdb_request_add_controls(search_req,
5011 DSDB_SEARCH_SHOW_RECYCLED|
5012 DSDB_SEARCH_SHOW_DELETED|
5013 DSDB_SEARCH_SHOW_EXTENDED_DN);
5014 if (ret != LDB_SUCCESS) {
5018 return ldb_next_request(ar->module, search_req);
5022 handle renames that come in over DRS replication
5024 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5025 struct ldb_message *msg,
5026 struct ldb_request *parent,
5030 TALLOC_CTX *tmp_ctx = talloc_new(msg);
5031 struct ldb_result *res;
5032 struct ldb_dn *conflict_dn;
5033 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5034 const struct ldb_val *omd_value;
5035 struct replPropertyMetaDataBlob omd, *rmd;
5036 enum ndr_err_code ndr_err;
5037 bool rename_incoming_record, rodc;
5038 struct replPropertyMetaData1 *rmd_name, *omd_name;
5039 struct ldb_dn *new_dn;
5042 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5043 ldb_dn_get_linearized(ar->search_msg->dn),
5044 ldb_dn_get_linearized(msg->dn)));
5047 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5048 DSDB_FLAG_NEXT_MODULE, ar->req);
5049 if (ret == LDB_SUCCESS) {
5050 talloc_free(tmp_ctx);
5055 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5056 talloc_free(tmp_ctx);
5057 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5058 ldb_dn_get_linearized(ar->search_msg->dn),
5059 ldb_dn_get_linearized(msg->dn),
5060 ldb_errstring(ldb_module_get_ctx(ar->module)));
5064 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5065 if (ret != LDB_SUCCESS) {
5066 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5067 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5068 ldb_errstring(ldb_module_get_ctx(ar->module)));
5069 return LDB_ERR_OPERATIONS_ERROR;
5072 * we have a conflict, and need to decide if we will keep the
5073 * new record or the old record
5076 conflict_dn = msg->dn;
5080 * We are on an RODC, or were a GC for this
5081 * partition, so we have to fail this until
5082 * someone who owns the partition sorts it
5085 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5086 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5087 " - We must fail the operation until a master for this partition resolves the conflict",
5088 ldb_dn_get_linearized(conflict_dn));
5093 * first we need the replPropertyMetaData attribute from the
5096 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5098 DSDB_FLAG_NEXT_MODULE |
5099 DSDB_SEARCH_SHOW_DELETED |
5100 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5101 if (ret != LDB_SUCCESS) {
5102 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5103 ldb_dn_get_linearized(conflict_dn)));
5107 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5108 if (omd_value == NULL) {
5109 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5110 ldb_dn_get_linearized(conflict_dn)));
5114 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5115 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5116 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5117 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5118 ldb_dn_get_linearized(conflict_dn)));
5122 rmd = ar->objs->objects[ar->index_current].meta_data;
5125 * we decide which is newer based on the RPMD on the name
5126 * attribute. See [MS-DRSR] ResolveNameConflict.
5128 * We expect omd_name to be present, as this is from a local
5129 * search, but while rmd_name should have been given to us by
5130 * the remote server, if it is missing we just prefer the
5132 * replmd_replPropertyMetaData1_new_should_be_taken()
5134 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5135 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5137 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5138 ldb_dn_get_linearized(conflict_dn)));
5143 * Should we preserve the current record, and so rename the
5144 * incoming record to be a conflict?
5146 rename_incoming_record =
5147 !replmd_replPropertyMetaData1_new_should_be_taken(
5148 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5149 omd_name, rmd_name);
5151 if (rename_incoming_record) {
5153 new_dn = replmd_conflict_dn(msg, msg->dn,
5154 &ar->objs->objects[ar->index_current].object_guid);
5155 if (new_dn == NULL) {
5156 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5157 "Failed to form conflict DN for %s\n",
5158 ldb_dn_get_linearized(msg->dn));
5160 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5163 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5164 DSDB_FLAG_NEXT_MODULE, ar->req);
5165 if (ret != LDB_SUCCESS) {
5166 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5167 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5168 ldb_dn_get_linearized(conflict_dn),
5169 ldb_dn_get_linearized(ar->search_msg->dn),
5170 ldb_dn_get_linearized(new_dn),
5171 ldb_errstring(ldb_module_get_ctx(ar->module)));
5172 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5180 /* we are renaming the existing record */
5182 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5183 if (GUID_all_zero(&guid)) {
5184 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5185 ldb_dn_get_linearized(conflict_dn)));
5189 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5190 if (new_dn == NULL) {
5191 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5192 ldb_dn_get_linearized(conflict_dn)));
5196 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5197 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5199 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5200 DSDB_FLAG_OWN_MODULE, ar->req);
5201 if (ret != LDB_SUCCESS) {
5202 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5203 ldb_dn_get_linearized(conflict_dn),
5204 ldb_dn_get_linearized(new_dn),
5205 ldb_errstring(ldb_module_get_ctx(ar->module))));
5210 * now we need to ensure that the rename is seen as an
5211 * originating update. We do that with a modify.
5213 ret = replmd_name_modify(ar, ar->req, new_dn);
5214 if (ret != LDB_SUCCESS) {
5218 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5219 ldb_dn_get_linearized(ar->search_msg->dn),
5220 ldb_dn_get_linearized(msg->dn)));
5223 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5224 DSDB_FLAG_NEXT_MODULE, ar->req);
5225 if (ret != LDB_SUCCESS) {
5226 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5227 ldb_dn_get_linearized(ar->search_msg->dn),
5228 ldb_dn_get_linearized(msg->dn),
5229 ldb_errstring(ldb_module_get_ctx(ar->module))));
5235 * On failure make the caller get the error
5236 * This means replication will stop with an error,
5237 * but there is not much else we can do. In the
5238 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5242 talloc_free(tmp_ctx);
5247 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5249 struct ldb_context *ldb;
5250 struct ldb_request *change_req;
5251 enum ndr_err_code ndr_err;
5252 struct ldb_message *msg;
5253 struct replPropertyMetaDataBlob *rmd;
5254 struct replPropertyMetaDataBlob omd;
5255 const struct ldb_val *omd_value;
5256 struct replPropertyMetaDataBlob nmd;
5257 struct ldb_val nmd_value;
5258 struct GUID remote_parent_guid;
5261 unsigned int removed_attrs = 0;
5263 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5264 bool isDeleted = false;
5265 bool local_isDeleted = false;
5266 bool remote_isDeleted = false;
5267 bool take_remote_isDeleted = false;
5268 bool sd_updated = false;
5269 bool renamed = false;
5270 bool is_schema_nc = false;
5272 const struct ldb_val *old_rdn, *new_rdn;
5273 struct replmd_private *replmd_private =
5274 talloc_get_type(ldb_module_get_private(ar->module),
5275 struct replmd_private);
5277 time_t t = time(NULL);
5278 unix_to_nt_time(&now, t);
5280 ldb = ldb_module_get_ctx(ar->module);
5281 msg = ar->objs->objects[ar->index_current].msg;
5283 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5285 rmd = ar->objs->objects[ar->index_current].meta_data;
5289 /* find existing meta data */
5290 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5292 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5293 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5294 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5295 nt_status = ndr_map_error2ntstatus(ndr_err);
5296 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5299 if (omd.version != 1) {
5300 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5305 struct GUID_txt_buf guid_txt;
5307 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5308 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
5311 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5313 ndr_print_struct_string(s,
5314 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5315 "existing replPropertyMetaData",
5317 ndr_print_struct_string(s,
5318 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5319 "incoming replPropertyMetaData",
5324 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5325 "isDeleted", false);
5326 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5327 "isDeleted", false);
5330 * Fill in the remote_parent_guid with the GUID or an all-zero
5333 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5334 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5336 remote_parent_guid = GUID_zero();
5340 * To ensure we follow a complex rename chain around, we have
5341 * to confirm that the DN is the same (mostly to confirm the
5342 * RDN) and the parentGUID is the same.
5344 * This ensures we keep things under the correct parent, which
5345 * replmd_replicated_handle_rename() will do.
5348 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5349 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5353 * handle renames, even just by case that come in over
5354 * DRS. Changes in the parent DN don't hit us here,
5355 * because the search for a parent will clean up those
5358 * We also have already filtered out the case where
5359 * the peer has an older name to what we have (see
5360 * replmd_replicated_apply_search_callback())
5362 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5365 if (ret != LDB_SUCCESS) {
5366 ldb_debug(ldb, LDB_DEBUG_FATAL,
5367 "replmd_replicated_request rename %s => %s failed - %s\n",
5368 ldb_dn_get_linearized(ar->search_msg->dn),
5369 ldb_dn_get_linearized(msg->dn),
5370 ldb_errstring(ldb));
5371 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5374 if (renamed == true) {
5376 * Set the callback to one that will fix up the name
5377 * metadata on the new conflict DN
5379 callback = replmd_op_name_modify_callback;
5384 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5385 nmd.ctr.ctr1.array = talloc_array(ar,
5386 struct replPropertyMetaData1,
5387 nmd.ctr.ctr1.count);
5388 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5390 /* first copy the old meta data */
5391 for (i=0; i < omd.ctr.ctr1.count; i++) {
5392 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5397 /* now merge in the new meta data */
5398 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5401 for (j=0; j < ni; j++) {
5404 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5408 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5409 ar->objs->dsdb_repl_flags,
5410 &nmd.ctr.ctr1.array[j],
5411 &rmd->ctr.ctr1.array[i]);
5413 /* replace the entry */
5414 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5415 if (ar->seq_num == 0) {
5416 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5417 if (ret != LDB_SUCCESS) {
5418 return replmd_replicated_request_error(ar, ret);
5421 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5422 switch (nmd.ctr.ctr1.array[j].attid) {
5423 case DRSUAPI_ATTID_ntSecurityDescriptor:
5426 case DRSUAPI_ATTID_isDeleted:
5427 take_remote_isDeleted = true;
5436 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5437 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5438 msg->elements[i-removed_attrs].name,
5439 ldb_dn_get_linearized(msg->dn),
5440 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5443 /* we don't want to apply this change so remove the attribute */
5444 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5451 if (found) continue;
5453 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5454 if (ar->seq_num == 0) {
5455 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5456 if (ret != LDB_SUCCESS) {
5457 return replmd_replicated_request_error(ar, ret);
5460 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5461 switch (nmd.ctr.ctr1.array[ni].attid) {
5462 case DRSUAPI_ATTID_ntSecurityDescriptor:
5465 case DRSUAPI_ATTID_isDeleted:
5466 take_remote_isDeleted = true;
5475 * finally correct the size of the meta_data array
5477 nmd.ctr.ctr1.count = ni;
5479 new_rdn = ldb_dn_get_rdn_val(msg->dn);
5480 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5483 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5484 &nmd, ar, now, is_schema_nc);
5485 if (ret != LDB_SUCCESS) {
5486 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5487 return replmd_replicated_request_error(ar, ret);
5491 * sort the new meta data array
5493 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5494 if (ret != LDB_SUCCESS) {
5495 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5500 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
5503 * This also controls SD propagation below
5505 if (take_remote_isDeleted) {
5506 isDeleted = remote_isDeleted;
5508 isDeleted = local_isDeleted;
5511 ar->isDeleted = isDeleted;
5514 * check if some replicated attributes left, otherwise skip the ldb_modify() call
5516 if (msg->num_elements == 0) {
5517 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5520 return replmd_replicated_apply_isDeleted(ar);
5523 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5524 ar->index_current, msg->num_elements);
5530 if (sd_updated && !isDeleted) {
5531 ret = dsdb_module_schedule_sd_propagation(ar->module,
5532 ar->objs->partition_dn,
5534 if (ret != LDB_SUCCESS) {
5535 return ldb_operr(ldb);
5539 /* create the meta data value */
5540 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5541 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5542 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5543 nt_status = ndr_map_error2ntstatus(ndr_err);
5544 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5548 * when we know that we'll modify the record, add the whenChanged, uSNChanged
5549 * and replPopertyMetaData attributes
5551 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5552 if (ret != LDB_SUCCESS) {
5553 return replmd_replicated_request_error(ar, ret);
5555 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5556 if (ret != LDB_SUCCESS) {
5557 return replmd_replicated_request_error(ar, ret);
5559 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5560 if (ret != LDB_SUCCESS) {
5561 return replmd_replicated_request_error(ar, ret);
5564 replmd_ldb_message_sort(msg, ar->schema);
5566 /* we want to replace the old values */
5567 for (i=0; i < msg->num_elements; i++) {
5568 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5569 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5570 if (msg->elements[i].num_values == 0) {
5571 ldb_asprintf_errstring(ldb, __location__
5572 ": objectClass removed on %s, aborting replication\n",
5573 ldb_dn_get_linearized(msg->dn));
5574 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5580 struct GUID_txt_buf guid_txt;
5582 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5583 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5584 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5589 ret = ldb_build_mod_req(&change_req,
5597 LDB_REQ_SET_LOCATION(change_req);
5598 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5600 /* current partition control needed by "repmd_op_callback" */
5601 ret = ldb_request_add_control(change_req,
5602 DSDB_CONTROL_CURRENT_PARTITION_OID,
5604 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5606 return ldb_next_request(ar->module, change_req);
5609 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5610 struct ldb_reply *ares)
5612 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5613 struct replmd_replicated_request);
5617 return ldb_module_done(ar->req, NULL, NULL,
5618 LDB_ERR_OPERATIONS_ERROR);
5620 if (ares->error != LDB_SUCCESS &&
5621 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5622 return ldb_module_done(ar->req, ares->controls,
5623 ares->response, ares->error);
5626 switch (ares->type) {
5627 case LDB_REPLY_ENTRY:
5628 ar->search_msg = talloc_steal(ar, ares->message);
5631 case LDB_REPLY_REFERRAL:
5632 /* we ignore referrals */
5635 case LDB_REPLY_DONE:
5637 struct replPropertyMetaData1 *md_remote;
5638 struct replPropertyMetaData1 *md_local;
5640 struct replPropertyMetaDataBlob omd;
5641 const struct ldb_val *omd_value;
5642 struct replPropertyMetaDataBlob *rmd;
5643 struct ldb_message *msg;
5645 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5646 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5649 * This is the ADD case, find the appropriate parent,
5650 * as this object doesn't exist locally:
5652 if (ar->search_msg == NULL) {
5653 ret = replmd_replicated_apply_search_for_parent(ar);
5654 if (ret != LDB_SUCCESS) {
5655 return ldb_module_done(ar->req, NULL, NULL, ret);
5662 * Otherwise, in the MERGE case, work out if we are
5663 * attempting a rename, and if so find the parent the
5664 * newly renamed object wants to belong under (which
5665 * may not be the parent in it's attached string DN
5667 rmd = ar->objs->objects[ar->index_current].meta_data;
5671 /* find existing meta data */
5672 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5674 enum ndr_err_code ndr_err;
5675 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5676 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5677 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5678 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5679 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5682 if (omd.version != 1) {
5683 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5687 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5689 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5690 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5691 && GUID_all_zero(&ar->local_parent_guid)) {
5692 DEBUG(0, ("Refusing to replicate new version of %s "
5693 "as local object has an all-zero parentGUID attribute, "
5694 "despite not being an NC root\n",
5695 ldb_dn_get_linearized(ar->search_msg->dn)));
5696 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5700 * now we need to check for double renames. We could have a
5701 * local rename pending which our replication partner hasn't
5702 * received yet. We choose which one wins by looking at the
5703 * attribute stamps on the two objects, the newer one wins.
5705 * This also simply applies the correct algorithms for
5706 * determining if a change was made to name at all, or
5707 * if the object has just been renamed under the same
5710 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5711 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5713 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5714 ldb_dn_get_linearized(ar->search_msg->dn)));
5715 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5719 * if there is no name attribute given then we have to assume the
5720 * object we've received has the older name
5722 if (replmd_replPropertyMetaData1_new_should_be_taken(
5723 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5724 md_local, md_remote)) {
5725 struct GUID_txt_buf p_guid_local;
5726 struct GUID_txt_buf p_guid_remote;
5727 msg = ar->objs->objects[ar->index_current].msg;
5729 /* Merge on the existing object, with rename */
5731 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5732 "as incoming object changing to %s under %s\n",
5733 ldb_dn_get_linearized(ar->search_msg->dn),
5734 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5735 ldb_dn_get_linearized(msg->dn),
5736 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5738 ret = replmd_replicated_apply_search_for_parent(ar);
5740 struct GUID_txt_buf p_guid_local;
5741 struct GUID_txt_buf p_guid_remote;
5742 msg = ar->objs->objects[ar->index_current].msg;
5745 * Merge on the existing object, force no
5746 * rename (code below just to explain why in
5750 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5751 ldb_dn_get_linearized(msg->dn)) == 0) {
5752 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5753 GUID_equal(&ar->local_parent_guid,
5754 ar->objs->objects[ar->index_current].parent_guid)
5756 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5757 "despite incoming object changing parent to %s\n",
5758 ldb_dn_get_linearized(ar->search_msg->dn),
5759 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5760 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5764 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5765 " and rejecting older rename to %s under %s\n",
5766 ldb_dn_get_linearized(ar->search_msg->dn),
5767 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5768 ldb_dn_get_linearized(msg->dn),
5769 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5773 * This assignment ensures that the strcmp()
5774 * and GUID_equal() calls in
5775 * replmd_replicated_apply_merge() avoids the
5778 ar->objs->objects[ar->index_current].parent_guid =
5779 &ar->local_parent_guid;
5781 msg->dn = ar->search_msg->dn;
5782 ret = replmd_replicated_apply_merge(ar);
5784 if (ret != LDB_SUCCESS) {
5785 return ldb_module_done(ar->req, NULL, NULL, ret);
5794 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
5796 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
5798 struct ldb_context *ldb;
5802 struct ldb_request *search_req;
5803 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
5804 "parentGUID", "instanceType",
5805 "replPropertyMetaData", "nTSecurityDescriptor",
5806 "isDeleted", NULL };
5807 struct GUID_txt_buf guid_str_buf;
5809 if (ar->index_current >= ar->objs->num_objects) {
5810 /* done with it, go to next stage */
5811 return replmd_replicated_uptodate_vector(ar);
5814 ldb = ldb_module_get_ctx(ar->module);
5815 ar->search_msg = NULL;
5816 ar->isDeleted = false;
5818 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5821 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5822 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5824 ret = ldb_build_search_req(&search_req,
5827 ar->objs->partition_dn,
5833 replmd_replicated_apply_search_callback,
5835 LDB_REQ_SET_LOCATION(search_req);
5837 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
5839 if (ret != LDB_SUCCESS) {
5843 return ldb_next_request(ar->module, search_req);
5847 * This is essentially a wrapper for replmd_replicated_apply_next()
5849 * This is needed to ensure that both codepaths call this handler.
5851 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
5853 struct ldb_dn *deleted_objects_dn;
5854 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5855 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
5856 &deleted_objects_dn);
5857 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
5859 * Do a delete here again, so that if there is
5860 * anything local that conflicts with this
5861 * object being deleted, it is removed. This
5862 * includes links. See MS-DRSR 4.1.10.6.9
5865 * If the object is already deleted, and there
5866 * is no more work required, it doesn't do
5870 /* This has been updated to point to the DN we eventually did the modify on */
5872 struct ldb_request *del_req;
5873 struct ldb_result *res;
5875 TALLOC_CTX *tmp_ctx = talloc_new(ar);
5877 ret = ldb_oom(ldb_module_get_ctx(ar->module));
5881 res = talloc_zero(tmp_ctx, struct ldb_result);
5883 ret = ldb_oom(ldb_module_get_ctx(ar->module));
5884 talloc_free(tmp_ctx);
5888 /* Build a delete request, which hopefully will artually turn into nothing */
5889 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
5893 ldb_modify_default_callback,
5895 LDB_REQ_SET_LOCATION(del_req);
5896 if (ret != LDB_SUCCESS) {
5897 talloc_free(tmp_ctx);
5902 * This is the guts of the call, call back
5903 * into our delete code, but setting the
5904 * re_delete flag so we delete anything that
5905 * shouldn't be there on a deleted or recycled
5908 ret = replmd_delete_internals(ar->module, del_req, true);
5909 if (ret == LDB_SUCCESS) {
5910 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
5913 talloc_free(tmp_ctx);
5914 if (ret != LDB_SUCCESS) {
5919 ar->index_current++;
5920 return replmd_replicated_apply_next(ar);
5923 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
5924 struct ldb_reply *ares)
5926 struct ldb_context *ldb;
5927 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5928 struct replmd_replicated_request);
5929 ldb = ldb_module_get_ctx(ar->module);
5932 return ldb_module_done(ar->req, NULL, NULL,
5933 LDB_ERR_OPERATIONS_ERROR);
5935 if (ares->error != LDB_SUCCESS) {
5936 return ldb_module_done(ar->req, ares->controls,
5937 ares->response, ares->error);
5940 if (ares->type != LDB_REPLY_DONE) {
5941 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
5942 return ldb_module_done(ar->req, NULL, NULL,
5943 LDB_ERR_OPERATIONS_ERROR);
5948 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5951 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
5953 struct ldb_context *ldb;
5954 struct ldb_request *change_req;
5955 enum ndr_err_code ndr_err;
5956 struct ldb_message *msg;
5957 struct replUpToDateVectorBlob ouv;
5958 const struct ldb_val *ouv_value;
5959 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
5960 struct replUpToDateVectorBlob nuv;
5961 struct ldb_val nuv_value;
5962 struct ldb_message_element *nuv_el = NULL;
5963 struct ldb_message_element *orf_el = NULL;
5964 struct repsFromToBlob nrf;
5965 struct ldb_val *nrf_value = NULL;
5966 struct ldb_message_element *nrf_el = NULL;
5970 time_t t = time(NULL);
5973 uint32_t instanceType;
5975 ldb = ldb_module_get_ctx(ar->module);
5976 ruv = ar->objs->uptodateness_vector;
5982 unix_to_nt_time(&now, t);
5984 if (ar->search_msg == NULL) {
5985 /* this happens for a REPL_OBJ call where we are
5986 creating the target object by replicating it. The
5987 subdomain join code does this for the partition DN
5989 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
5990 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5993 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
5994 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
5995 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
5996 ldb_dn_get_linearized(ar->search_msg->dn)));
5997 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6001 * first create the new replUpToDateVector
6003 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6005 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6006 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6007 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6008 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6009 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6012 if (ouv.version != 2) {
6013 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6018 * the new uptodateness vector will at least
6019 * contain 1 entry, one for the source_dsa
6021 * plus optional values from our old vector and the one from the source_dsa
6023 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6024 if (ruv) nuv.ctr.ctr2.count += ruv->count;
6025 nuv.ctr.ctr2.cursors = talloc_array(ar,
6026 struct drsuapi_DsReplicaCursor2,
6027 nuv.ctr.ctr2.count);
6028 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6030 /* first copy the old vector */
6031 for (i=0; i < ouv.ctr.ctr2.count; i++) {
6032 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6036 /* merge in the source_dsa vector is available */
6037 for (i=0; (ruv && i < ruv->count); i++) {
6040 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6041 &ar->our_invocation_id)) {
6045 for (j=0; j < ni; j++) {
6046 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6047 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6053 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6054 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6059 if (found) continue;
6061 /* if it's not there yet, add it */
6062 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6067 * finally correct the size of the cursors array
6069 nuv.ctr.ctr2.count = ni;
6074 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6077 * create the change ldb_message
6079 msg = ldb_msg_new(ar);
6080 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6081 msg->dn = ar->search_msg->dn;
6083 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6084 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6085 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6086 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6087 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6089 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6090 if (ret != LDB_SUCCESS) {
6091 return replmd_replicated_request_error(ar, ret);
6093 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6096 * now create the new repsFrom value from the given repsFromTo1 structure
6100 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6101 nrf.ctr.ctr1.last_attempt = now;
6102 nrf.ctr.ctr1.last_success = now;
6103 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6106 * first see if we already have a repsFrom value for the current source dsa
6107 * if so we'll later replace this value
6109 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6111 for (i=0; i < orf_el->num_values; i++) {
6112 struct repsFromToBlob *trf;
6114 trf = talloc(ar, struct repsFromToBlob);
6115 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6117 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6118 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6119 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6120 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6121 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6124 if (trf->version != 1) {
6125 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6129 * we compare the source dsa objectGUID not the invocation_id
6130 * because we want only one repsFrom value per source dsa
6131 * and when the invocation_id of the source dsa has changed we don't need
6132 * the old repsFrom with the old invocation_id
6134 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6135 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6141 nrf_value = &orf_el->values[i];
6146 * copy over all old values to the new ldb_message
6148 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6149 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6154 * if we haven't found an old repsFrom value for the current source dsa
6155 * we'll add a new value
6158 struct ldb_val zero_value;
6159 ZERO_STRUCT(zero_value);
6160 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6161 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6163 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6166 /* we now fill the value which is already attached to ldb_message */
6167 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6169 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6170 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6171 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6172 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6176 * the ldb_message_element for the attribute, has all the old values and the new one
6177 * so we'll replace the whole attribute with all values
6179 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6181 if (CHECK_DEBUGLVL(4)) {
6182 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
6183 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6187 /* prepare the ldb_modify() request */
6188 ret = ldb_build_mod_req(&change_req,
6194 replmd_replicated_uptodate_modify_callback,
6196 LDB_REQ_SET_LOCATION(change_req);
6197 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6199 return ldb_next_request(ar->module, change_req);
6202 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6203 struct ldb_reply *ares)
6205 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6206 struct replmd_replicated_request);
6210 return ldb_module_done(ar->req, NULL, NULL,
6211 LDB_ERR_OPERATIONS_ERROR);
6213 if (ares->error != LDB_SUCCESS &&
6214 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6215 return ldb_module_done(ar->req, ares->controls,
6216 ares->response, ares->error);
6219 switch (ares->type) {
6220 case LDB_REPLY_ENTRY:
6221 ar->search_msg = talloc_steal(ar, ares->message);
6224 case LDB_REPLY_REFERRAL:
6225 /* we ignore referrals */
6228 case LDB_REPLY_DONE:
6229 ret = replmd_replicated_uptodate_modify(ar);
6230 if (ret != LDB_SUCCESS) {
6231 return ldb_module_done(ar->req, NULL, NULL, ret);
6240 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6242 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6243 struct replmd_private *replmd_private =
6244 talloc_get_type_abort(ldb_module_get_private(ar->module),
6245 struct replmd_private);
6247 static const char *attrs[] = {
6248 "replUpToDateVector",
6253 struct ldb_request *search_req;
6255 ar->search_msg = NULL;
6258 * Let the caller know that we did an originating updates
6260 ar->objs->originating_updates = replmd_private->originating_updates;
6262 ret = ldb_build_search_req(&search_req,
6265 ar->objs->partition_dn,
6271 replmd_replicated_uptodate_search_callback,
6273 LDB_REQ_SET_LOCATION(search_req);
6274 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6276 return ldb_next_request(ar->module, search_req);
6281 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6283 struct ldb_context *ldb;
6284 struct dsdb_extended_replicated_objects *objs;
6285 struct replmd_replicated_request *ar;
6286 struct ldb_control **ctrls;
6289 struct replmd_private *replmd_private =
6290 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6292 ldb = ldb_module_get_ctx(module);
6294 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6296 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6298 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6299 return LDB_ERR_PROTOCOL_ERROR;
6302 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6303 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6304 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6305 return LDB_ERR_PROTOCOL_ERROR;
6308 ar = replmd_ctx_init(module, req);
6310 return LDB_ERR_OPERATIONS_ERROR;
6312 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6313 ar->apply_mode = true;
6315 ar->schema = dsdb_get_schema(ldb, ar);
6317 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6319 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6320 return LDB_ERR_CONSTRAINT_VIOLATION;
6323 ctrls = req->controls;
6325 if (req->controls) {
6326 req->controls = talloc_memdup(ar, req->controls,
6327 talloc_get_size(req->controls));
6328 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6331 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6332 if (ret != LDB_SUCCESS) {
6336 /* If this change contained linked attributes in the body
6337 * (rather than in the links section) we need to update
6338 * backlinks in linked_attributes */
6339 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6340 if (ret != LDB_SUCCESS) {
6344 ar->controls = req->controls;
6345 req->controls = ctrls;
6347 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
6349 /* save away the linked attributes for the end of the
6351 for (i=0; i<ar->objs->linked_attributes_count; i++) {
6352 struct la_entry *la_entry;
6354 if (replmd_private->la_ctx == NULL) {
6355 replmd_private->la_ctx = talloc_new(replmd_private);
6357 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6358 if (la_entry == NULL) {
6360 return LDB_ERR_OPERATIONS_ERROR;
6362 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6363 if (la_entry->la == NULL) {
6364 talloc_free(la_entry);
6366 return LDB_ERR_OPERATIONS_ERROR;
6368 *la_entry->la = ar->objs->linked_attributes[i];
6370 /* we need to steal the non-scalars so they stay
6371 around until the end of the transaction */
6372 talloc_steal(la_entry->la, la_entry->la->identifier);
6373 talloc_steal(la_entry->la, la_entry->la->value.blob);
6375 DLIST_ADD(replmd_private->la_list, la_entry);
6378 return replmd_replicated_apply_next(ar);
6382 process one linked attribute structure
6384 static int replmd_process_linked_attribute(struct ldb_module *module,
6385 struct replmd_private *replmd_private,
6386 struct la_entry *la_entry,
6387 struct ldb_request *parent)
6389 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6390 struct ldb_context *ldb = ldb_module_get_ctx(module);
6391 struct ldb_message *msg;
6392 struct ldb_message *target_msg = NULL;
6393 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6394 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
6396 const struct dsdb_attribute *attr;
6397 struct dsdb_dn *dsdb_dn;
6398 uint64_t seq_num = 0;
6399 struct ldb_message_element *old_el;
6401 time_t t = time(NULL);
6402 struct ldb_result *res;
6403 struct ldb_result *target_res;
6404 const char *attrs[4];
6405 const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
6406 struct parsed_dn *pdn_list, *pdn, *next;
6407 struct GUID guid = GUID_zero();
6409 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
6410 const struct GUID *our_invocation_id;
6412 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
6413 enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
6416 linked_attributes[0]:
6417 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6419 identifier: struct drsuapi_DsReplicaObjectIdentifier
6420 __ndr_size : 0x0000003a (58)
6421 __ndr_size_sid : 0x00000000 (0)
6422 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6424 __ndr_size_dn : 0x00000000 (0)
6426 attid : DRSUAPI_ATTID_member (0x1F)
6427 value: struct drsuapi_DsAttributeValue
6428 __ndr_size : 0x0000007e (126)
6430 blob : DATA_BLOB length=126
6431 flags : 0x00000001 (1)
6432 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6433 originating_add_time : Wed Sep 2 22:20:01 2009 EST
6434 meta_data: struct drsuapi_DsReplicaMetaData
6435 version : 0x00000015 (21)
6436 originating_change_time : Wed Sep 2 23:39:07 2009 EST
6437 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6438 originating_usn : 0x000000000001e19c (123292)
6440 (for cases where the link is to a normal DN)
6441 &target: struct drsuapi_DsReplicaObjectIdentifier3
6442 __ndr_size : 0x0000007e (126)
6443 __ndr_size_sid : 0x0000001c (28)
6444 guid : 7639e594-db75-4086-b0d4-67890ae46031
6445 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
6446 __ndr_size_dn : 0x00000022 (34)
6447 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
6450 /* find the attribute being modified */
6451 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
6453 struct GUID_txt_buf guid_str;
6454 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
6456 GUID_buf_string(&la->identifier->guid,
6458 talloc_free(tmp_ctx);
6459 return LDB_ERR_OPERATIONS_ERROR;
6462 attrs[0] = attr->lDAPDisplayName;
6463 attrs[1] = "isDeleted";
6464 attrs[2] = "isRecycled";
6467 /* get the existing message from the db for the object with
6468 this GUID, returning attribute being modified. We will then
6469 use this msg as the basis for a modify call */
6470 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
6471 DSDB_FLAG_NEXT_MODULE |
6472 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6473 DSDB_SEARCH_SHOW_RECYCLED |
6474 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
6475 DSDB_SEARCH_REVEAL_INTERNALS,
6477 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
6478 if (ret != LDB_SUCCESS) {
6479 talloc_free(tmp_ctx);
6482 if (res->count != 1) {
6483 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
6484 GUID_string(tmp_ctx, &la->identifier->guid));
6485 talloc_free(tmp_ctx);
6486 return LDB_ERR_NO_SUCH_OBJECT;
6491 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6492 * ProcessLinkValue, because link updates are not applied to
6493 * recycled and tombstone objects. We don't have to delete
6494 * any existing link, that should have happened when the
6495 * object deletion was replicated or initiated.
6498 replmd_deletion_state(module, msg, &deletion_state, NULL);
6500 if (deletion_state >= OBJECT_RECYCLED) {
6501 talloc_free(tmp_ctx);
6505 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6506 if (old_el == NULL) {
6507 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
6508 if (ret != LDB_SUCCESS) {
6509 ldb_module_oom(module);
6510 talloc_free(tmp_ctx);
6511 return LDB_ERR_OPERATIONS_ERROR;
6514 old_el->flags = LDB_FLAG_MOD_REPLACE;
6517 /* parse the existing links */
6518 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
6519 if (ret != LDB_SUCCESS) {
6520 talloc_free(tmp_ctx);
6524 /* get our invocationId */
6525 our_invocation_id = samdb_ntds_invocation_id(ldb);
6526 if (!our_invocation_id) {
6527 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
6528 talloc_free(tmp_ctx);
6529 return LDB_ERR_OPERATIONS_ERROR;
6532 ret = replmd_check_upgrade_links(ldb, pdn_list, old_el->num_values,
6533 old_el, our_invocation_id,
6534 attr->syntax->ldap_oid);
6535 if (ret != LDB_SUCCESS) {
6536 talloc_free(tmp_ctx);
6540 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
6541 if (!W_ERROR_IS_OK(status)) {
6542 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
6543 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
6544 talloc_free(tmp_ctx);
6545 return LDB_ERR_OPERATIONS_ERROR;
6548 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
6549 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6551 * This strange behaviour (allowing a NULL/missing
6552 * GUID) originally comes from:
6554 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6555 * Author: Andrew Tridgell <tridge@samba.org>
6556 * Date: Mon Dec 21 21:21:55 2009 +1100
6558 * s4-drs: cope better with NULL GUIDS from DRS
6560 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
6561 * need to match by DN if possible when seeing if we should update an
6564 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6567 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6568 dsdb_dn->dn, attrs2,
6569 DSDB_FLAG_NEXT_MODULE |
6570 DSDB_SEARCH_SHOW_RECYCLED |
6571 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6572 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6574 } else if (!NT_STATUS_IS_OK(ntstatus)) {
6575 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
6577 ldb_dn_get_linearized(dsdb_dn->dn),
6578 ldb_dn_get_linearized(msg->dn));
6579 talloc_free(tmp_ctx);
6580 return LDB_ERR_OPERATIONS_ERROR;
6582 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6583 NULL, LDB_SCOPE_SUBTREE,
6585 DSDB_FLAG_NEXT_MODULE |
6586 DSDB_SEARCH_SHOW_RECYCLED |
6587 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6588 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6591 GUID_string(tmp_ctx, &guid));
6594 if (ret != LDB_SUCCESS) {
6595 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6596 GUID_string(tmp_ctx, &guid),
6597 ldb_errstring(ldb_module_get_ctx(module)));
6598 talloc_free(tmp_ctx);
6602 if (target_res->count == 0) {
6603 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6604 GUID_string(tmp_ctx, &guid),
6605 ldb_dn_get_linearized(dsdb_dn->dn)));
6606 } else if (target_res->count != 1) {
6607 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6608 GUID_string(tmp_ctx, &guid));
6609 talloc_free(tmp_ctx);
6610 return LDB_ERR_OPERATIONS_ERROR;
6612 target_msg = target_res->msgs[0];
6613 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6617 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6618 * ProcessLinkValue, because link updates are not applied to
6619 * recycled and tombstone objects. We don't have to delete
6620 * any existing link, that should have happened when the
6621 * object deletion was replicated or initiated.
6623 replmd_deletion_state(module, target_msg,
6624 &target_deletion_state, NULL);
6626 if (target_deletion_state >= OBJECT_RECYCLED) {
6627 talloc_free(tmp_ctx);
6631 /* see if this link already exists */
6632 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
6636 attr->syntax->ldap_oid);
6637 if (ret != LDB_SUCCESS) {
6638 talloc_free(tmp_ctx);
6644 /* see if this update is newer than what we have already */
6645 struct GUID invocation_id = GUID_zero();
6646 uint32_t version = 0;
6647 uint32_t originating_usn = 0;
6648 NTTIME change_time = 0;
6649 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6651 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6652 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6653 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6654 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6656 if (!replmd_update_is_newer(&invocation_id,
6657 &la->meta_data.originating_invocation_id,
6659 la->meta_data.version,
6661 la->meta_data.originating_change_time)) {
6662 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6663 old_el->name, ldb_dn_get_linearized(msg->dn),
6664 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6665 talloc_free(tmp_ctx);
6669 /* get a seq_num for this change */
6670 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6671 if (ret != LDB_SUCCESS) {
6672 talloc_free(tmp_ctx);
6676 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6677 /* remove the existing backlink */
6678 ret = replmd_add_backlink(module, replmd_private,
6679 schema, &la->identifier->guid,
6680 &guid, false, attr, true);
6681 if (ret != LDB_SUCCESS) {
6682 talloc_free(tmp_ctx);
6687 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6688 &la->meta_data.originating_invocation_id,
6689 la->meta_data.originating_usn, seq_num,
6690 la->meta_data.originating_change_time,
6691 la->meta_data.version,
6693 if (ret != LDB_SUCCESS) {
6694 talloc_free(tmp_ctx);
6699 /* add the new backlink */
6700 ret = replmd_add_backlink(module, replmd_private,
6701 schema, &la->identifier->guid,
6702 &guid, true, attr, true);
6703 if (ret != LDB_SUCCESS) {
6704 talloc_free(tmp_ctx);
6709 /* get a seq_num for this change */
6710 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6711 if (ret != LDB_SUCCESS) {
6712 talloc_free(tmp_ctx);
6716 old_el->values = talloc_realloc(msg->elements, old_el->values,
6717 struct ldb_val, old_el->num_values+1);
6718 if (!old_el->values) {
6719 ldb_module_oom(module);
6720 return LDB_ERR_OPERATIONS_ERROR;
6722 old_el->num_values++;
6724 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
6725 &la->meta_data.originating_invocation_id,
6726 la->meta_data.originating_usn, seq_num,
6727 la->meta_data.originating_change_time,
6728 la->meta_data.version,
6730 if (ret != LDB_SUCCESS) {
6731 talloc_free(tmp_ctx);
6736 ret = replmd_add_backlink(module, replmd_private,
6737 schema, &la->identifier->guid,
6738 &guid, true, attr, true);
6739 if (ret != LDB_SUCCESS) {
6740 talloc_free(tmp_ctx);
6746 /* we only change whenChanged and uSNChanged if the seq_num
6748 ret = add_time_element(msg, "whenChanged", t);
6749 if (ret != LDB_SUCCESS) {
6750 talloc_free(tmp_ctx);
6755 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
6756 if (ret != LDB_SUCCESS) {
6757 talloc_free(tmp_ctx);
6762 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6763 if (old_el == NULL) {
6764 talloc_free(tmp_ctx);
6765 return ldb_operr(ldb);
6768 ret = dsdb_check_single_valued_link(attr, old_el);
6769 if (ret != LDB_SUCCESS) {
6770 talloc_free(tmp_ctx);
6774 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
6776 ret = linked_attr_modify(module, msg, parent);
6777 if (ret != LDB_SUCCESS) {
6778 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
6780 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
6781 talloc_free(tmp_ctx);
6785 talloc_free(tmp_ctx);
6790 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
6792 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
6793 return replmd_extended_replicated_objects(module, req);
6796 return ldb_next_request(module, req);
6801 we hook into the transaction operations to allow us to
6802 perform the linked attribute updates at the end of the whole
6803 transaction. This allows a forward linked attribute to be created
6804 before the object is created. During a vampire, w2k8 sends us linked
6805 attributes before the objects they are part of.
6807 static int replmd_start_transaction(struct ldb_module *module)
6809 /* create our private structure for this transaction */
6810 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
6811 struct replmd_private);
6812 replmd_txn_cleanup(replmd_private);
6814 /* free any leftover mod_usn records from cancelled
6816 while (replmd_private->ncs) {
6817 struct nc_entry *e = replmd_private->ncs;
6818 DLIST_REMOVE(replmd_private->ncs, e);
6822 replmd_private->originating_updates = false;
6824 return ldb_next_start_trans(module);
6828 on prepare commit we loop over our queued la_context structures and
6831 static int replmd_prepare_commit(struct ldb_module *module)
6833 struct replmd_private *replmd_private =
6834 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6835 struct la_entry *la, *prev;
6836 struct la_backlink *bl;
6839 /* walk the list backwards, to do the first entry first, as we
6840 * added the entries with DLIST_ADD() which puts them at the
6841 * start of the list */
6842 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
6843 prev = DLIST_PREV(la);
6844 DLIST_REMOVE(replmd_private->la_list, la);
6845 ret = replmd_process_linked_attribute(module, replmd_private,
6847 if (ret != LDB_SUCCESS) {
6848 replmd_txn_cleanup(replmd_private);
6853 /* process our backlink list, creating and deleting backlinks
6855 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
6856 ret = replmd_process_backlink(module, bl, NULL);
6857 if (ret != LDB_SUCCESS) {
6858 replmd_txn_cleanup(replmd_private);
6863 replmd_txn_cleanup(replmd_private);
6865 /* possibly change @REPLCHANGED */
6866 ret = replmd_notify_store(module, NULL);
6867 if (ret != LDB_SUCCESS) {
6871 return ldb_next_prepare_commit(module);
6874 static int replmd_del_transaction(struct ldb_module *module)
6876 struct replmd_private *replmd_private =
6877 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6878 replmd_txn_cleanup(replmd_private);
6880 return ldb_next_del_trans(module);
6884 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
6885 .name = "repl_meta_data",
6886 .init_context = replmd_init,
6888 .modify = replmd_modify,
6889 .rename = replmd_rename,
6890 .del = replmd_delete,
6891 .extended = replmd_extended,
6892 .start_transaction = replmd_start_transaction,
6893 .prepare_commit = replmd_prepare_commit,
6894 .del_transaction = replmd_del_transaction,
6897 int ldb_repl_meta_data_module_init(const char *version)
6899 LDB_MODULE_CHECK_VERSION(version);
6900 return ldb_register_module(&ldb_repl_meta_data_module_ops);