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;
1808 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1810 return GUID_compare(&pdn1->guid, &pdn2->guid);
1813 static int la_guid_compare_with_trusted_dn(struct compare_ctx *ctx,
1814 struct parsed_dn *p)
1817 * This works like a standard compare function in its return values,
1818 * but has an extra trick to deal with errors: zero is returned and
1819 * ctx->err is set to the ldb error code.
1821 * That is, if (as is expected in most cases) you get a non-zero
1822 * result, you don't need to check for errors.
1826 if (GUID_all_zero(&p->guid)) {
1828 status = dsdb_get_extended_dn_guid(p->dsdb_dn->dn, &p->guid, "GUID");
1829 if (!NT_STATUS_IS_OK(status)) {
1830 ctx->err = LDB_ERR_OPERATIONS_ERROR;
1835 return GUID_compare(ctx->guid, &p->guid);
1840 static int parsed_dn_find(struct ldb_context *ldb, struct parsed_dn *pdn,
1843 struct ldb_dn *target_dn,
1844 struct parsed_dn **exact,
1845 struct parsed_dn **next,
1846 const char *ldap_oid)
1849 struct compare_ctx ctx;
1856 if (unlikely(GUID_all_zero(guid))) {
1858 * When updating a link using DRS, we sometimes get a NULL
1859 * GUID when a forward link has been deleted and its GUID has
1860 * for some reason been forgotten. The best we can do is try
1861 * and match by DN via a linear search. Note that this
1862 * probably only happens in the ADD case, in which we only
1863 * allow modification of link if it is already deleted, so
1864 * this seems very close to an elaborate NO-OP, but we are not
1865 * quite prepared to declare it so.
1867 * If the DN is not in our list, we have to add it to the
1868 * beginning of the list, where it would naturally sort.
1870 struct parsed_dn *p;
1871 if (target_dn == NULL) {
1872 /* We don't know the target DN, so we can't search for DN */
1873 DEBUG(1, ("parsed_dn_find has a NULL GUID for a linked "
1874 "attribute but we don't have a DN to compare "
1876 return LDB_ERR_OPERATIONS_ERROR;
1881 DEBUG(3, ("parsed_dn_find has a NULL GUID for a link to DN "
1882 "%s; searching through links for it",
1883 ldb_dn_get_linearized(target_dn)));
1885 for (i = 0; i < count; i++) {
1888 cmp = ldb_dn_compare(p->dsdb_dn->dn, target_dn);
1890 dsdb_get_extended_dn_guid(p->dsdb_dn->dn,
1897 * Here we have a null guid which doesn't match any existing
1898 * link. This is a bit unexpected because null guids occur
1899 * when a forward link has been deleted and we are replicating
1902 * The best thing to do is weep into the logs and add the
1903 * offending link to the beginning of the list which is
1904 * at least the correct sort position.
1906 DEBUG(1, ("parsed_dn_find has been given a NULL GUID for a "
1907 "link to unknown DN %s\n",
1908 ldb_dn_get_linearized(target_dn)));
1916 ctx.ldap_oid = ldap_oid;
1919 BINARY_ARRAY_SEARCH_GTE(pdn, count, &ctx, la_guid_compare_with_trusted_dn,
1929 get a series of message element values as an array of DNs and GUIDs
1930 the result is sorted by GUID
1932 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1933 struct ldb_message_element *el, struct parsed_dn **pdn,
1934 const char *ldap_oid, struct ldb_request *parent)
1937 bool values_are_sorted = true;
1938 struct ldb_context *ldb = ldb_module_get_ctx(module);
1945 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1947 ldb_module_oom(module);
1948 return LDB_ERR_OPERATIONS_ERROR;
1951 for (i=0; i<el->num_values; i++) {
1952 struct ldb_val *v = &el->values[i];
1955 struct parsed_dn *p;
1959 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1960 if (p->dsdb_dn == NULL) {
1961 return LDB_ERR_INVALID_DN_SYNTAX;
1964 dn = p->dsdb_dn->dn;
1966 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
1967 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1968 /* we got a DN without a GUID - go find the GUID */
1969 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
1970 if (ret != LDB_SUCCESS) {
1971 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1972 ldb_dn_get_linearized(dn));
1973 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1974 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1975 ldb_attr_cmp(el->name, "member") == 0) {
1976 return LDB_ERR_UNWILLING_TO_PERFORM;
1980 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
1981 if (ret != LDB_SUCCESS) {
1984 } else if (!NT_STATUS_IS_OK(status)) {
1985 return LDB_ERR_OPERATIONS_ERROR;
1987 if (i > 0 && values_are_sorted) {
1988 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
1990 values_are_sorted = false;
1993 /* keep a pointer to the original ldb_val */
1996 if (! values_are_sorted) {
1997 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2003 build a new extended DN, including all meta data fields
2005 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2006 RMD_ADDTIME = originating_add_time
2007 RMD_INVOCID = originating_invocation_id
2008 RMD_CHANGETIME = originating_change_time
2009 RMD_ORIGINATING_USN = originating_usn
2010 RMD_LOCAL_USN = local_usn
2011 RMD_VERSION = version
2013 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2014 const struct GUID *invocation_id, uint64_t seq_num,
2015 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
2017 struct ldb_dn *dn = dsdb_dn->dn;
2018 const char *tstring, *usn_string, *flags_string;
2019 struct ldb_val tval;
2021 struct ldb_val usnv, local_usnv;
2022 struct ldb_val vers, flagsv;
2025 const char *dnstring;
2027 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2029 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2031 return LDB_ERR_OPERATIONS_ERROR;
2033 tval = data_blob_string_const(tstring);
2035 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
2037 return LDB_ERR_OPERATIONS_ERROR;
2039 usnv = data_blob_string_const(usn_string);
2041 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2043 return LDB_ERR_OPERATIONS_ERROR;
2045 local_usnv = data_blob_string_const(usn_string);
2047 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2049 return LDB_ERR_OPERATIONS_ERROR;
2051 vers = data_blob_string_const(vstring);
2053 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2054 if (!NT_STATUS_IS_OK(status)) {
2055 return LDB_ERR_OPERATIONS_ERROR;
2058 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2059 if (!flags_string) {
2060 return LDB_ERR_OPERATIONS_ERROR;
2062 flagsv = data_blob_string_const(flags_string);
2064 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2065 if (ret != LDB_SUCCESS) return ret;
2066 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
2067 if (ret != LDB_SUCCESS) return ret;
2068 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2069 if (ret != LDB_SUCCESS) return ret;
2070 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2071 if (ret != LDB_SUCCESS) return ret;
2072 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2073 if (ret != LDB_SUCCESS) return ret;
2074 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2075 if (ret != LDB_SUCCESS) return ret;
2076 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2077 if (ret != LDB_SUCCESS) return ret;
2079 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2080 if (dnstring == NULL) {
2081 return LDB_ERR_OPERATIONS_ERROR;
2083 *v = data_blob_string_const(dnstring);
2088 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2089 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2090 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2091 uint32_t version, bool deleted);
2094 check if any links need upgrading from w2k format
2096 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2097 struct parsed_dn *dns, uint32_t count,
2098 struct ldb_message_element *el,
2099 const struct GUID *invocation_id,
2100 const char *ldap_oid)
2103 for (i=0; i<count; i++) {
2107 if (dns[i].dsdb_dn == NULL) {
2108 dns[i].dsdb_dn = dsdb_dn_parse(dns, ldb, dns[i].v,
2110 if (dns[i].dsdb_dn == NULL) {
2111 return LDB_ERR_INVALID_DN_SYNTAX;
2115 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2116 &version, "RMD_VERSION");
2117 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2119 * We optimistically assume they are all the same; if
2120 * the first one is fixed, they are all fixed.
2122 * If the first one was *not* fixed and we find a
2123 * later one that is, that is an occasion to shout
2129 DEBUG(0, ("Mixed w2k and fixed format "
2130 "linked attributes\n"));
2134 /* it's an old one that needs upgrading */
2135 ret = replmd_update_la_val(el->values, dns[i].v,
2136 dns[i].dsdb_dn, dns[i].dsdb_dn,
2137 invocation_id, 1, 1, 0, 0, false);
2138 if (ret != LDB_SUCCESS) {
2146 update an extended DN, including all meta data fields
2148 see replmd_build_la_val for value names
2150 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2151 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2152 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2153 uint32_t version, bool deleted)
2155 struct ldb_dn *dn = dsdb_dn->dn;
2156 const char *tstring, *usn_string, *flags_string;
2157 struct ldb_val tval;
2159 struct ldb_val usnv, local_usnv;
2160 struct ldb_val vers, flagsv;
2161 const struct ldb_val *old_addtime;
2162 uint32_t old_version;
2165 const char *dnstring;
2167 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2169 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2171 return LDB_ERR_OPERATIONS_ERROR;
2173 tval = data_blob_string_const(tstring);
2175 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2177 return LDB_ERR_OPERATIONS_ERROR;
2179 usnv = data_blob_string_const(usn_string);
2181 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2183 return LDB_ERR_OPERATIONS_ERROR;
2185 local_usnv = data_blob_string_const(usn_string);
2187 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2188 if (!NT_STATUS_IS_OK(status)) {
2189 return LDB_ERR_OPERATIONS_ERROR;
2192 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2193 if (!flags_string) {
2194 return LDB_ERR_OPERATIONS_ERROR;
2196 flagsv = data_blob_string_const(flags_string);
2198 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2199 if (ret != LDB_SUCCESS) return ret;
2201 /* get the ADDTIME from the original */
2202 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2203 if (old_addtime == NULL) {
2204 old_addtime = &tval;
2206 if (dsdb_dn != old_dsdb_dn ||
2207 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2208 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2209 if (ret != LDB_SUCCESS) return ret;
2212 /* use our invocation id */
2213 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2214 if (ret != LDB_SUCCESS) return ret;
2216 /* changetime is the current time */
2217 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2218 if (ret != LDB_SUCCESS) return ret;
2220 /* update the USN */
2221 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2222 if (ret != LDB_SUCCESS) return ret;
2224 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2225 if (ret != LDB_SUCCESS) return ret;
2227 /* increase the version by 1 */
2228 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2229 if (NT_STATUS_IS_OK(status) && old_version >= version) {
2230 version = old_version+1;
2232 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2233 vers = data_blob_string_const(vstring);
2234 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2235 if (ret != LDB_SUCCESS) return ret;
2237 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2238 if (dnstring == NULL) {
2239 return LDB_ERR_OPERATIONS_ERROR;
2241 *v = data_blob_string_const(dnstring);
2247 handle adding a linked attribute
2249 static int replmd_modify_la_add(struct ldb_module *module,
2250 struct replmd_private *replmd_private,
2251 const struct dsdb_schema *schema,
2252 struct ldb_message *msg,
2253 struct ldb_message_element *el,
2254 struct ldb_message_element *old_el,
2255 const struct dsdb_attribute *schema_attr,
2258 struct GUID *msg_guid,
2259 struct ldb_request *parent)
2262 struct parsed_dn *dns, *old_dns;
2263 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2265 struct ldb_val *new_values = NULL;
2266 unsigned int num_new_values = 0;
2267 unsigned old_num_values = old_el?old_el->num_values:0;
2268 const struct GUID *invocation_id;
2269 struct ldb_context *ldb = ldb_module_get_ctx(module);
2272 unix_to_nt_time(&now, t);
2274 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2275 if (ret != LDB_SUCCESS) {
2276 talloc_free(tmp_ctx);
2280 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2281 if (ret != LDB_SUCCESS) {
2282 talloc_free(tmp_ctx);
2286 invocation_id = samdb_ntds_invocation_id(ldb);
2287 if (!invocation_id) {
2288 talloc_free(tmp_ctx);
2289 return LDB_ERR_OPERATIONS_ERROR;
2292 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2293 old_el, invocation_id,
2294 schema_attr->syntax->ldap_oid);
2295 if (ret != LDB_SUCCESS) {
2296 talloc_free(tmp_ctx);
2300 /* for each new value, see if it exists already with the same GUID */
2301 for (i=0; i<el->num_values; i++) {
2302 struct parsed_dn *p;
2303 struct parsed_dn *next;
2304 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2308 schema_attr->syntax->ldap_oid);
2309 if (err != LDB_SUCCESS) {
2310 talloc_free(tmp_ctx);
2314 /* this is a new linked attribute value */
2315 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
2316 if (new_values == NULL) {
2317 ldb_module_oom(module);
2318 talloc_free(tmp_ctx);
2319 return LDB_ERR_OPERATIONS_ERROR;
2321 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2322 invocation_id, seq_num, seq_num, now, 0, false);
2323 if (ret != LDB_SUCCESS) {
2324 talloc_free(tmp_ctx);
2329 /* this is only allowed if the GUID was
2330 previously deleted. */
2331 uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2332 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2333 struct GUID_txt_buf guid_str;
2334 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
2335 el->name, GUID_buf_string(&p->guid, &guid_str));
2336 talloc_free(tmp_ctx);
2337 /* error codes for 'member' need to be
2339 if (ldb_attr_cmp(el->name, "member") == 0) {
2340 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2342 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2345 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
2346 invocation_id, seq_num, seq_num, now, 0, false);
2347 if (ret != LDB_SUCCESS) {
2348 talloc_free(tmp_ctx);
2353 ret = replmd_add_backlink(module, replmd_private,
2354 schema, msg_guid, &dns[i].guid,
2355 true, schema_attr, true);
2356 if (ret != LDB_SUCCESS) {
2357 talloc_free(tmp_ctx);
2362 /* add the new ones on to the end of the old values, constructing a new el->values */
2363 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2365 old_num_values+num_new_values);
2366 if (el->values == NULL) {
2367 ldb_module_oom(module);
2368 return LDB_ERR_OPERATIONS_ERROR;
2371 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
2372 el->num_values = old_num_values + num_new_values;
2374 talloc_steal(msg->elements, el->values);
2375 talloc_steal(el->values, new_values);
2377 talloc_free(tmp_ctx);
2379 /* we now tell the backend to replace all existing values
2380 with the one we have constructed */
2381 el->flags = LDB_FLAG_MOD_REPLACE;
2388 handle deleting all active linked attributes
2390 static int replmd_modify_la_delete(struct ldb_module *module,
2391 struct replmd_private *replmd_private,
2392 const struct dsdb_schema *schema,
2393 struct ldb_message *msg,
2394 struct ldb_message_element *el,
2395 struct ldb_message_element *old_el,
2396 const struct dsdb_attribute *schema_attr,
2399 struct GUID *msg_guid,
2400 struct ldb_request *parent)
2403 struct parsed_dn *dns, *old_dns;
2404 TALLOC_CTX *tmp_ctx = NULL;
2406 const struct GUID *invocation_id;
2407 struct ldb_context *ldb = ldb_module_get_ctx(module);
2408 struct ldb_control *vanish_links_ctrl = NULL;
2409 bool vanish_links = false;
2410 unsigned int num_to_delete = el->num_values;
2413 unix_to_nt_time(&now, t);
2415 /* check if there is nothing to delete */
2416 if ((!old_el || old_el->num_values == 0) &&
2417 el->num_values == 0) {
2421 if (!old_el || old_el->num_values == 0) {
2422 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2425 tmp_ctx = talloc_new(msg);
2426 if (tmp_ctx == NULL) {
2427 return LDB_ERR_OPERATIONS_ERROR;
2430 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2431 if (ret != LDB_SUCCESS) {
2432 talloc_free(tmp_ctx);
2436 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2437 if (ret != LDB_SUCCESS) {
2438 talloc_free(tmp_ctx);
2442 invocation_id = samdb_ntds_invocation_id(ldb);
2443 if (!invocation_id) {
2444 talloc_free(tmp_ctx);
2445 return LDB_ERR_OPERATIONS_ERROR;
2448 ret = replmd_check_upgrade_links(ldb, old_dns, old_el->num_values,
2449 old_el, invocation_id,
2450 schema_attr->syntax->ldap_oid);
2451 if (ret != LDB_SUCCESS) {
2452 talloc_free(tmp_ctx);
2457 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2458 if (vanish_links_ctrl) {
2459 vanish_links = true;
2460 vanish_links_ctrl->critical = false;
2467 /* see if we are being asked to delete any links that
2468 don't exist or are already deleted */
2469 for (i=0; i < num_to_delete; i++) {
2470 struct parsed_dn *p = &dns[i];
2471 struct parsed_dn *p2;
2472 struct parsed_dn *next = NULL;
2474 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2478 schema_attr->syntax->ldap_oid);
2479 if (ret != LDB_SUCCESS) {
2480 talloc_free(tmp_ctx);
2485 struct GUID_txt_buf buf;
2486 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
2487 el->name, GUID_buf_string(&p->guid, &buf));
2488 if (ldb_attr_cmp(el->name, "member") == 0) {
2489 talloc_free(tmp_ctx);
2490 return LDB_ERR_UNWILLING_TO_PERFORM;
2492 talloc_free(tmp_ctx);
2493 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2496 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
2497 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2498 struct GUID_txt_buf buf;
2499 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2501 DEBUG(0, ("Deleting deleted linked attribute %s to %s, "
2502 "because vanish_links control is set\n",
2503 el->name, guid_str));
2506 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
2507 el->name, guid_str);
2508 if (ldb_attr_cmp(el->name, "member") == 0) {
2509 talloc_free(tmp_ctx);
2510 return LDB_ERR_UNWILLING_TO_PERFORM;
2512 talloc_free(tmp_ctx);
2513 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2519 if (num_to_delete == old_el->num_values || num_to_delete == 0) {
2520 el->flags = LDB_FLAG_MOD_REPLACE;
2522 for (i = 0; i < old_el->num_values; i++) {
2523 ret = replmd_add_backlink(module,
2529 if (ret != LDB_SUCCESS) {
2530 talloc_free(tmp_ctx);
2534 talloc_free(tmp_ctx);
2537 unsigned int num_values = 0;
2539 struct parsed_dn *exact = NULL, *next = NULL;
2541 for (i = 0; i < old_el->num_values; i++) {
2542 ret = parsed_dn_find(ldb, dns, num_to_delete,
2546 schema_attr->syntax->ldap_oid);
2547 if (ret != LDB_SUCCESS) {
2548 talloc_free(tmp_ctx);
2552 if (exact != NULL) {
2553 /* The element is in the delete list.
2555 ret = replmd_add_backlink(module,
2563 if (ret != LDB_SUCCESS) {
2564 talloc_free(tmp_ctx);
2567 old_dns[i].v->length = 0;
2572 for (i = 0; i < old_el->num_values; i++) {
2573 if (old_el->values[i].length != 0) {
2574 old_el->values[j] = old_el->values[i];
2576 if (j == num_values) {
2581 old_el->num_values = num_values;
2585 /* for each new value, see if it exists already with the same GUID
2586 if it is not already deleted and matches the delete list then delete it
2588 for (i=0; i<old_el->num_values; i++) {
2589 struct parsed_dn *p = &old_dns[i];
2590 struct parsed_dn *exact = NULL, *next = NULL;
2593 if (num_to_delete != 0) {
2594 ret = parsed_dn_find(ldb, dns, num_to_delete,
2598 schema_attr->syntax->ldap_oid);
2599 if (ret != LDB_SUCCESS) {
2600 talloc_free(tmp_ctx);
2603 if (exact == NULL) {
2608 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2609 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2611 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
2612 invocation_id, seq_num, seq_num, now, 0, true);
2613 if (ret != LDB_SUCCESS) {
2614 talloc_free(tmp_ctx);
2617 ret = replmd_add_backlink(module, replmd_private,
2618 schema, msg_guid, &p->guid,
2619 false, schema_attr, true);
2620 if (ret != LDB_SUCCESS) {
2621 talloc_free(tmp_ctx);
2626 el->values = talloc_steal(msg->elements, old_el->values);
2627 el->num_values = old_el->num_values;
2629 talloc_free(tmp_ctx);
2631 /* we now tell the backend to replace all existing values
2632 with the one we have constructed */
2633 el->flags = LDB_FLAG_MOD_REPLACE;
2639 handle replacing a linked attribute
2641 static int replmd_modify_la_replace(struct ldb_module *module,
2642 struct replmd_private *replmd_private,
2643 const struct dsdb_schema *schema,
2644 struct ldb_message *msg,
2645 struct ldb_message_element *el,
2646 struct ldb_message_element *old_el,
2647 const struct dsdb_attribute *schema_attr,
2650 struct GUID *msg_guid,
2651 struct ldb_request *parent)
2654 struct parsed_dn *dns, *old_dns;
2655 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2657 const struct GUID *invocation_id;
2658 struct ldb_context *ldb = ldb_module_get_ctx(module);
2659 struct ldb_val *new_values = NULL;
2660 unsigned int num_new_values = 0;
2661 unsigned int old_num_values = old_el?old_el->num_values:0;
2664 unix_to_nt_time(&now, t);
2666 /* check if there is nothing to replace */
2667 if ((!old_el || old_el->num_values == 0) &&
2668 el->num_values == 0) {
2672 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2673 if (ret != LDB_SUCCESS) {
2674 talloc_free(tmp_ctx);
2678 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2679 if (ret != LDB_SUCCESS) {
2680 talloc_free(tmp_ctx);
2684 invocation_id = samdb_ntds_invocation_id(ldb);
2685 if (!invocation_id) {
2686 return LDB_ERR_OPERATIONS_ERROR;
2689 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2690 old_el, invocation_id,
2691 schema_attr->syntax->ldap_oid);
2692 if (ret != LDB_SUCCESS) {
2693 talloc_free(tmp_ctx);
2697 /* mark all the old ones as deleted */
2698 for (i=0; i<old_num_values; i++) {
2699 struct parsed_dn *old_p = &old_dns[i];
2700 struct parsed_dn *exact = NULL, *next = NULL;
2701 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2703 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2705 ret = replmd_add_backlink(module, replmd_private,
2706 schema, msg_guid, &old_dns[i].guid,
2707 false, schema_attr, false);
2708 if (ret != LDB_SUCCESS) {
2709 talloc_free(tmp_ctx);
2713 ret = parsed_dn_find(ldb, dns, el->num_values,
2717 schema_attr->syntax->ldap_oid);
2718 if (ret != LDB_SUCCESS) {
2719 talloc_free(tmp_ctx);
2723 /* we don't delete it if we are re-adding it */
2727 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2728 invocation_id, seq_num, seq_num, now, 0, true);
2729 if (ret != LDB_SUCCESS) {
2730 talloc_free(tmp_ctx);
2735 /* for each new value, either update its meta-data, or add it
2738 for (i=0; i<el->num_values; i++) {
2739 struct parsed_dn *p = &dns[i];
2740 struct parsed_dn *old_p = NULL, *next = NULL;
2743 ret = parsed_dn_find(ldb, old_dns, old_num_values,
2747 schema_attr->syntax->ldap_oid);
2748 if (ret != LDB_SUCCESS) {
2749 talloc_free(tmp_ctx);
2754 if (old_p != NULL) {
2755 /* update in place */
2756 ret = replmd_update_la_val(old_el->values, old_p->v, p->dsdb_dn,
2757 old_p->dsdb_dn, invocation_id,
2758 seq_num, seq_num, now, 0, false);
2759 if (ret != LDB_SUCCESS) {
2760 talloc_free(tmp_ctx);
2765 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2767 if (new_values == NULL) {
2768 ldb_module_oom(module);
2769 talloc_free(tmp_ctx);
2770 return LDB_ERR_OPERATIONS_ERROR;
2772 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2773 invocation_id, seq_num, seq_num, now, 0, false);
2774 if (ret != LDB_SUCCESS) {
2775 talloc_free(tmp_ctx);
2781 ret = replmd_add_backlink(module, replmd_private,
2782 schema, msg_guid, &dns[i].guid,
2783 true, schema_attr, false);
2784 if (ret != LDB_SUCCESS) {
2785 talloc_free(tmp_ctx);
2790 /* add the new values to the end of old_el */
2791 if (num_new_values != 0) {
2792 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2793 struct ldb_val, old_num_values+num_new_values);
2794 if (el->values == NULL) {
2795 ldb_module_oom(module);
2796 return LDB_ERR_OPERATIONS_ERROR;
2798 memcpy(&el->values[old_num_values], &new_values[0],
2799 sizeof(struct ldb_val)*num_new_values);
2800 el->num_values = old_num_values + num_new_values;
2801 talloc_steal(msg->elements, new_values);
2803 el->values = old_el->values;
2804 el->num_values = old_el->num_values;
2805 talloc_steal(msg->elements, el->values);
2808 talloc_free(tmp_ctx);
2810 /* we now tell the backend to replace all existing values
2811 with the one we have constructed */
2812 el->flags = LDB_FLAG_MOD_REPLACE;
2819 handle linked attributes in modify requests
2821 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2822 struct replmd_private *replmd_private,
2823 struct ldb_message *msg,
2824 uint64_t seq_num, time_t t,
2825 struct ldb_request *parent)
2827 struct ldb_result *res;
2830 struct ldb_context *ldb = ldb_module_get_ctx(module);
2831 struct ldb_message *old_msg;
2833 const struct dsdb_schema *schema;
2834 struct GUID old_guid;
2836 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2838 * Nothing special is required for modifying or vanishing links
2839 * in fl2000 since they are just strings in a multi-valued
2842 struct ldb_control *ctrl = ldb_request_get_control(parent,
2843 DSDB_CONTROL_REPLMD_VANISH_LINKS);
2845 ctrl->critical = false;
2853 * We should restrict this to the intersection of the list of
2854 * linked attributes in the schema and the list of attributes
2857 * This will help performance a little, as otherwise we have
2858 * to allocate the entire object value-by-value.
2860 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2861 DSDB_FLAG_NEXT_MODULE |
2862 DSDB_SEARCH_SHOW_RECYCLED |
2863 DSDB_SEARCH_REVEAL_INTERNALS |
2864 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2866 if (ret != LDB_SUCCESS) {
2869 schema = dsdb_get_schema(ldb, res);
2871 return LDB_ERR_OPERATIONS_ERROR;
2874 old_msg = res->msgs[0];
2876 old_guid = samdb_result_guid(old_msg, "objectGUID");
2878 for (i=0; i<msg->num_elements; i++) {
2879 struct ldb_message_element *el = &msg->elements[i];
2880 struct ldb_message_element *old_el, *new_el;
2881 const struct dsdb_attribute *schema_attr
2882 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2884 ldb_asprintf_errstring(ldb,
2885 "%s: attribute %s is not a valid attribute in schema",
2886 __FUNCTION__, el->name);
2887 return LDB_ERR_OBJECT_CLASS_VIOLATION;
2889 if (schema_attr->linkID == 0) {
2892 if ((schema_attr->linkID & 1) == 1) {
2893 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
2896 /* Odd is for the target. Illegal to modify */
2897 ldb_asprintf_errstring(ldb,
2898 "attribute %s must not be modified directly, it is a linked attribute", el->name);
2899 return LDB_ERR_UNWILLING_TO_PERFORM;
2901 old_el = ldb_msg_find_element(old_msg, el->name);
2902 switch (el->flags & LDB_FLAG_MOD_MASK) {
2903 case LDB_FLAG_MOD_REPLACE:
2904 ret = replmd_modify_la_replace(module, replmd_private,
2905 schema, msg, el, old_el,
2906 schema_attr, seq_num, t,
2909 case LDB_FLAG_MOD_DELETE:
2910 ret = replmd_modify_la_delete(module, replmd_private,
2911 schema, msg, el, old_el,
2912 schema_attr, seq_num, t,
2915 case LDB_FLAG_MOD_ADD:
2916 ret = replmd_modify_la_add(module, replmd_private,
2917 schema, msg, el, old_el,
2918 schema_attr, seq_num, t,
2922 ldb_asprintf_errstring(ldb,
2923 "invalid flags 0x%x for %s linked attribute",
2924 el->flags, el->name);
2925 return LDB_ERR_UNWILLING_TO_PERFORM;
2927 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
2928 ldb_asprintf_errstring(ldb,
2929 "Attribute %s is single valued but more than one value has been supplied",
2931 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2933 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
2938 if (ret != LDB_SUCCESS) {
2942 ldb_msg_remove_attr(old_msg, el->name);
2944 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2945 new_el->num_values = el->num_values;
2946 new_el->values = talloc_steal(msg->elements, el->values);
2948 /* TODO: this relises a bit too heavily on the exact
2949 behaviour of ldb_msg_find_element and
2950 ldb_msg_remove_element */
2951 old_el = ldb_msg_find_element(msg, el->name);
2953 ldb_msg_remove_element(msg, old_el);
2964 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2966 struct ldb_context *ldb;
2967 struct replmd_replicated_request *ac;
2968 struct ldb_request *down_req;
2969 struct ldb_message *msg;
2970 time_t t = time(NULL);
2972 bool is_urgent = false, rodc = false;
2973 bool is_schema_nc = false;
2974 unsigned int functional_level;
2975 const struct ldb_message_element *guid_el = NULL;
2976 struct ldb_control *sd_propagation_control;
2977 struct replmd_private *replmd_private =
2978 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2980 /* do not manipulate our control entries */
2981 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2982 return ldb_next_request(module, req);
2985 sd_propagation_control = ldb_request_get_control(req,
2986 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
2987 if (sd_propagation_control != NULL) {
2988 if (req->op.mod.message->num_elements != 1) {
2989 return ldb_module_operr(module);
2991 ret = strcmp(req->op.mod.message->elements[0].name,
2992 "nTSecurityDescriptor");
2994 return ldb_module_operr(module);
2997 return ldb_next_request(module, req);
3000 ldb = ldb_module_get_ctx(module);
3002 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3004 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3005 if (guid_el != NULL) {
3006 ldb_set_errstring(ldb,
3007 "replmd_modify: it's not allowed to change the objectGUID!");
3008 return LDB_ERR_CONSTRAINT_VIOLATION;
3011 ac = replmd_ctx_init(module, req);
3013 return ldb_module_oom(module);
3016 functional_level = dsdb_functional_level(ldb);
3018 /* we have to copy the message as the caller might have it as a const */
3019 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3023 return LDB_ERR_OPERATIONS_ERROR;
3026 ldb_msg_remove_attr(msg, "whenChanged");
3027 ldb_msg_remove_attr(msg, "uSNChanged");
3029 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3031 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3032 msg, &ac->seq_num, t, is_schema_nc,
3034 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3035 struct loadparm_context *lp_ctx;
3038 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3039 struct loadparm_context);
3041 referral = talloc_asprintf(req,
3043 lpcfg_dnsdomain(lp_ctx),
3044 ldb_dn_get_linearized(msg->dn));
3045 ret = ldb_module_send_referral(req, referral);
3050 if (ret != LDB_SUCCESS) {
3055 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3056 msg, ac->seq_num, t, req);
3057 if (ret != LDB_SUCCESS) {
3063 * - replace the old object with the newly constructed one
3066 ac->is_urgent = is_urgent;
3068 ret = ldb_build_mod_req(&down_req, ldb, ac,
3071 ac, replmd_op_callback,
3073 LDB_REQ_SET_LOCATION(down_req);
3074 if (ret != LDB_SUCCESS) {
3079 /* current partition control is needed by "replmd_op_callback" */
3080 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3081 ret = ldb_request_add_control(down_req,
3082 DSDB_CONTROL_CURRENT_PARTITION_OID,
3084 if (ret != LDB_SUCCESS) {
3090 /* If we are in functional level 2000, then
3091 * replmd_modify_handle_linked_attribs will have done
3093 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3094 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3095 if (ret != LDB_SUCCESS) {
3101 talloc_steal(down_req, msg);
3103 /* we only change whenChanged and uSNChanged if the seq_num
3105 if (ac->seq_num != 0) {
3106 ret = add_time_element(msg, "whenChanged", t);
3107 if (ret != LDB_SUCCESS) {
3113 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3114 if (ret != LDB_SUCCESS) {
3121 /* go on with the call chain */
3122 return ldb_next_request(module, down_req);
3125 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3128 handle a rename request
3130 On a rename we need to do an extra ldb_modify which sets the
3131 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3133 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3135 struct ldb_context *ldb;
3136 struct replmd_replicated_request *ac;
3138 struct ldb_request *down_req;
3140 /* do not manipulate our control entries */
3141 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3142 return ldb_next_request(module, req);
3145 ldb = ldb_module_get_ctx(module);
3147 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3149 ac = replmd_ctx_init(module, req);
3151 return ldb_module_oom(module);
3154 ret = ldb_build_rename_req(&down_req, ldb, ac,
3155 ac->req->op.rename.olddn,
3156 ac->req->op.rename.newdn,
3158 ac, replmd_rename_callback,
3160 LDB_REQ_SET_LOCATION(down_req);
3161 if (ret != LDB_SUCCESS) {
3166 /* go on with the call chain */
3167 return ldb_next_request(module, down_req);
3170 /* After the rename is compleated, update the whenchanged etc */
3171 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3173 struct ldb_context *ldb;
3174 struct ldb_request *down_req;
3175 struct ldb_message *msg;
3176 const struct dsdb_attribute *rdn_attr;
3177 const char *rdn_name;
3178 const struct ldb_val *rdn_val;
3179 const char *attrs[5] = { NULL, };
3180 time_t t = time(NULL);
3182 bool is_urgent = false, rodc = false;
3184 struct replmd_replicated_request *ac =
3185 talloc_get_type(req->context, struct replmd_replicated_request);
3186 struct replmd_private *replmd_private =
3187 talloc_get_type(ldb_module_get_private(ac->module),
3188 struct replmd_private);
3190 ldb = ldb_module_get_ctx(ac->module);
3192 if (ares->error != LDB_SUCCESS) {
3193 return ldb_module_done(ac->req, ares->controls,
3194 ares->response, ares->error);
3197 if (ares->type != LDB_REPLY_DONE) {
3198 ldb_set_errstring(ldb,
3199 "invalid ldb_reply_type in callback");
3201 return ldb_module_done(ac->req, NULL, NULL,
3202 LDB_ERR_OPERATIONS_ERROR);
3206 * - replace the old object with the newly constructed one
3209 msg = ldb_msg_new(ac);
3212 return LDB_ERR_OPERATIONS_ERROR;
3215 msg->dn = ac->req->op.rename.newdn;
3217 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3219 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3220 if (rdn_name == NULL) {
3222 return ldb_module_done(ac->req, NULL, NULL,
3226 /* normalize the rdn attribute name */
3227 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3228 if (rdn_attr == NULL) {
3230 return ldb_module_done(ac->req, NULL, NULL,
3233 rdn_name = rdn_attr->lDAPDisplayName;
3235 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3236 if (rdn_val == NULL) {
3238 return ldb_module_done(ac->req, NULL, NULL,
3242 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3244 return ldb_module_done(ac->req, NULL, NULL,
3247 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3249 return ldb_module_done(ac->req, NULL, NULL,
3252 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3254 return ldb_module_done(ac->req, NULL, NULL,
3257 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3259 return ldb_module_done(ac->req, NULL, NULL,
3264 * here we let replmd_update_rpmd() only search for
3265 * the existing "replPropertyMetaData" and rdn_name attributes.
3267 * We do not want the existing "name" attribute as
3268 * the "name" attribute needs to get the version
3269 * updated on rename even if the rdn value hasn't changed.
3271 * This is the diff of the meta data, for a moved user
3272 * on a w2k8r2 server:
3275 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3276 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3277 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3278 * version : 0x00000001 (1)
3279 * reserved : 0x00000000 (0)
3280 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3281 * local_usn : 0x00000000000037a5 (14245)
3282 * array: struct replPropertyMetaData1
3283 * attid : DRSUAPI_ATTID_name (0x90001)
3284 * - version : 0x00000001 (1)
3285 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3286 * + version : 0x00000002 (2)
3287 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3288 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3289 * - originating_usn : 0x00000000000037a5 (14245)
3290 * - local_usn : 0x00000000000037a5 (14245)
3291 * + originating_usn : 0x0000000000003834 (14388)
3292 * + local_usn : 0x0000000000003834 (14388)
3293 * array: struct replPropertyMetaData1
3294 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3295 * version : 0x00000004 (4)
3297 attrs[0] = "replPropertyMetaData";
3298 attrs[1] = "objectClass";
3299 attrs[2] = "instanceType";
3300 attrs[3] = rdn_name;
3303 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3304 msg, &ac->seq_num, t,
3305 is_schema_nc, &is_urgent, &rodc);
3306 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3307 struct ldb_dn *olddn = ac->req->op.rename.olddn;
3308 struct loadparm_context *lp_ctx;
3311 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3312 struct loadparm_context);
3314 referral = talloc_asprintf(req,
3316 lpcfg_dnsdomain(lp_ctx),
3317 ldb_dn_get_linearized(olddn));
3318 ret = ldb_module_send_referral(req, referral);
3320 return ldb_module_done(req, NULL, NULL, ret);
3323 if (ret != LDB_SUCCESS) {
3325 return ldb_module_done(ac->req, NULL, NULL, ret);
3328 if (ac->seq_num == 0) {
3330 return ldb_module_done(ac->req, NULL, NULL,
3332 "internal error seq_num == 0"));
3334 ac->is_urgent = is_urgent;
3336 ret = ldb_build_mod_req(&down_req, ldb, ac,
3339 ac, replmd_op_callback,
3341 LDB_REQ_SET_LOCATION(down_req);
3342 if (ret != LDB_SUCCESS) {
3347 /* current partition control is needed by "replmd_op_callback" */
3348 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3349 ret = ldb_request_add_control(down_req,
3350 DSDB_CONTROL_CURRENT_PARTITION_OID,
3352 if (ret != LDB_SUCCESS) {
3358 talloc_steal(down_req, msg);
3360 ret = add_time_element(msg, "whenChanged", t);
3361 if (ret != LDB_SUCCESS) {
3367 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3368 if (ret != LDB_SUCCESS) {
3374 /* go on with the call chain - do the modify after the rename */
3375 return ldb_next_request(ac->module, down_req);
3379 * remove links from objects that point at this object when an object
3380 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3381 * RemoveObj which states that link removal due to the object being
3382 * deleted is NOT an originating update - they just go away!
3385 static int replmd_delete_remove_link(struct ldb_module *module,
3386 const struct dsdb_schema *schema,
3388 struct ldb_message_element *el,
3389 const struct dsdb_attribute *sa,
3390 struct ldb_request *parent)
3393 TALLOC_CTX *tmp_ctx = talloc_new(module);
3394 struct ldb_context *ldb = ldb_module_get_ctx(module);
3396 for (i=0; i<el->num_values; i++) {
3397 struct dsdb_dn *dsdb_dn;
3401 struct ldb_message *msg;
3402 const struct dsdb_attribute *target_attr;
3403 struct ldb_message_element *el2;
3404 struct ldb_val dn_val;
3405 uint32_t dsdb_flags = 0;
3407 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3411 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3413 talloc_free(tmp_ctx);
3414 return LDB_ERR_OPERATIONS_ERROR;
3417 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
3418 if (!NT_STATUS_IS_OK(status)) {
3419 talloc_free(tmp_ctx);
3420 return LDB_ERR_OPERATIONS_ERROR;
3423 /* remove the link */
3424 msg = ldb_msg_new(tmp_ctx);
3426 ldb_module_oom(module);
3427 talloc_free(tmp_ctx);
3428 return LDB_ERR_OPERATIONS_ERROR;
3432 msg->dn = dsdb_dn->dn;
3434 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3435 if (target_attr == NULL) {
3439 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
3440 if (ret != LDB_SUCCESS) {
3441 ldb_module_oom(module);
3442 talloc_free(tmp_ctx);
3443 return LDB_ERR_OPERATIONS_ERROR;
3445 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
3446 el2->values = &dn_val;
3447 el2->num_values = 1;
3450 * Ensure that we tell the modification to vanish any linked
3451 * attributes (not simply mark them as isDeleted = TRUE)
3453 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3455 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3456 if (ret != LDB_SUCCESS) {
3457 talloc_free(tmp_ctx);
3461 talloc_free(tmp_ctx);
3467 handle update of replication meta data for deletion of objects
3469 This also handles the mapping of delete to a rename operation
3470 to allow deletes to be replicated.
3472 It also handles the incoming deleted objects, to ensure they are
3473 fully deleted here. In that case re_delete is true, and we do not
3474 use this as a signal to change the deleted state, just reinforce it.
3477 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3479 int ret = LDB_ERR_OTHER;
3480 bool retb, disallow_move_on_delete;
3481 struct ldb_dn *old_dn, *new_dn;
3482 const char *rdn_name;
3483 const struct ldb_val *rdn_value, *new_rdn_value;
3485 struct ldb_context *ldb = ldb_module_get_ctx(module);
3486 const struct dsdb_schema *schema;
3487 struct ldb_message *msg, *old_msg;
3488 struct ldb_message_element *el;
3489 TALLOC_CTX *tmp_ctx;
3490 struct ldb_result *res, *parent_res;
3491 static const char * const preserved_attrs[] = {
3492 /* yes, this really is a hard coded list. See MS-ADTS
3493 section 3.1.1.5.5.1.1 */
3496 "dNReferenceUpdate",
3507 "msDS-LastKnownRDN",
3513 "distinguishedName",
3517 "proxiedObjectName",
3519 "nTSecurityDescriptor",
3520 "replPropertyMetaData",
3522 "securityIdentifier",
3530 "userAccountControl",
3537 static const char * const all_attrs[] = {
3538 DSDB_SECRET_ATTRIBUTES,
3542 unsigned int i, el_count = 0;
3543 uint32_t dsdb_flags = 0;
3544 enum deletion_state deletion_state, next_deletion_state;
3546 if (ldb_dn_is_special(req->op.del.dn)) {
3547 return ldb_next_request(module, req);
3551 * We have to allow dbcheck to remove an object that
3552 * is beyond repair, and to do so totally. This could
3553 * mean we we can get a partial object from the other
3554 * DC, causing havoc, so dbcheck suggests
3555 * re-replication first. dbcheck sets both DBCHECK
3556 * and RELAX in this situation.
3558 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3559 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3560 /* really, really remove it */
3561 return ldb_next_request(module, req);
3564 tmp_ctx = talloc_new(ldb);
3567 return LDB_ERR_OPERATIONS_ERROR;
3570 schema = dsdb_get_schema(ldb, tmp_ctx);
3572 talloc_free(tmp_ctx);
3573 return LDB_ERR_OPERATIONS_ERROR;
3576 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3578 /* we need the complete msg off disk, so we can work out which
3579 attributes need to be removed */
3580 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3581 DSDB_FLAG_NEXT_MODULE |
3582 DSDB_SEARCH_SHOW_RECYCLED |
3583 DSDB_SEARCH_REVEAL_INTERNALS |
3584 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3585 if (ret != LDB_SUCCESS) {
3586 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3587 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3588 re_delete ? "re-delete" : "delete",
3589 ldb_dn_get_linearized(old_dn),
3590 ldb_errstring(ldb_module_get_ctx(module)));
3591 talloc_free(tmp_ctx);
3594 old_msg = res->msgs[0];
3596 replmd_deletion_state(module, old_msg,
3598 &next_deletion_state);
3600 /* This supports us noticing an incoming isDeleted and acting on it */
3602 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3603 next_deletion_state = deletion_state;
3606 if (next_deletion_state == OBJECT_REMOVED) {
3608 * We have to prevent objects being deleted, even if
3609 * the administrator really wants them gone, as
3610 * without the tombstone, we can get a partial object
3611 * from the other DC, causing havoc.
3613 * The only other valid case is when the 180 day
3614 * timeout has expired, when relax is specified.
3616 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3617 /* it is already deleted - really remove it this time */
3618 talloc_free(tmp_ctx);
3619 return ldb_next_request(module, req);
3622 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3623 "This check is to prevent corruption of the replicated state.",
3624 ldb_dn_get_linearized(old_msg->dn));
3625 return LDB_ERR_UNWILLING_TO_PERFORM;
3628 rdn_name = ldb_dn_get_rdn_name(old_dn);
3629 rdn_value = ldb_dn_get_rdn_val(old_dn);
3630 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3631 talloc_free(tmp_ctx);
3632 return ldb_operr(ldb);
3635 msg = ldb_msg_new(tmp_ctx);
3637 ldb_module_oom(module);
3638 talloc_free(tmp_ctx);
3639 return LDB_ERR_OPERATIONS_ERROR;
3644 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3645 disallow_move_on_delete =
3646 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3647 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3649 /* work out where we will be renaming this object to */
3650 if (!disallow_move_on_delete) {
3651 struct ldb_dn *deleted_objects_dn;
3652 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3653 &deleted_objects_dn);
3656 * We should not move objects if we can't find the
3657 * deleted objects DN. Not moving (or otherwise
3658 * harming) the Deleted Objects DN itself is handled
3661 if (re_delete && (ret != LDB_SUCCESS)) {
3662 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3663 if (new_dn == NULL) {
3664 ldb_module_oom(module);
3665 talloc_free(tmp_ctx);
3666 return LDB_ERR_OPERATIONS_ERROR;
3668 } else if (ret != LDB_SUCCESS) {
3669 /* this is probably an attempted delete on a partition
3670 * that doesn't allow delete operations, such as the
3671 * schema partition */
3672 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3673 ldb_dn_get_linearized(old_dn));
3674 talloc_free(tmp_ctx);
3675 return LDB_ERR_UNWILLING_TO_PERFORM;
3677 new_dn = deleted_objects_dn;
3680 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3681 if (new_dn == NULL) {
3682 ldb_module_oom(module);
3683 talloc_free(tmp_ctx);
3684 return LDB_ERR_OPERATIONS_ERROR;
3688 if (deletion_state == OBJECT_NOT_DELETED) {
3689 /* get the objects GUID from the search we just did */
3690 guid = samdb_result_guid(old_msg, "objectGUID");
3692 /* Add a formatted child */
3693 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3695 ldb_dn_escape_value(tmp_ctx, *rdn_value),
3696 GUID_string(tmp_ctx, &guid));
3698 ldb_asprintf_errstring(ldb, __location__
3699 ": Unable to add a formatted child to dn: %s",
3700 ldb_dn_get_linearized(new_dn));
3701 talloc_free(tmp_ctx);
3702 return LDB_ERR_OPERATIONS_ERROR;
3705 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
3706 if (ret != LDB_SUCCESS) {
3707 ldb_asprintf_errstring(ldb, __location__
3708 ": Failed to add isDeleted string to the msg");
3709 talloc_free(tmp_ctx);
3712 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3715 * No matter what has happened with other renames etc, try again to
3716 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
3719 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
3720 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
3722 ldb_asprintf_errstring(ldb, __location__
3723 ": Unable to add a prepare rdn of %s",
3724 ldb_dn_get_linearized(rdn));
3725 talloc_free(tmp_ctx);
3726 return LDB_ERR_OPERATIONS_ERROR;
3728 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
3730 retb = ldb_dn_add_child(new_dn, rdn);
3732 ldb_asprintf_errstring(ldb, __location__
3733 ": Unable to add rdn %s to base dn: %s",
3734 ldb_dn_get_linearized(rdn),
3735 ldb_dn_get_linearized(new_dn));
3736 talloc_free(tmp_ctx);
3737 return LDB_ERR_OPERATIONS_ERROR;
3742 now we need to modify the object in the following ways:
3744 - add isDeleted=TRUE
3745 - update rDN and name, with new rDN
3746 - remove linked attributes
3747 - remove objectCategory and sAMAccountType
3748 - remove attribs not on the preserved list
3749 - preserved if in above list, or is rDN
3750 - remove all linked attribs from this object
3751 - remove all links from other objects to this object
3752 - add lastKnownParent
3753 - update replPropertyMetaData?
3755 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
3758 if (deletion_state == OBJECT_NOT_DELETED) {
3759 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3760 char *parent_dn_str = NULL;
3762 /* we need the storage form of the parent GUID */
3763 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
3765 DSDB_FLAG_NEXT_MODULE |
3766 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3767 DSDB_SEARCH_REVEAL_INTERNALS|
3768 DSDB_SEARCH_SHOW_RECYCLED, req);
3769 if (ret != LDB_SUCCESS) {
3770 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3771 "repmd_delete: Failed to %s %s, "
3772 "because we failed to find it's parent (%s): %s",
3773 re_delete ? "re-delete" : "delete",
3774 ldb_dn_get_linearized(old_dn),
3775 ldb_dn_get_linearized(parent_dn),
3776 ldb_errstring(ldb_module_get_ctx(module)));
3777 talloc_free(tmp_ctx);
3782 * Now we can use the DB version,
3783 * it will have the extended DN info in it
3785 parent_dn = parent_res->msgs[0]->dn;
3786 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
3789 if (parent_dn_str == NULL) {
3790 talloc_free(tmp_ctx);
3791 return ldb_module_oom(module);
3794 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3796 if (ret != LDB_SUCCESS) {
3797 ldb_asprintf_errstring(ldb, __location__
3798 ": Failed to add lastKnownParent "
3799 "string when deleting %s",
3800 ldb_dn_get_linearized(old_dn));
3801 talloc_free(tmp_ctx);
3804 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3806 if (next_deletion_state == OBJECT_DELETED) {
3807 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
3808 if (ret != LDB_SUCCESS) {
3809 ldb_asprintf_errstring(ldb, __location__
3810 ": Failed to add msDS-LastKnownRDN "
3811 "string when deleting %s",
3812 ldb_dn_get_linearized(old_dn));
3813 talloc_free(tmp_ctx);
3816 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
3820 switch (next_deletion_state) {
3822 case OBJECT_RECYCLED:
3823 case OBJECT_TOMBSTONE:
3826 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
3827 * describes what must be removed from a tombstone
3830 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
3831 * describes what must be removed from a recycled
3837 * we also mark it as recycled, meaning this object can't be
3838 * recovered (we are stripping its attributes).
3839 * This is done only if we have this schema object of course ...
3840 * This behavior is identical to the one of Windows 2008R2 which
3841 * always set the isRecycled attribute, even if the recycle-bin is
3842 * not activated and what ever the forest level is.
3844 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
3845 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
3846 if (ret != LDB_SUCCESS) {
3847 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
3848 ldb_module_oom(module);
3849 talloc_free(tmp_ctx);
3852 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3855 /* work out which of the old attributes we will be removing */
3856 for (i=0; i<old_msg->num_elements; i++) {
3857 const struct dsdb_attribute *sa;
3858 el = &old_msg->elements[i];
3859 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3861 talloc_free(tmp_ctx);
3862 return LDB_ERR_OPERATIONS_ERROR;
3864 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
3865 /* don't remove the rDN */
3868 if (sa->linkID && (sa->linkID & 1)) {
3870 we have a backlink in this object
3871 that needs to be removed. We're not
3872 allowed to remove it directly
3873 however, so we instead setup a
3874 modify to delete the corresponding
3877 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
3878 if (ret != LDB_SUCCESS) {
3879 const char *old_dn_str
3880 = ldb_dn_get_linearized(old_dn);
3881 ldb_asprintf_errstring(ldb,
3883 ": Failed to remove backlink of "
3884 "%s when deleting %s: %s",
3887 ldb_errstring(ldb));
3888 talloc_free(tmp_ctx);
3889 return LDB_ERR_OPERATIONS_ERROR;
3891 /* now we continue, which means we
3892 won't remove this backlink
3898 if (ldb_attr_in_list(preserved_attrs, el->name)) {
3901 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
3906 * Ensure that we tell the modification to vanish any linked
3907 * attributes (not simply mark them as isDeleted = TRUE)
3909 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3911 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
3912 if (ret != LDB_SUCCESS) {
3913 talloc_free(tmp_ctx);
3914 ldb_module_oom(module);
3921 case OBJECT_DELETED:
3923 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
3924 * describes what must be removed from a deleted
3928 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
3929 if (ret != LDB_SUCCESS) {
3930 talloc_free(tmp_ctx);
3931 ldb_module_oom(module);
3935 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
3936 if (ret != LDB_SUCCESS) {
3937 talloc_free(tmp_ctx);
3938 ldb_module_oom(module);
3948 if (deletion_state == OBJECT_NOT_DELETED) {
3949 const struct dsdb_attribute *sa;
3951 /* work out what the new rdn value is, for updating the
3952 rDN and name fields */
3953 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
3954 if (new_rdn_value == NULL) {
3955 talloc_free(tmp_ctx);
3956 return ldb_operr(ldb);
3959 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
3961 talloc_free(tmp_ctx);
3962 return LDB_ERR_OPERATIONS_ERROR;
3965 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
3967 if (ret != LDB_SUCCESS) {
3968 talloc_free(tmp_ctx);
3971 el->flags = LDB_FLAG_MOD_REPLACE;
3973 el = ldb_msg_find_element(old_msg, "name");
3975 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
3976 if (ret != LDB_SUCCESS) {
3977 talloc_free(tmp_ctx);
3980 el->flags = LDB_FLAG_MOD_REPLACE;
3985 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
3990 * No matter what has happned with other renames, try again to
3991 * get this to be under the deleted DN.
3993 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
3994 /* now rename onto the new DN */
3995 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
3996 if (ret != LDB_SUCCESS){
3997 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
3998 ldb_dn_get_linearized(old_dn),
3999 ldb_dn_get_linearized(new_dn),
4000 ldb_errstring(ldb)));
4001 talloc_free(tmp_ctx);
4007 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4008 if (ret != LDB_SUCCESS) {
4009 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4010 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4011 talloc_free(tmp_ctx);
4015 talloc_free(tmp_ctx);
4017 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4020 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4022 return replmd_delete_internals(module, req, false);
4026 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4031 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4033 int ret = LDB_ERR_OTHER;
4034 /* TODO: do some error mapping */
4036 /* Let the caller know the full WERROR */
4037 ar->objs->error = status;
4043 static struct replPropertyMetaData1 *
4044 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4045 enum drsuapi_DsAttributeId attid)
4048 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4050 for (i = 0; i < rpmd_ctr->count; i++) {
4051 if (rpmd_ctr->array[i].attid == attid) {
4052 return &rpmd_ctr->array[i];
4060 return true if an update is newer than an existing entry
4061 see section 5.11 of MS-ADTS
4063 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4064 const struct GUID *update_invocation_id,
4065 uint32_t current_version,
4066 uint32_t update_version,
4067 NTTIME current_change_time,
4068 NTTIME update_change_time)
4070 if (update_version != current_version) {
4071 return update_version > current_version;
4073 if (update_change_time != current_change_time) {
4074 return update_change_time > current_change_time;
4076 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4079 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4080 struct replPropertyMetaData1 *new_m)
4082 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4083 &new_m->originating_invocation_id,
4086 cur_m->originating_change_time,
4087 new_m->originating_change_time);
4090 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4091 struct replPropertyMetaData1 *cur_m,
4092 struct replPropertyMetaData1 *new_m)
4097 * If the new replPropertyMetaData entry for this attribute is
4098 * not provided (this happens in the case where we look for
4099 * ATTID_name, but the name was not changed), then the local
4100 * state is clearly still current, as the remote
4101 * server didn't send it due to being older the high watermark
4104 if (new_m == NULL) {
4108 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4110 * if we compare equal then do an
4111 * update. This is used when a client
4112 * asks for a FULL_SYNC, and can be
4113 * used to recover a corrupt
4116 * This call is a bit tricky, what we
4117 * are doing it turning the 'is_newer'
4118 * call into a 'not is older' by
4119 * swapping cur_m and new_m, and negating the
4122 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4125 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4135 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4137 const struct ldb_val *rdn_val;
4138 const char *rdn_name;
4139 struct ldb_dn *new_dn;
4141 rdn_val = ldb_dn_get_rdn_val(dn);
4142 rdn_name = ldb_dn_get_rdn_name(dn);
4143 if (!rdn_val || !rdn_name) {
4147 new_dn = ldb_dn_copy(mem_ctx, dn);
4152 if (!ldb_dn_remove_child_components(new_dn, 1)) {
4156 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4158 ldb_dn_escape_value(new_dn, *rdn_val),
4159 GUID_string(new_dn, guid))) {
4168 perform a modify operation which sets the rDN and name attributes to
4169 their current values. This has the effect of changing these
4170 attributes to have been last updated by the current DC. This is
4171 needed to ensure that renames performed as part of conflict
4172 resolution are propogated to other DCs
4174 static int replmd_name_modify(struct replmd_replicated_request *ar,
4175 struct ldb_request *req, struct ldb_dn *dn)
4177 struct ldb_message *msg;
4178 const char *rdn_name;
4179 const struct ldb_val *rdn_val;
4180 const struct dsdb_attribute *rdn_attr;
4183 msg = ldb_msg_new(req);
4189 rdn_name = ldb_dn_get_rdn_name(dn);
4190 if (rdn_name == NULL) {
4194 /* normalize the rdn attribute name */
4195 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4196 if (rdn_attr == NULL) {
4199 rdn_name = rdn_attr->lDAPDisplayName;
4201 rdn_val = ldb_dn_get_rdn_val(dn);
4202 if (rdn_val == NULL) {
4206 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4209 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4212 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4215 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4219 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4220 if (ret != LDB_SUCCESS) {
4221 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
4222 ldb_dn_get_linearized(dn),
4223 ldb_errstring(ldb_module_get_ctx(ar->module))));
4233 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
4234 ldb_dn_get_linearized(dn)));
4235 return LDB_ERR_OPERATIONS_ERROR;
4240 callback for conflict DN handling where we have renamed the incoming
4241 record. After renaming it, we need to ensure the change of name and
4242 rDN for the incoming record is seen as an originating update by this DC.
4244 This also handles updating lastKnownParent for entries sent to lostAndFound
4246 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4248 struct replmd_replicated_request *ar =
4249 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4250 struct ldb_dn *conflict_dn = NULL;
4253 if (ares->error != LDB_SUCCESS) {
4254 /* call the normal callback for everything except success */
4255 return replmd_op_callback(req, ares);
4258 switch (req->operation) {
4260 conflict_dn = req->op.add.message->dn;
4263 conflict_dn = req->op.mod.message->dn;
4266 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4269 /* perform a modify of the rDN and name of the record */
4270 ret = replmd_name_modify(ar, req, conflict_dn);
4271 if (ret != LDB_SUCCESS) {
4273 return replmd_op_callback(req, ares);
4276 if (ar->objs->objects[ar->index_current].last_known_parent) {
4277 struct ldb_message *msg = ldb_msg_new(req);
4279 ldb_module_oom(ar->module);
4280 return LDB_ERR_OPERATIONS_ERROR;
4283 msg->dn = req->op.add.message->dn;
4285 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4286 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4287 if (ret != LDB_SUCCESS) {
4288 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4289 ldb_module_oom(ar->module);
4292 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4294 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4295 if (ret != LDB_SUCCESS) {
4296 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4297 ldb_dn_get_linearized(msg->dn),
4298 ldb_errstring(ldb_module_get_ctx(ar->module))));
4304 return replmd_op_callback(req, ares);
4308 callback for replmd_replicated_apply_add()
4309 This copes with the creation of conflict records in the case where
4310 the DN exists, but with a different objectGUID
4312 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))
4314 struct ldb_dn *conflict_dn;
4315 struct replmd_replicated_request *ar =
4316 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4317 struct ldb_result *res;
4318 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4320 const struct ldb_val *omd_value;
4321 struct replPropertyMetaDataBlob omd, *rmd;
4322 enum ndr_err_code ndr_err;
4323 bool rename_incoming_record, rodc;
4324 struct replPropertyMetaData1 *rmd_name, *omd_name;
4325 struct ldb_message *msg;
4326 struct ldb_request *down_req = NULL;
4328 /* call the normal callback for success */
4329 if (ares->error == LDB_SUCCESS) {
4330 return callback(req, ares);
4334 * we have a conflict, and need to decide if we will keep the
4335 * new record or the old record
4338 msg = ar->objs->objects[ar->index_current].msg;
4339 conflict_dn = msg->dn;
4341 /* For failures other than conflicts, fail the whole operation here */
4342 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4343 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4344 ldb_dn_get_linearized(conflict_dn),
4345 ldb_errstring(ldb_module_get_ctx(ar->module)));
4347 return ldb_module_done(ar->req, NULL, NULL,
4348 LDB_ERR_OPERATIONS_ERROR);
4351 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4352 if (ret != LDB_SUCCESS) {
4353 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)));
4354 return ldb_module_done(ar->req, NULL, NULL,
4355 LDB_ERR_OPERATIONS_ERROR);
4361 * We are on an RODC, or were a GC for this
4362 * partition, so we have to fail this until
4363 * someone who owns the partition sorts it
4366 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4367 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
4368 " - We must fail the operation until a master for this partition resolves the conflict",
4369 ldb_dn_get_linearized(conflict_dn));
4374 * first we need the replPropertyMetaData attribute from the
4375 * local, conflicting record
4377 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4379 DSDB_FLAG_NEXT_MODULE |
4380 DSDB_SEARCH_SHOW_DELETED |
4381 DSDB_SEARCH_SHOW_RECYCLED, req);
4382 if (ret != LDB_SUCCESS) {
4383 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4384 ldb_dn_get_linearized(conflict_dn)));
4388 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4389 if (omd_value == NULL) {
4390 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4391 ldb_dn_get_linearized(conflict_dn)));
4395 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4396 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4397 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4398 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4399 ldb_dn_get_linearized(conflict_dn)));
4403 rmd = ar->objs->objects[ar->index_current].meta_data;
4406 * we decide which is newer based on the RPMD on the name
4407 * attribute. See [MS-DRSR] ResolveNameConflict.
4409 * We expect omd_name to be present, as this is from a local
4410 * search, but while rmd_name should have been given to us by
4411 * the remote server, if it is missing we just prefer the
4413 * replmd_replPropertyMetaData1_new_should_be_taken()
4415 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4416 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4418 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4419 ldb_dn_get_linearized(conflict_dn)));
4424 * Should we preserve the current record, and so rename the
4425 * incoming record to be a conflict?
4427 rename_incoming_record
4428 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4429 omd_name, rmd_name);
4431 if (rename_incoming_record) {
4433 struct ldb_dn *new_dn;
4435 guid = samdb_result_guid(msg, "objectGUID");
4436 if (GUID_all_zero(&guid)) {
4437 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4438 ldb_dn_get_linearized(conflict_dn)));
4441 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4442 if (new_dn == NULL) {
4443 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4444 ldb_dn_get_linearized(conflict_dn)));
4448 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4449 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4451 /* re-submit the request, but with the new DN */
4452 callback = replmd_op_name_modify_callback;
4455 /* we are renaming the existing record */
4457 struct ldb_dn *new_dn;
4459 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4460 if (GUID_all_zero(&guid)) {
4461 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4462 ldb_dn_get_linearized(conflict_dn)));
4466 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4467 if (new_dn == NULL) {
4468 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4469 ldb_dn_get_linearized(conflict_dn)));
4473 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4474 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4476 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4477 DSDB_FLAG_OWN_MODULE, req);
4478 if (ret != LDB_SUCCESS) {
4479 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4480 ldb_dn_get_linearized(conflict_dn),
4481 ldb_dn_get_linearized(new_dn),
4482 ldb_errstring(ldb_module_get_ctx(ar->module))));
4487 * now we need to ensure that the rename is seen as an
4488 * originating update. We do that with a modify.
4490 ret = replmd_name_modify(ar, req, new_dn);
4491 if (ret != LDB_SUCCESS) {
4495 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4496 ldb_dn_get_linearized(req->op.add.message->dn)));
4499 ret = ldb_build_add_req(&down_req,
4500 ldb_module_get_ctx(ar->module),
4507 if (ret != LDB_SUCCESS) {
4510 LDB_REQ_SET_LOCATION(down_req);
4512 /* current partition control needed by "repmd_op_callback" */
4513 ret = ldb_request_add_control(down_req,
4514 DSDB_CONTROL_CURRENT_PARTITION_OID,
4516 if (ret != LDB_SUCCESS) {
4517 return replmd_replicated_request_error(ar, ret);
4520 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4521 /* this tells the partition module to make it a
4522 partial replica if creating an NC */
4523 ret = ldb_request_add_control(down_req,
4524 DSDB_CONTROL_PARTIAL_REPLICA,
4526 if (ret != LDB_SUCCESS) {
4527 return replmd_replicated_request_error(ar, ret);
4532 * Finally we re-run the add, otherwise the new record won't
4533 * exist, as we are here because of that exact failure!
4535 return ldb_next_request(ar->module, down_req);
4538 /* on failure make the caller get the error. This means
4539 * replication will stop with an error, but there is not much
4542 return ldb_module_done(ar->req, NULL, NULL,
4547 callback for replmd_replicated_apply_add()
4548 This copes with the creation of conflict records in the case where
4549 the DN exists, but with a different objectGUID
4551 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4553 struct replmd_replicated_request *ar =
4554 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4556 if (ar->objs->objects[ar->index_current].last_known_parent) {
4557 /* This is like a conflict DN, where we put the object in LostAndFound
4558 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4559 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4562 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4566 this is called when a new object comes in over DRS
4568 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4570 struct ldb_context *ldb;
4571 struct ldb_request *change_req;
4572 enum ndr_err_code ndr_err;
4573 struct ldb_message *msg;
4574 struct replPropertyMetaDataBlob *md;
4575 struct ldb_val md_value;
4578 bool remote_isDeleted = false;
4581 time_t t = time(NULL);
4582 const struct ldb_val *rdn_val;
4583 struct replmd_private *replmd_private =
4584 talloc_get_type(ldb_module_get_private(ar->module),
4585 struct replmd_private);
4586 unix_to_nt_time(&now, t);
4588 ldb = ldb_module_get_ctx(ar->module);
4589 msg = ar->objs->objects[ar->index_current].msg;
4590 md = ar->objs->objects[ar->index_current].meta_data;
4591 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4593 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4594 if (ret != LDB_SUCCESS) {
4595 return replmd_replicated_request_error(ar, ret);
4598 ret = dsdb_msg_add_guid(msg,
4599 &ar->objs->objects[ar->index_current].object_guid,
4601 if (ret != LDB_SUCCESS) {
4602 return replmd_replicated_request_error(ar, ret);
4605 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4606 if (ret != LDB_SUCCESS) {
4607 return replmd_replicated_request_error(ar, ret);
4610 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4611 if (ret != LDB_SUCCESS) {
4612 return replmd_replicated_request_error(ar, ret);
4615 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4616 if (ret != LDB_SUCCESS) {
4617 return replmd_replicated_request_error(ar, ret);
4620 /* remove any message elements that have zero values */
4621 for (i=0; i<msg->num_elements; i++) {
4622 struct ldb_message_element *el = &msg->elements[i];
4624 if (el->num_values == 0) {
4625 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4626 ldb_asprintf_errstring(ldb, __location__
4627 ": empty objectClass sent on %s, aborting replication\n",
4628 ldb_dn_get_linearized(msg->dn));
4629 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4632 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4634 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4635 msg->num_elements--;
4642 struct GUID_txt_buf guid_txt;
4644 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4645 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4646 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4651 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4652 "isDeleted", false);
4655 * the meta data array is already sorted by the caller, except
4656 * for the RDN, which needs to be added.
4660 rdn_val = ldb_dn_get_rdn_val(msg->dn);
4661 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4662 md, ar, now, is_schema_nc);
4663 if (ret != LDB_SUCCESS) {
4664 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4665 return replmd_replicated_request_error(ar, ret);
4668 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4669 if (ret != LDB_SUCCESS) {
4670 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4671 return replmd_replicated_request_error(ar, ret);
4674 for (i=0; i < md->ctr.ctr1.count; i++) {
4675 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4677 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4678 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4679 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4680 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4681 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4683 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4684 if (ret != LDB_SUCCESS) {
4685 return replmd_replicated_request_error(ar, ret);
4688 replmd_ldb_message_sort(msg, ar->schema);
4690 if (!remote_isDeleted) {
4691 ret = dsdb_module_schedule_sd_propagation(ar->module,
4692 ar->objs->partition_dn,
4694 if (ret != LDB_SUCCESS) {
4695 return replmd_replicated_request_error(ar, ret);
4699 ar->isDeleted = remote_isDeleted;
4701 ret = ldb_build_add_req(&change_req,
4707 replmd_op_add_callback,
4709 LDB_REQ_SET_LOCATION(change_req);
4710 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4712 /* current partition control needed by "repmd_op_callback" */
4713 ret = ldb_request_add_control(change_req,
4714 DSDB_CONTROL_CURRENT_PARTITION_OID,
4716 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4718 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4719 /* this tells the partition module to make it a
4720 partial replica if creating an NC */
4721 ret = ldb_request_add_control(change_req,
4722 DSDB_CONTROL_PARTIAL_REPLICA,
4724 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4727 return ldb_next_request(ar->module, change_req);
4730 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
4731 struct ldb_reply *ares)
4733 struct replmd_replicated_request *ar = talloc_get_type(req->context,
4734 struct replmd_replicated_request);
4738 return ldb_module_done(ar->req, NULL, NULL,
4739 LDB_ERR_OPERATIONS_ERROR);
4743 * The error NO_SUCH_OBJECT is not expected, unless the search
4744 * base is the partition DN, and that case doesn't happen here
4745 * because then we wouldn't get a parent_guid_value in any
4748 if (ares->error != LDB_SUCCESS) {
4749 return ldb_module_done(ar->req, ares->controls,
4750 ares->response, ares->error);
4753 switch (ares->type) {
4754 case LDB_REPLY_ENTRY:
4756 struct ldb_message *parent_msg = ares->message;
4757 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
4758 struct ldb_dn *parent_dn;
4761 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
4762 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
4763 /* Per MS-DRSR 4.1.10.6.10
4764 * FindBestParentObject we need to move this
4765 * new object under a deleted object to
4767 struct ldb_dn *nc_root;
4769 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
4770 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4771 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4772 "No suitable NC root found for %s. "
4773 "We need to move this object because parent object %s "
4774 "is deleted, but this object is not.",
4775 ldb_dn_get_linearized(msg->dn),
4776 ldb_dn_get_linearized(parent_msg->dn));
4777 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4778 } else if (ret != LDB_SUCCESS) {
4779 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4780 "Unable to find NC root for %s: %s. "
4781 "We need to move this object because parent object %s "
4782 "is deleted, but this object is not.",
4783 ldb_dn_get_linearized(msg->dn),
4784 ldb_errstring(ldb_module_get_ctx(ar->module)),
4785 ldb_dn_get_linearized(parent_msg->dn));
4786 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4789 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
4791 DS_GUID_LOSTANDFOUND_CONTAINER,
4793 if (ret != LDB_SUCCESS) {
4794 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4795 "Unable to find LostAndFound Container for %s "
4796 "in partition %s: %s. "
4797 "We need to move this object because parent object %s "
4798 "is deleted, but this object is not.",
4799 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
4800 ldb_errstring(ldb_module_get_ctx(ar->module)),
4801 ldb_dn_get_linearized(parent_msg->dn));
4802 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4804 ar->objs->objects[ar->index_current].last_known_parent
4805 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4809 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4812 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
4814 comp_num = ldb_dn_get_comp_num(msg->dn);
4816 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
4818 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4821 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
4823 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4827 case LDB_REPLY_REFERRAL:
4828 /* we ignore referrals */
4831 case LDB_REPLY_DONE:
4833 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
4834 struct GUID_txt_buf str_buf;
4835 if (ar->search_msg != NULL) {
4836 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4837 "No parent with GUID %s found for object locally known as %s",
4838 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4839 ldb_dn_get_linearized(ar->search_msg->dn));
4841 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4842 "No parent with GUID %s found for object remotely known as %s",
4843 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4844 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
4848 * This error code is really important, as it
4849 * is the flag back to the callers to retry
4850 * this with DRSUAPI_DRS_GET_ANC, and so get
4851 * the parent objects before the child
4854 return ldb_module_done(ar->req, NULL, NULL,
4855 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
4858 if (ar->search_msg != NULL) {
4859 ret = replmd_replicated_apply_merge(ar);
4861 ret = replmd_replicated_apply_add(ar);
4863 if (ret != LDB_SUCCESS) {
4864 return ldb_module_done(ar->req, NULL, NULL, ret);
4873 * Look for the parent object, so we put the new object in the right
4874 * place This is akin to NameObject in MS-DRSR - this routine and the
4875 * callbacks find the right parent name, and correct name for this
4879 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
4881 struct ldb_context *ldb;
4885 struct ldb_request *search_req;
4886 static const char *attrs[] = {"isDeleted", NULL};
4887 struct GUID_txt_buf guid_str_buf;
4889 ldb = ldb_module_get_ctx(ar->module);
4891 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
4892 if (ar->search_msg != NULL) {
4893 return replmd_replicated_apply_merge(ar);
4895 return replmd_replicated_apply_add(ar);
4899 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
4902 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
4903 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
4905 ret = ldb_build_search_req(&search_req,
4908 ar->objs->partition_dn,
4914 replmd_replicated_apply_search_for_parent_callback,
4916 LDB_REQ_SET_LOCATION(search_req);
4918 ret = dsdb_request_add_controls(search_req,
4919 DSDB_SEARCH_SHOW_RECYCLED|
4920 DSDB_SEARCH_SHOW_DELETED|
4921 DSDB_SEARCH_SHOW_EXTENDED_DN);
4922 if (ret != LDB_SUCCESS) {
4926 return ldb_next_request(ar->module, search_req);
4930 handle renames that come in over DRS replication
4932 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
4933 struct ldb_message *msg,
4934 struct ldb_request *parent,
4938 TALLOC_CTX *tmp_ctx = talloc_new(msg);
4939 struct ldb_result *res;
4940 struct ldb_dn *conflict_dn;
4941 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4942 const struct ldb_val *omd_value;
4943 struct replPropertyMetaDataBlob omd, *rmd;
4944 enum ndr_err_code ndr_err;
4945 bool rename_incoming_record, rodc;
4946 struct replPropertyMetaData1 *rmd_name, *omd_name;
4947 struct ldb_dn *new_dn;
4950 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
4951 ldb_dn_get_linearized(ar->search_msg->dn),
4952 ldb_dn_get_linearized(msg->dn)));
4955 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
4956 DSDB_FLAG_NEXT_MODULE, ar->req);
4957 if (ret == LDB_SUCCESS) {
4958 talloc_free(tmp_ctx);
4963 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4964 talloc_free(tmp_ctx);
4965 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
4966 ldb_dn_get_linearized(ar->search_msg->dn),
4967 ldb_dn_get_linearized(msg->dn),
4968 ldb_errstring(ldb_module_get_ctx(ar->module)));
4972 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4973 if (ret != LDB_SUCCESS) {
4974 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4975 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
4976 ldb_errstring(ldb_module_get_ctx(ar->module)));
4977 return LDB_ERR_OPERATIONS_ERROR;
4980 * we have a conflict, and need to decide if we will keep the
4981 * new record or the old record
4984 conflict_dn = msg->dn;
4988 * We are on an RODC, or were a GC for this
4989 * partition, so we have to fail this until
4990 * someone who owns the partition sorts it
4993 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4994 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
4995 " - We must fail the operation until a master for this partition resolves the conflict",
4996 ldb_dn_get_linearized(conflict_dn));
5001 * first we need the replPropertyMetaData attribute from the
5004 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5006 DSDB_FLAG_NEXT_MODULE |
5007 DSDB_SEARCH_SHOW_DELETED |
5008 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5009 if (ret != LDB_SUCCESS) {
5010 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5011 ldb_dn_get_linearized(conflict_dn)));
5015 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5016 if (omd_value == NULL) {
5017 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5018 ldb_dn_get_linearized(conflict_dn)));
5022 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5023 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5024 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5025 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5026 ldb_dn_get_linearized(conflict_dn)));
5030 rmd = ar->objs->objects[ar->index_current].meta_data;
5033 * we decide which is newer based on the RPMD on the name
5034 * attribute. See [MS-DRSR] ResolveNameConflict.
5036 * We expect omd_name to be present, as this is from a local
5037 * search, but while rmd_name should have been given to us by
5038 * the remote server, if it is missing we just prefer the
5040 * replmd_replPropertyMetaData1_new_should_be_taken()
5042 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5043 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5045 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5046 ldb_dn_get_linearized(conflict_dn)));
5051 * Should we preserve the current record, and so rename the
5052 * incoming record to be a conflict?
5054 rename_incoming_record =
5055 !replmd_replPropertyMetaData1_new_should_be_taken(
5056 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5057 omd_name, rmd_name);
5059 if (rename_incoming_record) {
5061 new_dn = replmd_conflict_dn(msg, msg->dn,
5062 &ar->objs->objects[ar->index_current].object_guid);
5063 if (new_dn == NULL) {
5064 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5065 "Failed to form conflict DN for %s\n",
5066 ldb_dn_get_linearized(msg->dn));
5068 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5071 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5072 DSDB_FLAG_NEXT_MODULE, ar->req);
5073 if (ret != LDB_SUCCESS) {
5074 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5075 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5076 ldb_dn_get_linearized(conflict_dn),
5077 ldb_dn_get_linearized(ar->search_msg->dn),
5078 ldb_dn_get_linearized(new_dn),
5079 ldb_errstring(ldb_module_get_ctx(ar->module)));
5080 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5088 /* we are renaming the existing record */
5090 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5091 if (GUID_all_zero(&guid)) {
5092 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5093 ldb_dn_get_linearized(conflict_dn)));
5097 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5098 if (new_dn == NULL) {
5099 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5100 ldb_dn_get_linearized(conflict_dn)));
5104 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5105 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5107 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5108 DSDB_FLAG_OWN_MODULE, ar->req);
5109 if (ret != LDB_SUCCESS) {
5110 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5111 ldb_dn_get_linearized(conflict_dn),
5112 ldb_dn_get_linearized(new_dn),
5113 ldb_errstring(ldb_module_get_ctx(ar->module))));
5118 * now we need to ensure that the rename is seen as an
5119 * originating update. We do that with a modify.
5121 ret = replmd_name_modify(ar, ar->req, new_dn);
5122 if (ret != LDB_SUCCESS) {
5126 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5127 ldb_dn_get_linearized(ar->search_msg->dn),
5128 ldb_dn_get_linearized(msg->dn)));
5131 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5132 DSDB_FLAG_NEXT_MODULE, ar->req);
5133 if (ret != LDB_SUCCESS) {
5134 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5135 ldb_dn_get_linearized(ar->search_msg->dn),
5136 ldb_dn_get_linearized(msg->dn),
5137 ldb_errstring(ldb_module_get_ctx(ar->module))));
5143 * On failure make the caller get the error
5144 * This means replication will stop with an error,
5145 * but there is not much else we can do. In the
5146 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5150 talloc_free(tmp_ctx);
5155 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5157 struct ldb_context *ldb;
5158 struct ldb_request *change_req;
5159 enum ndr_err_code ndr_err;
5160 struct ldb_message *msg;
5161 struct replPropertyMetaDataBlob *rmd;
5162 struct replPropertyMetaDataBlob omd;
5163 const struct ldb_val *omd_value;
5164 struct replPropertyMetaDataBlob nmd;
5165 struct ldb_val nmd_value;
5166 struct GUID remote_parent_guid;
5169 unsigned int removed_attrs = 0;
5171 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5172 bool isDeleted = false;
5173 bool local_isDeleted = false;
5174 bool remote_isDeleted = false;
5175 bool take_remote_isDeleted = false;
5176 bool sd_updated = false;
5177 bool renamed = false;
5178 bool is_schema_nc = false;
5180 const struct ldb_val *old_rdn, *new_rdn;
5181 struct replmd_private *replmd_private =
5182 talloc_get_type(ldb_module_get_private(ar->module),
5183 struct replmd_private);
5185 time_t t = time(NULL);
5186 unix_to_nt_time(&now, t);
5188 ldb = ldb_module_get_ctx(ar->module);
5189 msg = ar->objs->objects[ar->index_current].msg;
5191 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5193 rmd = ar->objs->objects[ar->index_current].meta_data;
5197 /* find existing meta data */
5198 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5200 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5201 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5202 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5203 nt_status = ndr_map_error2ntstatus(ndr_err);
5204 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5207 if (omd.version != 1) {
5208 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5213 struct GUID_txt_buf guid_txt;
5215 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5216 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
5219 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5221 ndr_print_struct_string(s,
5222 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5223 "existing replPropertyMetaData",
5225 ndr_print_struct_string(s,
5226 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5227 "incoming replPropertyMetaData",
5232 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5233 "isDeleted", false);
5234 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5235 "isDeleted", false);
5238 * Fill in the remote_parent_guid with the GUID or an all-zero
5241 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5242 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5244 remote_parent_guid = GUID_zero();
5248 * To ensure we follow a complex rename chain around, we have
5249 * to confirm that the DN is the same (mostly to confirm the
5250 * RDN) and the parentGUID is the same.
5252 * This ensures we keep things under the correct parent, which
5253 * replmd_replicated_handle_rename() will do.
5256 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5257 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5261 * handle renames, even just by case that come in over
5262 * DRS. Changes in the parent DN don't hit us here,
5263 * because the search for a parent will clean up those
5266 * We also have already filtered out the case where
5267 * the peer has an older name to what we have (see
5268 * replmd_replicated_apply_search_callback())
5270 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5273 if (ret != LDB_SUCCESS) {
5274 ldb_debug(ldb, LDB_DEBUG_FATAL,
5275 "replmd_replicated_request rename %s => %s failed - %s\n",
5276 ldb_dn_get_linearized(ar->search_msg->dn),
5277 ldb_dn_get_linearized(msg->dn),
5278 ldb_errstring(ldb));
5279 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5282 if (renamed == true) {
5284 * Set the callback to one that will fix up the name
5285 * metadata on the new conflict DN
5287 callback = replmd_op_name_modify_callback;
5292 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5293 nmd.ctr.ctr1.array = talloc_array(ar,
5294 struct replPropertyMetaData1,
5295 nmd.ctr.ctr1.count);
5296 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5298 /* first copy the old meta data */
5299 for (i=0; i < omd.ctr.ctr1.count; i++) {
5300 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5305 /* now merge in the new meta data */
5306 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5309 for (j=0; j < ni; j++) {
5312 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5316 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5317 ar->objs->dsdb_repl_flags,
5318 &nmd.ctr.ctr1.array[j],
5319 &rmd->ctr.ctr1.array[i]);
5321 /* replace the entry */
5322 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5323 if (ar->seq_num == 0) {
5324 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5325 if (ret != LDB_SUCCESS) {
5326 return replmd_replicated_request_error(ar, ret);
5329 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5330 switch (nmd.ctr.ctr1.array[j].attid) {
5331 case DRSUAPI_ATTID_ntSecurityDescriptor:
5334 case DRSUAPI_ATTID_isDeleted:
5335 take_remote_isDeleted = true;
5344 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5345 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5346 msg->elements[i-removed_attrs].name,
5347 ldb_dn_get_linearized(msg->dn),
5348 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5351 /* we don't want to apply this change so remove the attribute */
5352 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5359 if (found) continue;
5361 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5362 if (ar->seq_num == 0) {
5363 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5364 if (ret != LDB_SUCCESS) {
5365 return replmd_replicated_request_error(ar, ret);
5368 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5369 switch (nmd.ctr.ctr1.array[ni].attid) {
5370 case DRSUAPI_ATTID_ntSecurityDescriptor:
5373 case DRSUAPI_ATTID_isDeleted:
5374 take_remote_isDeleted = true;
5383 * finally correct the size of the meta_data array
5385 nmd.ctr.ctr1.count = ni;
5387 new_rdn = ldb_dn_get_rdn_val(msg->dn);
5388 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5391 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5392 &nmd, ar, now, is_schema_nc);
5393 if (ret != LDB_SUCCESS) {
5394 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5395 return replmd_replicated_request_error(ar, ret);
5399 * sort the new meta data array
5401 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5402 if (ret != LDB_SUCCESS) {
5403 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5408 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
5411 * This also controls SD propagation below
5413 if (take_remote_isDeleted) {
5414 isDeleted = remote_isDeleted;
5416 isDeleted = local_isDeleted;
5419 ar->isDeleted = isDeleted;
5422 * check if some replicated attributes left, otherwise skip the ldb_modify() call
5424 if (msg->num_elements == 0) {
5425 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5428 return replmd_replicated_apply_isDeleted(ar);
5431 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5432 ar->index_current, msg->num_elements);
5438 if (sd_updated && !isDeleted) {
5439 ret = dsdb_module_schedule_sd_propagation(ar->module,
5440 ar->objs->partition_dn,
5442 if (ret != LDB_SUCCESS) {
5443 return ldb_operr(ldb);
5447 /* create the meta data value */
5448 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5449 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5450 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5451 nt_status = ndr_map_error2ntstatus(ndr_err);
5452 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5456 * when we know that we'll modify the record, add the whenChanged, uSNChanged
5457 * and replPopertyMetaData attributes
5459 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5460 if (ret != LDB_SUCCESS) {
5461 return replmd_replicated_request_error(ar, ret);
5463 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5464 if (ret != LDB_SUCCESS) {
5465 return replmd_replicated_request_error(ar, ret);
5467 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5468 if (ret != LDB_SUCCESS) {
5469 return replmd_replicated_request_error(ar, ret);
5472 replmd_ldb_message_sort(msg, ar->schema);
5474 /* we want to replace the old values */
5475 for (i=0; i < msg->num_elements; i++) {
5476 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5477 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5478 if (msg->elements[i].num_values == 0) {
5479 ldb_asprintf_errstring(ldb, __location__
5480 ": objectClass removed on %s, aborting replication\n",
5481 ldb_dn_get_linearized(msg->dn));
5482 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5488 struct GUID_txt_buf guid_txt;
5490 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5491 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5492 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5497 ret = ldb_build_mod_req(&change_req,
5505 LDB_REQ_SET_LOCATION(change_req);
5506 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5508 /* current partition control needed by "repmd_op_callback" */
5509 ret = ldb_request_add_control(change_req,
5510 DSDB_CONTROL_CURRENT_PARTITION_OID,
5512 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5514 return ldb_next_request(ar->module, change_req);
5517 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5518 struct ldb_reply *ares)
5520 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5521 struct replmd_replicated_request);
5525 return ldb_module_done(ar->req, NULL, NULL,
5526 LDB_ERR_OPERATIONS_ERROR);
5528 if (ares->error != LDB_SUCCESS &&
5529 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5530 return ldb_module_done(ar->req, ares->controls,
5531 ares->response, ares->error);
5534 switch (ares->type) {
5535 case LDB_REPLY_ENTRY:
5536 ar->search_msg = talloc_steal(ar, ares->message);
5539 case LDB_REPLY_REFERRAL:
5540 /* we ignore referrals */
5543 case LDB_REPLY_DONE:
5545 struct replPropertyMetaData1 *md_remote;
5546 struct replPropertyMetaData1 *md_local;
5548 struct replPropertyMetaDataBlob omd;
5549 const struct ldb_val *omd_value;
5550 struct replPropertyMetaDataBlob *rmd;
5551 struct ldb_message *msg;
5553 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5554 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5557 * This is the ADD case, find the appropriate parent,
5558 * as this object doesn't exist locally:
5560 if (ar->search_msg == NULL) {
5561 ret = replmd_replicated_apply_search_for_parent(ar);
5562 if (ret != LDB_SUCCESS) {
5563 return ldb_module_done(ar->req, NULL, NULL, ret);
5570 * Otherwise, in the MERGE case, work out if we are
5571 * attempting a rename, and if so find the parent the
5572 * newly renamed object wants to belong under (which
5573 * may not be the parent in it's attached string DN
5575 rmd = ar->objs->objects[ar->index_current].meta_data;
5579 /* find existing meta data */
5580 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5582 enum ndr_err_code ndr_err;
5583 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5584 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5585 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5586 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5587 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5590 if (omd.version != 1) {
5591 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5595 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5597 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5598 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5599 && GUID_all_zero(&ar->local_parent_guid)) {
5600 DEBUG(0, ("Refusing to replicate new version of %s "
5601 "as local object has an all-zero parentGUID attribute, "
5602 "despite not being an NC root\n",
5603 ldb_dn_get_linearized(ar->search_msg->dn)));
5604 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5608 * now we need to check for double renames. We could have a
5609 * local rename pending which our replication partner hasn't
5610 * received yet. We choose which one wins by looking at the
5611 * attribute stamps on the two objects, the newer one wins.
5613 * This also simply applies the correct algorithms for
5614 * determining if a change was made to name at all, or
5615 * if the object has just been renamed under the same
5618 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5619 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5621 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5622 ldb_dn_get_linearized(ar->search_msg->dn)));
5623 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5627 * if there is no name attribute given then we have to assume the
5628 * object we've received has the older name
5630 if (replmd_replPropertyMetaData1_new_should_be_taken(
5631 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5632 md_local, md_remote)) {
5633 struct GUID_txt_buf p_guid_local;
5634 struct GUID_txt_buf p_guid_remote;
5635 msg = ar->objs->objects[ar->index_current].msg;
5637 /* Merge on the existing object, with rename */
5639 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5640 "as incoming object changing to %s under %s\n",
5641 ldb_dn_get_linearized(ar->search_msg->dn),
5642 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5643 ldb_dn_get_linearized(msg->dn),
5644 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5646 ret = replmd_replicated_apply_search_for_parent(ar);
5648 struct GUID_txt_buf p_guid_local;
5649 struct GUID_txt_buf p_guid_remote;
5650 msg = ar->objs->objects[ar->index_current].msg;
5653 * Merge on the existing object, force no
5654 * rename (code below just to explain why in
5658 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5659 ldb_dn_get_linearized(msg->dn)) == 0) {
5660 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5661 GUID_equal(&ar->local_parent_guid,
5662 ar->objs->objects[ar->index_current].parent_guid)
5664 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5665 "despite incoming object changing parent to %s\n",
5666 ldb_dn_get_linearized(ar->search_msg->dn),
5667 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5668 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5672 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5673 " and rejecting older rename to %s under %s\n",
5674 ldb_dn_get_linearized(ar->search_msg->dn),
5675 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5676 ldb_dn_get_linearized(msg->dn),
5677 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5681 * This assignment ensures that the strcmp()
5682 * and GUID_equal() calls in
5683 * replmd_replicated_apply_merge() avoids the
5686 ar->objs->objects[ar->index_current].parent_guid =
5687 &ar->local_parent_guid;
5689 msg->dn = ar->search_msg->dn;
5690 ret = replmd_replicated_apply_merge(ar);
5692 if (ret != LDB_SUCCESS) {
5693 return ldb_module_done(ar->req, NULL, NULL, ret);
5702 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
5704 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
5706 struct ldb_context *ldb;
5710 struct ldb_request *search_req;
5711 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
5712 "parentGUID", "instanceType",
5713 "replPropertyMetaData", "nTSecurityDescriptor",
5714 "isDeleted", NULL };
5715 struct GUID_txt_buf guid_str_buf;
5717 if (ar->index_current >= ar->objs->num_objects) {
5718 /* done with it, go to next stage */
5719 return replmd_replicated_uptodate_vector(ar);
5722 ldb = ldb_module_get_ctx(ar->module);
5723 ar->search_msg = NULL;
5724 ar->isDeleted = false;
5726 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5729 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5730 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5732 ret = ldb_build_search_req(&search_req,
5735 ar->objs->partition_dn,
5741 replmd_replicated_apply_search_callback,
5743 LDB_REQ_SET_LOCATION(search_req);
5745 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
5747 if (ret != LDB_SUCCESS) {
5751 return ldb_next_request(ar->module, search_req);
5755 * This is essentially a wrapper for replmd_replicated_apply_next()
5757 * This is needed to ensure that both codepaths call this handler.
5759 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
5761 struct ldb_dn *deleted_objects_dn;
5762 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5763 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
5764 &deleted_objects_dn);
5765 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
5767 * Do a delete here again, so that if there is
5768 * anything local that conflicts with this
5769 * object being deleted, it is removed. This
5770 * includes links. See MS-DRSR 4.1.10.6.9
5773 * If the object is already deleted, and there
5774 * is no more work required, it doesn't do
5778 /* This has been updated to point to the DN we eventually did the modify on */
5780 struct ldb_request *del_req;
5781 struct ldb_result *res;
5783 TALLOC_CTX *tmp_ctx = talloc_new(ar);
5785 ret = ldb_oom(ldb_module_get_ctx(ar->module));
5789 res = talloc_zero(tmp_ctx, struct ldb_result);
5791 ret = ldb_oom(ldb_module_get_ctx(ar->module));
5792 talloc_free(tmp_ctx);
5796 /* Build a delete request, which hopefully will artually turn into nothing */
5797 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
5801 ldb_modify_default_callback,
5803 LDB_REQ_SET_LOCATION(del_req);
5804 if (ret != LDB_SUCCESS) {
5805 talloc_free(tmp_ctx);
5810 * This is the guts of the call, call back
5811 * into our delete code, but setting the
5812 * re_delete flag so we delete anything that
5813 * shouldn't be there on a deleted or recycled
5816 ret = replmd_delete_internals(ar->module, del_req, true);
5817 if (ret == LDB_SUCCESS) {
5818 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
5821 talloc_free(tmp_ctx);
5822 if (ret != LDB_SUCCESS) {
5827 ar->index_current++;
5828 return replmd_replicated_apply_next(ar);
5831 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
5832 struct ldb_reply *ares)
5834 struct ldb_context *ldb;
5835 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5836 struct replmd_replicated_request);
5837 ldb = ldb_module_get_ctx(ar->module);
5840 return ldb_module_done(ar->req, NULL, NULL,
5841 LDB_ERR_OPERATIONS_ERROR);
5843 if (ares->error != LDB_SUCCESS) {
5844 return ldb_module_done(ar->req, ares->controls,
5845 ares->response, ares->error);
5848 if (ares->type != LDB_REPLY_DONE) {
5849 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
5850 return ldb_module_done(ar->req, NULL, NULL,
5851 LDB_ERR_OPERATIONS_ERROR);
5856 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5859 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
5861 struct ldb_context *ldb;
5862 struct ldb_request *change_req;
5863 enum ndr_err_code ndr_err;
5864 struct ldb_message *msg;
5865 struct replUpToDateVectorBlob ouv;
5866 const struct ldb_val *ouv_value;
5867 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
5868 struct replUpToDateVectorBlob nuv;
5869 struct ldb_val nuv_value;
5870 struct ldb_message_element *nuv_el = NULL;
5871 struct ldb_message_element *orf_el = NULL;
5872 struct repsFromToBlob nrf;
5873 struct ldb_val *nrf_value = NULL;
5874 struct ldb_message_element *nrf_el = NULL;
5878 time_t t = time(NULL);
5881 uint32_t instanceType;
5883 ldb = ldb_module_get_ctx(ar->module);
5884 ruv = ar->objs->uptodateness_vector;
5890 unix_to_nt_time(&now, t);
5892 if (ar->search_msg == NULL) {
5893 /* this happens for a REPL_OBJ call where we are
5894 creating the target object by replicating it. The
5895 subdomain join code does this for the partition DN
5897 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
5898 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5901 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
5902 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
5903 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
5904 ldb_dn_get_linearized(ar->search_msg->dn)));
5905 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5909 * first create the new replUpToDateVector
5911 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
5913 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
5914 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
5915 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5916 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5917 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5920 if (ouv.version != 2) {
5921 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5926 * the new uptodateness vector will at least
5927 * contain 1 entry, one for the source_dsa
5929 * plus optional values from our old vector and the one from the source_dsa
5931 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
5932 if (ruv) nuv.ctr.ctr2.count += ruv->count;
5933 nuv.ctr.ctr2.cursors = talloc_array(ar,
5934 struct drsuapi_DsReplicaCursor2,
5935 nuv.ctr.ctr2.count);
5936 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5938 /* first copy the old vector */
5939 for (i=0; i < ouv.ctr.ctr2.count; i++) {
5940 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
5944 /* merge in the source_dsa vector is available */
5945 for (i=0; (ruv && i < ruv->count); i++) {
5948 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
5949 &ar->our_invocation_id)) {
5953 for (j=0; j < ni; j++) {
5954 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
5955 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
5961 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
5962 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
5967 if (found) continue;
5969 /* if it's not there yet, add it */
5970 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
5975 * finally correct the size of the cursors array
5977 nuv.ctr.ctr2.count = ni;
5982 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
5985 * create the change ldb_message
5987 msg = ldb_msg_new(ar);
5988 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5989 msg->dn = ar->search_msg->dn;
5991 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
5992 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
5993 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5994 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5995 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5997 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
5998 if (ret != LDB_SUCCESS) {
5999 return replmd_replicated_request_error(ar, ret);
6001 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6004 * now create the new repsFrom value from the given repsFromTo1 structure
6008 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6009 nrf.ctr.ctr1.last_attempt = now;
6010 nrf.ctr.ctr1.last_success = now;
6011 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6014 * first see if we already have a repsFrom value for the current source dsa
6015 * if so we'll later replace this value
6017 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6019 for (i=0; i < orf_el->num_values; i++) {
6020 struct repsFromToBlob *trf;
6022 trf = talloc(ar, struct repsFromToBlob);
6023 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6025 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6026 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6027 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6028 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6029 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6032 if (trf->version != 1) {
6033 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6037 * we compare the source dsa objectGUID not the invocation_id
6038 * because we want only one repsFrom value per source dsa
6039 * and when the invocation_id of the source dsa has changed we don't need
6040 * the old repsFrom with the old invocation_id
6042 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6043 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6049 nrf_value = &orf_el->values[i];
6054 * copy over all old values to the new ldb_message
6056 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6057 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6062 * if we haven't found an old repsFrom value for the current source dsa
6063 * we'll add a new value
6066 struct ldb_val zero_value;
6067 ZERO_STRUCT(zero_value);
6068 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6069 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6071 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6074 /* we now fill the value which is already attached to ldb_message */
6075 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6077 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6078 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6079 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6080 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6084 * the ldb_message_element for the attribute, has all the old values and the new one
6085 * so we'll replace the whole attribute with all values
6087 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6089 if (CHECK_DEBUGLVL(4)) {
6090 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
6091 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6095 /* prepare the ldb_modify() request */
6096 ret = ldb_build_mod_req(&change_req,
6102 replmd_replicated_uptodate_modify_callback,
6104 LDB_REQ_SET_LOCATION(change_req);
6105 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6107 return ldb_next_request(ar->module, change_req);
6110 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6111 struct ldb_reply *ares)
6113 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6114 struct replmd_replicated_request);
6118 return ldb_module_done(ar->req, NULL, NULL,
6119 LDB_ERR_OPERATIONS_ERROR);
6121 if (ares->error != LDB_SUCCESS &&
6122 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6123 return ldb_module_done(ar->req, ares->controls,
6124 ares->response, ares->error);
6127 switch (ares->type) {
6128 case LDB_REPLY_ENTRY:
6129 ar->search_msg = talloc_steal(ar, ares->message);
6132 case LDB_REPLY_REFERRAL:
6133 /* we ignore referrals */
6136 case LDB_REPLY_DONE:
6137 ret = replmd_replicated_uptodate_modify(ar);
6138 if (ret != LDB_SUCCESS) {
6139 return ldb_module_done(ar->req, NULL, NULL, ret);
6148 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6150 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6151 struct replmd_private *replmd_private =
6152 talloc_get_type_abort(ldb_module_get_private(ar->module),
6153 struct replmd_private);
6155 static const char *attrs[] = {
6156 "replUpToDateVector",
6161 struct ldb_request *search_req;
6163 ar->search_msg = NULL;
6166 * Let the caller know that we did an originating updates
6168 ar->objs->originating_updates = replmd_private->originating_updates;
6170 ret = ldb_build_search_req(&search_req,
6173 ar->objs->partition_dn,
6179 replmd_replicated_uptodate_search_callback,
6181 LDB_REQ_SET_LOCATION(search_req);
6182 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6184 return ldb_next_request(ar->module, search_req);
6189 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6191 struct ldb_context *ldb;
6192 struct dsdb_extended_replicated_objects *objs;
6193 struct replmd_replicated_request *ar;
6194 struct ldb_control **ctrls;
6197 struct replmd_private *replmd_private =
6198 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6200 ldb = ldb_module_get_ctx(module);
6202 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6204 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6206 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6207 return LDB_ERR_PROTOCOL_ERROR;
6210 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6211 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6212 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6213 return LDB_ERR_PROTOCOL_ERROR;
6216 ar = replmd_ctx_init(module, req);
6218 return LDB_ERR_OPERATIONS_ERROR;
6220 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6221 ar->apply_mode = true;
6223 ar->schema = dsdb_get_schema(ldb, ar);
6225 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6227 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6228 return LDB_ERR_CONSTRAINT_VIOLATION;
6231 ctrls = req->controls;
6233 if (req->controls) {
6234 req->controls = talloc_memdup(ar, req->controls,
6235 talloc_get_size(req->controls));
6236 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6239 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6240 if (ret != LDB_SUCCESS) {
6244 /* If this change contained linked attributes in the body
6245 * (rather than in the links section) we need to update
6246 * backlinks in linked_attributes */
6247 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6248 if (ret != LDB_SUCCESS) {
6252 ar->controls = req->controls;
6253 req->controls = ctrls;
6255 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
6257 /* save away the linked attributes for the end of the
6259 for (i=0; i<ar->objs->linked_attributes_count; i++) {
6260 struct la_entry *la_entry;
6262 if (replmd_private->la_ctx == NULL) {
6263 replmd_private->la_ctx = talloc_new(replmd_private);
6265 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6266 if (la_entry == NULL) {
6268 return LDB_ERR_OPERATIONS_ERROR;
6270 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6271 if (la_entry->la == NULL) {
6272 talloc_free(la_entry);
6274 return LDB_ERR_OPERATIONS_ERROR;
6276 *la_entry->la = ar->objs->linked_attributes[i];
6278 /* we need to steal the non-scalars so they stay
6279 around until the end of the transaction */
6280 talloc_steal(la_entry->la, la_entry->la->identifier);
6281 talloc_steal(la_entry->la, la_entry->la->value.blob);
6283 DLIST_ADD(replmd_private->la_list, la_entry);
6286 return replmd_replicated_apply_next(ar);
6290 process one linked attribute structure
6292 static int replmd_process_linked_attribute(struct ldb_module *module,
6293 struct replmd_private *replmd_private,
6294 struct la_entry *la_entry,
6295 struct ldb_request *parent)
6297 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6298 struct ldb_context *ldb = ldb_module_get_ctx(module);
6299 struct ldb_message *msg;
6300 struct ldb_message *target_msg = NULL;
6301 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6302 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
6304 const struct dsdb_attribute *attr;
6305 struct dsdb_dn *dsdb_dn;
6306 uint64_t seq_num = 0;
6307 struct ldb_message_element *old_el;
6309 time_t t = time(NULL);
6310 struct ldb_result *res;
6311 struct ldb_result *target_res;
6312 const char *attrs[4];
6313 const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
6314 struct parsed_dn *pdn_list, *pdn, *next;
6315 struct GUID guid = GUID_zero();
6317 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
6318 const struct GUID *our_invocation_id;
6320 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
6321 enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
6324 linked_attributes[0]:
6325 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6327 identifier: struct drsuapi_DsReplicaObjectIdentifier
6328 __ndr_size : 0x0000003a (58)
6329 __ndr_size_sid : 0x00000000 (0)
6330 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6332 __ndr_size_dn : 0x00000000 (0)
6334 attid : DRSUAPI_ATTID_member (0x1F)
6335 value: struct drsuapi_DsAttributeValue
6336 __ndr_size : 0x0000007e (126)
6338 blob : DATA_BLOB length=126
6339 flags : 0x00000001 (1)
6340 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6341 originating_add_time : Wed Sep 2 22:20:01 2009 EST
6342 meta_data: struct drsuapi_DsReplicaMetaData
6343 version : 0x00000015 (21)
6344 originating_change_time : Wed Sep 2 23:39:07 2009 EST
6345 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6346 originating_usn : 0x000000000001e19c (123292)
6348 (for cases where the link is to a normal DN)
6349 &target: struct drsuapi_DsReplicaObjectIdentifier3
6350 __ndr_size : 0x0000007e (126)
6351 __ndr_size_sid : 0x0000001c (28)
6352 guid : 7639e594-db75-4086-b0d4-67890ae46031
6353 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
6354 __ndr_size_dn : 0x00000022 (34)
6355 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
6358 /* find the attribute being modified */
6359 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
6361 struct GUID_txt_buf guid_str;
6362 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
6364 GUID_buf_string(&la->identifier->guid,
6366 talloc_free(tmp_ctx);
6367 return LDB_ERR_OPERATIONS_ERROR;
6370 attrs[0] = attr->lDAPDisplayName;
6371 attrs[1] = "isDeleted";
6372 attrs[2] = "isRecycled";
6375 /* get the existing message from the db for the object with
6376 this GUID, returning attribute being modified. We will then
6377 use this msg as the basis for a modify call */
6378 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
6379 DSDB_FLAG_NEXT_MODULE |
6380 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6381 DSDB_SEARCH_SHOW_RECYCLED |
6382 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
6383 DSDB_SEARCH_REVEAL_INTERNALS,
6385 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
6386 if (ret != LDB_SUCCESS) {
6387 talloc_free(tmp_ctx);
6390 if (res->count != 1) {
6391 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
6392 GUID_string(tmp_ctx, &la->identifier->guid));
6393 talloc_free(tmp_ctx);
6394 return LDB_ERR_NO_SUCH_OBJECT;
6399 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6400 * ProcessLinkValue, because link updates are not applied to
6401 * recycled and tombstone objects. We don't have to delete
6402 * any existing link, that should have happened when the
6403 * object deletion was replicated or initiated.
6406 replmd_deletion_state(module, msg, &deletion_state, NULL);
6408 if (deletion_state >= OBJECT_RECYCLED) {
6409 talloc_free(tmp_ctx);
6413 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6414 if (old_el == NULL) {
6415 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
6416 if (ret != LDB_SUCCESS) {
6417 ldb_module_oom(module);
6418 talloc_free(tmp_ctx);
6419 return LDB_ERR_OPERATIONS_ERROR;
6422 old_el->flags = LDB_FLAG_MOD_REPLACE;
6425 /* parse the existing links */
6426 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
6427 if (ret != LDB_SUCCESS) {
6428 talloc_free(tmp_ctx);
6432 /* get our invocationId */
6433 our_invocation_id = samdb_ntds_invocation_id(ldb);
6434 if (!our_invocation_id) {
6435 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
6436 talloc_free(tmp_ctx);
6437 return LDB_ERR_OPERATIONS_ERROR;
6440 ret = replmd_check_upgrade_links(ldb, pdn_list, old_el->num_values,
6441 old_el, our_invocation_id,
6442 attr->syntax->ldap_oid);
6443 if (ret != LDB_SUCCESS) {
6444 talloc_free(tmp_ctx);
6448 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
6449 if (!W_ERROR_IS_OK(status)) {
6450 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
6451 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
6452 talloc_free(tmp_ctx);
6453 return LDB_ERR_OPERATIONS_ERROR;
6456 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
6457 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6459 * This strange behaviour (allowing a NULL/missing
6460 * GUID) originally comes from:
6462 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6463 * Author: Andrew Tridgell <tridge@samba.org>
6464 * Date: Mon Dec 21 21:21:55 2009 +1100
6466 * s4-drs: cope better with NULL GUIDS from DRS
6468 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
6469 * need to match by DN if possible when seeing if we should update an
6472 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6475 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6476 dsdb_dn->dn, attrs2,
6477 DSDB_FLAG_NEXT_MODULE |
6478 DSDB_SEARCH_SHOW_RECYCLED |
6479 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6480 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6482 } else if (!NT_STATUS_IS_OK(ntstatus)) {
6483 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
6485 ldb_dn_get_linearized(dsdb_dn->dn),
6486 ldb_dn_get_linearized(msg->dn));
6487 talloc_free(tmp_ctx);
6488 return LDB_ERR_OPERATIONS_ERROR;
6490 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6491 NULL, LDB_SCOPE_SUBTREE,
6493 DSDB_FLAG_NEXT_MODULE |
6494 DSDB_SEARCH_SHOW_RECYCLED |
6495 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6496 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6499 GUID_string(tmp_ctx, &guid));
6502 if (ret != LDB_SUCCESS) {
6503 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6504 GUID_string(tmp_ctx, &guid),
6505 ldb_errstring(ldb_module_get_ctx(module)));
6506 talloc_free(tmp_ctx);
6510 if (target_res->count == 0) {
6511 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6512 GUID_string(tmp_ctx, &guid),
6513 ldb_dn_get_linearized(dsdb_dn->dn)));
6514 } else if (target_res->count != 1) {
6515 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6516 GUID_string(tmp_ctx, &guid));
6517 talloc_free(tmp_ctx);
6518 return LDB_ERR_OPERATIONS_ERROR;
6520 target_msg = target_res->msgs[0];
6521 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6525 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6526 * ProcessLinkValue, because link updates are not applied to
6527 * recycled and tombstone objects. We don't have to delete
6528 * any existing link, that should have happened when the
6529 * object deletion was replicated or initiated.
6531 replmd_deletion_state(module, target_msg,
6532 &target_deletion_state, NULL);
6534 if (target_deletion_state >= OBJECT_RECYCLED) {
6535 talloc_free(tmp_ctx);
6539 /* see if this link already exists */
6540 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
6544 attr->syntax->ldap_oid);
6545 if (ret != LDB_SUCCESS) {
6546 talloc_free(tmp_ctx);
6552 /* see if this update is newer than what we have already */
6553 struct GUID invocation_id = GUID_zero();
6554 uint32_t version = 0;
6555 uint32_t originating_usn = 0;
6556 NTTIME change_time = 0;
6557 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6559 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6560 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6561 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6562 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6564 if (!replmd_update_is_newer(&invocation_id,
6565 &la->meta_data.originating_invocation_id,
6567 la->meta_data.version,
6569 la->meta_data.originating_change_time)) {
6570 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6571 old_el->name, ldb_dn_get_linearized(msg->dn),
6572 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6573 talloc_free(tmp_ctx);
6577 /* get a seq_num for this change */
6578 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6579 if (ret != LDB_SUCCESS) {
6580 talloc_free(tmp_ctx);
6584 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6585 /* remove the existing backlink */
6586 ret = replmd_add_backlink(module, replmd_private,
6587 schema, &la->identifier->guid,
6588 &guid, false, attr, true);
6589 if (ret != LDB_SUCCESS) {
6590 talloc_free(tmp_ctx);
6595 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6596 &la->meta_data.originating_invocation_id,
6597 la->meta_data.originating_usn, seq_num,
6598 la->meta_data.originating_change_time,
6599 la->meta_data.version,
6601 if (ret != LDB_SUCCESS) {
6602 talloc_free(tmp_ctx);
6607 /* add the new backlink */
6608 ret = replmd_add_backlink(module, replmd_private,
6609 schema, &la->identifier->guid,
6610 &guid, true, attr, true);
6611 if (ret != LDB_SUCCESS) {
6612 talloc_free(tmp_ctx);
6617 /* get a seq_num for this change */
6618 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6619 if (ret != LDB_SUCCESS) {
6620 talloc_free(tmp_ctx);
6624 old_el->values = talloc_realloc(msg->elements, old_el->values,
6625 struct ldb_val, old_el->num_values+1);
6626 if (!old_el->values) {
6627 ldb_module_oom(module);
6628 return LDB_ERR_OPERATIONS_ERROR;
6630 old_el->num_values++;
6632 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
6633 &la->meta_data.originating_invocation_id,
6634 la->meta_data.originating_usn, seq_num,
6635 la->meta_data.originating_change_time,
6636 la->meta_data.version,
6638 if (ret != LDB_SUCCESS) {
6639 talloc_free(tmp_ctx);
6644 ret = replmd_add_backlink(module, replmd_private,
6645 schema, &la->identifier->guid,
6646 &guid, true, attr, true);
6647 if (ret != LDB_SUCCESS) {
6648 talloc_free(tmp_ctx);
6654 /* we only change whenChanged and uSNChanged if the seq_num
6656 ret = add_time_element(msg, "whenChanged", t);
6657 if (ret != LDB_SUCCESS) {
6658 talloc_free(tmp_ctx);
6663 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
6664 if (ret != LDB_SUCCESS) {
6665 talloc_free(tmp_ctx);
6670 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6671 if (old_el == NULL) {
6672 talloc_free(tmp_ctx);
6673 return ldb_operr(ldb);
6676 ret = dsdb_check_single_valued_link(attr, old_el);
6677 if (ret != LDB_SUCCESS) {
6678 talloc_free(tmp_ctx);
6682 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
6684 ret = linked_attr_modify(module, msg, parent);
6685 if (ret != LDB_SUCCESS) {
6686 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
6688 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
6689 talloc_free(tmp_ctx);
6693 talloc_free(tmp_ctx);
6698 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
6700 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
6701 return replmd_extended_replicated_objects(module, req);
6704 return ldb_next_request(module, req);
6709 we hook into the transaction operations to allow us to
6710 perform the linked attribute updates at the end of the whole
6711 transaction. This allows a forward linked attribute to be created
6712 before the object is created. During a vampire, w2k8 sends us linked
6713 attributes before the objects they are part of.
6715 static int replmd_start_transaction(struct ldb_module *module)
6717 /* create our private structure for this transaction */
6718 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
6719 struct replmd_private);
6720 replmd_txn_cleanup(replmd_private);
6722 /* free any leftover mod_usn records from cancelled
6724 while (replmd_private->ncs) {
6725 struct nc_entry *e = replmd_private->ncs;
6726 DLIST_REMOVE(replmd_private->ncs, e);
6730 replmd_private->originating_updates = false;
6732 return ldb_next_start_trans(module);
6736 on prepare commit we loop over our queued la_context structures and
6739 static int replmd_prepare_commit(struct ldb_module *module)
6741 struct replmd_private *replmd_private =
6742 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6743 struct la_entry *la, *prev;
6744 struct la_backlink *bl;
6747 /* walk the list backwards, to do the first entry first, as we
6748 * added the entries with DLIST_ADD() which puts them at the
6749 * start of the list */
6750 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
6751 prev = DLIST_PREV(la);
6752 DLIST_REMOVE(replmd_private->la_list, la);
6753 ret = replmd_process_linked_attribute(module, replmd_private,
6755 if (ret != LDB_SUCCESS) {
6756 replmd_txn_cleanup(replmd_private);
6761 /* process our backlink list, creating and deleting backlinks
6763 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
6764 ret = replmd_process_backlink(module, bl, NULL);
6765 if (ret != LDB_SUCCESS) {
6766 replmd_txn_cleanup(replmd_private);
6771 replmd_txn_cleanup(replmd_private);
6773 /* possibly change @REPLCHANGED */
6774 ret = replmd_notify_store(module, NULL);
6775 if (ret != LDB_SUCCESS) {
6779 return ldb_next_prepare_commit(module);
6782 static int replmd_del_transaction(struct ldb_module *module)
6784 struct replmd_private *replmd_private =
6785 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6786 replmd_txn_cleanup(replmd_private);
6788 return ldb_next_del_trans(module);
6792 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
6793 .name = "repl_meta_data",
6794 .init_context = replmd_init,
6796 .modify = replmd_modify,
6797 .rename = replmd_rename,
6798 .del = replmd_delete,
6799 .extended = replmd_extended,
6800 .start_transaction = replmd_start_transaction,
6801 .prepare_commit = replmd_prepare_commit,
6802 .del_transaction = replmd_del_transaction,
6805 int ldb_repl_meta_data_module_init(const char *version)
6807 LDB_MODULE_CHECK_VERSION(version);
6808 return ldb_register_module(&ldb_repl_meta_data_module_ops);