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;
75 struct la_entry *next, *prev;
76 struct drsuapi_DsReplicaLinkedAttribute *la;
79 struct replmd_replicated_request {
80 struct ldb_module *module;
81 struct ldb_request *req;
83 const struct dsdb_schema *schema;
84 struct GUID our_invocation_id;
86 /* the controls we pass down */
87 struct ldb_control **controls;
89 /* details for the mode where we apply a bunch of inbound replication meessages */
91 uint32_t index_current;
92 struct dsdb_extended_replicated_objects *objs;
94 struct ldb_message *search_msg;
95 struct GUID local_parent_guid;
103 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
104 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
106 enum urgent_situation {
107 REPL_URGENT_ON_CREATE = 1,
108 REPL_URGENT_ON_UPDATE = 2,
109 REPL_URGENT_ON_DELETE = 4
112 enum deletion_state {
113 OBJECT_NOT_DELETED=1,
120 static void replmd_deletion_state(struct ldb_module *module,
121 const struct ldb_message *msg,
122 enum deletion_state *current_state,
123 enum deletion_state *next_state)
126 bool enabled = false;
129 *current_state = OBJECT_REMOVED;
130 if (next_state != NULL) {
131 *next_state = OBJECT_REMOVED;
136 ret = dsdb_recyclebin_enabled(module, &enabled);
137 if (ret != LDB_SUCCESS) {
141 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
143 *current_state = OBJECT_TOMBSTONE;
144 if (next_state != NULL) {
145 *next_state = OBJECT_REMOVED;
150 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
151 *current_state = OBJECT_RECYCLED;
152 if (next_state != NULL) {
153 *next_state = OBJECT_REMOVED;
158 *current_state = OBJECT_DELETED;
159 if (next_state != NULL) {
160 *next_state = OBJECT_RECYCLED;
165 *current_state = OBJECT_NOT_DELETED;
166 if (next_state == NULL) {
171 *next_state = OBJECT_DELETED;
173 *next_state = OBJECT_TOMBSTONE;
177 static const struct {
178 const char *update_name;
179 enum urgent_situation repl_situation;
180 } urgent_objects[] = {
181 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
182 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
183 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
184 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
185 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
186 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
190 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
191 static const char *urgent_attrs[] = {
194 "userAccountControl",
199 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
200 enum urgent_situation situation)
203 for (i=0; urgent_objects[i].update_name; i++) {
205 if ((situation & urgent_objects[i].repl_situation) == 0) {
209 for (j=0; j<objectclass_el->num_values; j++) {
210 const struct ldb_val *v = &objectclass_el->values[j];
211 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
219 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
221 if (ldb_attr_in_list(urgent_attrs, el->name)) {
228 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
231 initialise the module
232 allocate the private structure and build the list
233 of partition DNs for use by replmd_notify()
235 static int replmd_init(struct ldb_module *module)
237 struct replmd_private *replmd_private;
238 struct ldb_context *ldb = ldb_module_get_ctx(module);
240 replmd_private = talloc_zero(module, struct replmd_private);
241 if (replmd_private == NULL) {
243 return LDB_ERR_OPERATIONS_ERROR;
245 ldb_module_set_private(module, replmd_private);
247 replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
249 return ldb_next_init(module);
253 cleanup our per-transaction contexts
255 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
257 talloc_free(replmd_private->la_ctx);
258 replmd_private->la_list = NULL;
259 replmd_private->la_ctx = NULL;
261 talloc_free(replmd_private->bl_ctx);
262 replmd_private->la_backlinks = NULL;
263 replmd_private->bl_ctx = NULL;
268 struct la_backlink *next, *prev;
269 const char *attr_name;
270 struct GUID forward_guid, target_guid;
275 a ldb_modify request operating on modules below the
278 static int linked_attr_modify(struct ldb_module *module,
279 const struct ldb_message *message,
280 struct ldb_request *parent)
282 struct ldb_request *mod_req;
284 struct ldb_context *ldb = ldb_module_get_ctx(module);
285 TALLOC_CTX *tmp_ctx = talloc_new(module);
286 struct ldb_result *res;
288 res = talloc_zero(tmp_ctx, struct ldb_result);
290 talloc_free(tmp_ctx);
291 return ldb_oom(ldb_module_get_ctx(module));
294 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
298 ldb_modify_default_callback,
300 LDB_REQ_SET_LOCATION(mod_req);
301 if (ret != LDB_SUCCESS) {
302 talloc_free(tmp_ctx);
306 ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
308 if (ret != LDB_SUCCESS) {
312 /* Run the new request */
313 ret = ldb_next_request(module, mod_req);
315 if (ret == LDB_SUCCESS) {
316 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
319 talloc_free(tmp_ctx);
324 process a backlinks we accumulated during a transaction, adding and
325 deleting the backlinks from the target objects
327 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
329 struct ldb_dn *target_dn, *source_dn;
331 struct ldb_context *ldb = ldb_module_get_ctx(module);
332 struct ldb_message *msg;
333 TALLOC_CTX *tmp_ctx = talloc_new(bl);
339 - construct ldb_message
340 - either an add or a delete
342 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn, parent);
343 if (ret != LDB_SUCCESS) {
344 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
345 GUID_string(bl, &bl->target_guid)));
349 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn, parent);
350 if (ret != LDB_SUCCESS) {
351 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
352 GUID_string(bl, &bl->forward_guid));
353 talloc_free(tmp_ctx);
357 msg = ldb_msg_new(tmp_ctx);
359 ldb_module_oom(module);
360 talloc_free(tmp_ctx);
361 return LDB_ERR_OPERATIONS_ERROR;
364 /* construct a ldb_message for adding/deleting the backlink */
366 dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
368 ldb_module_oom(module);
369 talloc_free(tmp_ctx);
370 return LDB_ERR_OPERATIONS_ERROR;
372 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
373 if (ret != LDB_SUCCESS) {
374 talloc_free(tmp_ctx);
377 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
379 /* a backlink should never be single valued. Unfortunately the
380 exchange schema has a attribute
381 msExchBridgeheadedLocalConnectorsDNBL which is single
382 valued and a backlink. We need to cope with that by
383 ignoring the single value flag */
384 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
386 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
387 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
388 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
389 cope with possible corruption where the backlink has
390 already been removed */
391 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
392 ldb_dn_get_linearized(target_dn),
393 ldb_dn_get_linearized(source_dn),
394 ldb_errstring(ldb)));
396 } else if (ret != LDB_SUCCESS) {
397 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
398 bl->active?"add":"remove",
399 ldb_dn_get_linearized(source_dn),
400 ldb_dn_get_linearized(target_dn),
402 talloc_free(tmp_ctx);
405 talloc_free(tmp_ctx);
410 add a backlink to the list of backlinks to add/delete in the prepare
413 static int replmd_add_backlink(struct ldb_module *module,
414 struct replmd_private *replmd_private,
415 const struct dsdb_schema *schema,
416 struct GUID *forward_guid,
417 struct GUID *target_guid, bool active,
418 const struct dsdb_attribute *schema_attr,
421 const struct dsdb_attribute *target_attr;
422 struct la_backlink *bl;
424 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
427 * windows 2003 has a broken schema where the
428 * definition of msDS-IsDomainFor is missing (which is
429 * supposed to be the backlink of the
430 * msDS-HasDomainNCs attribute
435 /* see if its already in the list */
436 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
437 if (GUID_equal(forward_guid, &bl->forward_guid) &&
438 GUID_equal(target_guid, &bl->target_guid) &&
439 (target_attr->lDAPDisplayName == bl->attr_name ||
440 strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
446 /* we found an existing one */
447 if (bl->active == active) {
450 DLIST_REMOVE(replmd_private->la_backlinks, bl);
455 if (replmd_private->bl_ctx == NULL) {
456 replmd_private->bl_ctx = talloc_new(replmd_private);
457 if (replmd_private->bl_ctx == NULL) {
458 ldb_module_oom(module);
459 return LDB_ERR_OPERATIONS_ERROR;
464 bl = talloc(replmd_private->bl_ctx, struct la_backlink);
466 ldb_module_oom(module);
467 return LDB_ERR_OPERATIONS_ERROR;
470 /* Ensure the schema does not go away before the bl->attr_name is used */
471 if (!talloc_reference(bl, schema)) {
473 ldb_module_oom(module);
474 return LDB_ERR_OPERATIONS_ERROR;
477 bl->attr_name = target_attr->lDAPDisplayName;
478 bl->forward_guid = *forward_guid;
479 bl->target_guid = *target_guid;
482 /* the caller may ask for this backlink to be processed
485 int ret = replmd_process_backlink(module, bl, NULL);
490 DLIST_ADD(replmd_private->la_backlinks, bl);
497 * Callback for most write operations in this module:
499 * notify the repl task that a object has changed. The notifies are
500 * gathered up in the replmd_private structure then written to the
501 * @REPLCHANGED object in each partition during the prepare_commit
503 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
506 struct replmd_replicated_request *ac =
507 talloc_get_type_abort(req->context, struct replmd_replicated_request);
508 struct replmd_private *replmd_private =
509 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
510 struct nc_entry *modified_partition;
511 struct ldb_control *partition_ctrl;
512 const struct dsdb_control_current_partition *partition;
514 struct ldb_control **controls;
516 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
518 controls = ares->controls;
519 if (ldb_request_get_control(ac->req,
520 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
522 * Remove the current partition control from what we pass up
523 * the chain if it hasn't been requested manually.
525 controls = ldb_controls_except_specified(ares->controls, ares,
529 if (ares->error != LDB_SUCCESS) {
530 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
531 return ldb_module_done(ac->req, controls,
532 ares->response, ares->error);
535 if (ares->type != LDB_REPLY_DONE) {
536 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
537 return ldb_module_done(ac->req, NULL,
538 NULL, LDB_ERR_OPERATIONS_ERROR);
541 if (!partition_ctrl) {
542 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
543 return ldb_module_done(ac->req, NULL,
544 NULL, LDB_ERR_OPERATIONS_ERROR);
547 partition = talloc_get_type_abort(partition_ctrl->data,
548 struct dsdb_control_current_partition);
550 if (ac->seq_num > 0) {
551 for (modified_partition = replmd_private->ncs; modified_partition;
552 modified_partition = modified_partition->next) {
553 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
558 if (modified_partition == NULL) {
559 modified_partition = talloc_zero(replmd_private, struct nc_entry);
560 if (!modified_partition) {
561 ldb_oom(ldb_module_get_ctx(ac->module));
562 return ldb_module_done(ac->req, NULL,
563 NULL, LDB_ERR_OPERATIONS_ERROR);
565 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
566 if (!modified_partition->dn) {
567 ldb_oom(ldb_module_get_ctx(ac->module));
568 return ldb_module_done(ac->req, NULL,
569 NULL, LDB_ERR_OPERATIONS_ERROR);
571 DLIST_ADD(replmd_private->ncs, modified_partition);
574 if (ac->seq_num > modified_partition->mod_usn) {
575 modified_partition->mod_usn = ac->seq_num;
577 modified_partition->mod_usn_urgent = ac->seq_num;
580 if (!ac->apply_mode) {
581 replmd_private->originating_updates = true;
585 if (ac->apply_mode) {
586 ret = replmd_replicated_apply_isDeleted(ac);
587 if (ret != LDB_SUCCESS) {
588 return ldb_module_done(ac->req, NULL, NULL, ret);
592 /* free the partition control container here, for the
593 * common path. Other cases will have it cleaned up
594 * eventually with the ares */
595 talloc_free(partition_ctrl);
596 return ldb_module_done(ac->req, controls,
597 ares->response, LDB_SUCCESS);
603 * update a @REPLCHANGED record in each partition if there have been
604 * any writes of replicated data in the partition
606 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
608 struct replmd_private *replmd_private =
609 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
611 while (replmd_private->ncs) {
613 struct nc_entry *modified_partition = replmd_private->ncs;
615 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
616 modified_partition->mod_usn,
617 modified_partition->mod_usn_urgent, parent);
618 if (ret != LDB_SUCCESS) {
619 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
620 ldb_dn_get_linearized(modified_partition->dn)));
624 if (ldb_dn_compare(modified_partition->dn,
625 replmd_private->schema_dn) == 0) {
626 struct ldb_result *ext_res;
627 ret = dsdb_module_extended(module,
628 replmd_private->schema_dn,
630 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
632 DSDB_FLAG_NEXT_MODULE,
634 if (ret != LDB_SUCCESS) {
637 talloc_free(ext_res);
640 DLIST_REMOVE(replmd_private->ncs, modified_partition);
641 talloc_free(modified_partition);
649 created a replmd_replicated_request context
651 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
652 struct ldb_request *req)
654 struct ldb_context *ldb;
655 struct replmd_replicated_request *ac;
656 const struct GUID *our_invocation_id;
658 ldb = ldb_module_get_ctx(module);
660 ac = talloc_zero(req, struct replmd_replicated_request);
669 ac->schema = dsdb_get_schema(ldb, ac);
671 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
672 "replmd_modify: no dsdb_schema loaded");
673 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
678 /* get our invocationId */
679 our_invocation_id = samdb_ntds_invocation_id(ldb);
680 if (!our_invocation_id) {
681 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
682 "replmd_add: unable to find invocationId\n");
686 ac->our_invocation_id = *our_invocation_id;
692 add a time element to a record
694 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
696 struct ldb_message_element *el;
700 if (ldb_msg_find_element(msg, attr) != NULL) {
704 s = ldb_timestring(msg, t);
706 return LDB_ERR_OPERATIONS_ERROR;
709 ret = ldb_msg_add_string(msg, attr, s);
710 if (ret != LDB_SUCCESS) {
714 el = ldb_msg_find_element(msg, attr);
715 /* always set as replace. This works because on add ops, the flag
717 el->flags = LDB_FLAG_MOD_REPLACE;
723 add a uint64_t element to a record
725 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
726 const char *attr, uint64_t v)
728 struct ldb_message_element *el;
731 if (ldb_msg_find_element(msg, attr) != NULL) {
735 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
736 if (ret != LDB_SUCCESS) {
740 el = ldb_msg_find_element(msg, attr);
741 /* always set as replace. This works because on add ops, the flag
743 el->flags = LDB_FLAG_MOD_REPLACE;
748 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
749 const struct replPropertyMetaData1 *m2,
750 const uint32_t *rdn_attid)
753 * This assignment seems inoccous, but it is critical for the
754 * system, as we need to do the comparisons as a unsigned
755 * quantity, not signed (enums are signed integers)
757 uint32_t attid_1 = m1->attid;
758 uint32_t attid_2 = m2->attid;
760 if (attid_1 == attid_2) {
765 * See above regarding this being an unsigned comparison.
766 * Otherwise when the high bit is set on non-standard
767 * attributes, they would end up first, before objectClass
770 return attid_1 > attid_2 ? 1 : -1;
773 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
774 struct replPropertyMetaDataCtr1 *ctr1,
777 if (ctr1->count == 0) {
778 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
779 "No elements found in replPropertyMetaData for %s!\n",
780 ldb_dn_get_linearized(dn));
781 return LDB_ERR_CONSTRAINT_VIOLATION;
784 /* the objectClass attribute is value 0x00000000, so must be first */
785 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
786 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
787 "No objectClass found in replPropertyMetaData for %s!\n",
788 ldb_dn_get_linearized(dn));
789 return LDB_ERR_OBJECT_CLASS_VIOLATION;
795 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
796 struct replPropertyMetaDataCtr1 *ctr1,
799 /* Note this is O(n^2) for the almost-sorted case, which this is */
800 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
801 replmd_replPropertyMetaData1_attid_sort);
802 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
805 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
806 const struct ldb_message_element *e2,
807 const struct dsdb_schema *schema)
809 const struct dsdb_attribute *a1;
810 const struct dsdb_attribute *a2;
813 * TODO: make this faster by caching the dsdb_attribute pointer
814 * on the ldb_messag_element
817 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
818 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
821 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
825 return strcasecmp(e1->name, e2->name);
827 if (a1->attributeID_id == a2->attributeID_id) {
830 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
833 static void replmd_ldb_message_sort(struct ldb_message *msg,
834 const struct dsdb_schema *schema)
836 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
839 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
840 const struct GUID *invocation_id, uint64_t seq_num,
841 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
845 fix up linked attributes in replmd_add.
846 This involves setting up the right meta-data in extended DN
847 components, and creating backlinks to the object
849 static int replmd_add_fix_la(struct ldb_module *module,
850 struct replmd_private *replmd_private,
851 struct ldb_message_element *el,
852 uint64_t seq_num, const struct GUID *invocationId, NTTIME now,
853 struct GUID *guid, const struct dsdb_attribute *sa, struct ldb_request *parent)
856 TALLOC_CTX *tmp_ctx = talloc_new(el->values);
857 struct ldb_context *ldb = ldb_module_get_ctx(module);
859 /* We will take a reference to the schema in replmd_add_backlink */
860 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
862 for (i=0; i<el->num_values; i++) {
863 struct ldb_val *v = &el->values[i];
864 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
865 struct GUID target_guid;
869 if (dsdb_dn == NULL) {
870 talloc_free(tmp_ctx);
871 return LDB_ERR_INVALID_DN_SYNTAX;
874 /* note that the DN already has the extended
875 components from the extended_dn_store module */
876 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
877 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
878 ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
879 if (ret != LDB_SUCCESS) {
880 talloc_free(tmp_ctx);
883 ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
884 if (ret != LDB_SUCCESS) {
885 talloc_free(tmp_ctx);
890 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
891 seq_num, seq_num, now, 0, false);
892 if (ret != LDB_SUCCESS) {
893 talloc_free(tmp_ctx);
897 ret = replmd_add_backlink(module, replmd_private,
898 schema, guid, &target_guid, true, sa,
900 if (ret != LDB_SUCCESS) {
901 talloc_free(tmp_ctx);
906 talloc_free(tmp_ctx);
912 intercept add requests
914 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
916 struct ldb_context *ldb;
917 struct ldb_control *control;
918 struct replmd_replicated_request *ac;
919 enum ndr_err_code ndr_err;
920 struct ldb_request *down_req;
921 struct ldb_message *msg;
922 const DATA_BLOB *guid_blob;
924 struct replPropertyMetaDataBlob nmd;
925 struct ldb_val nmd_value;
928 * The use of a time_t here seems odd, but as the NTTIME
929 * elements are actually declared as NTTIME_1sec in the IDL,
930 * getting a higher resolution timestamp is not required.
932 time_t t = time(NULL);
937 unsigned int functional_level;
939 bool allow_add_guid = false;
940 bool remove_current_guid = false;
941 bool is_urgent = false;
942 bool is_schema_nc = false;
943 struct ldb_message_element *objectclass_el;
944 struct replmd_private *replmd_private =
945 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
947 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
948 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
950 allow_add_guid = true;
953 /* do not manipulate our control entries */
954 if (ldb_dn_is_special(req->op.add.message->dn)) {
955 return ldb_next_request(module, req);
958 ldb = ldb_module_get_ctx(module);
960 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
962 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
963 if (guid_blob != NULL) {
964 if (!allow_add_guid) {
965 ldb_set_errstring(ldb,
966 "replmd_add: it's not allowed to add an object with objectGUID!");
967 return LDB_ERR_UNWILLING_TO_PERFORM;
969 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
970 if (!NT_STATUS_IS_OK(status)) {
971 ldb_set_errstring(ldb,
972 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
973 return LDB_ERR_UNWILLING_TO_PERFORM;
975 /* we remove this attribute as it can be a string and
976 * will not be treated correctly and then we will re-add
977 * it later on in the good format */
978 remove_current_guid = true;
982 guid = GUID_random();
985 ac = replmd_ctx_init(module, req);
987 return ldb_module_oom(module);
990 functional_level = dsdb_functional_level(ldb);
992 /* Get a sequence number from the backend */
993 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
994 if (ret != LDB_SUCCESS) {
999 /* we have to copy the message as the caller might have it as a const */
1000 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1004 return LDB_ERR_OPERATIONS_ERROR;
1007 /* generated times */
1008 unix_to_nt_time(&now, t);
1009 time_str = ldb_timestring(msg, t);
1013 return LDB_ERR_OPERATIONS_ERROR;
1015 if (remove_current_guid) {
1016 ldb_msg_remove_attr(msg,"objectGUID");
1020 * remove autogenerated attributes
1022 ldb_msg_remove_attr(msg, "whenCreated");
1023 ldb_msg_remove_attr(msg, "whenChanged");
1024 ldb_msg_remove_attr(msg, "uSNCreated");
1025 ldb_msg_remove_attr(msg, "uSNChanged");
1026 ldb_msg_remove_attr(msg, "replPropertyMetaData");
1029 * readd replicated attributes
1031 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1032 if (ret != LDB_SUCCESS) {
1038 /* build the replication meta_data */
1041 nmd.ctr.ctr1.count = msg->num_elements;
1042 nmd.ctr.ctr1.array = talloc_array(msg,
1043 struct replPropertyMetaData1,
1044 nmd.ctr.ctr1.count);
1045 if (!nmd.ctr.ctr1.array) {
1048 return LDB_ERR_OPERATIONS_ERROR;
1051 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1053 for (i=0; i < msg->num_elements;) {
1054 struct ldb_message_element *e = &msg->elements[i];
1055 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1056 const struct dsdb_attribute *sa;
1058 if (e->name[0] == '@') {
1063 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1065 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1066 "replmd_add: attribute '%s' not defined in schema\n",
1069 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1072 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1073 /* if the attribute is not replicated (0x00000001)
1074 * or constructed (0x00000004) it has no metadata
1080 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1081 ret = replmd_add_fix_la(module, replmd_private, e,
1083 &ac->our_invocation_id, now,
1085 if (ret != LDB_SUCCESS) {
1089 /* linked attributes are not stored in
1090 replPropertyMetaData in FL above w2k */
1095 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1097 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1098 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1101 if (rdn_val == NULL) {
1104 return LDB_ERR_OPERATIONS_ERROR;
1107 rdn = (const char*)rdn_val->data;
1108 if (strcmp(rdn, "Deleted Objects") == 0) {
1110 * Set the originating_change_time to 29/12/9999 at 23:59:59
1111 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1113 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1115 m->originating_change_time = now;
1118 m->originating_change_time = now;
1120 m->originating_invocation_id = ac->our_invocation_id;
1121 m->originating_usn = ac->seq_num;
1122 m->local_usn = ac->seq_num;
1125 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1130 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1132 if (e->num_values != 0) {
1137 ldb_msg_remove_element(msg, e);
1140 /* fix meta data count */
1141 nmd.ctr.ctr1.count = ni;
1144 * sort meta data array
1146 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1147 if (ret != LDB_SUCCESS) {
1148 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1153 /* generated NDR encoded values */
1154 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1156 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1157 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1160 return LDB_ERR_OPERATIONS_ERROR;
1164 * add the autogenerated values
1166 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1167 if (ret != LDB_SUCCESS) {
1172 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1173 if (ret != LDB_SUCCESS) {
1178 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1179 if (ret != LDB_SUCCESS) {
1184 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1185 if (ret != LDB_SUCCESS) {
1190 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1191 if (ret != LDB_SUCCESS) {
1198 * sort the attributes by attid before storing the object
1200 replmd_ldb_message_sort(msg, ac->schema);
1203 * Assert that we do have an objectClass
1205 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1206 if (objectclass_el == NULL) {
1207 ldb_asprintf_errstring(ldb, __location__
1208 ": objectClass missing on %s\n",
1209 ldb_dn_get_linearized(msg->dn));
1211 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1213 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1214 REPL_URGENT_ON_CREATE);
1216 ac->is_urgent = is_urgent;
1217 ret = ldb_build_add_req(&down_req, ldb, ac,
1220 ac, replmd_op_callback,
1223 LDB_REQ_SET_LOCATION(down_req);
1224 if (ret != LDB_SUCCESS) {
1229 /* current partition control is needed by "replmd_op_callback" */
1230 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1231 ret = ldb_request_add_control(down_req,
1232 DSDB_CONTROL_CURRENT_PARTITION_OID,
1234 if (ret != LDB_SUCCESS) {
1240 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1241 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1242 if (ret != LDB_SUCCESS) {
1248 /* mark the control done */
1250 control->critical = 0;
1252 /* go on with the call chain */
1253 return ldb_next_request(module, down_req);
1258 * update the replPropertyMetaData for one element
1260 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1261 struct ldb_message *msg,
1262 struct ldb_message_element *el,
1263 struct ldb_message_element *old_el,
1264 struct replPropertyMetaDataBlob *omd,
1265 const struct dsdb_schema *schema,
1267 const struct GUID *our_invocation_id,
1270 struct ldb_request *req)
1273 const struct dsdb_attribute *a;
1274 struct replPropertyMetaData1 *md1;
1275 bool may_skip = false;
1278 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1280 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1281 /* allow this to make it possible for dbcheck
1282 to remove bad attributes */
1286 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1288 return LDB_ERR_OPERATIONS_ERROR;
1291 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1293 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1298 * if the attribute's value haven't changed, and this isn't
1299 * just a delete of everything then return LDB_SUCCESS Unless
1300 * we have the provision control or if the attribute is
1301 * interSiteTopologyGenerator as this page explain:
1302 * http://support.microsoft.com/kb/224815 this attribute is
1303 * periodicaly written by the DC responsible for the intersite
1304 * generation in a given site
1306 * Unchanged could be deleting or replacing an already-gone
1307 * thing with an unconstrained delete/empty replace or a
1308 * replace with the same value, but not an add with the same
1309 * value because that could be about adding a duplicate (which
1310 * is for someone else to error out on).
1312 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1313 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1316 } else if (old_el == NULL && el->num_values == 0) {
1317 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1319 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1322 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1323 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1325 * We intentionally skip the version bump when attempting to
1328 * The control is set by dbcheck and expunge-tombstones which
1329 * both attempt to be non-replicating. Otherwise, making an
1330 * alteration to the replication state would trigger a
1331 * broadcast of all expunged objects.
1336 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1338 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1342 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1343 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1345 * allow this to make it possible for dbcheck
1346 * to rebuild broken metadata
1352 for (i=0; i<omd->ctr.ctr1.count; i++) {
1354 * First check if we find it under the msDS-IntID,
1355 * then check if we find it under the OID and
1358 * This allows the administrator to simply re-write
1359 * the attributes and so restore replication, which is
1360 * likely what they will try to do.
1362 if (attid == omd->ctr.ctr1.array[i].attid) {
1366 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1371 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1372 /* linked attributes are not stored in
1373 replPropertyMetaData in FL above w2k, but we do
1374 raise the seqnum for the object */
1375 if (*seq_num == 0 &&
1376 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1377 return LDB_ERR_OPERATIONS_ERROR;
1382 if (i == omd->ctr.ctr1.count) {
1383 /* we need to add a new one */
1384 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1385 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1386 if (omd->ctr.ctr1.array == NULL) {
1388 return LDB_ERR_OPERATIONS_ERROR;
1390 omd->ctr.ctr1.count++;
1391 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1394 /* Get a new sequence number from the backend. We only do this
1395 * if we have a change that requires a new
1396 * replPropertyMetaData element
1398 if (*seq_num == 0) {
1399 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1400 if (ret != LDB_SUCCESS) {
1401 return LDB_ERR_OPERATIONS_ERROR;
1405 md1 = &omd->ctr.ctr1.array[i];
1408 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1409 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1412 if (rdn_val == NULL) {
1414 return LDB_ERR_OPERATIONS_ERROR;
1417 rdn = (const char*)rdn_val->data;
1418 if (strcmp(rdn, "Deleted Objects") == 0) {
1420 * Set the originating_change_time to 29/12/9999 at 23:59:59
1421 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1423 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1425 md1->originating_change_time = now;
1428 md1->originating_change_time = now;
1430 md1->originating_invocation_id = *our_invocation_id;
1431 md1->originating_usn = *seq_num;
1432 md1->local_usn = *seq_num;
1438 * Bump the replPropertyMetaData version on an attribute, and if it
1439 * has changed (or forced by leaving rdn_old NULL), update the value
1442 * This is important, as calling a modify operation may not change the
1443 * version number if the values appear unchanged, but a rename between
1444 * parents bumps this value.
1447 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1448 struct ldb_message *msg,
1449 const struct ldb_val *rdn_new,
1450 const struct ldb_val *rdn_old,
1451 struct replPropertyMetaDataBlob *omd,
1452 struct replmd_replicated_request *ar,
1456 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1457 const struct dsdb_attribute *rdn_attr =
1458 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1459 const char *attr_name = rdn_attr != NULL ?
1460 rdn_attr->lDAPDisplayName :
1462 struct ldb_message_element new_el = {
1463 .flags = LDB_FLAG_MOD_REPLACE,
1466 .values = discard_const_p(struct ldb_val, rdn_new)
1468 struct ldb_message_element old_el = {
1469 .flags = LDB_FLAG_MOD_REPLACE,
1471 .num_values = rdn_old ? 1 : 0,
1472 .values = discard_const_p(struct ldb_val, rdn_old)
1475 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1476 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1477 if (ret != LDB_SUCCESS) {
1478 return ldb_oom(ldb);
1482 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1483 omd, ar->schema, &ar->seq_num,
1484 &ar->our_invocation_id,
1485 now, is_schema_nc, ar->req);
1489 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1491 uint32_t count = omd.ctr.ctr1.count;
1494 for (i=0; i < count; i++) {
1495 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1496 if (max < m.local_usn) {
1504 * update the replPropertyMetaData object each time we modify an
1505 * object. This is needed for DRS replication, as the merge on the
1506 * client is based on this object
1508 static int replmd_update_rpmd(struct ldb_module *module,
1509 const struct dsdb_schema *schema,
1510 struct ldb_request *req,
1511 const char * const *rename_attrs,
1512 struct ldb_message *msg, uint64_t *seq_num,
1513 time_t t, bool is_schema_nc,
1514 bool *is_urgent, bool *rodc)
1516 const struct ldb_val *omd_value;
1517 enum ndr_err_code ndr_err;
1518 struct replPropertyMetaDataBlob omd;
1521 const struct GUID *our_invocation_id;
1523 const char * const *attrs = NULL;
1524 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1525 struct ldb_result *res;
1526 struct ldb_context *ldb;
1527 struct ldb_message_element *objectclass_el;
1528 enum urgent_situation situation;
1529 bool rmd_is_provided;
1530 bool rmd_is_just_resorted = false;
1531 const char *not_rename_attrs[4 + msg->num_elements];
1534 attrs = rename_attrs;
1536 for (i = 0; i < msg->num_elements; i++) {
1537 not_rename_attrs[i] = msg->elements[i].name;
1539 not_rename_attrs[i] = "replPropertyMetaData";
1540 not_rename_attrs[i+1] = "objectClass";
1541 not_rename_attrs[i+2] = "instanceType";
1542 not_rename_attrs[i+3] = NULL;
1543 attrs = not_rename_attrs;
1546 ldb = ldb_module_get_ctx(module);
1548 our_invocation_id = samdb_ntds_invocation_id(ldb);
1549 if (!our_invocation_id) {
1550 /* this happens during an initial vampire while
1551 updating the schema */
1552 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1556 unix_to_nt_time(&now, t);
1558 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1559 rmd_is_provided = true;
1560 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1561 rmd_is_just_resorted = true;
1564 rmd_is_provided = false;
1567 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1568 * otherwise we consider we are updating */
1569 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1570 situation = REPL_URGENT_ON_DELETE;
1571 } else if (rename_attrs) {
1572 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1574 situation = REPL_URGENT_ON_UPDATE;
1577 if (rmd_is_provided) {
1578 /* In this case the change_replmetadata control was supplied */
1579 /* We check that it's the only attribute that is provided
1580 * (it's a rare case so it's better to keep the code simplier)
1581 * We also check that the highest local_usn is bigger or the same as
1584 if( msg->num_elements != 1 ||
1585 strncmp(msg->elements[0].name,
1586 "replPropertyMetaData", 20) ) {
1587 DEBUG(0,(__location__ ": changereplmetada control called without "\
1588 "a specified replPropertyMetaData attribute or with others\n"));
1589 return LDB_ERR_OPERATIONS_ERROR;
1591 if (situation != REPL_URGENT_ON_UPDATE) {
1592 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1593 return LDB_ERR_OPERATIONS_ERROR;
1595 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1597 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1598 ldb_dn_get_linearized(msg->dn)));
1599 return LDB_ERR_OPERATIONS_ERROR;
1601 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1602 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1603 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1604 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1605 ldb_dn_get_linearized(msg->dn)));
1606 return LDB_ERR_OPERATIONS_ERROR;
1609 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1610 DSDB_FLAG_NEXT_MODULE |
1611 DSDB_SEARCH_SHOW_RECYCLED |
1612 DSDB_SEARCH_SHOW_EXTENDED_DN |
1613 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1614 DSDB_SEARCH_REVEAL_INTERNALS, req);
1616 if (ret != LDB_SUCCESS) {
1620 if (rmd_is_just_resorted == false) {
1621 *seq_num = find_max_local_usn(omd);
1623 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1626 * The test here now allows for a new
1627 * replPropertyMetaData with no change, if was
1628 * just dbcheck re-sorting the values.
1630 if (*seq_num <= db_seq) {
1631 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1632 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1633 (long long)*seq_num, (long long)db_seq));
1634 return LDB_ERR_OPERATIONS_ERROR;
1639 /* search for the existing replPropertyMetaDataBlob. We need
1640 * to use REVEAL and ask for DNs in storage format to support
1641 * the check for values being the same in
1642 * replmd_update_rpmd_element()
1644 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1645 DSDB_FLAG_NEXT_MODULE |
1646 DSDB_SEARCH_SHOW_RECYCLED |
1647 DSDB_SEARCH_SHOW_EXTENDED_DN |
1648 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1649 DSDB_SEARCH_REVEAL_INTERNALS, req);
1650 if (ret != LDB_SUCCESS) {
1654 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1656 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1657 ldb_dn_get_linearized(msg->dn)));
1658 return LDB_ERR_OPERATIONS_ERROR;
1661 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1662 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1663 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1664 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1665 ldb_dn_get_linearized(msg->dn)));
1666 return LDB_ERR_OPERATIONS_ERROR;
1669 if (omd.version != 1) {
1670 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1671 omd.version, ldb_dn_get_linearized(msg->dn)));
1672 return LDB_ERR_OPERATIONS_ERROR;
1675 for (i=0; i<msg->num_elements;) {
1676 struct ldb_message_element *el = &msg->elements[i];
1677 struct ldb_message_element *old_el;
1679 old_el = ldb_msg_find_element(res->msgs[0], el->name);
1680 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1681 &omd, schema, seq_num,
1685 if (ret != LDB_SUCCESS) {
1689 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1690 *is_urgent = replmd_check_urgent_attribute(el);
1693 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1698 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1700 if (el->num_values != 0) {
1705 ldb_msg_remove_element(msg, el);
1710 * Assert that we have an objectClass attribute - this is major
1711 * corruption if we don't have this!
1713 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1714 if (objectclass_el != NULL) {
1716 * Now check if this objectClass means we need to do urgent replication
1718 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1722 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1723 ldb_asprintf_errstring(ldb, __location__
1724 ": objectClass missing on %s\n",
1725 ldb_dn_get_linearized(msg->dn));
1726 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1730 * replmd_update_rpmd_element has done an update if the
1733 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1734 struct ldb_val *md_value;
1735 struct ldb_message_element *el;
1737 /*if we are RODC and this is a DRSR update then its ok*/
1738 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1739 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
1740 unsigned instanceType;
1742 ret = samdb_rodc(ldb, rodc);
1743 if (ret != LDB_SUCCESS) {
1744 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1746 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1747 return LDB_ERR_REFERRAL;
1750 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1751 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1752 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1753 "cannot change replicated attribute on partial replica");
1757 md_value = talloc(msg, struct ldb_val);
1758 if (md_value == NULL) {
1760 return LDB_ERR_OPERATIONS_ERROR;
1763 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1764 if (ret != LDB_SUCCESS) {
1765 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1769 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1770 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1771 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1772 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1773 ldb_dn_get_linearized(msg->dn)));
1774 return LDB_ERR_OPERATIONS_ERROR;
1777 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1778 if (ret != LDB_SUCCESS) {
1779 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1780 ldb_dn_get_linearized(msg->dn)));
1785 el->values = md_value;
1792 struct dsdb_dn *dsdb_dn;
1797 struct compare_ctx {
1799 struct ldb_context *ldb;
1800 TALLOC_CTX *mem_ctx;
1801 const char *ldap_oid;
1803 const struct GUID *invocation_id;
1807 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1809 return GUID_compare(&pdn1->guid, &pdn2->guid);
1812 static int la_guid_compare_with_trusted_dn(struct compare_ctx *ctx,
1813 struct parsed_dn *p)
1816 * This works like a standard compare function in its return values,
1817 * but has an extra trick to deal with errors: zero is returned and
1818 * ctx->err is set to the ldb error code.
1820 * That is, if (as is expected in most cases) you get a non-zero
1821 * result, you don't need to check for errors.
1825 if (GUID_all_zero(&p->guid)) {
1827 status = dsdb_get_extended_dn_guid(p->dsdb_dn->dn, &p->guid, "GUID");
1828 if (!NT_STATUS_IS_OK(status)) {
1829 ctx->err = LDB_ERR_OPERATIONS_ERROR;
1834 return GUID_compare(ctx->guid, &p->guid);
1839 static int parsed_dn_find(struct ldb_context *ldb, struct parsed_dn *pdn,
1842 struct ldb_dn *target_dn,
1843 struct parsed_dn **exact,
1844 struct parsed_dn **next,
1845 const char *ldap_oid)
1848 struct compare_ctx ctx;
1855 if (unlikely(GUID_all_zero(guid))) {
1857 * When updating a link using DRS, we sometimes get a NULL
1858 * GUID when a forward link has been deleted and its GUID has
1859 * for some reason been forgotten. The best we can do is try
1860 * and match by DN via a linear search. Note that this
1861 * probably only happens in the ADD case, in which we only
1862 * allow modification of link if it is already deleted, so
1863 * this seems very close to an elaborate NO-OP, but we are not
1864 * quite prepared to declare it so.
1866 * If the DN is not in our list, we have to add it to the
1867 * beginning of the list, where it would naturally sort.
1869 struct parsed_dn *p;
1870 if (target_dn == NULL) {
1871 /* We don't know the target DN, so we can't search for DN */
1872 DEBUG(1, ("parsed_dn_find has a NULL GUID for a linked "
1873 "attribute but we don't have a DN to compare "
1875 return LDB_ERR_OPERATIONS_ERROR;
1880 DEBUG(3, ("parsed_dn_find has a NULL GUID for a link to DN "
1881 "%s; searching through links for it",
1882 ldb_dn_get_linearized(target_dn)));
1884 for (i = 0; i < count; i++) {
1887 cmp = ldb_dn_compare(p->dsdb_dn->dn, target_dn);
1889 dsdb_get_extended_dn_guid(p->dsdb_dn->dn,
1896 * Here we have a null guid which doesn't match any existing
1897 * link. This is a bit unexpected because null guids occur
1898 * when a forward link has been deleted and we are replicating
1901 * The best thing to do is weep into the logs and add the
1902 * offending link to the beginning of the list which is
1903 * at least the correct sort position.
1905 DEBUG(1, ("parsed_dn_find has been given a NULL GUID for a "
1906 "link to unknown DN %s\n",
1907 ldb_dn_get_linearized(target_dn)));
1915 ctx.ldap_oid = ldap_oid;
1918 BINARY_ARRAY_SEARCH_GTE(pdn, count, &ctx, la_guid_compare_with_trusted_dn,
1928 get a series of message element values as an array of DNs and GUIDs
1929 the result is sorted by GUID
1931 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1932 struct ldb_message_element *el, struct parsed_dn **pdn,
1933 const char *ldap_oid, struct ldb_request *parent)
1936 bool values_are_sorted = true;
1937 struct ldb_context *ldb = ldb_module_get_ctx(module);
1944 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1946 ldb_module_oom(module);
1947 return LDB_ERR_OPERATIONS_ERROR;
1950 for (i=0; i<el->num_values; i++) {
1951 struct ldb_val *v = &el->values[i];
1954 struct parsed_dn *p;
1958 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1959 if (p->dsdb_dn == NULL) {
1960 return LDB_ERR_INVALID_DN_SYNTAX;
1963 dn = p->dsdb_dn->dn;
1965 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
1966 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1967 /* we got a DN without a GUID - go find the GUID */
1968 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
1969 if (ret != LDB_SUCCESS) {
1970 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1971 ldb_dn_get_linearized(dn));
1972 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1973 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1974 ldb_attr_cmp(el->name, "member") == 0) {
1975 return LDB_ERR_UNWILLING_TO_PERFORM;
1979 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
1980 if (ret != LDB_SUCCESS) {
1983 } else if (!NT_STATUS_IS_OK(status)) {
1984 return LDB_ERR_OPERATIONS_ERROR;
1986 if (i > 0 && values_are_sorted) {
1987 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
1989 values_are_sorted = false;
1992 /* keep a pointer to the original ldb_val */
1995 if (! values_are_sorted) {
1996 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2002 build a new extended DN, including all meta data fields
2004 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2005 RMD_ADDTIME = originating_add_time
2006 RMD_INVOCID = originating_invocation_id
2007 RMD_CHANGETIME = originating_change_time
2008 RMD_ORIGINATING_USN = originating_usn
2009 RMD_LOCAL_USN = local_usn
2010 RMD_VERSION = version
2012 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2013 const struct GUID *invocation_id, uint64_t seq_num,
2014 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
2016 struct ldb_dn *dn = dsdb_dn->dn;
2017 const char *tstring, *usn_string, *flags_string;
2018 struct ldb_val tval;
2020 struct ldb_val usnv, local_usnv;
2021 struct ldb_val vers, flagsv;
2024 const char *dnstring;
2026 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2028 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2030 return LDB_ERR_OPERATIONS_ERROR;
2032 tval = data_blob_string_const(tstring);
2034 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
2036 return LDB_ERR_OPERATIONS_ERROR;
2038 usnv = data_blob_string_const(usn_string);
2040 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2042 return LDB_ERR_OPERATIONS_ERROR;
2044 local_usnv = data_blob_string_const(usn_string);
2046 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2048 return LDB_ERR_OPERATIONS_ERROR;
2050 vers = data_blob_string_const(vstring);
2052 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2053 if (!NT_STATUS_IS_OK(status)) {
2054 return LDB_ERR_OPERATIONS_ERROR;
2057 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2058 if (!flags_string) {
2059 return LDB_ERR_OPERATIONS_ERROR;
2061 flagsv = data_blob_string_const(flags_string);
2063 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2064 if (ret != LDB_SUCCESS) return ret;
2065 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
2066 if (ret != LDB_SUCCESS) return ret;
2067 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2068 if (ret != LDB_SUCCESS) return ret;
2069 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2070 if (ret != LDB_SUCCESS) return ret;
2071 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2072 if (ret != LDB_SUCCESS) return ret;
2073 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2074 if (ret != LDB_SUCCESS) return ret;
2075 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2076 if (ret != LDB_SUCCESS) return ret;
2078 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2079 if (dnstring == NULL) {
2080 return LDB_ERR_OPERATIONS_ERROR;
2082 *v = data_blob_string_const(dnstring);
2087 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2088 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2089 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2090 uint32_t version, bool deleted);
2093 check if any links need upgrading from w2k format
2095 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2096 struct parsed_dn *dns, uint32_t count,
2097 struct ldb_message_element *el,
2098 const struct GUID *invocation_id,
2099 const char *ldap_oid)
2102 for (i=0; i<count; i++) {
2106 if (dns[i].dsdb_dn == NULL) {
2107 dns[i].dsdb_dn = dsdb_dn_parse(dns, ldb, dns[i].v,
2109 if (dns[i].dsdb_dn == NULL) {
2110 return LDB_ERR_INVALID_DN_SYNTAX;
2114 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2115 &version, "RMD_VERSION");
2116 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2118 * We optimistically assume they are all the same; if
2119 * the first one is fixed, they are all fixed.
2121 * If the first one was *not* fixed and we find a
2122 * later one that is, that is an occasion to shout
2128 DEBUG(0, ("Mixed w2k and fixed format "
2129 "linked attributes\n"));
2133 /* it's an old one that needs upgrading */
2134 ret = replmd_update_la_val(el->values, dns[i].v,
2135 dns[i].dsdb_dn, dns[i].dsdb_dn,
2136 invocation_id, 1, 1, 0, 0, false);
2137 if (ret != LDB_SUCCESS) {
2145 update an extended DN, including all meta data fields
2147 see replmd_build_la_val for value names
2149 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2150 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2151 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2152 uint32_t version, bool deleted)
2154 struct ldb_dn *dn = dsdb_dn->dn;
2155 const char *tstring, *usn_string, *flags_string;
2156 struct ldb_val tval;
2158 struct ldb_val usnv, local_usnv;
2159 struct ldb_val vers, flagsv;
2160 const struct ldb_val *old_addtime;
2161 uint32_t old_version;
2164 const char *dnstring;
2166 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2168 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2170 return LDB_ERR_OPERATIONS_ERROR;
2172 tval = data_blob_string_const(tstring);
2174 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2176 return LDB_ERR_OPERATIONS_ERROR;
2178 usnv = data_blob_string_const(usn_string);
2180 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2182 return LDB_ERR_OPERATIONS_ERROR;
2184 local_usnv = data_blob_string_const(usn_string);
2186 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2187 if (!NT_STATUS_IS_OK(status)) {
2188 return LDB_ERR_OPERATIONS_ERROR;
2191 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2192 if (!flags_string) {
2193 return LDB_ERR_OPERATIONS_ERROR;
2195 flagsv = data_blob_string_const(flags_string);
2197 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2198 if (ret != LDB_SUCCESS) return ret;
2200 /* get the ADDTIME from the original */
2201 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2202 if (old_addtime == NULL) {
2203 old_addtime = &tval;
2205 if (dsdb_dn != old_dsdb_dn ||
2206 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2207 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2208 if (ret != LDB_SUCCESS) return ret;
2211 /* use our invocation id */
2212 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2213 if (ret != LDB_SUCCESS) return ret;
2215 /* changetime is the current time */
2216 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2217 if (ret != LDB_SUCCESS) return ret;
2219 /* update the USN */
2220 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2221 if (ret != LDB_SUCCESS) return ret;
2223 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2224 if (ret != LDB_SUCCESS) return ret;
2226 /* increase the version by 1 */
2227 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2228 if (NT_STATUS_IS_OK(status) && old_version >= version) {
2229 version = old_version+1;
2231 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2232 vers = data_blob_string_const(vstring);
2233 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2234 if (ret != LDB_SUCCESS) return ret;
2236 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2237 if (dnstring == NULL) {
2238 return LDB_ERR_OPERATIONS_ERROR;
2240 *v = data_blob_string_const(dnstring);
2246 handle adding a linked attribute
2248 static int replmd_modify_la_add(struct ldb_module *module,
2249 struct replmd_private *replmd_private,
2250 const struct dsdb_schema *schema,
2251 struct ldb_message *msg,
2252 struct ldb_message_element *el,
2253 struct ldb_message_element *old_el,
2254 const struct dsdb_attribute *schema_attr,
2257 struct GUID *msg_guid,
2258 struct ldb_request *parent)
2261 struct parsed_dn *dns, *old_dns;
2262 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2264 struct ldb_val *new_values = NULL;
2265 unsigned int num_new_values = 0;
2266 unsigned old_num_values = old_el?old_el->num_values:0;
2267 const struct GUID *invocation_id;
2268 struct ldb_context *ldb = ldb_module_get_ctx(module);
2271 unix_to_nt_time(&now, t);
2273 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2274 if (ret != LDB_SUCCESS) {
2275 talloc_free(tmp_ctx);
2279 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2280 if (ret != LDB_SUCCESS) {
2281 talloc_free(tmp_ctx);
2285 invocation_id = samdb_ntds_invocation_id(ldb);
2286 if (!invocation_id) {
2287 talloc_free(tmp_ctx);
2288 return LDB_ERR_OPERATIONS_ERROR;
2291 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2292 old_el, invocation_id,
2293 schema_attr->syntax->ldap_oid);
2294 if (ret != LDB_SUCCESS) {
2295 talloc_free(tmp_ctx);
2299 /* for each new value, see if it exists already with the same GUID */
2300 for (i=0; i<el->num_values; i++) {
2301 struct parsed_dn *p;
2302 struct parsed_dn *next;
2303 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2307 schema_attr->syntax->ldap_oid);
2308 if (err != LDB_SUCCESS) {
2309 talloc_free(tmp_ctx);
2313 /* this is a new linked attribute value */
2314 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
2315 if (new_values == NULL) {
2316 ldb_module_oom(module);
2317 talloc_free(tmp_ctx);
2318 return LDB_ERR_OPERATIONS_ERROR;
2320 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2321 invocation_id, seq_num, seq_num, now, 0, false);
2322 if (ret != LDB_SUCCESS) {
2323 talloc_free(tmp_ctx);
2328 /* this is only allowed if the GUID was
2329 previously deleted. */
2330 uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2331 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2332 struct GUID_txt_buf guid_str;
2333 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
2334 el->name, GUID_buf_string(&p->guid, &guid_str));
2335 talloc_free(tmp_ctx);
2336 /* error codes for 'member' need to be
2338 if (ldb_attr_cmp(el->name, "member") == 0) {
2339 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2341 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2344 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
2345 invocation_id, seq_num, seq_num, now, 0, false);
2346 if (ret != LDB_SUCCESS) {
2347 talloc_free(tmp_ctx);
2352 ret = replmd_add_backlink(module, replmd_private,
2353 schema, msg_guid, &dns[i].guid,
2354 true, schema_attr, true);
2355 if (ret != LDB_SUCCESS) {
2356 talloc_free(tmp_ctx);
2361 /* add the new ones on to the end of the old values, constructing a new el->values */
2362 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2364 old_num_values+num_new_values);
2365 if (el->values == NULL) {
2366 ldb_module_oom(module);
2367 return LDB_ERR_OPERATIONS_ERROR;
2370 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
2371 el->num_values = old_num_values + num_new_values;
2373 talloc_steal(msg->elements, el->values);
2374 talloc_steal(el->values, new_values);
2376 talloc_free(tmp_ctx);
2378 /* we now tell the backend to replace all existing values
2379 with the one we have constructed */
2380 el->flags = LDB_FLAG_MOD_REPLACE;
2387 handle deleting all active linked attributes
2389 static int replmd_modify_la_delete(struct ldb_module *module,
2390 struct replmd_private *replmd_private,
2391 const struct dsdb_schema *schema,
2392 struct ldb_message *msg,
2393 struct ldb_message_element *el,
2394 struct ldb_message_element *old_el,
2395 const struct dsdb_attribute *schema_attr,
2398 struct GUID *msg_guid,
2399 struct ldb_request *parent)
2402 struct parsed_dn *dns, *old_dns;
2403 TALLOC_CTX *tmp_ctx = NULL;
2405 const struct GUID *invocation_id;
2406 struct ldb_context *ldb = ldb_module_get_ctx(module);
2407 struct ldb_control *vanish_links_ctrl = NULL;
2408 bool vanish_links = false;
2409 unsigned int num_to_delete = el->num_values;
2412 unix_to_nt_time(&now, t);
2414 /* check if there is nothing to delete */
2415 if ((!old_el || old_el->num_values == 0) &&
2416 el->num_values == 0) {
2420 if (!old_el || old_el->num_values == 0) {
2421 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2424 tmp_ctx = talloc_new(msg);
2425 if (tmp_ctx == NULL) {
2426 return LDB_ERR_OPERATIONS_ERROR;
2429 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2430 if (ret != LDB_SUCCESS) {
2431 talloc_free(tmp_ctx);
2435 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2436 if (ret != LDB_SUCCESS) {
2437 talloc_free(tmp_ctx);
2441 invocation_id = samdb_ntds_invocation_id(ldb);
2442 if (!invocation_id) {
2443 talloc_free(tmp_ctx);
2444 return LDB_ERR_OPERATIONS_ERROR;
2447 ret = replmd_check_upgrade_links(ldb, old_dns, old_el->num_values,
2448 old_el, invocation_id,
2449 schema_attr->syntax->ldap_oid);
2450 if (ret != LDB_SUCCESS) {
2451 talloc_free(tmp_ctx);
2456 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2457 if (vanish_links_ctrl) {
2458 vanish_links = true;
2459 vanish_links_ctrl->critical = false;
2466 /* see if we are being asked to delete any links that
2467 don't exist or are already deleted */
2468 for (i=0; i < num_to_delete; i++) {
2469 struct parsed_dn *p = &dns[i];
2470 struct parsed_dn *p2;
2471 struct parsed_dn *next = NULL;
2473 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2477 schema_attr->syntax->ldap_oid);
2478 if (ret != LDB_SUCCESS) {
2479 talloc_free(tmp_ctx);
2484 struct GUID_txt_buf buf;
2485 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
2486 el->name, GUID_buf_string(&p->guid, &buf));
2487 if (ldb_attr_cmp(el->name, "member") == 0) {
2488 talloc_free(tmp_ctx);
2489 return LDB_ERR_UNWILLING_TO_PERFORM;
2491 talloc_free(tmp_ctx);
2492 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2495 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
2496 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2497 struct GUID_txt_buf buf;
2498 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2500 DEBUG(0, ("Deleting deleted linked attribute %s to %s, "
2501 "because vanish_links control is set\n",
2502 el->name, guid_str));
2505 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
2506 el->name, guid_str);
2507 if (ldb_attr_cmp(el->name, "member") == 0) {
2508 talloc_free(tmp_ctx);
2509 return LDB_ERR_UNWILLING_TO_PERFORM;
2511 talloc_free(tmp_ctx);
2512 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2518 if (num_to_delete == old_el->num_values || num_to_delete == 0) {
2519 el->flags = LDB_FLAG_MOD_REPLACE;
2521 for (i = 0; i < old_el->num_values; i++) {
2522 ret = replmd_add_backlink(module,
2528 if (ret != LDB_SUCCESS) {
2529 talloc_free(tmp_ctx);
2533 talloc_free(tmp_ctx);
2536 unsigned int num_values = 0;
2538 struct parsed_dn *exact = NULL, *next = NULL;
2540 for (i = 0; i < old_el->num_values; i++) {
2541 ret = parsed_dn_find(ldb, dns, num_to_delete,
2545 schema_attr->syntax->ldap_oid);
2546 if (ret != LDB_SUCCESS) {
2547 talloc_free(tmp_ctx);
2551 if (exact != NULL) {
2552 /* The element is in the delete list.
2554 ret = replmd_add_backlink(module,
2562 if (ret != LDB_SUCCESS) {
2563 talloc_free(tmp_ctx);
2566 old_dns[i].v->length = 0;
2571 for (i = 0; i < old_el->num_values; i++) {
2572 if (old_el->values[i].length != 0) {
2573 old_el->values[j] = old_el->values[i];
2575 if (j == num_values) {
2580 old_el->num_values = num_values;
2584 /* for each new value, see if it exists already with the same GUID
2585 if it is not already deleted and matches the delete list then delete it
2587 for (i=0; i<old_el->num_values; i++) {
2588 struct parsed_dn *p = &old_dns[i];
2589 struct parsed_dn *exact = NULL, *next = NULL;
2592 if (num_to_delete != 0) {
2593 ret = parsed_dn_find(ldb, dns, num_to_delete,
2597 schema_attr->syntax->ldap_oid);
2598 if (ret != LDB_SUCCESS) {
2599 talloc_free(tmp_ctx);
2602 if (exact == NULL) {
2607 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2608 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2610 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
2611 invocation_id, seq_num, seq_num, now, 0, true);
2612 if (ret != LDB_SUCCESS) {
2613 talloc_free(tmp_ctx);
2616 ret = replmd_add_backlink(module, replmd_private,
2617 schema, msg_guid, &p->guid,
2618 false, schema_attr, true);
2619 if (ret != LDB_SUCCESS) {
2620 talloc_free(tmp_ctx);
2625 el->values = talloc_steal(msg->elements, old_el->values);
2626 el->num_values = old_el->num_values;
2628 talloc_free(tmp_ctx);
2630 /* we now tell the backend to replace all existing values
2631 with the one we have constructed */
2632 el->flags = LDB_FLAG_MOD_REPLACE;
2638 handle replacing a linked attribute
2640 static int replmd_modify_la_replace(struct ldb_module *module,
2641 struct replmd_private *replmd_private,
2642 const struct dsdb_schema *schema,
2643 struct ldb_message *msg,
2644 struct ldb_message_element *el,
2645 struct ldb_message_element *old_el,
2646 const struct dsdb_attribute *schema_attr,
2649 struct GUID *msg_guid,
2650 struct ldb_request *parent)
2653 struct parsed_dn *dns, *old_dns;
2654 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2656 const struct GUID *invocation_id;
2657 struct ldb_context *ldb = ldb_module_get_ctx(module);
2658 struct ldb_val *new_values = NULL;
2659 unsigned int num_new_values = 0;
2660 unsigned int old_num_values = old_el?old_el->num_values:0;
2663 unix_to_nt_time(&now, t);
2665 /* check if there is nothing to replace */
2666 if ((!old_el || old_el->num_values == 0) &&
2667 el->num_values == 0) {
2671 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2672 if (ret != LDB_SUCCESS) {
2673 talloc_free(tmp_ctx);
2677 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2678 if (ret != LDB_SUCCESS) {
2679 talloc_free(tmp_ctx);
2683 invocation_id = samdb_ntds_invocation_id(ldb);
2684 if (!invocation_id) {
2685 return LDB_ERR_OPERATIONS_ERROR;
2688 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2689 old_el, invocation_id,
2690 schema_attr->syntax->ldap_oid);
2691 if (ret != LDB_SUCCESS) {
2692 talloc_free(tmp_ctx);
2696 /* mark all the old ones as deleted */
2697 for (i=0; i<old_num_values; i++) {
2698 struct parsed_dn *old_p = &old_dns[i];
2699 struct parsed_dn *exact = NULL, *next = NULL;
2700 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2702 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2704 ret = replmd_add_backlink(module, replmd_private,
2705 schema, msg_guid, &old_dns[i].guid,
2706 false, schema_attr, false);
2707 if (ret != LDB_SUCCESS) {
2708 talloc_free(tmp_ctx);
2712 ret = parsed_dn_find(ldb, dns, el->num_values,
2716 schema_attr->syntax->ldap_oid);
2717 if (ret != LDB_SUCCESS) {
2718 talloc_free(tmp_ctx);
2722 /* we don't delete it if we are re-adding it */
2726 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2727 invocation_id, seq_num, seq_num, now, 0, true);
2728 if (ret != LDB_SUCCESS) {
2729 talloc_free(tmp_ctx);
2734 /* for each new value, either update its meta-data, or add it
2737 for (i=0; i<el->num_values; i++) {
2738 struct parsed_dn *p = &dns[i];
2739 struct parsed_dn *old_p = NULL, *next = NULL;
2742 ret = parsed_dn_find(ldb, old_dns, old_num_values,
2746 schema_attr->syntax->ldap_oid);
2747 if (ret != LDB_SUCCESS) {
2748 talloc_free(tmp_ctx);
2753 if (old_p != NULL) {
2754 /* update in place */
2755 ret = replmd_update_la_val(old_el->values, old_p->v, p->dsdb_dn,
2756 old_p->dsdb_dn, invocation_id,
2757 seq_num, seq_num, now, 0, false);
2758 if (ret != LDB_SUCCESS) {
2759 talloc_free(tmp_ctx);
2764 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2766 if (new_values == NULL) {
2767 ldb_module_oom(module);
2768 talloc_free(tmp_ctx);
2769 return LDB_ERR_OPERATIONS_ERROR;
2771 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2772 invocation_id, seq_num, seq_num, now, 0, false);
2773 if (ret != LDB_SUCCESS) {
2774 talloc_free(tmp_ctx);
2780 ret = replmd_add_backlink(module, replmd_private,
2781 schema, msg_guid, &dns[i].guid,
2782 true, schema_attr, false);
2783 if (ret != LDB_SUCCESS) {
2784 talloc_free(tmp_ctx);
2789 /* add the new values to the end of old_el */
2790 if (num_new_values != 0) {
2791 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2792 struct ldb_val, old_num_values+num_new_values);
2793 if (el->values == NULL) {
2794 ldb_module_oom(module);
2795 return LDB_ERR_OPERATIONS_ERROR;
2797 memcpy(&el->values[old_num_values], &new_values[0],
2798 sizeof(struct ldb_val)*num_new_values);
2799 el->num_values = old_num_values + num_new_values;
2800 talloc_steal(msg->elements, new_values);
2802 el->values = old_el->values;
2803 el->num_values = old_el->num_values;
2804 talloc_steal(msg->elements, el->values);
2807 talloc_free(tmp_ctx);
2809 /* we now tell the backend to replace all existing values
2810 with the one we have constructed */
2811 el->flags = LDB_FLAG_MOD_REPLACE;
2818 handle linked attributes in modify requests
2820 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2821 struct replmd_private *replmd_private,
2822 struct ldb_message *msg,
2823 uint64_t seq_num, time_t t,
2824 struct ldb_request *parent)
2826 struct ldb_result *res;
2829 struct ldb_context *ldb = ldb_module_get_ctx(module);
2830 struct ldb_message *old_msg;
2832 const struct dsdb_schema *schema;
2833 struct GUID old_guid;
2835 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2837 * Nothing special is required for modifying or vanishing links
2838 * in fl2000 since they are just strings in a multi-valued
2841 struct ldb_control *ctrl = ldb_request_get_control(parent,
2842 DSDB_CONTROL_REPLMD_VANISH_LINKS);
2844 ctrl->critical = false;
2852 * We should restrict this to the intersection of the list of
2853 * linked attributes in the schema and the list of attributes
2856 * This will help performance a little, as otherwise we have
2857 * to allocate the entire object value-by-value.
2859 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2860 DSDB_FLAG_NEXT_MODULE |
2861 DSDB_SEARCH_SHOW_RECYCLED |
2862 DSDB_SEARCH_REVEAL_INTERNALS |
2863 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2865 if (ret != LDB_SUCCESS) {
2868 schema = dsdb_get_schema(ldb, res);
2870 return LDB_ERR_OPERATIONS_ERROR;
2873 old_msg = res->msgs[0];
2875 old_guid = samdb_result_guid(old_msg, "objectGUID");
2877 for (i=0; i<msg->num_elements; i++) {
2878 struct ldb_message_element *el = &msg->elements[i];
2879 struct ldb_message_element *old_el, *new_el;
2880 const struct dsdb_attribute *schema_attr
2881 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2883 ldb_asprintf_errstring(ldb,
2884 "%s: attribute %s is not a valid attribute in schema",
2885 __FUNCTION__, el->name);
2886 return LDB_ERR_OBJECT_CLASS_VIOLATION;
2888 if (schema_attr->linkID == 0) {
2891 if ((schema_attr->linkID & 1) == 1) {
2892 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
2895 /* Odd is for the target. Illegal to modify */
2896 ldb_asprintf_errstring(ldb,
2897 "attribute %s must not be modified directly, it is a linked attribute", el->name);
2898 return LDB_ERR_UNWILLING_TO_PERFORM;
2900 old_el = ldb_msg_find_element(old_msg, el->name);
2901 switch (el->flags & LDB_FLAG_MOD_MASK) {
2902 case LDB_FLAG_MOD_REPLACE:
2903 ret = replmd_modify_la_replace(module, replmd_private,
2904 schema, msg, el, old_el,
2905 schema_attr, seq_num, t,
2908 case LDB_FLAG_MOD_DELETE:
2909 ret = replmd_modify_la_delete(module, replmd_private,
2910 schema, msg, el, old_el,
2911 schema_attr, seq_num, t,
2914 case LDB_FLAG_MOD_ADD:
2915 ret = replmd_modify_la_add(module, replmd_private,
2916 schema, msg, el, old_el,
2917 schema_attr, seq_num, t,
2921 ldb_asprintf_errstring(ldb,
2922 "invalid flags 0x%x for %s linked attribute",
2923 el->flags, el->name);
2924 return LDB_ERR_UNWILLING_TO_PERFORM;
2926 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
2927 ldb_asprintf_errstring(ldb,
2928 "Attribute %s is single valued but more than one value has been supplied",
2930 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2932 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
2937 if (ret != LDB_SUCCESS) {
2941 ldb_msg_remove_attr(old_msg, el->name);
2943 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2944 new_el->num_values = el->num_values;
2945 new_el->values = talloc_steal(msg->elements, el->values);
2947 /* TODO: this relises a bit too heavily on the exact
2948 behaviour of ldb_msg_find_element and
2949 ldb_msg_remove_element */
2950 old_el = ldb_msg_find_element(msg, el->name);
2952 ldb_msg_remove_element(msg, old_el);
2963 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2965 struct ldb_context *ldb;
2966 struct replmd_replicated_request *ac;
2967 struct ldb_request *down_req;
2968 struct ldb_message *msg;
2969 time_t t = time(NULL);
2971 bool is_urgent = false, rodc = false;
2972 bool is_schema_nc = false;
2973 unsigned int functional_level;
2974 const struct ldb_message_element *guid_el = NULL;
2975 struct ldb_control *sd_propagation_control;
2976 struct replmd_private *replmd_private =
2977 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2979 /* do not manipulate our control entries */
2980 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2981 return ldb_next_request(module, req);
2984 sd_propagation_control = ldb_request_get_control(req,
2985 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
2986 if (sd_propagation_control != NULL) {
2987 if (req->op.mod.message->num_elements != 1) {
2988 return ldb_module_operr(module);
2990 ret = strcmp(req->op.mod.message->elements[0].name,
2991 "nTSecurityDescriptor");
2993 return ldb_module_operr(module);
2996 return ldb_next_request(module, req);
2999 ldb = ldb_module_get_ctx(module);
3001 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3003 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3004 if (guid_el != NULL) {
3005 ldb_set_errstring(ldb,
3006 "replmd_modify: it's not allowed to change the objectGUID!");
3007 return LDB_ERR_CONSTRAINT_VIOLATION;
3010 ac = replmd_ctx_init(module, req);
3012 return ldb_module_oom(module);
3015 functional_level = dsdb_functional_level(ldb);
3017 /* we have to copy the message as the caller might have it as a const */
3018 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3022 return LDB_ERR_OPERATIONS_ERROR;
3025 ldb_msg_remove_attr(msg, "whenChanged");
3026 ldb_msg_remove_attr(msg, "uSNChanged");
3028 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3030 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3031 msg, &ac->seq_num, t, is_schema_nc,
3033 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3034 struct loadparm_context *lp_ctx;
3037 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3038 struct loadparm_context);
3040 referral = talloc_asprintf(req,
3042 lpcfg_dnsdomain(lp_ctx),
3043 ldb_dn_get_linearized(msg->dn));
3044 ret = ldb_module_send_referral(req, referral);
3049 if (ret != LDB_SUCCESS) {
3054 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3055 msg, ac->seq_num, t, req);
3056 if (ret != LDB_SUCCESS) {
3062 * - replace the old object with the newly constructed one
3065 ac->is_urgent = is_urgent;
3067 ret = ldb_build_mod_req(&down_req, ldb, ac,
3070 ac, replmd_op_callback,
3072 LDB_REQ_SET_LOCATION(down_req);
3073 if (ret != LDB_SUCCESS) {
3078 /* current partition control is needed by "replmd_op_callback" */
3079 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3080 ret = ldb_request_add_control(down_req,
3081 DSDB_CONTROL_CURRENT_PARTITION_OID,
3083 if (ret != LDB_SUCCESS) {
3089 /* If we are in functional level 2000, then
3090 * replmd_modify_handle_linked_attribs will have done
3092 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3093 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3094 if (ret != LDB_SUCCESS) {
3100 talloc_steal(down_req, msg);
3102 /* we only change whenChanged and uSNChanged if the seq_num
3104 if (ac->seq_num != 0) {
3105 ret = add_time_element(msg, "whenChanged", t);
3106 if (ret != LDB_SUCCESS) {
3112 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3113 if (ret != LDB_SUCCESS) {
3120 /* go on with the call chain */
3121 return ldb_next_request(module, down_req);
3124 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3127 handle a rename request
3129 On a rename we need to do an extra ldb_modify which sets the
3130 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3132 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3134 struct ldb_context *ldb;
3135 struct replmd_replicated_request *ac;
3137 struct ldb_request *down_req;
3139 /* do not manipulate our control entries */
3140 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3141 return ldb_next_request(module, req);
3144 ldb = ldb_module_get_ctx(module);
3146 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3148 ac = replmd_ctx_init(module, req);
3150 return ldb_module_oom(module);
3153 ret = ldb_build_rename_req(&down_req, ldb, ac,
3154 ac->req->op.rename.olddn,
3155 ac->req->op.rename.newdn,
3157 ac, replmd_rename_callback,
3159 LDB_REQ_SET_LOCATION(down_req);
3160 if (ret != LDB_SUCCESS) {
3165 /* go on with the call chain */
3166 return ldb_next_request(module, down_req);
3169 /* After the rename is compleated, update the whenchanged etc */
3170 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3172 struct ldb_context *ldb;
3173 struct ldb_request *down_req;
3174 struct ldb_message *msg;
3175 const struct dsdb_attribute *rdn_attr;
3176 const char *rdn_name;
3177 const struct ldb_val *rdn_val;
3178 const char *attrs[5] = { NULL, };
3179 time_t t = time(NULL);
3181 bool is_urgent = false, rodc = false;
3183 struct replmd_replicated_request *ac =
3184 talloc_get_type(req->context, struct replmd_replicated_request);
3185 struct replmd_private *replmd_private =
3186 talloc_get_type(ldb_module_get_private(ac->module),
3187 struct replmd_private);
3189 ldb = ldb_module_get_ctx(ac->module);
3191 if (ares->error != LDB_SUCCESS) {
3192 return ldb_module_done(ac->req, ares->controls,
3193 ares->response, ares->error);
3196 if (ares->type != LDB_REPLY_DONE) {
3197 ldb_set_errstring(ldb,
3198 "invalid ldb_reply_type in callback");
3200 return ldb_module_done(ac->req, NULL, NULL,
3201 LDB_ERR_OPERATIONS_ERROR);
3205 * - replace the old object with the newly constructed one
3208 msg = ldb_msg_new(ac);
3211 return LDB_ERR_OPERATIONS_ERROR;
3214 msg->dn = ac->req->op.rename.newdn;
3216 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3218 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3219 if (rdn_name == NULL) {
3221 return ldb_module_done(ac->req, NULL, NULL,
3225 /* normalize the rdn attribute name */
3226 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3227 if (rdn_attr == NULL) {
3229 return ldb_module_done(ac->req, NULL, NULL,
3232 rdn_name = rdn_attr->lDAPDisplayName;
3234 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3235 if (rdn_val == NULL) {
3237 return ldb_module_done(ac->req, NULL, NULL,
3241 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3243 return ldb_module_done(ac->req, NULL, NULL,
3246 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3248 return ldb_module_done(ac->req, NULL, NULL,
3251 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3253 return ldb_module_done(ac->req, NULL, NULL,
3256 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3258 return ldb_module_done(ac->req, NULL, NULL,
3263 * here we let replmd_update_rpmd() only search for
3264 * the existing "replPropertyMetaData" and rdn_name attributes.
3266 * We do not want the existing "name" attribute as
3267 * the "name" attribute needs to get the version
3268 * updated on rename even if the rdn value hasn't changed.
3270 * This is the diff of the meta data, for a moved user
3271 * on a w2k8r2 server:
3274 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3275 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3276 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3277 * version : 0x00000001 (1)
3278 * reserved : 0x00000000 (0)
3279 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3280 * local_usn : 0x00000000000037a5 (14245)
3281 * array: struct replPropertyMetaData1
3282 * attid : DRSUAPI_ATTID_name (0x90001)
3283 * - version : 0x00000001 (1)
3284 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3285 * + version : 0x00000002 (2)
3286 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3287 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3288 * - originating_usn : 0x00000000000037a5 (14245)
3289 * - local_usn : 0x00000000000037a5 (14245)
3290 * + originating_usn : 0x0000000000003834 (14388)
3291 * + local_usn : 0x0000000000003834 (14388)
3292 * array: struct replPropertyMetaData1
3293 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3294 * version : 0x00000004 (4)
3296 attrs[0] = "replPropertyMetaData";
3297 attrs[1] = "objectClass";
3298 attrs[2] = "instanceType";
3299 attrs[3] = rdn_name;
3302 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3303 msg, &ac->seq_num, t,
3304 is_schema_nc, &is_urgent, &rodc);
3305 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3306 struct ldb_dn *olddn = ac->req->op.rename.olddn;
3307 struct loadparm_context *lp_ctx;
3310 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3311 struct loadparm_context);
3313 referral = talloc_asprintf(req,
3315 lpcfg_dnsdomain(lp_ctx),
3316 ldb_dn_get_linearized(olddn));
3317 ret = ldb_module_send_referral(req, referral);
3319 return ldb_module_done(req, NULL, NULL, ret);
3322 if (ret != LDB_SUCCESS) {
3324 return ldb_module_done(ac->req, NULL, NULL, ret);
3327 if (ac->seq_num == 0) {
3329 return ldb_module_done(ac->req, NULL, NULL,
3331 "internal error seq_num == 0"));
3333 ac->is_urgent = is_urgent;
3335 ret = ldb_build_mod_req(&down_req, ldb, ac,
3338 ac, replmd_op_callback,
3340 LDB_REQ_SET_LOCATION(down_req);
3341 if (ret != LDB_SUCCESS) {
3346 /* current partition control is needed by "replmd_op_callback" */
3347 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3348 ret = ldb_request_add_control(down_req,
3349 DSDB_CONTROL_CURRENT_PARTITION_OID,
3351 if (ret != LDB_SUCCESS) {
3357 talloc_steal(down_req, msg);
3359 ret = add_time_element(msg, "whenChanged", t);
3360 if (ret != LDB_SUCCESS) {
3366 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3367 if (ret != LDB_SUCCESS) {
3373 /* go on with the call chain - do the modify after the rename */
3374 return ldb_next_request(ac->module, down_req);
3378 * remove links from objects that point at this object when an object
3379 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3380 * RemoveObj which states that link removal due to the object being
3381 * deleted is NOT an originating update - they just go away!
3384 static int replmd_delete_remove_link(struct ldb_module *module,
3385 const struct dsdb_schema *schema,
3387 struct ldb_message_element *el,
3388 const struct dsdb_attribute *sa,
3389 struct ldb_request *parent)
3392 TALLOC_CTX *tmp_ctx = talloc_new(module);
3393 struct ldb_context *ldb = ldb_module_get_ctx(module);
3395 for (i=0; i<el->num_values; i++) {
3396 struct dsdb_dn *dsdb_dn;
3400 struct ldb_message *msg;
3401 const struct dsdb_attribute *target_attr;
3402 struct ldb_message_element *el2;
3403 struct ldb_val dn_val;
3404 uint32_t dsdb_flags = 0;
3406 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3410 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3412 talloc_free(tmp_ctx);
3413 return LDB_ERR_OPERATIONS_ERROR;
3416 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
3417 if (!NT_STATUS_IS_OK(status)) {
3418 talloc_free(tmp_ctx);
3419 return LDB_ERR_OPERATIONS_ERROR;
3422 /* remove the link */
3423 msg = ldb_msg_new(tmp_ctx);
3425 ldb_module_oom(module);
3426 talloc_free(tmp_ctx);
3427 return LDB_ERR_OPERATIONS_ERROR;
3431 msg->dn = dsdb_dn->dn;
3433 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3434 if (target_attr == NULL) {
3438 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
3439 if (ret != LDB_SUCCESS) {
3440 ldb_module_oom(module);
3441 talloc_free(tmp_ctx);
3442 return LDB_ERR_OPERATIONS_ERROR;
3444 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
3445 el2->values = &dn_val;
3446 el2->num_values = 1;
3449 * Ensure that we tell the modification to vanish any linked
3450 * attributes (not simply mark them as isDeleted = TRUE)
3452 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3454 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3455 if (ret != LDB_SUCCESS) {
3456 talloc_free(tmp_ctx);
3460 talloc_free(tmp_ctx);
3466 handle update of replication meta data for deletion of objects
3468 This also handles the mapping of delete to a rename operation
3469 to allow deletes to be replicated.
3471 It also handles the incoming deleted objects, to ensure they are
3472 fully deleted here. In that case re_delete is true, and we do not
3473 use this as a signal to change the deleted state, just reinforce it.
3476 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3478 int ret = LDB_ERR_OTHER;
3479 bool retb, disallow_move_on_delete;
3480 struct ldb_dn *old_dn, *new_dn;
3481 const char *rdn_name;
3482 const struct ldb_val *rdn_value, *new_rdn_value;
3484 struct ldb_context *ldb = ldb_module_get_ctx(module);
3485 const struct dsdb_schema *schema;
3486 struct ldb_message *msg, *old_msg;
3487 struct ldb_message_element *el;
3488 TALLOC_CTX *tmp_ctx;
3489 struct ldb_result *res, *parent_res;
3490 static const char * const preserved_attrs[] = {
3491 /* yes, this really is a hard coded list. See MS-ADTS
3492 section 3.1.1.5.5.1.1 */
3495 "dNReferenceUpdate",
3506 "msDS-LastKnownRDN",
3512 "distinguishedName",
3516 "proxiedObjectName",
3518 "nTSecurityDescriptor",
3519 "replPropertyMetaData",
3521 "securityIdentifier",
3529 "userAccountControl",
3536 static const char * const all_attrs[] = {
3537 DSDB_SECRET_ATTRIBUTES,
3541 unsigned int i, el_count = 0;
3542 uint32_t dsdb_flags = 0;
3543 enum deletion_state deletion_state, next_deletion_state;
3545 if (ldb_dn_is_special(req->op.del.dn)) {
3546 return ldb_next_request(module, req);
3550 * We have to allow dbcheck to remove an object that
3551 * is beyond repair, and to do so totally. This could
3552 * mean we we can get a partial object from the other
3553 * DC, causing havoc, so dbcheck suggests
3554 * re-replication first. dbcheck sets both DBCHECK
3555 * and RELAX in this situation.
3557 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3558 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3559 /* really, really remove it */
3560 return ldb_next_request(module, req);
3563 tmp_ctx = talloc_new(ldb);
3566 return LDB_ERR_OPERATIONS_ERROR;
3569 schema = dsdb_get_schema(ldb, tmp_ctx);
3571 talloc_free(tmp_ctx);
3572 return LDB_ERR_OPERATIONS_ERROR;
3575 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3577 /* we need the complete msg off disk, so we can work out which
3578 attributes need to be removed */
3579 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3580 DSDB_FLAG_NEXT_MODULE |
3581 DSDB_SEARCH_SHOW_RECYCLED |
3582 DSDB_SEARCH_REVEAL_INTERNALS |
3583 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3584 if (ret != LDB_SUCCESS) {
3585 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3586 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3587 re_delete ? "re-delete" : "delete",
3588 ldb_dn_get_linearized(old_dn),
3589 ldb_errstring(ldb_module_get_ctx(module)));
3590 talloc_free(tmp_ctx);
3593 old_msg = res->msgs[0];
3595 replmd_deletion_state(module, old_msg,
3597 &next_deletion_state);
3599 /* This supports us noticing an incoming isDeleted and acting on it */
3601 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3602 next_deletion_state = deletion_state;
3605 if (next_deletion_state == OBJECT_REMOVED) {
3607 * We have to prevent objects being deleted, even if
3608 * the administrator really wants them gone, as
3609 * without the tombstone, we can get a partial object
3610 * from the other DC, causing havoc.
3612 * The only other valid case is when the 180 day
3613 * timeout has expired, when relax is specified.
3615 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3616 /* it is already deleted - really remove it this time */
3617 talloc_free(tmp_ctx);
3618 return ldb_next_request(module, req);
3621 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3622 "This check is to prevent corruption of the replicated state.",
3623 ldb_dn_get_linearized(old_msg->dn));
3624 return LDB_ERR_UNWILLING_TO_PERFORM;
3627 rdn_name = ldb_dn_get_rdn_name(old_dn);
3628 rdn_value = ldb_dn_get_rdn_val(old_dn);
3629 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3630 talloc_free(tmp_ctx);
3631 return ldb_operr(ldb);
3634 msg = ldb_msg_new(tmp_ctx);
3636 ldb_module_oom(module);
3637 talloc_free(tmp_ctx);
3638 return LDB_ERR_OPERATIONS_ERROR;
3643 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3644 disallow_move_on_delete =
3645 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3646 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3648 /* work out where we will be renaming this object to */
3649 if (!disallow_move_on_delete) {
3650 struct ldb_dn *deleted_objects_dn;
3651 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3652 &deleted_objects_dn);
3655 * We should not move objects if we can't find the
3656 * deleted objects DN. Not moving (or otherwise
3657 * harming) the Deleted Objects DN itself is handled
3660 if (re_delete && (ret != LDB_SUCCESS)) {
3661 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3662 if (new_dn == NULL) {
3663 ldb_module_oom(module);
3664 talloc_free(tmp_ctx);
3665 return LDB_ERR_OPERATIONS_ERROR;
3667 } else if (ret != LDB_SUCCESS) {
3668 /* this is probably an attempted delete on a partition
3669 * that doesn't allow delete operations, such as the
3670 * schema partition */
3671 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3672 ldb_dn_get_linearized(old_dn));
3673 talloc_free(tmp_ctx);
3674 return LDB_ERR_UNWILLING_TO_PERFORM;
3676 new_dn = deleted_objects_dn;
3679 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3680 if (new_dn == NULL) {
3681 ldb_module_oom(module);
3682 talloc_free(tmp_ctx);
3683 return LDB_ERR_OPERATIONS_ERROR;
3687 if (deletion_state == OBJECT_NOT_DELETED) {
3688 /* get the objects GUID from the search we just did */
3689 guid = samdb_result_guid(old_msg, "objectGUID");
3691 /* Add a formatted child */
3692 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3694 ldb_dn_escape_value(tmp_ctx, *rdn_value),
3695 GUID_string(tmp_ctx, &guid));
3697 ldb_asprintf_errstring(ldb, __location__
3698 ": Unable to add a formatted child to dn: %s",
3699 ldb_dn_get_linearized(new_dn));
3700 talloc_free(tmp_ctx);
3701 return LDB_ERR_OPERATIONS_ERROR;
3704 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
3705 if (ret != LDB_SUCCESS) {
3706 ldb_asprintf_errstring(ldb, __location__
3707 ": Failed to add isDeleted string to the msg");
3708 talloc_free(tmp_ctx);
3711 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3714 * No matter what has happened with other renames etc, try again to
3715 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
3718 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
3719 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
3721 ldb_asprintf_errstring(ldb, __location__
3722 ": Unable to add a prepare rdn of %s",
3723 ldb_dn_get_linearized(rdn));
3724 talloc_free(tmp_ctx);
3725 return LDB_ERR_OPERATIONS_ERROR;
3727 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
3729 retb = ldb_dn_add_child(new_dn, rdn);
3731 ldb_asprintf_errstring(ldb, __location__
3732 ": Unable to add rdn %s to base dn: %s",
3733 ldb_dn_get_linearized(rdn),
3734 ldb_dn_get_linearized(new_dn));
3735 talloc_free(tmp_ctx);
3736 return LDB_ERR_OPERATIONS_ERROR;
3741 now we need to modify the object in the following ways:
3743 - add isDeleted=TRUE
3744 - update rDN and name, with new rDN
3745 - remove linked attributes
3746 - remove objectCategory and sAMAccountType
3747 - remove attribs not on the preserved list
3748 - preserved if in above list, or is rDN
3749 - remove all linked attribs from this object
3750 - remove all links from other objects to this object
3751 - add lastKnownParent
3752 - update replPropertyMetaData?
3754 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
3757 if (deletion_state == OBJECT_NOT_DELETED) {
3758 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3759 char *parent_dn_str = NULL;
3761 /* we need the storage form of the parent GUID */
3762 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
3764 DSDB_FLAG_NEXT_MODULE |
3765 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3766 DSDB_SEARCH_REVEAL_INTERNALS|
3767 DSDB_SEARCH_SHOW_RECYCLED, req);
3768 if (ret != LDB_SUCCESS) {
3769 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3770 "repmd_delete: Failed to %s %s, "
3771 "because we failed to find it's parent (%s): %s",
3772 re_delete ? "re-delete" : "delete",
3773 ldb_dn_get_linearized(old_dn),
3774 ldb_dn_get_linearized(parent_dn),
3775 ldb_errstring(ldb_module_get_ctx(module)));
3776 talloc_free(tmp_ctx);
3781 * Now we can use the DB version,
3782 * it will have the extended DN info in it
3784 parent_dn = parent_res->msgs[0]->dn;
3785 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
3788 if (parent_dn_str == NULL) {
3789 talloc_free(tmp_ctx);
3790 return ldb_module_oom(module);
3793 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3795 if (ret != LDB_SUCCESS) {
3796 ldb_asprintf_errstring(ldb, __location__
3797 ": Failed to add lastKnownParent "
3798 "string when deleting %s",
3799 ldb_dn_get_linearized(old_dn));
3800 talloc_free(tmp_ctx);
3803 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3805 if (next_deletion_state == OBJECT_DELETED) {
3806 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
3807 if (ret != LDB_SUCCESS) {
3808 ldb_asprintf_errstring(ldb, __location__
3809 ": Failed to add msDS-LastKnownRDN "
3810 "string when deleting %s",
3811 ldb_dn_get_linearized(old_dn));
3812 talloc_free(tmp_ctx);
3815 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
3819 switch (next_deletion_state) {
3821 case OBJECT_RECYCLED:
3822 case OBJECT_TOMBSTONE:
3825 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
3826 * describes what must be removed from a tombstone
3829 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
3830 * describes what must be removed from a recycled
3836 * we also mark it as recycled, meaning this object can't be
3837 * recovered (we are stripping its attributes).
3838 * This is done only if we have this schema object of course ...
3839 * This behavior is identical to the one of Windows 2008R2 which
3840 * always set the isRecycled attribute, even if the recycle-bin is
3841 * not activated and what ever the forest level is.
3843 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
3844 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
3845 if (ret != LDB_SUCCESS) {
3846 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
3847 ldb_module_oom(module);
3848 talloc_free(tmp_ctx);
3851 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3854 /* work out which of the old attributes we will be removing */
3855 for (i=0; i<old_msg->num_elements; i++) {
3856 const struct dsdb_attribute *sa;
3857 el = &old_msg->elements[i];
3858 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3860 talloc_free(tmp_ctx);
3861 return LDB_ERR_OPERATIONS_ERROR;
3863 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
3864 /* don't remove the rDN */
3867 if (sa->linkID && (sa->linkID & 1)) {
3869 we have a backlink in this object
3870 that needs to be removed. We're not
3871 allowed to remove it directly
3872 however, so we instead setup a
3873 modify to delete the corresponding
3876 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
3877 if (ret != LDB_SUCCESS) {
3878 const char *old_dn_str
3879 = ldb_dn_get_linearized(old_dn);
3880 ldb_asprintf_errstring(ldb,
3882 ": Failed to remove backlink of "
3883 "%s when deleting %s: %s",
3886 ldb_errstring(ldb));
3887 talloc_free(tmp_ctx);
3888 return LDB_ERR_OPERATIONS_ERROR;
3890 /* now we continue, which means we
3891 won't remove this backlink
3897 if (ldb_attr_in_list(preserved_attrs, el->name)) {
3900 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
3905 * Ensure that we tell the modification to vanish any linked
3906 * attributes (not simply mark them as isDeleted = TRUE)
3908 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3910 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
3911 if (ret != LDB_SUCCESS) {
3912 talloc_free(tmp_ctx);
3913 ldb_module_oom(module);
3920 case OBJECT_DELETED:
3922 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
3923 * describes what must be removed from a deleted
3927 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
3928 if (ret != LDB_SUCCESS) {
3929 talloc_free(tmp_ctx);
3930 ldb_module_oom(module);
3934 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
3935 if (ret != LDB_SUCCESS) {
3936 talloc_free(tmp_ctx);
3937 ldb_module_oom(module);
3947 if (deletion_state == OBJECT_NOT_DELETED) {
3948 const struct dsdb_attribute *sa;
3950 /* work out what the new rdn value is, for updating the
3951 rDN and name fields */
3952 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
3953 if (new_rdn_value == NULL) {
3954 talloc_free(tmp_ctx);
3955 return ldb_operr(ldb);
3958 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
3960 talloc_free(tmp_ctx);
3961 return LDB_ERR_OPERATIONS_ERROR;
3964 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
3966 if (ret != LDB_SUCCESS) {
3967 talloc_free(tmp_ctx);
3970 el->flags = LDB_FLAG_MOD_REPLACE;
3972 el = ldb_msg_find_element(old_msg, "name");
3974 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
3975 if (ret != LDB_SUCCESS) {
3976 talloc_free(tmp_ctx);
3979 el->flags = LDB_FLAG_MOD_REPLACE;
3984 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
3989 * No matter what has happned with other renames, try again to
3990 * get this to be under the deleted DN.
3992 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
3993 /* now rename onto the new DN */
3994 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
3995 if (ret != LDB_SUCCESS){
3996 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
3997 ldb_dn_get_linearized(old_dn),
3998 ldb_dn_get_linearized(new_dn),
3999 ldb_errstring(ldb)));
4000 talloc_free(tmp_ctx);
4006 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4007 if (ret != LDB_SUCCESS) {
4008 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4009 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4010 talloc_free(tmp_ctx);
4014 talloc_free(tmp_ctx);
4016 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4019 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4021 return replmd_delete_internals(module, req, false);
4025 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4030 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4032 int ret = LDB_ERR_OTHER;
4033 /* TODO: do some error mapping */
4035 /* Let the caller know the full WERROR */
4036 ar->objs->error = status;
4042 static struct replPropertyMetaData1 *
4043 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4044 enum drsuapi_DsAttributeId attid)
4047 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4049 for (i = 0; i < rpmd_ctr->count; i++) {
4050 if (rpmd_ctr->array[i].attid == attid) {
4051 return &rpmd_ctr->array[i];
4059 return true if an update is newer than an existing entry
4060 see section 5.11 of MS-ADTS
4062 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4063 const struct GUID *update_invocation_id,
4064 uint32_t current_version,
4065 uint32_t update_version,
4066 NTTIME current_change_time,
4067 NTTIME update_change_time)
4069 if (update_version != current_version) {
4070 return update_version > current_version;
4072 if (update_change_time != current_change_time) {
4073 return update_change_time > current_change_time;
4075 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4078 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4079 struct replPropertyMetaData1 *new_m)
4081 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4082 &new_m->originating_invocation_id,
4085 cur_m->originating_change_time,
4086 new_m->originating_change_time);
4089 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4090 struct replPropertyMetaData1 *cur_m,
4091 struct replPropertyMetaData1 *new_m)
4096 * If the new replPropertyMetaData entry for this attribute is
4097 * not provided (this happens in the case where we look for
4098 * ATTID_name, but the name was not changed), then the local
4099 * state is clearly still current, as the remote
4100 * server didn't send it due to being older the high watermark
4103 if (new_m == NULL) {
4107 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4109 * if we compare equal then do an
4110 * update. This is used when a client
4111 * asks for a FULL_SYNC, and can be
4112 * used to recover a corrupt
4115 * This call is a bit tricky, what we
4116 * are doing it turning the 'is_newer'
4117 * call into a 'not is older' by
4118 * swapping cur_m and new_m, and negating the
4121 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4124 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4134 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4136 const struct ldb_val *rdn_val;
4137 const char *rdn_name;
4138 struct ldb_dn *new_dn;
4140 rdn_val = ldb_dn_get_rdn_val(dn);
4141 rdn_name = ldb_dn_get_rdn_name(dn);
4142 if (!rdn_val || !rdn_name) {
4146 new_dn = ldb_dn_copy(mem_ctx, dn);
4151 if (!ldb_dn_remove_child_components(new_dn, 1)) {
4155 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4157 ldb_dn_escape_value(new_dn, *rdn_val),
4158 GUID_string(new_dn, guid))) {
4167 perform a modify operation which sets the rDN and name attributes to
4168 their current values. This has the effect of changing these
4169 attributes to have been last updated by the current DC. This is
4170 needed to ensure that renames performed as part of conflict
4171 resolution are propogated to other DCs
4173 static int replmd_name_modify(struct replmd_replicated_request *ar,
4174 struct ldb_request *req, struct ldb_dn *dn)
4176 struct ldb_message *msg;
4177 const char *rdn_name;
4178 const struct ldb_val *rdn_val;
4179 const struct dsdb_attribute *rdn_attr;
4182 msg = ldb_msg_new(req);
4188 rdn_name = ldb_dn_get_rdn_name(dn);
4189 if (rdn_name == NULL) {
4193 /* normalize the rdn attribute name */
4194 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4195 if (rdn_attr == NULL) {
4198 rdn_name = rdn_attr->lDAPDisplayName;
4200 rdn_val = ldb_dn_get_rdn_val(dn);
4201 if (rdn_val == NULL) {
4205 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4208 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4211 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4214 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4218 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4219 if (ret != LDB_SUCCESS) {
4220 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
4221 ldb_dn_get_linearized(dn),
4222 ldb_errstring(ldb_module_get_ctx(ar->module))));
4232 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
4233 ldb_dn_get_linearized(dn)));
4234 return LDB_ERR_OPERATIONS_ERROR;
4239 callback for conflict DN handling where we have renamed the incoming
4240 record. After renaming it, we need to ensure the change of name and
4241 rDN for the incoming record is seen as an originating update by this DC.
4243 This also handles updating lastKnownParent for entries sent to lostAndFound
4245 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4247 struct replmd_replicated_request *ar =
4248 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4249 struct ldb_dn *conflict_dn = NULL;
4252 if (ares->error != LDB_SUCCESS) {
4253 /* call the normal callback for everything except success */
4254 return replmd_op_callback(req, ares);
4257 switch (req->operation) {
4259 conflict_dn = req->op.add.message->dn;
4262 conflict_dn = req->op.mod.message->dn;
4265 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4268 /* perform a modify of the rDN and name of the record */
4269 ret = replmd_name_modify(ar, req, conflict_dn);
4270 if (ret != LDB_SUCCESS) {
4272 return replmd_op_callback(req, ares);
4275 if (ar->objs->objects[ar->index_current].last_known_parent) {
4276 struct ldb_message *msg = ldb_msg_new(req);
4278 ldb_module_oom(ar->module);
4279 return LDB_ERR_OPERATIONS_ERROR;
4282 msg->dn = req->op.add.message->dn;
4284 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4285 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4286 if (ret != LDB_SUCCESS) {
4287 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4288 ldb_module_oom(ar->module);
4291 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4293 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4294 if (ret != LDB_SUCCESS) {
4295 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4296 ldb_dn_get_linearized(msg->dn),
4297 ldb_errstring(ldb_module_get_ctx(ar->module))));
4303 return replmd_op_callback(req, ares);
4307 callback for replmd_replicated_apply_add()
4308 This copes with the creation of conflict records in the case where
4309 the DN exists, but with a different objectGUID
4311 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))
4313 struct ldb_dn *conflict_dn;
4314 struct replmd_replicated_request *ar =
4315 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4316 struct ldb_result *res;
4317 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4319 const struct ldb_val *omd_value;
4320 struct replPropertyMetaDataBlob omd, *rmd;
4321 enum ndr_err_code ndr_err;
4322 bool rename_incoming_record, rodc;
4323 struct replPropertyMetaData1 *rmd_name, *omd_name;
4324 struct ldb_message *msg;
4325 struct ldb_request *down_req = NULL;
4327 /* call the normal callback for success */
4328 if (ares->error == LDB_SUCCESS) {
4329 return callback(req, ares);
4333 * we have a conflict, and need to decide if we will keep the
4334 * new record or the old record
4337 msg = ar->objs->objects[ar->index_current].msg;
4338 conflict_dn = msg->dn;
4340 /* For failures other than conflicts, fail the whole operation here */
4341 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4342 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4343 ldb_dn_get_linearized(conflict_dn),
4344 ldb_errstring(ldb_module_get_ctx(ar->module)));
4346 return ldb_module_done(ar->req, NULL, NULL,
4347 LDB_ERR_OPERATIONS_ERROR);
4350 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4351 if (ret != LDB_SUCCESS) {
4352 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)));
4353 return ldb_module_done(ar->req, NULL, NULL,
4354 LDB_ERR_OPERATIONS_ERROR);
4360 * We are on an RODC, or were a GC for this
4361 * partition, so we have to fail this until
4362 * someone who owns the partition sorts it
4365 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4366 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
4367 " - We must fail the operation until a master for this partition resolves the conflict",
4368 ldb_dn_get_linearized(conflict_dn));
4373 * first we need the replPropertyMetaData attribute from the
4374 * local, conflicting record
4376 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4378 DSDB_FLAG_NEXT_MODULE |
4379 DSDB_SEARCH_SHOW_DELETED |
4380 DSDB_SEARCH_SHOW_RECYCLED, req);
4381 if (ret != LDB_SUCCESS) {
4382 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4383 ldb_dn_get_linearized(conflict_dn)));
4387 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4388 if (omd_value == NULL) {
4389 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4390 ldb_dn_get_linearized(conflict_dn)));
4394 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4395 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4396 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4397 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4398 ldb_dn_get_linearized(conflict_dn)));
4402 rmd = ar->objs->objects[ar->index_current].meta_data;
4405 * we decide which is newer based on the RPMD on the name
4406 * attribute. See [MS-DRSR] ResolveNameConflict.
4408 * We expect omd_name to be present, as this is from a local
4409 * search, but while rmd_name should have been given to us by
4410 * the remote server, if it is missing we just prefer the
4412 * replmd_replPropertyMetaData1_new_should_be_taken()
4414 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4415 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4417 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4418 ldb_dn_get_linearized(conflict_dn)));
4423 * Should we preserve the current record, and so rename the
4424 * incoming record to be a conflict?
4426 rename_incoming_record
4427 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4428 omd_name, rmd_name);
4430 if (rename_incoming_record) {
4432 struct ldb_dn *new_dn;
4434 guid = samdb_result_guid(msg, "objectGUID");
4435 if (GUID_all_zero(&guid)) {
4436 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4437 ldb_dn_get_linearized(conflict_dn)));
4440 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4441 if (new_dn == NULL) {
4442 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4443 ldb_dn_get_linearized(conflict_dn)));
4447 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4448 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4450 /* re-submit the request, but with the new DN */
4451 callback = replmd_op_name_modify_callback;
4454 /* we are renaming the existing record */
4456 struct ldb_dn *new_dn;
4458 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4459 if (GUID_all_zero(&guid)) {
4460 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4461 ldb_dn_get_linearized(conflict_dn)));
4465 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4466 if (new_dn == NULL) {
4467 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4468 ldb_dn_get_linearized(conflict_dn)));
4472 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4473 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4475 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4476 DSDB_FLAG_OWN_MODULE, req);
4477 if (ret != LDB_SUCCESS) {
4478 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4479 ldb_dn_get_linearized(conflict_dn),
4480 ldb_dn_get_linearized(new_dn),
4481 ldb_errstring(ldb_module_get_ctx(ar->module))));
4486 * now we need to ensure that the rename is seen as an
4487 * originating update. We do that with a modify.
4489 ret = replmd_name_modify(ar, req, new_dn);
4490 if (ret != LDB_SUCCESS) {
4494 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4495 ldb_dn_get_linearized(req->op.add.message->dn)));
4498 ret = ldb_build_add_req(&down_req,
4499 ldb_module_get_ctx(ar->module),
4506 if (ret != LDB_SUCCESS) {
4509 LDB_REQ_SET_LOCATION(down_req);
4511 /* current partition control needed by "repmd_op_callback" */
4512 ret = ldb_request_add_control(down_req,
4513 DSDB_CONTROL_CURRENT_PARTITION_OID,
4515 if (ret != LDB_SUCCESS) {
4516 return replmd_replicated_request_error(ar, ret);
4519 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4520 /* this tells the partition module to make it a
4521 partial replica if creating an NC */
4522 ret = ldb_request_add_control(down_req,
4523 DSDB_CONTROL_PARTIAL_REPLICA,
4525 if (ret != LDB_SUCCESS) {
4526 return replmd_replicated_request_error(ar, ret);
4531 * Finally we re-run the add, otherwise the new record won't
4532 * exist, as we are here because of that exact failure!
4534 return ldb_next_request(ar->module, down_req);
4537 /* on failure make the caller get the error. This means
4538 * replication will stop with an error, but there is not much
4541 return ldb_module_done(ar->req, NULL, NULL,
4546 callback for replmd_replicated_apply_add()
4547 This copes with the creation of conflict records in the case where
4548 the DN exists, but with a different objectGUID
4550 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4552 struct replmd_replicated_request *ar =
4553 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4555 if (ar->objs->objects[ar->index_current].last_known_parent) {
4556 /* This is like a conflict DN, where we put the object in LostAndFound
4557 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4558 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4561 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4565 this is called when a new object comes in over DRS
4567 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4569 struct ldb_context *ldb;
4570 struct ldb_request *change_req;
4571 enum ndr_err_code ndr_err;
4572 struct ldb_message *msg;
4573 struct replPropertyMetaDataBlob *md;
4574 struct ldb_val md_value;
4577 bool remote_isDeleted = false;
4580 time_t t = time(NULL);
4581 const struct ldb_val *rdn_val;
4582 struct replmd_private *replmd_private =
4583 talloc_get_type(ldb_module_get_private(ar->module),
4584 struct replmd_private);
4585 unix_to_nt_time(&now, t);
4587 ldb = ldb_module_get_ctx(ar->module);
4588 msg = ar->objs->objects[ar->index_current].msg;
4589 md = ar->objs->objects[ar->index_current].meta_data;
4590 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4592 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4593 if (ret != LDB_SUCCESS) {
4594 return replmd_replicated_request_error(ar, ret);
4597 ret = dsdb_msg_add_guid(msg,
4598 &ar->objs->objects[ar->index_current].object_guid,
4600 if (ret != LDB_SUCCESS) {
4601 return replmd_replicated_request_error(ar, ret);
4604 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4605 if (ret != LDB_SUCCESS) {
4606 return replmd_replicated_request_error(ar, ret);
4609 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4610 if (ret != LDB_SUCCESS) {
4611 return replmd_replicated_request_error(ar, ret);
4614 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4615 if (ret != LDB_SUCCESS) {
4616 return replmd_replicated_request_error(ar, ret);
4619 /* remove any message elements that have zero values */
4620 for (i=0; i<msg->num_elements; i++) {
4621 struct ldb_message_element *el = &msg->elements[i];
4623 if (el->num_values == 0) {
4624 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4625 ldb_asprintf_errstring(ldb, __location__
4626 ": empty objectClass sent on %s, aborting replication\n",
4627 ldb_dn_get_linearized(msg->dn));
4628 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4631 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4633 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4634 msg->num_elements--;
4641 struct GUID_txt_buf guid_txt;
4643 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4644 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4645 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4650 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4651 "isDeleted", false);
4654 * the meta data array is already sorted by the caller, except
4655 * for the RDN, which needs to be added.
4659 rdn_val = ldb_dn_get_rdn_val(msg->dn);
4660 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4661 md, ar, now, is_schema_nc);
4662 if (ret != LDB_SUCCESS) {
4663 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4664 return replmd_replicated_request_error(ar, ret);
4667 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4668 if (ret != LDB_SUCCESS) {
4669 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4670 return replmd_replicated_request_error(ar, ret);
4673 for (i=0; i < md->ctr.ctr1.count; i++) {
4674 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4676 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4677 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4678 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4679 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4680 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4682 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4683 if (ret != LDB_SUCCESS) {
4684 return replmd_replicated_request_error(ar, ret);
4687 replmd_ldb_message_sort(msg, ar->schema);
4689 if (!remote_isDeleted) {
4690 ret = dsdb_module_schedule_sd_propagation(ar->module,
4691 ar->objs->partition_dn,
4693 if (ret != LDB_SUCCESS) {
4694 return replmd_replicated_request_error(ar, ret);
4698 ar->isDeleted = remote_isDeleted;
4700 ret = ldb_build_add_req(&change_req,
4706 replmd_op_add_callback,
4708 LDB_REQ_SET_LOCATION(change_req);
4709 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4711 /* current partition control needed by "repmd_op_callback" */
4712 ret = ldb_request_add_control(change_req,
4713 DSDB_CONTROL_CURRENT_PARTITION_OID,
4715 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4717 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4718 /* this tells the partition module to make it a
4719 partial replica if creating an NC */
4720 ret = ldb_request_add_control(change_req,
4721 DSDB_CONTROL_PARTIAL_REPLICA,
4723 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4726 return ldb_next_request(ar->module, change_req);
4729 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
4730 struct ldb_reply *ares)
4732 struct replmd_replicated_request *ar = talloc_get_type(req->context,
4733 struct replmd_replicated_request);
4737 return ldb_module_done(ar->req, NULL, NULL,
4738 LDB_ERR_OPERATIONS_ERROR);
4742 * The error NO_SUCH_OBJECT is not expected, unless the search
4743 * base is the partition DN, and that case doesn't happen here
4744 * because then we wouldn't get a parent_guid_value in any
4747 if (ares->error != LDB_SUCCESS) {
4748 return ldb_module_done(ar->req, ares->controls,
4749 ares->response, ares->error);
4752 switch (ares->type) {
4753 case LDB_REPLY_ENTRY:
4755 struct ldb_message *parent_msg = ares->message;
4756 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
4757 struct ldb_dn *parent_dn;
4760 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
4761 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
4762 /* Per MS-DRSR 4.1.10.6.10
4763 * FindBestParentObject we need to move this
4764 * new object under a deleted object to
4766 struct ldb_dn *nc_root;
4768 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
4769 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4770 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4771 "No suitable NC root found for %s. "
4772 "We need to move this object because parent object %s "
4773 "is deleted, but this object is not.",
4774 ldb_dn_get_linearized(msg->dn),
4775 ldb_dn_get_linearized(parent_msg->dn));
4776 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4777 } else if (ret != LDB_SUCCESS) {
4778 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4779 "Unable to find NC root for %s: %s. "
4780 "We need to move this object because parent object %s "
4781 "is deleted, but this object is not.",
4782 ldb_dn_get_linearized(msg->dn),
4783 ldb_errstring(ldb_module_get_ctx(ar->module)),
4784 ldb_dn_get_linearized(parent_msg->dn));
4785 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4788 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
4790 DS_GUID_LOSTANDFOUND_CONTAINER,
4792 if (ret != LDB_SUCCESS) {
4793 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4794 "Unable to find LostAndFound Container for %s "
4795 "in partition %s: %s. "
4796 "We need to move this object because parent object %s "
4797 "is deleted, but this object is not.",
4798 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
4799 ldb_errstring(ldb_module_get_ctx(ar->module)),
4800 ldb_dn_get_linearized(parent_msg->dn));
4801 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4803 ar->objs->objects[ar->index_current].last_known_parent
4804 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4808 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4811 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
4813 comp_num = ldb_dn_get_comp_num(msg->dn);
4815 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
4817 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4820 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
4822 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4826 case LDB_REPLY_REFERRAL:
4827 /* we ignore referrals */
4830 case LDB_REPLY_DONE:
4832 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
4833 struct GUID_txt_buf str_buf;
4834 if (ar->search_msg != NULL) {
4835 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4836 "No parent with GUID %s found for object locally known as %s",
4837 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4838 ldb_dn_get_linearized(ar->search_msg->dn));
4840 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4841 "No parent with GUID %s found for object remotely known as %s",
4842 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4843 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
4847 * This error code is really important, as it
4848 * is the flag back to the callers to retry
4849 * this with DRSUAPI_DRS_GET_ANC, and so get
4850 * the parent objects before the child
4853 return ldb_module_done(ar->req, NULL, NULL,
4854 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
4857 if (ar->search_msg != NULL) {
4858 ret = replmd_replicated_apply_merge(ar);
4860 ret = replmd_replicated_apply_add(ar);
4862 if (ret != LDB_SUCCESS) {
4863 return ldb_module_done(ar->req, NULL, NULL, ret);
4872 * Look for the parent object, so we put the new object in the right
4873 * place This is akin to NameObject in MS-DRSR - this routine and the
4874 * callbacks find the right parent name, and correct name for this
4878 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
4880 struct ldb_context *ldb;
4884 struct ldb_request *search_req;
4885 static const char *attrs[] = {"isDeleted", NULL};
4886 struct GUID_txt_buf guid_str_buf;
4888 ldb = ldb_module_get_ctx(ar->module);
4890 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
4891 if (ar->search_msg != NULL) {
4892 return replmd_replicated_apply_merge(ar);
4894 return replmd_replicated_apply_add(ar);
4898 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
4901 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
4902 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
4904 ret = ldb_build_search_req(&search_req,
4907 ar->objs->partition_dn,
4913 replmd_replicated_apply_search_for_parent_callback,
4915 LDB_REQ_SET_LOCATION(search_req);
4917 ret = dsdb_request_add_controls(search_req,
4918 DSDB_SEARCH_SHOW_RECYCLED|
4919 DSDB_SEARCH_SHOW_DELETED|
4920 DSDB_SEARCH_SHOW_EXTENDED_DN);
4921 if (ret != LDB_SUCCESS) {
4925 return ldb_next_request(ar->module, search_req);
4929 handle renames that come in over DRS replication
4931 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
4932 struct ldb_message *msg,
4933 struct ldb_request *parent,
4937 TALLOC_CTX *tmp_ctx = talloc_new(msg);
4938 struct ldb_result *res;
4939 struct ldb_dn *conflict_dn;
4940 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4941 const struct ldb_val *omd_value;
4942 struct replPropertyMetaDataBlob omd, *rmd;
4943 enum ndr_err_code ndr_err;
4944 bool rename_incoming_record, rodc;
4945 struct replPropertyMetaData1 *rmd_name, *omd_name;
4946 struct ldb_dn *new_dn;
4949 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
4950 ldb_dn_get_linearized(ar->search_msg->dn),
4951 ldb_dn_get_linearized(msg->dn)));
4954 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
4955 DSDB_FLAG_NEXT_MODULE, ar->req);
4956 if (ret == LDB_SUCCESS) {
4957 talloc_free(tmp_ctx);
4962 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4963 talloc_free(tmp_ctx);
4964 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
4965 ldb_dn_get_linearized(ar->search_msg->dn),
4966 ldb_dn_get_linearized(msg->dn),
4967 ldb_errstring(ldb_module_get_ctx(ar->module)));
4971 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4972 if (ret != LDB_SUCCESS) {
4973 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4974 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
4975 ldb_errstring(ldb_module_get_ctx(ar->module)));
4976 return LDB_ERR_OPERATIONS_ERROR;
4979 * we have a conflict, and need to decide if we will keep the
4980 * new record or the old record
4983 conflict_dn = msg->dn;
4987 * We are on an RODC, or were a GC for this
4988 * partition, so we have to fail this until
4989 * someone who owns the partition sorts it
4992 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4993 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
4994 " - We must fail the operation until a master for this partition resolves the conflict",
4995 ldb_dn_get_linearized(conflict_dn));
5000 * first we need the replPropertyMetaData attribute from the
5003 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5005 DSDB_FLAG_NEXT_MODULE |
5006 DSDB_SEARCH_SHOW_DELETED |
5007 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5008 if (ret != LDB_SUCCESS) {
5009 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5010 ldb_dn_get_linearized(conflict_dn)));
5014 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5015 if (omd_value == NULL) {
5016 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5017 ldb_dn_get_linearized(conflict_dn)));
5021 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5022 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5023 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5024 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5025 ldb_dn_get_linearized(conflict_dn)));
5029 rmd = ar->objs->objects[ar->index_current].meta_data;
5032 * we decide which is newer based on the RPMD on the name
5033 * attribute. See [MS-DRSR] ResolveNameConflict.
5035 * We expect omd_name to be present, as this is from a local
5036 * search, but while rmd_name should have been given to us by
5037 * the remote server, if it is missing we just prefer the
5039 * replmd_replPropertyMetaData1_new_should_be_taken()
5041 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5042 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5044 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5045 ldb_dn_get_linearized(conflict_dn)));
5050 * Should we preserve the current record, and so rename the
5051 * incoming record to be a conflict?
5053 rename_incoming_record =
5054 !replmd_replPropertyMetaData1_new_should_be_taken(
5055 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5056 omd_name, rmd_name);
5058 if (rename_incoming_record) {
5060 new_dn = replmd_conflict_dn(msg, msg->dn,
5061 &ar->objs->objects[ar->index_current].object_guid);
5062 if (new_dn == NULL) {
5063 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5064 "Failed to form conflict DN for %s\n",
5065 ldb_dn_get_linearized(msg->dn));
5067 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5070 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5071 DSDB_FLAG_NEXT_MODULE, ar->req);
5072 if (ret != LDB_SUCCESS) {
5073 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5074 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5075 ldb_dn_get_linearized(conflict_dn),
5076 ldb_dn_get_linearized(ar->search_msg->dn),
5077 ldb_dn_get_linearized(new_dn),
5078 ldb_errstring(ldb_module_get_ctx(ar->module)));
5079 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5087 /* we are renaming the existing record */
5089 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5090 if (GUID_all_zero(&guid)) {
5091 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5092 ldb_dn_get_linearized(conflict_dn)));
5096 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5097 if (new_dn == NULL) {
5098 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5099 ldb_dn_get_linearized(conflict_dn)));
5103 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5104 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5106 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5107 DSDB_FLAG_OWN_MODULE, ar->req);
5108 if (ret != LDB_SUCCESS) {
5109 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5110 ldb_dn_get_linearized(conflict_dn),
5111 ldb_dn_get_linearized(new_dn),
5112 ldb_errstring(ldb_module_get_ctx(ar->module))));
5117 * now we need to ensure that the rename is seen as an
5118 * originating update. We do that with a modify.
5120 ret = replmd_name_modify(ar, ar->req, new_dn);
5121 if (ret != LDB_SUCCESS) {
5125 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5126 ldb_dn_get_linearized(ar->search_msg->dn),
5127 ldb_dn_get_linearized(msg->dn)));
5130 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5131 DSDB_FLAG_NEXT_MODULE, ar->req);
5132 if (ret != LDB_SUCCESS) {
5133 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5134 ldb_dn_get_linearized(ar->search_msg->dn),
5135 ldb_dn_get_linearized(msg->dn),
5136 ldb_errstring(ldb_module_get_ctx(ar->module))));
5142 * On failure make the caller get the error
5143 * This means replication will stop with an error,
5144 * but there is not much else we can do. In the
5145 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5149 talloc_free(tmp_ctx);
5154 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5156 struct ldb_context *ldb;
5157 struct ldb_request *change_req;
5158 enum ndr_err_code ndr_err;
5159 struct ldb_message *msg;
5160 struct replPropertyMetaDataBlob *rmd;
5161 struct replPropertyMetaDataBlob omd;
5162 const struct ldb_val *omd_value;
5163 struct replPropertyMetaDataBlob nmd;
5164 struct ldb_val nmd_value;
5165 struct GUID remote_parent_guid;
5168 unsigned int removed_attrs = 0;
5170 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5171 bool isDeleted = false;
5172 bool local_isDeleted = false;
5173 bool remote_isDeleted = false;
5174 bool take_remote_isDeleted = false;
5175 bool sd_updated = false;
5176 bool renamed = false;
5177 bool is_schema_nc = false;
5179 const struct ldb_val *old_rdn, *new_rdn;
5180 struct replmd_private *replmd_private =
5181 talloc_get_type(ldb_module_get_private(ar->module),
5182 struct replmd_private);
5184 time_t t = time(NULL);
5185 unix_to_nt_time(&now, t);
5187 ldb = ldb_module_get_ctx(ar->module);
5188 msg = ar->objs->objects[ar->index_current].msg;
5190 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5192 rmd = ar->objs->objects[ar->index_current].meta_data;
5196 /* find existing meta data */
5197 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5199 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5200 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5201 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5202 nt_status = ndr_map_error2ntstatus(ndr_err);
5203 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5206 if (omd.version != 1) {
5207 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5212 struct GUID_txt_buf guid_txt;
5214 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5215 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
5218 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5220 ndr_print_struct_string(s,
5221 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5222 "existing replPropertyMetaData",
5224 ndr_print_struct_string(s,
5225 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5226 "incoming replPropertyMetaData",
5231 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5232 "isDeleted", false);
5233 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5234 "isDeleted", false);
5237 * Fill in the remote_parent_guid with the GUID or an all-zero
5240 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5241 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5243 remote_parent_guid = GUID_zero();
5247 * To ensure we follow a complex rename chain around, we have
5248 * to confirm that the DN is the same (mostly to confirm the
5249 * RDN) and the parentGUID is the same.
5251 * This ensures we keep things under the correct parent, which
5252 * replmd_replicated_handle_rename() will do.
5255 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5256 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5260 * handle renames, even just by case that come in over
5261 * DRS. Changes in the parent DN don't hit us here,
5262 * because the search for a parent will clean up those
5265 * We also have already filtered out the case where
5266 * the peer has an older name to what we have (see
5267 * replmd_replicated_apply_search_callback())
5269 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5272 if (ret != LDB_SUCCESS) {
5273 ldb_debug(ldb, LDB_DEBUG_FATAL,
5274 "replmd_replicated_request rename %s => %s failed - %s\n",
5275 ldb_dn_get_linearized(ar->search_msg->dn),
5276 ldb_dn_get_linearized(msg->dn),
5277 ldb_errstring(ldb));
5278 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5281 if (renamed == true) {
5283 * Set the callback to one that will fix up the name
5284 * metadata on the new conflict DN
5286 callback = replmd_op_name_modify_callback;
5291 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5292 nmd.ctr.ctr1.array = talloc_array(ar,
5293 struct replPropertyMetaData1,
5294 nmd.ctr.ctr1.count);
5295 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5297 /* first copy the old meta data */
5298 for (i=0; i < omd.ctr.ctr1.count; i++) {
5299 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5304 /* now merge in the new meta data */
5305 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5308 for (j=0; j < ni; j++) {
5311 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5315 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5316 ar->objs->dsdb_repl_flags,
5317 &nmd.ctr.ctr1.array[j],
5318 &rmd->ctr.ctr1.array[i]);
5320 /* replace the entry */
5321 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5322 if (ar->seq_num == 0) {
5323 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5324 if (ret != LDB_SUCCESS) {
5325 return replmd_replicated_request_error(ar, ret);
5328 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5329 switch (nmd.ctr.ctr1.array[j].attid) {
5330 case DRSUAPI_ATTID_ntSecurityDescriptor:
5333 case DRSUAPI_ATTID_isDeleted:
5334 take_remote_isDeleted = true;
5343 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5344 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5345 msg->elements[i-removed_attrs].name,
5346 ldb_dn_get_linearized(msg->dn),
5347 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5350 /* we don't want to apply this change so remove the attribute */
5351 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5358 if (found) continue;
5360 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5361 if (ar->seq_num == 0) {
5362 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5363 if (ret != LDB_SUCCESS) {
5364 return replmd_replicated_request_error(ar, ret);
5367 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5368 switch (nmd.ctr.ctr1.array[ni].attid) {
5369 case DRSUAPI_ATTID_ntSecurityDescriptor:
5372 case DRSUAPI_ATTID_isDeleted:
5373 take_remote_isDeleted = true;
5382 * finally correct the size of the meta_data array
5384 nmd.ctr.ctr1.count = ni;
5386 new_rdn = ldb_dn_get_rdn_val(msg->dn);
5387 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5390 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5391 &nmd, ar, now, is_schema_nc);
5392 if (ret != LDB_SUCCESS) {
5393 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5394 return replmd_replicated_request_error(ar, ret);
5398 * sort the new meta data array
5400 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5401 if (ret != LDB_SUCCESS) {
5402 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5407 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
5410 * This also controls SD propagation below
5412 if (take_remote_isDeleted) {
5413 isDeleted = remote_isDeleted;
5415 isDeleted = local_isDeleted;
5418 ar->isDeleted = isDeleted;
5421 * check if some replicated attributes left, otherwise skip the ldb_modify() call
5423 if (msg->num_elements == 0) {
5424 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5427 return replmd_replicated_apply_isDeleted(ar);
5430 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5431 ar->index_current, msg->num_elements);
5437 if (sd_updated && !isDeleted) {
5438 ret = dsdb_module_schedule_sd_propagation(ar->module,
5439 ar->objs->partition_dn,
5441 if (ret != LDB_SUCCESS) {
5442 return ldb_operr(ldb);
5446 /* create the meta data value */
5447 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5448 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5449 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5450 nt_status = ndr_map_error2ntstatus(ndr_err);
5451 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5455 * when we know that we'll modify the record, add the whenChanged, uSNChanged
5456 * and replPopertyMetaData attributes
5458 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5459 if (ret != LDB_SUCCESS) {
5460 return replmd_replicated_request_error(ar, ret);
5462 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5463 if (ret != LDB_SUCCESS) {
5464 return replmd_replicated_request_error(ar, ret);
5466 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5467 if (ret != LDB_SUCCESS) {
5468 return replmd_replicated_request_error(ar, ret);
5471 replmd_ldb_message_sort(msg, ar->schema);
5473 /* we want to replace the old values */
5474 for (i=0; i < msg->num_elements; i++) {
5475 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5476 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5477 if (msg->elements[i].num_values == 0) {
5478 ldb_asprintf_errstring(ldb, __location__
5479 ": objectClass removed on %s, aborting replication\n",
5480 ldb_dn_get_linearized(msg->dn));
5481 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5487 struct GUID_txt_buf guid_txt;
5489 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5490 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5491 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5496 ret = ldb_build_mod_req(&change_req,
5504 LDB_REQ_SET_LOCATION(change_req);
5505 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5507 /* current partition control needed by "repmd_op_callback" */
5508 ret = ldb_request_add_control(change_req,
5509 DSDB_CONTROL_CURRENT_PARTITION_OID,
5511 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5513 return ldb_next_request(ar->module, change_req);
5516 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5517 struct ldb_reply *ares)
5519 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5520 struct replmd_replicated_request);
5524 return ldb_module_done(ar->req, NULL, NULL,
5525 LDB_ERR_OPERATIONS_ERROR);
5527 if (ares->error != LDB_SUCCESS &&
5528 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5529 return ldb_module_done(ar->req, ares->controls,
5530 ares->response, ares->error);
5533 switch (ares->type) {
5534 case LDB_REPLY_ENTRY:
5535 ar->search_msg = talloc_steal(ar, ares->message);
5538 case LDB_REPLY_REFERRAL:
5539 /* we ignore referrals */
5542 case LDB_REPLY_DONE:
5544 struct replPropertyMetaData1 *md_remote;
5545 struct replPropertyMetaData1 *md_local;
5547 struct replPropertyMetaDataBlob omd;
5548 const struct ldb_val *omd_value;
5549 struct replPropertyMetaDataBlob *rmd;
5550 struct ldb_message *msg;
5552 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5553 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5556 * This is the ADD case, find the appropriate parent,
5557 * as this object doesn't exist locally:
5559 if (ar->search_msg == NULL) {
5560 ret = replmd_replicated_apply_search_for_parent(ar);
5561 if (ret != LDB_SUCCESS) {
5562 return ldb_module_done(ar->req, NULL, NULL, ret);
5569 * Otherwise, in the MERGE case, work out if we are
5570 * attempting a rename, and if so find the parent the
5571 * newly renamed object wants to belong under (which
5572 * may not be the parent in it's attached string DN
5574 rmd = ar->objs->objects[ar->index_current].meta_data;
5578 /* find existing meta data */
5579 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5581 enum ndr_err_code ndr_err;
5582 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5583 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5584 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5585 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5586 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5589 if (omd.version != 1) {
5590 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5594 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5596 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5597 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5598 && GUID_all_zero(&ar->local_parent_guid)) {
5599 DEBUG(0, ("Refusing to replicate new version of %s "
5600 "as local object has an all-zero parentGUID attribute, "
5601 "despite not being an NC root\n",
5602 ldb_dn_get_linearized(ar->search_msg->dn)));
5603 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5607 * now we need to check for double renames. We could have a
5608 * local rename pending which our replication partner hasn't
5609 * received yet. We choose which one wins by looking at the
5610 * attribute stamps on the two objects, the newer one wins.
5612 * This also simply applies the correct algorithms for
5613 * determining if a change was made to name at all, or
5614 * if the object has just been renamed under the same
5617 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5618 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5620 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5621 ldb_dn_get_linearized(ar->search_msg->dn)));
5622 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5626 * if there is no name attribute given then we have to assume the
5627 * object we've received has the older name
5629 if (replmd_replPropertyMetaData1_new_should_be_taken(
5630 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5631 md_local, md_remote)) {
5632 struct GUID_txt_buf p_guid_local;
5633 struct GUID_txt_buf p_guid_remote;
5634 msg = ar->objs->objects[ar->index_current].msg;
5636 /* Merge on the existing object, with rename */
5638 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5639 "as incoming object changing to %s under %s\n",
5640 ldb_dn_get_linearized(ar->search_msg->dn),
5641 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5642 ldb_dn_get_linearized(msg->dn),
5643 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5645 ret = replmd_replicated_apply_search_for_parent(ar);
5647 struct GUID_txt_buf p_guid_local;
5648 struct GUID_txt_buf p_guid_remote;
5649 msg = ar->objs->objects[ar->index_current].msg;
5652 * Merge on the existing object, force no
5653 * rename (code below just to explain why in
5657 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5658 ldb_dn_get_linearized(msg->dn)) == 0) {
5659 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5660 GUID_equal(&ar->local_parent_guid,
5661 ar->objs->objects[ar->index_current].parent_guid)
5663 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5664 "despite incoming object changing parent to %s\n",
5665 ldb_dn_get_linearized(ar->search_msg->dn),
5666 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5667 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5671 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5672 " and rejecting older rename to %s under %s\n",
5673 ldb_dn_get_linearized(ar->search_msg->dn),
5674 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5675 ldb_dn_get_linearized(msg->dn),
5676 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5680 * This assignment ensures that the strcmp()
5681 * and GUID_equal() calls in
5682 * replmd_replicated_apply_merge() avoids the
5685 ar->objs->objects[ar->index_current].parent_guid =
5686 &ar->local_parent_guid;
5688 msg->dn = ar->search_msg->dn;
5689 ret = replmd_replicated_apply_merge(ar);
5691 if (ret != LDB_SUCCESS) {
5692 return ldb_module_done(ar->req, NULL, NULL, ret);
5701 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
5703 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
5705 struct ldb_context *ldb;
5709 struct ldb_request *search_req;
5710 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
5711 "parentGUID", "instanceType",
5712 "replPropertyMetaData", "nTSecurityDescriptor",
5713 "isDeleted", NULL };
5714 struct GUID_txt_buf guid_str_buf;
5716 if (ar->index_current >= ar->objs->num_objects) {
5717 /* done with it, go to next stage */
5718 return replmd_replicated_uptodate_vector(ar);
5721 ldb = ldb_module_get_ctx(ar->module);
5722 ar->search_msg = NULL;
5723 ar->isDeleted = false;
5725 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5728 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5729 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5731 ret = ldb_build_search_req(&search_req,
5734 ar->objs->partition_dn,
5740 replmd_replicated_apply_search_callback,
5742 LDB_REQ_SET_LOCATION(search_req);
5744 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
5746 if (ret != LDB_SUCCESS) {
5750 return ldb_next_request(ar->module, search_req);
5754 * This is essentially a wrapper for replmd_replicated_apply_next()
5756 * This is needed to ensure that both codepaths call this handler.
5758 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
5760 struct ldb_dn *deleted_objects_dn;
5761 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5762 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
5763 &deleted_objects_dn);
5764 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
5766 * Do a delete here again, so that if there is
5767 * anything local that conflicts with this
5768 * object being deleted, it is removed. This
5769 * includes links. See MS-DRSR 4.1.10.6.9
5772 * If the object is already deleted, and there
5773 * is no more work required, it doesn't do
5777 /* This has been updated to point to the DN we eventually did the modify on */
5779 struct ldb_request *del_req;
5780 struct ldb_result *res;
5782 TALLOC_CTX *tmp_ctx = talloc_new(ar);
5784 ret = ldb_oom(ldb_module_get_ctx(ar->module));
5788 res = talloc_zero(tmp_ctx, struct ldb_result);
5790 ret = ldb_oom(ldb_module_get_ctx(ar->module));
5791 talloc_free(tmp_ctx);
5795 /* Build a delete request, which hopefully will artually turn into nothing */
5796 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
5800 ldb_modify_default_callback,
5802 LDB_REQ_SET_LOCATION(del_req);
5803 if (ret != LDB_SUCCESS) {
5804 talloc_free(tmp_ctx);
5809 * This is the guts of the call, call back
5810 * into our delete code, but setting the
5811 * re_delete flag so we delete anything that
5812 * shouldn't be there on a deleted or recycled
5815 ret = replmd_delete_internals(ar->module, del_req, true);
5816 if (ret == LDB_SUCCESS) {
5817 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
5820 talloc_free(tmp_ctx);
5821 if (ret != LDB_SUCCESS) {
5826 ar->index_current++;
5827 return replmd_replicated_apply_next(ar);
5830 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
5831 struct ldb_reply *ares)
5833 struct ldb_context *ldb;
5834 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5835 struct replmd_replicated_request);
5836 ldb = ldb_module_get_ctx(ar->module);
5839 return ldb_module_done(ar->req, NULL, NULL,
5840 LDB_ERR_OPERATIONS_ERROR);
5842 if (ares->error != LDB_SUCCESS) {
5843 return ldb_module_done(ar->req, ares->controls,
5844 ares->response, ares->error);
5847 if (ares->type != LDB_REPLY_DONE) {
5848 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
5849 return ldb_module_done(ar->req, NULL, NULL,
5850 LDB_ERR_OPERATIONS_ERROR);
5855 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5858 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
5860 struct ldb_context *ldb;
5861 struct ldb_request *change_req;
5862 enum ndr_err_code ndr_err;
5863 struct ldb_message *msg;
5864 struct replUpToDateVectorBlob ouv;
5865 const struct ldb_val *ouv_value;
5866 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
5867 struct replUpToDateVectorBlob nuv;
5868 struct ldb_val nuv_value;
5869 struct ldb_message_element *nuv_el = NULL;
5870 struct ldb_message_element *orf_el = NULL;
5871 struct repsFromToBlob nrf;
5872 struct ldb_val *nrf_value = NULL;
5873 struct ldb_message_element *nrf_el = NULL;
5877 time_t t = time(NULL);
5880 uint32_t instanceType;
5882 ldb = ldb_module_get_ctx(ar->module);
5883 ruv = ar->objs->uptodateness_vector;
5889 unix_to_nt_time(&now, t);
5891 if (ar->search_msg == NULL) {
5892 /* this happens for a REPL_OBJ call where we are
5893 creating the target object by replicating it. The
5894 subdomain join code does this for the partition DN
5896 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
5897 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5900 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
5901 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
5902 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
5903 ldb_dn_get_linearized(ar->search_msg->dn)));
5904 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5908 * first create the new replUpToDateVector
5910 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
5912 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
5913 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
5914 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5915 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5916 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5919 if (ouv.version != 2) {
5920 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5925 * the new uptodateness vector will at least
5926 * contain 1 entry, one for the source_dsa
5928 * plus optional values from our old vector and the one from the source_dsa
5930 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
5931 if (ruv) nuv.ctr.ctr2.count += ruv->count;
5932 nuv.ctr.ctr2.cursors = talloc_array(ar,
5933 struct drsuapi_DsReplicaCursor2,
5934 nuv.ctr.ctr2.count);
5935 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5937 /* first copy the old vector */
5938 for (i=0; i < ouv.ctr.ctr2.count; i++) {
5939 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
5943 /* merge in the source_dsa vector is available */
5944 for (i=0; (ruv && i < ruv->count); i++) {
5947 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
5948 &ar->our_invocation_id)) {
5952 for (j=0; j < ni; j++) {
5953 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
5954 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
5960 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
5961 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
5966 if (found) continue;
5968 /* if it's not there yet, add it */
5969 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
5974 * finally correct the size of the cursors array
5976 nuv.ctr.ctr2.count = ni;
5981 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
5984 * create the change ldb_message
5986 msg = ldb_msg_new(ar);
5987 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5988 msg->dn = ar->search_msg->dn;
5990 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
5991 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
5992 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5993 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5994 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5996 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
5997 if (ret != LDB_SUCCESS) {
5998 return replmd_replicated_request_error(ar, ret);
6000 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6003 * now create the new repsFrom value from the given repsFromTo1 structure
6007 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6008 nrf.ctr.ctr1.last_attempt = now;
6009 nrf.ctr.ctr1.last_success = now;
6010 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6013 * first see if we already have a repsFrom value for the current source dsa
6014 * if so we'll later replace this value
6016 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6018 for (i=0; i < orf_el->num_values; i++) {
6019 struct repsFromToBlob *trf;
6021 trf = talloc(ar, struct repsFromToBlob);
6022 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6024 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6025 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6026 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6027 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6028 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6031 if (trf->version != 1) {
6032 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6036 * we compare the source dsa objectGUID not the invocation_id
6037 * because we want only one repsFrom value per source dsa
6038 * and when the invocation_id of the source dsa has changed we don't need
6039 * the old repsFrom with the old invocation_id
6041 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6042 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6048 nrf_value = &orf_el->values[i];
6053 * copy over all old values to the new ldb_message
6055 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6056 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6061 * if we haven't found an old repsFrom value for the current source dsa
6062 * we'll add a new value
6065 struct ldb_val zero_value;
6066 ZERO_STRUCT(zero_value);
6067 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6068 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6070 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6073 /* we now fill the value which is already attached to ldb_message */
6074 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6076 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6077 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6078 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6079 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6083 * the ldb_message_element for the attribute, has all the old values and the new one
6084 * so we'll replace the whole attribute with all values
6086 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6088 if (CHECK_DEBUGLVL(4)) {
6089 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
6090 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6094 /* prepare the ldb_modify() request */
6095 ret = ldb_build_mod_req(&change_req,
6101 replmd_replicated_uptodate_modify_callback,
6103 LDB_REQ_SET_LOCATION(change_req);
6104 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6106 return ldb_next_request(ar->module, change_req);
6109 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6110 struct ldb_reply *ares)
6112 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6113 struct replmd_replicated_request);
6117 return ldb_module_done(ar->req, NULL, NULL,
6118 LDB_ERR_OPERATIONS_ERROR);
6120 if (ares->error != LDB_SUCCESS &&
6121 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6122 return ldb_module_done(ar->req, ares->controls,
6123 ares->response, ares->error);
6126 switch (ares->type) {
6127 case LDB_REPLY_ENTRY:
6128 ar->search_msg = talloc_steal(ar, ares->message);
6131 case LDB_REPLY_REFERRAL:
6132 /* we ignore referrals */
6135 case LDB_REPLY_DONE:
6136 ret = replmd_replicated_uptodate_modify(ar);
6137 if (ret != LDB_SUCCESS) {
6138 return ldb_module_done(ar->req, NULL, NULL, ret);
6147 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6149 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6150 struct replmd_private *replmd_private =
6151 talloc_get_type_abort(ldb_module_get_private(ar->module),
6152 struct replmd_private);
6154 static const char *attrs[] = {
6155 "replUpToDateVector",
6160 struct ldb_request *search_req;
6162 ar->search_msg = NULL;
6165 * Let the caller know that we did an originating updates
6167 ar->objs->originating_updates = replmd_private->originating_updates;
6169 ret = ldb_build_search_req(&search_req,
6172 ar->objs->partition_dn,
6178 replmd_replicated_uptodate_search_callback,
6180 LDB_REQ_SET_LOCATION(search_req);
6181 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6183 return ldb_next_request(ar->module, search_req);
6188 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6190 struct ldb_context *ldb;
6191 struct dsdb_extended_replicated_objects *objs;
6192 struct replmd_replicated_request *ar;
6193 struct ldb_control **ctrls;
6196 struct replmd_private *replmd_private =
6197 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6199 ldb = ldb_module_get_ctx(module);
6201 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6203 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6205 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6206 return LDB_ERR_PROTOCOL_ERROR;
6209 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6210 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6211 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6212 return LDB_ERR_PROTOCOL_ERROR;
6215 ar = replmd_ctx_init(module, req);
6217 return LDB_ERR_OPERATIONS_ERROR;
6219 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6220 ar->apply_mode = true;
6222 ar->schema = dsdb_get_schema(ldb, ar);
6224 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6226 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6227 return LDB_ERR_CONSTRAINT_VIOLATION;
6230 ctrls = req->controls;
6232 if (req->controls) {
6233 req->controls = talloc_memdup(ar, req->controls,
6234 talloc_get_size(req->controls));
6235 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6238 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6239 if (ret != LDB_SUCCESS) {
6243 /* If this change contained linked attributes in the body
6244 * (rather than in the links section) we need to update
6245 * backlinks in linked_attributes */
6246 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6247 if (ret != LDB_SUCCESS) {
6251 ar->controls = req->controls;
6252 req->controls = ctrls;
6254 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
6256 /* save away the linked attributes for the end of the
6258 for (i=0; i<ar->objs->linked_attributes_count; i++) {
6259 struct la_entry *la_entry;
6261 if (replmd_private->la_ctx == NULL) {
6262 replmd_private->la_ctx = talloc_new(replmd_private);
6264 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6265 if (la_entry == NULL) {
6267 return LDB_ERR_OPERATIONS_ERROR;
6269 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6270 if (la_entry->la == NULL) {
6271 talloc_free(la_entry);
6273 return LDB_ERR_OPERATIONS_ERROR;
6275 *la_entry->la = ar->objs->linked_attributes[i];
6277 /* we need to steal the non-scalars so they stay
6278 around until the end of the transaction */
6279 talloc_steal(la_entry->la, la_entry->la->identifier);
6280 talloc_steal(la_entry->la, la_entry->la->value.blob);
6282 DLIST_ADD(replmd_private->la_list, la_entry);
6285 return replmd_replicated_apply_next(ar);
6289 process one linked attribute structure
6291 static int replmd_process_linked_attribute(struct ldb_module *module,
6292 struct replmd_private *replmd_private,
6293 struct la_entry *la_entry,
6294 struct ldb_request *parent)
6296 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6297 struct ldb_context *ldb = ldb_module_get_ctx(module);
6298 struct ldb_message *msg;
6299 struct ldb_message *target_msg = NULL;
6300 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6301 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
6303 const struct dsdb_attribute *attr;
6304 struct dsdb_dn *dsdb_dn;
6305 uint64_t seq_num = 0;
6306 struct ldb_message_element *old_el;
6308 time_t t = time(NULL);
6309 struct ldb_result *res;
6310 struct ldb_result *target_res;
6311 const char *attrs[4];
6312 const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
6313 struct parsed_dn *pdn_list, *pdn, *next;
6314 struct GUID guid = GUID_zero();
6316 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
6317 const struct GUID *our_invocation_id;
6319 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
6320 enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
6323 linked_attributes[0]:
6324 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6326 identifier: struct drsuapi_DsReplicaObjectIdentifier
6327 __ndr_size : 0x0000003a (58)
6328 __ndr_size_sid : 0x00000000 (0)
6329 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6331 __ndr_size_dn : 0x00000000 (0)
6333 attid : DRSUAPI_ATTID_member (0x1F)
6334 value: struct drsuapi_DsAttributeValue
6335 __ndr_size : 0x0000007e (126)
6337 blob : DATA_BLOB length=126
6338 flags : 0x00000001 (1)
6339 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6340 originating_add_time : Wed Sep 2 22:20:01 2009 EST
6341 meta_data: struct drsuapi_DsReplicaMetaData
6342 version : 0x00000015 (21)
6343 originating_change_time : Wed Sep 2 23:39:07 2009 EST
6344 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6345 originating_usn : 0x000000000001e19c (123292)
6347 (for cases where the link is to a normal DN)
6348 &target: struct drsuapi_DsReplicaObjectIdentifier3
6349 __ndr_size : 0x0000007e (126)
6350 __ndr_size_sid : 0x0000001c (28)
6351 guid : 7639e594-db75-4086-b0d4-67890ae46031
6352 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
6353 __ndr_size_dn : 0x00000022 (34)
6354 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
6357 /* find the attribute being modified */
6358 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
6360 struct GUID_txt_buf guid_str;
6361 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
6363 GUID_buf_string(&la->identifier->guid,
6365 talloc_free(tmp_ctx);
6366 return LDB_ERR_OPERATIONS_ERROR;
6369 attrs[0] = attr->lDAPDisplayName;
6370 attrs[1] = "isDeleted";
6371 attrs[2] = "isRecycled";
6374 /* get the existing message from the db for the object with
6375 this GUID, returning attribute being modified. We will then
6376 use this msg as the basis for a modify call */
6377 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
6378 DSDB_FLAG_NEXT_MODULE |
6379 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6380 DSDB_SEARCH_SHOW_RECYCLED |
6381 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
6382 DSDB_SEARCH_REVEAL_INTERNALS,
6384 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
6385 if (ret != LDB_SUCCESS) {
6386 talloc_free(tmp_ctx);
6389 if (res->count != 1) {
6390 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
6391 GUID_string(tmp_ctx, &la->identifier->guid));
6392 talloc_free(tmp_ctx);
6393 return LDB_ERR_NO_SUCH_OBJECT;
6398 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6399 * ProcessLinkValue, because link updates are not applied to
6400 * recycled and tombstone objects. We don't have to delete
6401 * any existing link, that should have happened when the
6402 * object deletion was replicated or initiated.
6405 replmd_deletion_state(module, msg, &deletion_state, NULL);
6407 if (deletion_state >= OBJECT_RECYCLED) {
6408 talloc_free(tmp_ctx);
6412 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6413 if (old_el == NULL) {
6414 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
6415 if (ret != LDB_SUCCESS) {
6416 ldb_module_oom(module);
6417 talloc_free(tmp_ctx);
6418 return LDB_ERR_OPERATIONS_ERROR;
6421 old_el->flags = LDB_FLAG_MOD_REPLACE;
6424 /* parse the existing links */
6425 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
6426 if (ret != LDB_SUCCESS) {
6427 talloc_free(tmp_ctx);
6431 /* get our invocationId */
6432 our_invocation_id = samdb_ntds_invocation_id(ldb);
6433 if (!our_invocation_id) {
6434 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
6435 talloc_free(tmp_ctx);
6436 return LDB_ERR_OPERATIONS_ERROR;
6439 ret = replmd_check_upgrade_links(ldb, pdn_list, old_el->num_values,
6440 old_el, our_invocation_id,
6441 attr->syntax->ldap_oid);
6442 if (ret != LDB_SUCCESS) {
6443 talloc_free(tmp_ctx);
6447 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
6448 if (!W_ERROR_IS_OK(status)) {
6449 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
6450 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
6451 talloc_free(tmp_ctx);
6452 return LDB_ERR_OPERATIONS_ERROR;
6455 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
6456 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6458 * This strange behaviour (allowing a NULL/missing
6459 * GUID) originally comes from:
6461 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6462 * Author: Andrew Tridgell <tridge@samba.org>
6463 * Date: Mon Dec 21 21:21:55 2009 +1100
6465 * s4-drs: cope better with NULL GUIDS from DRS
6467 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
6468 * need to match by DN if possible when seeing if we should update an
6471 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6474 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6475 dsdb_dn->dn, attrs2,
6476 DSDB_FLAG_NEXT_MODULE |
6477 DSDB_SEARCH_SHOW_RECYCLED |
6478 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6479 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6481 } else if (!NT_STATUS_IS_OK(ntstatus)) {
6482 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
6484 ldb_dn_get_linearized(dsdb_dn->dn),
6485 ldb_dn_get_linearized(msg->dn));
6486 talloc_free(tmp_ctx);
6487 return LDB_ERR_OPERATIONS_ERROR;
6489 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6490 NULL, LDB_SCOPE_SUBTREE,
6492 DSDB_FLAG_NEXT_MODULE |
6493 DSDB_SEARCH_SHOW_RECYCLED |
6494 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6495 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6498 GUID_string(tmp_ctx, &guid));
6501 if (ret != LDB_SUCCESS) {
6502 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6503 GUID_string(tmp_ctx, &guid),
6504 ldb_errstring(ldb_module_get_ctx(module)));
6505 talloc_free(tmp_ctx);
6509 if (target_res->count == 0) {
6510 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6511 GUID_string(tmp_ctx, &guid),
6512 ldb_dn_get_linearized(dsdb_dn->dn)));
6513 } else if (target_res->count != 1) {
6514 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6515 GUID_string(tmp_ctx, &guid));
6516 talloc_free(tmp_ctx);
6517 return LDB_ERR_OPERATIONS_ERROR;
6519 target_msg = target_res->msgs[0];
6520 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6524 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6525 * ProcessLinkValue, because link updates are not applied to
6526 * recycled and tombstone objects. We don't have to delete
6527 * any existing link, that should have happened when the
6528 * object deletion was replicated or initiated.
6530 replmd_deletion_state(module, target_msg,
6531 &target_deletion_state, NULL);
6533 if (target_deletion_state >= OBJECT_RECYCLED) {
6534 talloc_free(tmp_ctx);
6538 /* see if this link already exists */
6539 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
6543 attr->syntax->ldap_oid);
6544 if (ret != LDB_SUCCESS) {
6545 talloc_free(tmp_ctx);
6551 /* see if this update is newer than what we have already */
6552 struct GUID invocation_id = GUID_zero();
6553 uint32_t version = 0;
6554 uint32_t originating_usn = 0;
6555 NTTIME change_time = 0;
6556 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6558 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6559 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6560 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6561 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6563 if (!replmd_update_is_newer(&invocation_id,
6564 &la->meta_data.originating_invocation_id,
6566 la->meta_data.version,
6568 la->meta_data.originating_change_time)) {
6569 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6570 old_el->name, ldb_dn_get_linearized(msg->dn),
6571 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6572 talloc_free(tmp_ctx);
6576 /* get a seq_num for this change */
6577 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6578 if (ret != LDB_SUCCESS) {
6579 talloc_free(tmp_ctx);
6583 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6584 /* remove the existing backlink */
6585 ret = replmd_add_backlink(module, replmd_private,
6586 schema, &la->identifier->guid,
6587 &guid, false, attr, true);
6588 if (ret != LDB_SUCCESS) {
6589 talloc_free(tmp_ctx);
6594 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6595 &la->meta_data.originating_invocation_id,
6596 la->meta_data.originating_usn, seq_num,
6597 la->meta_data.originating_change_time,
6598 la->meta_data.version,
6600 if (ret != LDB_SUCCESS) {
6601 talloc_free(tmp_ctx);
6606 /* add the new backlink */
6607 ret = replmd_add_backlink(module, replmd_private,
6608 schema, &la->identifier->guid,
6609 &guid, true, attr, true);
6610 if (ret != LDB_SUCCESS) {
6611 talloc_free(tmp_ctx);
6616 /* get a seq_num for this change */
6617 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6618 if (ret != LDB_SUCCESS) {
6619 talloc_free(tmp_ctx);
6623 old_el->values = talloc_realloc(msg->elements, old_el->values,
6624 struct ldb_val, old_el->num_values+1);
6625 if (!old_el->values) {
6626 ldb_module_oom(module);
6627 return LDB_ERR_OPERATIONS_ERROR;
6629 old_el->num_values++;
6631 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
6632 &la->meta_data.originating_invocation_id,
6633 la->meta_data.originating_usn, seq_num,
6634 la->meta_data.originating_change_time,
6635 la->meta_data.version,
6637 if (ret != LDB_SUCCESS) {
6638 talloc_free(tmp_ctx);
6643 ret = replmd_add_backlink(module, replmd_private,
6644 schema, &la->identifier->guid,
6645 &guid, true, attr, true);
6646 if (ret != LDB_SUCCESS) {
6647 talloc_free(tmp_ctx);
6653 /* we only change whenChanged and uSNChanged if the seq_num
6655 ret = add_time_element(msg, "whenChanged", t);
6656 if (ret != LDB_SUCCESS) {
6657 talloc_free(tmp_ctx);
6662 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
6663 if (ret != LDB_SUCCESS) {
6664 talloc_free(tmp_ctx);
6669 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6670 if (old_el == NULL) {
6671 talloc_free(tmp_ctx);
6672 return ldb_operr(ldb);
6675 ret = dsdb_check_single_valued_link(attr, old_el);
6676 if (ret != LDB_SUCCESS) {
6677 talloc_free(tmp_ctx);
6681 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
6683 ret = linked_attr_modify(module, msg, parent);
6684 if (ret != LDB_SUCCESS) {
6685 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
6687 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
6688 talloc_free(tmp_ctx);
6692 talloc_free(tmp_ctx);
6697 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
6699 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
6700 return replmd_extended_replicated_objects(module, req);
6703 return ldb_next_request(module, req);
6708 we hook into the transaction operations to allow us to
6709 perform the linked attribute updates at the end of the whole
6710 transaction. This allows a forward linked attribute to be created
6711 before the object is created. During a vampire, w2k8 sends us linked
6712 attributes before the objects they are part of.
6714 static int replmd_start_transaction(struct ldb_module *module)
6716 /* create our private structure for this transaction */
6717 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
6718 struct replmd_private);
6719 replmd_txn_cleanup(replmd_private);
6721 /* free any leftover mod_usn records from cancelled
6723 while (replmd_private->ncs) {
6724 struct nc_entry *e = replmd_private->ncs;
6725 DLIST_REMOVE(replmd_private->ncs, e);
6729 replmd_private->originating_updates = false;
6731 return ldb_next_start_trans(module);
6735 on prepare commit we loop over our queued la_context structures and
6738 static int replmd_prepare_commit(struct ldb_module *module)
6740 struct replmd_private *replmd_private =
6741 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6742 struct la_entry *la, *prev;
6743 struct la_backlink *bl;
6746 /* walk the list backwards, to do the first entry first, as we
6747 * added the entries with DLIST_ADD() which puts them at the
6748 * start of the list */
6749 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
6750 prev = DLIST_PREV(la);
6751 DLIST_REMOVE(replmd_private->la_list, la);
6752 ret = replmd_process_linked_attribute(module, replmd_private,
6754 if (ret != LDB_SUCCESS) {
6755 replmd_txn_cleanup(replmd_private);
6760 /* process our backlink list, creating and deleting backlinks
6762 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
6763 ret = replmd_process_backlink(module, bl, NULL);
6764 if (ret != LDB_SUCCESS) {
6765 replmd_txn_cleanup(replmd_private);
6770 replmd_txn_cleanup(replmd_private);
6772 /* possibly change @REPLCHANGED */
6773 ret = replmd_notify_store(module, NULL);
6774 if (ret != LDB_SUCCESS) {
6778 return ldb_next_prepare_commit(module);
6781 static int replmd_del_transaction(struct ldb_module *module)
6783 struct replmd_private *replmd_private =
6784 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6785 replmd_txn_cleanup(replmd_private);
6787 return ldb_next_del_trans(module);
6791 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
6792 .name = "repl_meta_data",
6793 .init_context = replmd_init,
6795 .modify = replmd_modify,
6796 .rename = replmd_rename,
6797 .del = replmd_delete,
6798 .extended = replmd_extended,
6799 .start_transaction = replmd_start_transaction,
6800 .prepare_commit = replmd_prepare_commit,
6801 .del_transaction = replmd_del_transaction,
6804 int ldb_repl_meta_data_module_init(const char *version)
6806 LDB_MODULE_CHECK_VERSION(version);
6807 return ldb_register_module(&ldb_repl_meta_data_module_ops);