4 Copyright (C) Simo Sorce 2004-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2013
6 Copyright (C) Andrew Tridgell 2005-2009
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8 Copyright (C) Matthieu Patou <mat@samba.org> 2010-2011
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 * Component: ldb repl_meta_data module
29 * Description: - add a unique objectGUID onto every new record,
30 * - handle whenCreated, whenChanged timestamps
31 * - handle uSNCreated, uSNChanged numbers
32 * - handle replPropertyMetaData attribute
35 * Author: Stefan Metzmacher
39 #include "ldb_module.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "dsdb/common/proto.h"
42 #include "../libds/common/flags.h"
43 #include "librpc/gen_ndr/ndr_misc.h"
44 #include "librpc/gen_ndr/ndr_drsuapi.h"
45 #include "librpc/gen_ndr/ndr_drsblobs.h"
46 #include "param/param.h"
47 #include "libcli/security/security.h"
48 #include "lib/util/dlinklist.h"
49 #include "dsdb/samdb/ldb_modules/util.h"
50 #include "lib/util/binsearch.h"
51 #include "lib/util/tsort.h"
54 * It's 29/12/9999 at 23:59:59 UTC as specified in MS-ADTS 7.1.1.4.2
55 * Deleted Objects Container
57 static const NTTIME DELETED_OBJECT_CONTAINER_CHANGE_TIME = 2650466015990000000ULL;
59 struct replmd_private {
61 struct la_entry *la_list;
63 struct la_backlink *la_backlinks;
65 struct nc_entry *prev, *next;
68 uint64_t mod_usn_urgent;
70 struct ldb_dn *schema_dn;
71 bool originating_updates;
76 struct la_entry *next, *prev;
77 struct drsuapi_DsReplicaLinkedAttribute *la;
80 struct replmd_replicated_request {
81 struct ldb_module *module;
82 struct ldb_request *req;
84 const struct dsdb_schema *schema;
85 struct GUID our_invocation_id;
87 /* the controls we pass down */
88 struct ldb_control **controls;
90 /* details for the mode where we apply a bunch of inbound replication meessages */
92 uint32_t index_current;
93 struct dsdb_extended_replicated_objects *objs;
95 struct ldb_message *search_msg;
96 struct GUID local_parent_guid;
105 struct dsdb_dn *dsdb_dn;
110 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
111 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
112 static int replmd_check_upgrade_links(struct ldb_context *ldb,
113 struct parsed_dn *dns, uint32_t count,
114 struct ldb_message_element *el,
115 const char *ldap_oid);
117 enum urgent_situation {
118 REPL_URGENT_ON_CREATE = 1,
119 REPL_URGENT_ON_UPDATE = 2,
120 REPL_URGENT_ON_DELETE = 4
123 enum deletion_state {
124 OBJECT_NOT_DELETED=1,
131 static void replmd_deletion_state(struct ldb_module *module,
132 const struct ldb_message *msg,
133 enum deletion_state *current_state,
134 enum deletion_state *next_state)
137 bool enabled = false;
140 *current_state = OBJECT_REMOVED;
141 if (next_state != NULL) {
142 *next_state = OBJECT_REMOVED;
147 ret = dsdb_recyclebin_enabled(module, &enabled);
148 if (ret != LDB_SUCCESS) {
152 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
154 *current_state = OBJECT_TOMBSTONE;
155 if (next_state != NULL) {
156 *next_state = OBJECT_REMOVED;
161 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
162 *current_state = OBJECT_RECYCLED;
163 if (next_state != NULL) {
164 *next_state = OBJECT_REMOVED;
169 *current_state = OBJECT_DELETED;
170 if (next_state != NULL) {
171 *next_state = OBJECT_RECYCLED;
176 *current_state = OBJECT_NOT_DELETED;
177 if (next_state == NULL) {
182 *next_state = OBJECT_DELETED;
184 *next_state = OBJECT_TOMBSTONE;
188 static const struct {
189 const char *update_name;
190 enum urgent_situation repl_situation;
191 } urgent_objects[] = {
192 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
193 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
194 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
195 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
196 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
197 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
201 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
202 static const char *urgent_attrs[] = {
205 "userAccountControl",
210 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
211 enum urgent_situation situation)
214 for (i=0; urgent_objects[i].update_name; i++) {
216 if ((situation & urgent_objects[i].repl_situation) == 0) {
220 for (j=0; j<objectclass_el->num_values; j++) {
221 const struct ldb_val *v = &objectclass_el->values[j];
222 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
230 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
232 if (ldb_attr_in_list(urgent_attrs, el->name)) {
239 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
242 initialise the module
243 allocate the private structure and build the list
244 of partition DNs for use by replmd_notify()
246 static int replmd_init(struct ldb_module *module)
248 struct replmd_private *replmd_private;
249 struct ldb_context *ldb = ldb_module_get_ctx(module);
250 static const char *samba_dsdb_attrs[] = { SAMBA_COMPATIBLE_FEATURES_ATTR, NULL };
251 struct ldb_dn *samba_dsdb_dn;
252 struct ldb_result *res;
254 TALLOC_CTX *frame = talloc_stackframe();
255 replmd_private = talloc_zero(module, struct replmd_private);
256 if (replmd_private == NULL) {
259 return LDB_ERR_OPERATIONS_ERROR;
261 ldb_module_set_private(module, replmd_private);
263 replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
265 samba_dsdb_dn = ldb_dn_new(frame, ldb, "@SAMBA_DSDB");
266 if (!samba_dsdb_dn) {
271 ret = dsdb_module_search_dn(module, frame, &res, samba_dsdb_dn,
272 samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
273 if (ret == LDB_SUCCESS) {
274 replmd_private->sorted_links
275 = ldb_msg_check_string_attribute(res->msgs[0],
276 SAMBA_COMPATIBLE_FEATURES_ATTR,
277 SAMBA_SORTED_LINKS_FEATURE);
281 return ldb_next_init(module);
285 cleanup our per-transaction contexts
287 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
289 talloc_free(replmd_private->la_ctx);
290 replmd_private->la_list = NULL;
291 replmd_private->la_ctx = NULL;
293 talloc_free(replmd_private->bl_ctx);
294 replmd_private->la_backlinks = NULL;
295 replmd_private->bl_ctx = NULL;
300 struct la_backlink *next, *prev;
301 const char *attr_name;
302 struct GUID forward_guid, target_guid;
307 a ldb_modify request operating on modules below the
310 static int linked_attr_modify(struct ldb_module *module,
311 const struct ldb_message *message,
312 struct ldb_request *parent)
314 struct ldb_request *mod_req;
316 struct ldb_context *ldb = ldb_module_get_ctx(module);
317 TALLOC_CTX *tmp_ctx = talloc_new(module);
318 struct ldb_result *res;
320 res = talloc_zero(tmp_ctx, struct ldb_result);
322 talloc_free(tmp_ctx);
323 return ldb_oom(ldb_module_get_ctx(module));
326 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
330 ldb_modify_default_callback,
332 LDB_REQ_SET_LOCATION(mod_req);
333 if (ret != LDB_SUCCESS) {
334 talloc_free(tmp_ctx);
338 ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
340 if (ret != LDB_SUCCESS) {
344 /* Run the new request */
345 ret = ldb_next_request(module, mod_req);
347 if (ret == LDB_SUCCESS) {
348 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
351 talloc_free(tmp_ctx);
356 process a backlinks we accumulated during a transaction, adding and
357 deleting the backlinks from the target objects
359 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
361 struct ldb_dn *target_dn, *source_dn;
363 struct ldb_context *ldb = ldb_module_get_ctx(module);
364 struct ldb_message *msg;
365 TALLOC_CTX *tmp_ctx = talloc_new(bl);
371 - construct ldb_message
372 - either an add or a delete
374 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn, parent);
375 if (ret != LDB_SUCCESS) {
376 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
377 GUID_string(bl, &bl->target_guid)));
381 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn, parent);
382 if (ret != LDB_SUCCESS) {
383 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
384 GUID_string(bl, &bl->forward_guid));
385 talloc_free(tmp_ctx);
389 msg = ldb_msg_new(tmp_ctx);
391 ldb_module_oom(module);
392 talloc_free(tmp_ctx);
393 return LDB_ERR_OPERATIONS_ERROR;
396 /* construct a ldb_message for adding/deleting the backlink */
398 dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
400 ldb_module_oom(module);
401 talloc_free(tmp_ctx);
402 return LDB_ERR_OPERATIONS_ERROR;
404 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
405 if (ret != LDB_SUCCESS) {
406 talloc_free(tmp_ctx);
409 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
411 /* a backlink should never be single valued. Unfortunately the
412 exchange schema has a attribute
413 msExchBridgeheadedLocalConnectorsDNBL which is single
414 valued and a backlink. We need to cope with that by
415 ignoring the single value flag */
416 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
418 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
419 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
420 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
421 cope with possible corruption where the backlink has
422 already been removed */
423 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
424 ldb_dn_get_linearized(target_dn),
425 ldb_dn_get_linearized(source_dn),
426 ldb_errstring(ldb)));
428 } else if (ret != LDB_SUCCESS) {
429 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
430 bl->active?"add":"remove",
431 ldb_dn_get_linearized(source_dn),
432 ldb_dn_get_linearized(target_dn),
434 talloc_free(tmp_ctx);
437 talloc_free(tmp_ctx);
442 add a backlink to the list of backlinks to add/delete in the prepare
445 static int replmd_add_backlink(struct ldb_module *module,
446 struct replmd_private *replmd_private,
447 const struct dsdb_schema *schema,
448 struct GUID *forward_guid,
449 struct GUID *target_guid, bool active,
450 const struct dsdb_attribute *schema_attr,
453 const struct dsdb_attribute *target_attr;
454 struct la_backlink *bl;
456 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
459 * windows 2003 has a broken schema where the
460 * definition of msDS-IsDomainFor is missing (which is
461 * supposed to be the backlink of the
462 * msDS-HasDomainNCs attribute
467 /* see if its already in the list */
468 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
469 if (GUID_equal(forward_guid, &bl->forward_guid) &&
470 GUID_equal(target_guid, &bl->target_guid) &&
471 (target_attr->lDAPDisplayName == bl->attr_name ||
472 strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
478 /* we found an existing one */
479 if (bl->active == active) {
482 DLIST_REMOVE(replmd_private->la_backlinks, bl);
487 if (replmd_private->bl_ctx == NULL) {
488 replmd_private->bl_ctx = talloc_new(replmd_private);
489 if (replmd_private->bl_ctx == NULL) {
490 ldb_module_oom(module);
491 return LDB_ERR_OPERATIONS_ERROR;
496 bl = talloc(replmd_private->bl_ctx, struct la_backlink);
498 ldb_module_oom(module);
499 return LDB_ERR_OPERATIONS_ERROR;
502 /* Ensure the schema does not go away before the bl->attr_name is used */
503 if (!talloc_reference(bl, schema)) {
505 ldb_module_oom(module);
506 return LDB_ERR_OPERATIONS_ERROR;
509 bl->attr_name = target_attr->lDAPDisplayName;
510 bl->forward_guid = *forward_guid;
511 bl->target_guid = *target_guid;
514 /* the caller may ask for this backlink to be processed
517 int ret = replmd_process_backlink(module, bl, NULL);
522 DLIST_ADD(replmd_private->la_backlinks, bl);
529 * Callback for most write operations in this module:
531 * notify the repl task that a object has changed. The notifies are
532 * gathered up in the replmd_private structure then written to the
533 * @REPLCHANGED object in each partition during the prepare_commit
535 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
538 struct replmd_replicated_request *ac =
539 talloc_get_type_abort(req->context, struct replmd_replicated_request);
540 struct replmd_private *replmd_private =
541 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
542 struct nc_entry *modified_partition;
543 struct ldb_control *partition_ctrl;
544 const struct dsdb_control_current_partition *partition;
546 struct ldb_control **controls;
548 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
550 controls = ares->controls;
551 if (ldb_request_get_control(ac->req,
552 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
554 * Remove the current partition control from what we pass up
555 * the chain if it hasn't been requested manually.
557 controls = ldb_controls_except_specified(ares->controls, ares,
561 if (ares->error != LDB_SUCCESS) {
562 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
563 return ldb_module_done(ac->req, controls,
564 ares->response, ares->error);
567 if (ares->type != LDB_REPLY_DONE) {
568 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
569 return ldb_module_done(ac->req, NULL,
570 NULL, LDB_ERR_OPERATIONS_ERROR);
573 if (!partition_ctrl) {
574 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
575 return ldb_module_done(ac->req, NULL,
576 NULL, LDB_ERR_OPERATIONS_ERROR);
579 partition = talloc_get_type_abort(partition_ctrl->data,
580 struct dsdb_control_current_partition);
582 if (ac->seq_num > 0) {
583 for (modified_partition = replmd_private->ncs; modified_partition;
584 modified_partition = modified_partition->next) {
585 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
590 if (modified_partition == NULL) {
591 modified_partition = talloc_zero(replmd_private, struct nc_entry);
592 if (!modified_partition) {
593 ldb_oom(ldb_module_get_ctx(ac->module));
594 return ldb_module_done(ac->req, NULL,
595 NULL, LDB_ERR_OPERATIONS_ERROR);
597 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
598 if (!modified_partition->dn) {
599 ldb_oom(ldb_module_get_ctx(ac->module));
600 return ldb_module_done(ac->req, NULL,
601 NULL, LDB_ERR_OPERATIONS_ERROR);
603 DLIST_ADD(replmd_private->ncs, modified_partition);
606 if (ac->seq_num > modified_partition->mod_usn) {
607 modified_partition->mod_usn = ac->seq_num;
609 modified_partition->mod_usn_urgent = ac->seq_num;
612 if (!ac->apply_mode) {
613 replmd_private->originating_updates = true;
617 if (ac->apply_mode) {
618 ret = replmd_replicated_apply_isDeleted(ac);
619 if (ret != LDB_SUCCESS) {
620 return ldb_module_done(ac->req, NULL, NULL, ret);
624 /* free the partition control container here, for the
625 * common path. Other cases will have it cleaned up
626 * eventually with the ares */
627 talloc_free(partition_ctrl);
628 return ldb_module_done(ac->req, controls,
629 ares->response, LDB_SUCCESS);
635 * update a @REPLCHANGED record in each partition if there have been
636 * any writes of replicated data in the partition
638 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
640 struct replmd_private *replmd_private =
641 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
643 while (replmd_private->ncs) {
645 struct nc_entry *modified_partition = replmd_private->ncs;
647 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
648 modified_partition->mod_usn,
649 modified_partition->mod_usn_urgent, parent);
650 if (ret != LDB_SUCCESS) {
651 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
652 ldb_dn_get_linearized(modified_partition->dn)));
656 if (ldb_dn_compare(modified_partition->dn,
657 replmd_private->schema_dn) == 0) {
658 struct ldb_result *ext_res;
659 ret = dsdb_module_extended(module,
660 replmd_private->schema_dn,
662 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
664 DSDB_FLAG_NEXT_MODULE,
666 if (ret != LDB_SUCCESS) {
669 talloc_free(ext_res);
672 DLIST_REMOVE(replmd_private->ncs, modified_partition);
673 talloc_free(modified_partition);
681 created a replmd_replicated_request context
683 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
684 struct ldb_request *req)
686 struct ldb_context *ldb;
687 struct replmd_replicated_request *ac;
688 const struct GUID *our_invocation_id;
690 ldb = ldb_module_get_ctx(module);
692 ac = talloc_zero(req, struct replmd_replicated_request);
701 ac->schema = dsdb_get_schema(ldb, ac);
703 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
704 "replmd_modify: no dsdb_schema loaded");
705 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
710 /* get our invocationId */
711 our_invocation_id = samdb_ntds_invocation_id(ldb);
712 if (!our_invocation_id) {
713 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
714 "replmd_add: unable to find invocationId\n");
718 ac->our_invocation_id = *our_invocation_id;
724 add a time element to a record
726 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
728 struct ldb_message_element *el;
732 if (ldb_msg_find_element(msg, attr) != NULL) {
736 s = ldb_timestring(msg, t);
738 return LDB_ERR_OPERATIONS_ERROR;
741 ret = ldb_msg_add_string(msg, attr, s);
742 if (ret != LDB_SUCCESS) {
746 el = ldb_msg_find_element(msg, attr);
747 /* always set as replace. This works because on add ops, the flag
749 el->flags = LDB_FLAG_MOD_REPLACE;
755 add a uint64_t element to a record
757 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
758 const char *attr, uint64_t v)
760 struct ldb_message_element *el;
763 if (ldb_msg_find_element(msg, attr) != NULL) {
767 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
768 if (ret != LDB_SUCCESS) {
772 el = ldb_msg_find_element(msg, attr);
773 /* always set as replace. This works because on add ops, the flag
775 el->flags = LDB_FLAG_MOD_REPLACE;
780 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
781 const struct replPropertyMetaData1 *m2,
782 const uint32_t *rdn_attid)
785 * This assignment seems inoccous, but it is critical for the
786 * system, as we need to do the comparisons as a unsigned
787 * quantity, not signed (enums are signed integers)
789 uint32_t attid_1 = m1->attid;
790 uint32_t attid_2 = m2->attid;
792 if (attid_1 == attid_2) {
797 * See above regarding this being an unsigned comparison.
798 * Otherwise when the high bit is set on non-standard
799 * attributes, they would end up first, before objectClass
802 return attid_1 > attid_2 ? 1 : -1;
805 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
806 struct replPropertyMetaDataCtr1 *ctr1,
809 if (ctr1->count == 0) {
810 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
811 "No elements found in replPropertyMetaData for %s!\n",
812 ldb_dn_get_linearized(dn));
813 return LDB_ERR_CONSTRAINT_VIOLATION;
816 /* the objectClass attribute is value 0x00000000, so must be first */
817 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
818 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
819 "No objectClass found in replPropertyMetaData for %s!\n",
820 ldb_dn_get_linearized(dn));
821 return LDB_ERR_OBJECT_CLASS_VIOLATION;
827 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
828 struct replPropertyMetaDataCtr1 *ctr1,
831 /* Note this is O(n^2) for the almost-sorted case, which this is */
832 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
833 replmd_replPropertyMetaData1_attid_sort);
834 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
837 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
838 const struct ldb_message_element *e2,
839 const struct dsdb_schema *schema)
841 const struct dsdb_attribute *a1;
842 const struct dsdb_attribute *a2;
845 * TODO: make this faster by caching the dsdb_attribute pointer
846 * on the ldb_messag_element
849 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
850 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
853 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
857 return strcasecmp(e1->name, e2->name);
859 if (a1->attributeID_id == a2->attributeID_id) {
862 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
865 static void replmd_ldb_message_sort(struct ldb_message *msg,
866 const struct dsdb_schema *schema)
868 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
871 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
872 const struct GUID *invocation_id, uint64_t seq_num,
873 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
875 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
876 struct ldb_message_element *el, struct parsed_dn **pdn,
877 const char *ldap_oid, struct ldb_request *parent);
880 fix up linked attributes in replmd_add.
881 This involves setting up the right meta-data in extended DN
882 components, and creating backlinks to the object
884 static int replmd_add_fix_la(struct ldb_module *module, TALLOC_CTX *mem_ctx,
885 struct replmd_private *replmd_private,
886 struct ldb_message_element *el,
887 uint64_t seq_num, const struct GUID *invocationId, NTTIME now,
888 struct GUID *guid, const struct dsdb_attribute *sa,
889 struct ldb_request *parent)
892 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
893 struct ldb_context *ldb = ldb_module_get_ctx(module);
894 struct parsed_dn *pdn;
895 /* We will take a reference to the schema in replmd_add_backlink */
896 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
897 struct ldb_val *new_values = NULL;
899 int ret = get_parsed_dns(module, tmp_ctx, el, &pdn,
900 sa->syntax->ldap_oid, parent);
901 if (ret != LDB_SUCCESS) {
902 talloc_free(tmp_ctx);
906 new_values = talloc_array(tmp_ctx, struct ldb_val, el->num_values);
907 if (new_values == NULL) {
908 ldb_module_oom(module);
909 talloc_free(tmp_ctx);
910 return LDB_ERR_OPERATIONS_ERROR;
913 for (i = 0; i < el->num_values; i++) {
914 struct parsed_dn *p = &pdn[i];
915 ret = replmd_build_la_val(el->values, p->v, p->dsdb_dn,
917 seq_num, seq_num, now, 0, false);
918 if (ret != LDB_SUCCESS) {
919 talloc_free(tmp_ctx);
923 /* This is the only place we are doing deferred back-links */
924 ret = replmd_add_backlink(module, replmd_private,
925 schema, guid, &p->guid, true, sa,
927 if (ret != LDB_SUCCESS) {
928 talloc_free(tmp_ctx);
932 new_values[i] = *p->v;
934 el->values = talloc_steal(mem_ctx, new_values);
936 talloc_free(tmp_ctx);
942 intercept add requests
944 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
946 struct ldb_context *ldb;
947 struct ldb_control *control;
948 struct replmd_replicated_request *ac;
949 enum ndr_err_code ndr_err;
950 struct ldb_request *down_req;
951 struct ldb_message *msg;
952 const DATA_BLOB *guid_blob;
954 struct replPropertyMetaDataBlob nmd;
955 struct ldb_val nmd_value;
958 * The use of a time_t here seems odd, but as the NTTIME
959 * elements are actually declared as NTTIME_1sec in the IDL,
960 * getting a higher resolution timestamp is not required.
962 time_t t = time(NULL);
967 unsigned int functional_level;
969 bool allow_add_guid = false;
970 bool remove_current_guid = false;
971 bool is_urgent = false;
972 bool is_schema_nc = false;
973 struct ldb_message_element *objectclass_el;
974 struct replmd_private *replmd_private =
975 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
977 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
978 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
980 allow_add_guid = true;
983 /* do not manipulate our control entries */
984 if (ldb_dn_is_special(req->op.add.message->dn)) {
985 return ldb_next_request(module, req);
988 ldb = ldb_module_get_ctx(module);
990 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
992 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
993 if (guid_blob != NULL) {
994 if (!allow_add_guid) {
995 ldb_set_errstring(ldb,
996 "replmd_add: it's not allowed to add an object with objectGUID!");
997 return LDB_ERR_UNWILLING_TO_PERFORM;
999 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
1000 if (!NT_STATUS_IS_OK(status)) {
1001 ldb_set_errstring(ldb,
1002 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1003 return LDB_ERR_UNWILLING_TO_PERFORM;
1005 /* we remove this attribute as it can be a string and
1006 * will not be treated correctly and then we will re-add
1007 * it later on in the good format */
1008 remove_current_guid = true;
1012 guid = GUID_random();
1015 ac = replmd_ctx_init(module, req);
1017 return ldb_module_oom(module);
1020 functional_level = dsdb_functional_level(ldb);
1022 /* Get a sequence number from the backend */
1023 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1024 if (ret != LDB_SUCCESS) {
1029 /* we have to copy the message as the caller might have it as a const */
1030 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1034 return LDB_ERR_OPERATIONS_ERROR;
1037 /* generated times */
1038 unix_to_nt_time(&now, t);
1039 time_str = ldb_timestring(msg, t);
1043 return LDB_ERR_OPERATIONS_ERROR;
1045 if (remove_current_guid) {
1046 ldb_msg_remove_attr(msg,"objectGUID");
1050 * remove autogenerated attributes
1052 ldb_msg_remove_attr(msg, "whenCreated");
1053 ldb_msg_remove_attr(msg, "whenChanged");
1054 ldb_msg_remove_attr(msg, "uSNCreated");
1055 ldb_msg_remove_attr(msg, "uSNChanged");
1056 ldb_msg_remove_attr(msg, "replPropertyMetaData");
1059 * readd replicated attributes
1061 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1062 if (ret != LDB_SUCCESS) {
1068 /* build the replication meta_data */
1071 nmd.ctr.ctr1.count = msg->num_elements;
1072 nmd.ctr.ctr1.array = talloc_array(msg,
1073 struct replPropertyMetaData1,
1074 nmd.ctr.ctr1.count);
1075 if (!nmd.ctr.ctr1.array) {
1078 return LDB_ERR_OPERATIONS_ERROR;
1081 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1083 for (i=0; i < msg->num_elements;) {
1084 struct ldb_message_element *e = &msg->elements[i];
1085 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1086 const struct dsdb_attribute *sa;
1088 if (e->name[0] == '@') {
1093 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1095 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1096 "replmd_add: attribute '%s' not defined in schema\n",
1099 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1102 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1103 /* if the attribute is not replicated (0x00000001)
1104 * or constructed (0x00000004) it has no metadata
1110 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1111 ret = replmd_add_fix_la(module, msg->elements,
1114 &ac->our_invocation_id, now,
1116 if (ret != LDB_SUCCESS) {
1120 /* linked attributes are not stored in
1121 replPropertyMetaData in FL above w2k */
1126 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1128 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1129 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1132 if (rdn_val == NULL) {
1135 return LDB_ERR_OPERATIONS_ERROR;
1138 rdn = (const char*)rdn_val->data;
1139 if (strcmp(rdn, "Deleted Objects") == 0) {
1141 * Set the originating_change_time to 29/12/9999 at 23:59:59
1142 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1144 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1146 m->originating_change_time = now;
1149 m->originating_change_time = now;
1151 m->originating_invocation_id = ac->our_invocation_id;
1152 m->originating_usn = ac->seq_num;
1153 m->local_usn = ac->seq_num;
1156 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1161 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1163 if (e->num_values != 0) {
1168 ldb_msg_remove_element(msg, e);
1171 /* fix meta data count */
1172 nmd.ctr.ctr1.count = ni;
1175 * sort meta data array
1177 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1178 if (ret != LDB_SUCCESS) {
1179 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1184 /* generated NDR encoded values */
1185 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1187 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1188 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1191 return LDB_ERR_OPERATIONS_ERROR;
1195 * add the autogenerated values
1197 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1198 if (ret != LDB_SUCCESS) {
1203 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1204 if (ret != LDB_SUCCESS) {
1209 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1210 if (ret != LDB_SUCCESS) {
1215 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1216 if (ret != LDB_SUCCESS) {
1221 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1222 if (ret != LDB_SUCCESS) {
1229 * sort the attributes by attid before storing the object
1231 replmd_ldb_message_sort(msg, ac->schema);
1234 * Assert that we do have an objectClass
1236 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1237 if (objectclass_el == NULL) {
1238 ldb_asprintf_errstring(ldb, __location__
1239 ": objectClass missing on %s\n",
1240 ldb_dn_get_linearized(msg->dn));
1242 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1244 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1245 REPL_URGENT_ON_CREATE);
1247 ac->is_urgent = is_urgent;
1248 ret = ldb_build_add_req(&down_req, ldb, ac,
1251 ac, replmd_op_callback,
1254 LDB_REQ_SET_LOCATION(down_req);
1255 if (ret != LDB_SUCCESS) {
1260 /* current partition control is needed by "replmd_op_callback" */
1261 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1262 ret = ldb_request_add_control(down_req,
1263 DSDB_CONTROL_CURRENT_PARTITION_OID,
1265 if (ret != LDB_SUCCESS) {
1271 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1272 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1273 if (ret != LDB_SUCCESS) {
1279 /* mark the control done */
1281 control->critical = 0;
1283 /* go on with the call chain */
1284 return ldb_next_request(module, down_req);
1289 * update the replPropertyMetaData for one element
1291 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1292 struct ldb_message *msg,
1293 struct ldb_message_element *el,
1294 struct ldb_message_element *old_el,
1295 struct replPropertyMetaDataBlob *omd,
1296 const struct dsdb_schema *schema,
1298 const struct GUID *our_invocation_id,
1301 struct ldb_request *req)
1304 const struct dsdb_attribute *a;
1305 struct replPropertyMetaData1 *md1;
1306 bool may_skip = false;
1309 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1311 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1312 /* allow this to make it possible for dbcheck
1313 to remove bad attributes */
1317 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1319 return LDB_ERR_OPERATIONS_ERROR;
1322 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1324 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1329 * if the attribute's value haven't changed, and this isn't
1330 * just a delete of everything then return LDB_SUCCESS Unless
1331 * we have the provision control or if the attribute is
1332 * interSiteTopologyGenerator as this page explain:
1333 * http://support.microsoft.com/kb/224815 this attribute is
1334 * periodicaly written by the DC responsible for the intersite
1335 * generation in a given site
1337 * Unchanged could be deleting or replacing an already-gone
1338 * thing with an unconstrained delete/empty replace or a
1339 * replace with the same value, but not an add with the same
1340 * value because that could be about adding a duplicate (which
1341 * is for someone else to error out on).
1343 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1344 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1347 } else if (old_el == NULL && el->num_values == 0) {
1348 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1350 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1353 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1354 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1356 * We intentionally skip the version bump when attempting to
1359 * The control is set by dbcheck and expunge-tombstones which
1360 * both attempt to be non-replicating. Otherwise, making an
1361 * alteration to the replication state would trigger a
1362 * broadcast of all expunged objects.
1367 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1369 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1373 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1374 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1376 * allow this to make it possible for dbcheck
1377 * to rebuild broken metadata
1383 for (i=0; i<omd->ctr.ctr1.count; i++) {
1385 * First check if we find it under the msDS-IntID,
1386 * then check if we find it under the OID and
1389 * This allows the administrator to simply re-write
1390 * the attributes and so restore replication, which is
1391 * likely what they will try to do.
1393 if (attid == omd->ctr.ctr1.array[i].attid) {
1397 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1402 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1403 /* linked attributes are not stored in
1404 replPropertyMetaData in FL above w2k, but we do
1405 raise the seqnum for the object */
1406 if (*seq_num == 0 &&
1407 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1408 return LDB_ERR_OPERATIONS_ERROR;
1413 if (i == omd->ctr.ctr1.count) {
1414 /* we need to add a new one */
1415 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1416 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1417 if (omd->ctr.ctr1.array == NULL) {
1419 return LDB_ERR_OPERATIONS_ERROR;
1421 omd->ctr.ctr1.count++;
1422 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1425 /* Get a new sequence number from the backend. We only do this
1426 * if we have a change that requires a new
1427 * replPropertyMetaData element
1429 if (*seq_num == 0) {
1430 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1431 if (ret != LDB_SUCCESS) {
1432 return LDB_ERR_OPERATIONS_ERROR;
1436 md1 = &omd->ctr.ctr1.array[i];
1439 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1440 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1443 if (rdn_val == NULL) {
1445 return LDB_ERR_OPERATIONS_ERROR;
1448 rdn = (const char*)rdn_val->data;
1449 if (strcmp(rdn, "Deleted Objects") == 0) {
1451 * Set the originating_change_time to 29/12/9999 at 23:59:59
1452 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1454 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1456 md1->originating_change_time = now;
1459 md1->originating_change_time = now;
1461 md1->originating_invocation_id = *our_invocation_id;
1462 md1->originating_usn = *seq_num;
1463 md1->local_usn = *seq_num;
1469 * Bump the replPropertyMetaData version on an attribute, and if it
1470 * has changed (or forced by leaving rdn_old NULL), update the value
1473 * This is important, as calling a modify operation may not change the
1474 * version number if the values appear unchanged, but a rename between
1475 * parents bumps this value.
1478 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1479 struct ldb_message *msg,
1480 const struct ldb_val *rdn_new,
1481 const struct ldb_val *rdn_old,
1482 struct replPropertyMetaDataBlob *omd,
1483 struct replmd_replicated_request *ar,
1487 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1488 const struct dsdb_attribute *rdn_attr =
1489 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1490 const char *attr_name = rdn_attr != NULL ?
1491 rdn_attr->lDAPDisplayName :
1493 struct ldb_message_element new_el = {
1494 .flags = LDB_FLAG_MOD_REPLACE,
1497 .values = discard_const_p(struct ldb_val, rdn_new)
1499 struct ldb_message_element old_el = {
1500 .flags = LDB_FLAG_MOD_REPLACE,
1502 .num_values = rdn_old ? 1 : 0,
1503 .values = discard_const_p(struct ldb_val, rdn_old)
1506 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1507 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1508 if (ret != LDB_SUCCESS) {
1509 return ldb_oom(ldb);
1513 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1514 omd, ar->schema, &ar->seq_num,
1515 &ar->our_invocation_id,
1516 now, is_schema_nc, ar->req);
1520 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1522 uint32_t count = omd.ctr.ctr1.count;
1525 for (i=0; i < count; i++) {
1526 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1527 if (max < m.local_usn) {
1535 * update the replPropertyMetaData object each time we modify an
1536 * object. This is needed for DRS replication, as the merge on the
1537 * client is based on this object
1539 static int replmd_update_rpmd(struct ldb_module *module,
1540 const struct dsdb_schema *schema,
1541 struct ldb_request *req,
1542 const char * const *rename_attrs,
1543 struct ldb_message *msg, uint64_t *seq_num,
1544 time_t t, bool is_schema_nc,
1545 bool *is_urgent, bool *rodc)
1547 const struct ldb_val *omd_value;
1548 enum ndr_err_code ndr_err;
1549 struct replPropertyMetaDataBlob omd;
1552 const struct GUID *our_invocation_id;
1554 const char * const *attrs = NULL;
1555 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1556 struct ldb_result *res;
1557 struct ldb_context *ldb;
1558 struct ldb_message_element *objectclass_el;
1559 enum urgent_situation situation;
1560 bool rmd_is_provided;
1561 bool rmd_is_just_resorted = false;
1562 const char *not_rename_attrs[4 + msg->num_elements];
1565 attrs = rename_attrs;
1567 for (i = 0; i < msg->num_elements; i++) {
1568 not_rename_attrs[i] = msg->elements[i].name;
1570 not_rename_attrs[i] = "replPropertyMetaData";
1571 not_rename_attrs[i+1] = "objectClass";
1572 not_rename_attrs[i+2] = "instanceType";
1573 not_rename_attrs[i+3] = NULL;
1574 attrs = not_rename_attrs;
1577 ldb = ldb_module_get_ctx(module);
1579 our_invocation_id = samdb_ntds_invocation_id(ldb);
1580 if (!our_invocation_id) {
1581 /* this happens during an initial vampire while
1582 updating the schema */
1583 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1587 unix_to_nt_time(&now, t);
1589 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1590 rmd_is_provided = true;
1591 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1592 rmd_is_just_resorted = true;
1595 rmd_is_provided = false;
1598 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1599 * otherwise we consider we are updating */
1600 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1601 situation = REPL_URGENT_ON_DELETE;
1602 } else if (rename_attrs) {
1603 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1605 situation = REPL_URGENT_ON_UPDATE;
1608 if (rmd_is_provided) {
1609 /* In this case the change_replmetadata control was supplied */
1610 /* We check that it's the only attribute that is provided
1611 * (it's a rare case so it's better to keep the code simplier)
1612 * We also check that the highest local_usn is bigger or the same as
1615 if( msg->num_elements != 1 ||
1616 strncmp(msg->elements[0].name,
1617 "replPropertyMetaData", 20) ) {
1618 DEBUG(0,(__location__ ": changereplmetada control called without "\
1619 "a specified replPropertyMetaData attribute or with others\n"));
1620 return LDB_ERR_OPERATIONS_ERROR;
1622 if (situation != REPL_URGENT_ON_UPDATE) {
1623 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1624 return LDB_ERR_OPERATIONS_ERROR;
1626 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1628 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1629 ldb_dn_get_linearized(msg->dn)));
1630 return LDB_ERR_OPERATIONS_ERROR;
1632 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1633 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1634 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1635 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1636 ldb_dn_get_linearized(msg->dn)));
1637 return LDB_ERR_OPERATIONS_ERROR;
1640 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1641 DSDB_FLAG_NEXT_MODULE |
1642 DSDB_SEARCH_SHOW_RECYCLED |
1643 DSDB_SEARCH_SHOW_EXTENDED_DN |
1644 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1645 DSDB_SEARCH_REVEAL_INTERNALS, req);
1647 if (ret != LDB_SUCCESS) {
1651 if (rmd_is_just_resorted == false) {
1652 *seq_num = find_max_local_usn(omd);
1654 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1657 * The test here now allows for a new
1658 * replPropertyMetaData with no change, if was
1659 * just dbcheck re-sorting the values.
1661 if (*seq_num <= db_seq) {
1662 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1663 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1664 (long long)*seq_num, (long long)db_seq));
1665 return LDB_ERR_OPERATIONS_ERROR;
1670 /* search for the existing replPropertyMetaDataBlob. We need
1671 * to use REVEAL and ask for DNs in storage format to support
1672 * the check for values being the same in
1673 * replmd_update_rpmd_element()
1675 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1676 DSDB_FLAG_NEXT_MODULE |
1677 DSDB_SEARCH_SHOW_RECYCLED |
1678 DSDB_SEARCH_SHOW_EXTENDED_DN |
1679 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1680 DSDB_SEARCH_REVEAL_INTERNALS, req);
1681 if (ret != LDB_SUCCESS) {
1685 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1687 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1688 ldb_dn_get_linearized(msg->dn)));
1689 return LDB_ERR_OPERATIONS_ERROR;
1692 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1693 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1694 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1695 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1696 ldb_dn_get_linearized(msg->dn)));
1697 return LDB_ERR_OPERATIONS_ERROR;
1700 if (omd.version != 1) {
1701 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1702 omd.version, ldb_dn_get_linearized(msg->dn)));
1703 return LDB_ERR_OPERATIONS_ERROR;
1706 for (i=0; i<msg->num_elements;) {
1707 struct ldb_message_element *el = &msg->elements[i];
1708 struct ldb_message_element *old_el;
1710 old_el = ldb_msg_find_element(res->msgs[0], el->name);
1711 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1712 &omd, schema, seq_num,
1716 if (ret != LDB_SUCCESS) {
1720 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1721 *is_urgent = replmd_check_urgent_attribute(el);
1724 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1729 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1731 if (el->num_values != 0) {
1736 ldb_msg_remove_element(msg, el);
1741 * Assert that we have an objectClass attribute - this is major
1742 * corruption if we don't have this!
1744 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1745 if (objectclass_el != NULL) {
1747 * Now check if this objectClass means we need to do urgent replication
1749 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1753 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1754 ldb_asprintf_errstring(ldb, __location__
1755 ": objectClass missing on %s\n",
1756 ldb_dn_get_linearized(msg->dn));
1757 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1761 * replmd_update_rpmd_element has done an update if the
1764 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1765 struct ldb_val *md_value;
1766 struct ldb_message_element *el;
1768 /*if we are RODC and this is a DRSR update then its ok*/
1769 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1770 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
1771 unsigned instanceType;
1773 ret = samdb_rodc(ldb, rodc);
1774 if (ret != LDB_SUCCESS) {
1775 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1777 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1778 return LDB_ERR_REFERRAL;
1781 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1782 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1783 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1784 "cannot change replicated attribute on partial replica");
1788 md_value = talloc(msg, struct ldb_val);
1789 if (md_value == NULL) {
1791 return LDB_ERR_OPERATIONS_ERROR;
1794 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1795 if (ret != LDB_SUCCESS) {
1796 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1800 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1801 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1802 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1803 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1804 ldb_dn_get_linearized(msg->dn)));
1805 return LDB_ERR_OPERATIONS_ERROR;
1808 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1809 if (ret != LDB_SUCCESS) {
1810 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1811 ldb_dn_get_linearized(msg->dn)));
1816 el->values = md_value;
1822 struct compare_ctx {
1824 struct ldb_context *ldb;
1825 TALLOC_CTX *mem_ctx;
1826 const char *ldap_oid;
1828 const struct GUID *invocation_id;
1831 /* When a parsed_dn comes from the database, sometimes it is not really parsed. */
1833 static int really_parse_trusted_dn(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
1834 struct parsed_dn *pdn, const char *ldap_oid)
1837 struct dsdb_dn *dsdb_dn = dsdb_dn_parse_trusted(mem_ctx, ldb, pdn->v,
1839 if (dsdb_dn == NULL) {
1840 return LDB_ERR_INVALID_DN_SYNTAX;
1843 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &pdn->guid, "GUID");
1844 if (!NT_STATUS_IS_OK(status)) {
1845 return LDB_ERR_OPERATIONS_ERROR;
1847 pdn->dsdb_dn = dsdb_dn;
1852 * We choose, as the sort order, the same order as is used in DRS replication,
1853 * which is the memcmp() order of the NDR GUID, not that obtained from
1856 * This means that sorted links will be in the same order as a new DC would
1859 static int ndr_guid_compare(struct GUID *guid1, struct GUID *guid2)
1861 uint8_t v1_data[16];
1862 struct ldb_val v1 = data_blob_const(v1_data, sizeof(v1_data));
1863 uint8_t v2_data[16];
1864 struct ldb_val v2 = data_blob_const(v2_data, sizeof(v2_data));
1866 /* This can't fail */
1867 ndr_push_struct_into_fixed_blob(&v1, guid1,
1868 (ndr_push_flags_fn_t)ndr_push_GUID);
1869 /* This can't fail */
1870 ndr_push_struct_into_fixed_blob(&v2, guid2,
1871 (ndr_push_flags_fn_t)ndr_push_GUID);
1872 return data_blob_cmp(&v1, &v2);
1875 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1877 return ndr_guid_compare(&pdn1->guid, &pdn2->guid);
1880 static int la_guid_compare_with_trusted_dn(struct compare_ctx *ctx,
1881 struct parsed_dn *p)
1884 * This works like a standard compare function in its return values,
1885 * but has an extra trick to deal with errors: zero is returned and
1886 * ctx->err is set to the ldb error code.
1888 * That is, if (as is expected in most cases) you get a non-zero
1889 * result, you don't need to check for errors.
1891 * We assume the second argument refers to a DN is from the database
1892 * and has a GUID -- but this GUID might not have been parsed out yet.
1894 if (p->dsdb_dn == NULL) {
1895 int ret = really_parse_trusted_dn(ctx->mem_ctx, ctx->ldb, p,
1897 if (ret != LDB_SUCCESS) {
1902 return ndr_guid_compare(ctx->guid, &p->guid);
1907 static int parsed_dn_find(struct ldb_context *ldb, struct parsed_dn *pdn,
1910 struct ldb_dn *target_dn,
1911 struct parsed_dn **exact,
1912 struct parsed_dn **next,
1913 const char *ldap_oid)
1916 struct compare_ctx ctx;
1923 if (unlikely(GUID_all_zero(guid))) {
1925 * When updating a link using DRS, we sometimes get a NULL
1926 * GUID when a forward link has been deleted and its GUID has
1927 * for some reason been forgotten. The best we can do is try
1928 * and match by DN via a linear search. Note that this
1929 * probably only happens in the ADD case, in which we only
1930 * allow modification of link if it is already deleted, so
1931 * this seems very close to an elaborate NO-OP, but we are not
1932 * quite prepared to declare it so.
1934 * If the DN is not in our list, we have to add it to the
1935 * beginning of the list, where it would naturally sort.
1937 struct parsed_dn *p;
1938 if (target_dn == NULL) {
1939 /* We don't know the target DN, so we can't search for DN */
1940 DEBUG(1, ("parsed_dn_find has a NULL GUID for a linked "
1941 "attribute but we don't have a DN to compare "
1943 return LDB_ERR_OPERATIONS_ERROR;
1948 DEBUG(3, ("parsed_dn_find has a NULL GUID for a link to DN "
1949 "%s; searching through links for it",
1950 ldb_dn_get_linearized(target_dn)));
1952 for (i = 0; i < count; i++) {
1955 if (p->dsdb_dn == NULL) {
1956 int ret = really_parse_trusted_dn(pdn, ldb, p, ldap_oid);
1957 if (ret != LDB_SUCCESS) {
1958 return LDB_ERR_OPERATIONS_ERROR;
1962 cmp = ldb_dn_compare(p->dsdb_dn->dn, target_dn);
1969 * Here we have a null guid which doesn't match any existing
1970 * link. This is a bit unexpected because null guids occur
1971 * when a forward link has been deleted and we are replicating
1974 * The best thing to do is weep into the logs and add the
1975 * offending link to the beginning of the list which is
1976 * at least the correct sort position.
1978 DEBUG(1, ("parsed_dn_find has been given a NULL GUID for a "
1979 "link to unknown DN %s\n",
1980 ldb_dn_get_linearized(target_dn)));
1988 ctx.ldap_oid = ldap_oid;
1991 BINARY_ARRAY_SEARCH_GTE(pdn, count, &ctx, la_guid_compare_with_trusted_dn,
2001 get a series of message element values as an array of DNs and GUIDs
2002 the result is sorted by GUID
2004 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
2005 struct ldb_message_element *el, struct parsed_dn **pdn,
2006 const char *ldap_oid, struct ldb_request *parent)
2009 bool values_are_sorted = true;
2010 struct ldb_context *ldb = ldb_module_get_ctx(module);
2017 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
2019 ldb_module_oom(module);
2020 return LDB_ERR_OPERATIONS_ERROR;
2023 for (i=0; i<el->num_values; i++) {
2024 struct ldb_val *v = &el->values[i];
2027 struct parsed_dn *p;
2031 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
2032 if (p->dsdb_dn == NULL) {
2033 return LDB_ERR_INVALID_DN_SYNTAX;
2036 dn = p->dsdb_dn->dn;
2038 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
2039 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
2040 unlikely(GUID_all_zero(&p->guid))) {
2041 /* we got a DN without a GUID - go find the GUID */
2042 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
2043 if (ret != LDB_SUCCESS) {
2044 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
2045 ldb_dn_get_linearized(dn));
2046 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
2047 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
2048 ldb_attr_cmp(el->name, "member") == 0) {
2049 return LDB_ERR_UNWILLING_TO_PERFORM;
2053 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
2054 if (ret != LDB_SUCCESS) {
2057 } else if (!NT_STATUS_IS_OK(status)) {
2058 return LDB_ERR_OPERATIONS_ERROR;
2060 if (i > 0 && values_are_sorted) {
2061 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2063 values_are_sorted = false;
2066 /* keep a pointer to the original ldb_val */
2069 if (! values_are_sorted) {
2070 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2076 * Get a series of trusted message element values. The result is sorted by
2077 * GUID, even though the GUIDs might not be known. That works because we trust
2078 * the database to give us the elements like that if the
2079 * replmd_private->sorted_links flag is set.
2081 * We also ensure that the links are in the Functional Level 2003
2082 * linked attributes format.
2084 static int get_parsed_dns_trusted(struct ldb_module *module,
2085 struct replmd_private *replmd_private,
2086 TALLOC_CTX *mem_ctx,
2087 struct ldb_message_element *el,
2088 struct parsed_dn **pdn,
2089 const char *ldap_oid,
2090 struct ldb_request *parent)
2099 if (!replmd_private->sorted_links) {
2100 /* We need to sort the list. This is the slow old path we want
2103 ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2105 if (ret != LDB_SUCCESS) {
2109 /* Here we get a list of 'struct parsed_dns' without the parsing */
2110 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2113 ldb_module_oom(module);
2114 return LDB_ERR_OPERATIONS_ERROR;
2117 for (i = 0; i < el->num_values; i++) {
2118 (*pdn)[i].v = &el->values[i];
2122 ret = replmd_check_upgrade_links(ldb_module_get_ctx(module),
2123 *pdn, el->num_values,
2126 if (ret != LDB_SUCCESS) {
2134 build a new extended DN, including all meta data fields
2136 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2137 RMD_ADDTIME = originating_add_time
2138 RMD_INVOCID = originating_invocation_id
2139 RMD_CHANGETIME = originating_change_time
2140 RMD_ORIGINATING_USN = originating_usn
2141 RMD_LOCAL_USN = local_usn
2142 RMD_VERSION = version
2144 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2145 const struct GUID *invocation_id, uint64_t seq_num,
2146 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
2148 struct ldb_dn *dn = dsdb_dn->dn;
2149 const char *tstring, *usn_string, *flags_string;
2150 struct ldb_val tval;
2152 struct ldb_val usnv, local_usnv;
2153 struct ldb_val vers, flagsv;
2156 const char *dnstring;
2158 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2160 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2162 return LDB_ERR_OPERATIONS_ERROR;
2164 tval = data_blob_string_const(tstring);
2166 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
2168 return LDB_ERR_OPERATIONS_ERROR;
2170 usnv = data_blob_string_const(usn_string);
2172 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2174 return LDB_ERR_OPERATIONS_ERROR;
2176 local_usnv = data_blob_string_const(usn_string);
2178 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2180 return LDB_ERR_OPERATIONS_ERROR;
2182 vers = data_blob_string_const(vstring);
2184 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2185 if (!NT_STATUS_IS_OK(status)) {
2186 return LDB_ERR_OPERATIONS_ERROR;
2189 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2190 if (!flags_string) {
2191 return LDB_ERR_OPERATIONS_ERROR;
2193 flagsv = data_blob_string_const(flags_string);
2195 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2196 if (ret != LDB_SUCCESS) return ret;
2197 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
2198 if (ret != LDB_SUCCESS) return ret;
2199 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2200 if (ret != LDB_SUCCESS) return ret;
2201 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2202 if (ret != LDB_SUCCESS) return ret;
2203 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2204 if (ret != LDB_SUCCESS) return ret;
2205 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2206 if (ret != LDB_SUCCESS) return ret;
2207 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2208 if (ret != LDB_SUCCESS) return ret;
2210 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2211 if (dnstring == NULL) {
2212 return LDB_ERR_OPERATIONS_ERROR;
2214 *v = data_blob_string_const(dnstring);
2219 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2220 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2221 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2222 uint32_t version, bool deleted);
2225 check if any links need upgrading from w2k format
2227 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2228 struct parsed_dn *dns, uint32_t count,
2229 struct ldb_message_element *el,
2230 const char *ldap_oid)
2233 const struct GUID *invocation_id = NULL;
2234 for (i=0; i<count; i++) {
2238 if (dns[i].dsdb_dn == NULL) {
2239 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2241 if (ret != LDB_SUCCESS) {
2242 return LDB_ERR_INVALID_DN_SYNTAX;
2246 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2247 &version, "RMD_VERSION");
2248 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2250 * We optimistically assume they are all the same; if
2251 * the first one is fixed, they are all fixed.
2253 * If the first one was *not* fixed and we find a
2254 * later one that is, that is an occasion to shout
2260 DEBUG(0, ("Mixed w2k and fixed format "
2261 "linked attributes\n"));
2265 if (invocation_id == NULL) {
2266 invocation_id = samdb_ntds_invocation_id(ldb);
2267 if (invocation_id == NULL) {
2268 return LDB_ERR_OPERATIONS_ERROR;
2273 /* it's an old one that needs upgrading */
2274 ret = replmd_update_la_val(el->values, dns[i].v,
2275 dns[i].dsdb_dn, dns[i].dsdb_dn,
2276 invocation_id, 1, 1, 0, 0, false);
2277 if (ret != LDB_SUCCESS) {
2283 * This sort() is critical for the operation of
2284 * get_parsed_dns_trusted() because callers of this function
2285 * expect a sorted list, and FL2000 style links are not
2286 * sorted. In particular, as well as the upgrade case,
2287 * get_parsed_dns_trusted() is called from
2288 * replmd_delete_remove_link() even in FL2000 mode
2290 * We do not normally pay the cost of the qsort() due to the
2291 * early return in the RMD_VERSION found case.
2293 TYPESAFE_QSORT(dns, count, parsed_dn_compare);
2298 update an extended DN, including all meta data fields
2300 see replmd_build_la_val for value names
2302 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2303 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2304 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2305 uint32_t version, bool deleted)
2307 struct ldb_dn *dn = dsdb_dn->dn;
2308 const char *tstring, *usn_string, *flags_string;
2309 struct ldb_val tval;
2311 struct ldb_val usnv, local_usnv;
2312 struct ldb_val vers, flagsv;
2313 const struct ldb_val *old_addtime;
2314 uint32_t old_version;
2317 const char *dnstring;
2319 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2321 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2323 return LDB_ERR_OPERATIONS_ERROR;
2325 tval = data_blob_string_const(tstring);
2327 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2329 return LDB_ERR_OPERATIONS_ERROR;
2331 usnv = data_blob_string_const(usn_string);
2333 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2335 return LDB_ERR_OPERATIONS_ERROR;
2337 local_usnv = data_blob_string_const(usn_string);
2339 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2340 if (!NT_STATUS_IS_OK(status)) {
2341 return LDB_ERR_OPERATIONS_ERROR;
2344 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2345 if (!flags_string) {
2346 return LDB_ERR_OPERATIONS_ERROR;
2348 flagsv = data_blob_string_const(flags_string);
2350 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2351 if (ret != LDB_SUCCESS) return ret;
2353 /* get the ADDTIME from the original */
2354 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2355 if (old_addtime == NULL) {
2356 old_addtime = &tval;
2358 if (dsdb_dn != old_dsdb_dn ||
2359 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2360 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2361 if (ret != LDB_SUCCESS) return ret;
2364 /* use our invocation id */
2365 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2366 if (ret != LDB_SUCCESS) return ret;
2368 /* changetime is the current time */
2369 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2370 if (ret != LDB_SUCCESS) return ret;
2372 /* update the USN */
2373 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2374 if (ret != LDB_SUCCESS) return ret;
2376 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2377 if (ret != LDB_SUCCESS) return ret;
2379 /* increase the version by 1 */
2380 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2381 if (NT_STATUS_IS_OK(status) && old_version >= version) {
2382 version = old_version+1;
2384 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2385 vers = data_blob_string_const(vstring);
2386 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2387 if (ret != LDB_SUCCESS) return ret;
2389 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2390 if (dnstring == NULL) {
2391 return LDB_ERR_OPERATIONS_ERROR;
2393 *v = data_blob_string_const(dnstring);
2399 handle adding a linked attribute
2401 static int replmd_modify_la_add(struct ldb_module *module,
2402 struct replmd_private *replmd_private,
2403 const struct dsdb_schema *schema,
2404 struct ldb_message *msg,
2405 struct ldb_message_element *el,
2406 struct ldb_message_element *old_el,
2407 const struct dsdb_attribute *schema_attr,
2410 struct GUID *msg_guid,
2411 struct ldb_request *parent)
2414 struct parsed_dn *dns, *old_dns;
2415 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2417 struct ldb_val *new_values = NULL;
2418 unsigned old_num_values = old_el ? old_el->num_values : 0;
2419 unsigned num_values = 0;
2420 unsigned max_num_values;
2421 const struct GUID *invocation_id;
2422 struct ldb_context *ldb = ldb_module_get_ctx(module);
2424 unix_to_nt_time(&now, t);
2426 invocation_id = samdb_ntds_invocation_id(ldb);
2427 if (!invocation_id) {
2428 talloc_free(tmp_ctx);
2429 return LDB_ERR_OPERATIONS_ERROR;
2432 /* get the DNs to be added, fully parsed.
2434 * We need full parsing because they came off the wire and we don't
2435 * trust them, besides which we need their details to know where to put
2438 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2439 schema_attr->syntax->ldap_oid, parent);
2440 if (ret != LDB_SUCCESS) {
2441 talloc_free(tmp_ctx);
2445 /* get the existing DNs, lazily parsed */
2446 ret = get_parsed_dns_trusted(module, replmd_private,
2447 tmp_ctx, old_el, &old_dns,
2448 schema_attr->syntax->ldap_oid, parent);
2450 if (ret != LDB_SUCCESS) {
2451 talloc_free(tmp_ctx);
2455 max_num_values = old_num_values + el->num_values;
2456 if (max_num_values < old_num_values) {
2457 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2458 "old values: %u, new values: %u, sum: %u",
2459 old_num_values, el->num_values, max_num_values));
2460 talloc_free(tmp_ctx);
2461 return LDB_ERR_OPERATIONS_ERROR;
2464 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2466 if (new_values == NULL) {
2467 ldb_module_oom(module);
2468 talloc_free(tmp_ctx);
2469 return LDB_ERR_OPERATIONS_ERROR;
2473 * For each new value, find where it would go in the list. If there is
2474 * a matching GUID there, we update the existing value; otherwise we
2478 for (i = 0; i < el->num_values; i++) {
2479 struct parsed_dn *exact;
2480 struct parsed_dn *next;
2482 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2486 schema_attr->syntax->ldap_oid);
2487 if (err != LDB_SUCCESS) {
2488 talloc_free(tmp_ctx);
2492 if (exact != NULL) {
2494 * We are trying to add one that exists, which is only
2495 * allowed if it was previously deleted.
2497 * When we do undelete a link we change it in place.
2498 * It will be copied across into the right spot in due
2502 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2504 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2505 struct GUID_txt_buf guid_str;
2506 ldb_asprintf_errstring(ldb,
2507 "Attribute %s already "
2508 "exists for target GUID %s",
2510 GUID_buf_string(&exact->guid,
2512 talloc_free(tmp_ctx);
2513 /* error codes for 'member' need to be
2515 if (ldb_attr_cmp(el->name, "member") == 0) {
2516 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2518 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2522 ret = replmd_update_la_val(new_values, exact->v,
2525 invocation_id, seq_num,
2526 seq_num, now, 0, false);
2527 if (ret != LDB_SUCCESS) {
2528 talloc_free(tmp_ctx);
2532 ret = replmd_add_backlink(module, replmd_private,
2536 if (ret != LDB_SUCCESS) {
2537 talloc_free(tmp_ctx);
2543 * Here we don't have an exact match.
2545 * If next is NULL, this one goes beyond the end of the
2546 * existing list, so we need to add all of those ones first.
2548 * If next is not NULL, we need to add all the ones before
2552 offset = old_num_values;
2554 /* next should have been parsed, but let's make sure */
2555 if (next->dsdb_dn == NULL) {
2556 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2557 schema_attr->syntax->ldap_oid);
2558 if (ret != LDB_SUCCESS) {
2562 offset = MIN(next - old_dns, old_num_values);
2565 /* put all the old ones before next on the list */
2566 for (; j < offset; j++) {
2567 new_values[num_values] = *old_dns[j].v;
2571 ret = replmd_add_backlink(module, replmd_private,
2572 schema, msg_guid, &dns[i].guid,
2573 true, schema_attr, true);
2574 /* Make the new linked attribute ldb_val. */
2575 ret = replmd_build_la_val(new_values, &new_values[num_values],
2576 dns[i].dsdb_dn, invocation_id,
2579 if (ret != LDB_SUCCESS) {
2580 talloc_free(tmp_ctx);
2584 if (ret != LDB_SUCCESS) {
2585 talloc_free(tmp_ctx);
2589 /* copy the rest of the old ones (if any) */
2590 for (; j < old_num_values; j++) {
2591 new_values[num_values] = *old_dns[j].v;
2595 talloc_steal(msg->elements, new_values);
2596 if (old_el != NULL) {
2597 talloc_steal(msg->elements, old_el->values);
2599 el->values = new_values;
2600 el->num_values = num_values;
2602 talloc_free(tmp_ctx);
2604 /* we now tell the backend to replace all existing values
2605 with the one we have constructed */
2606 el->flags = LDB_FLAG_MOD_REPLACE;
2613 handle deleting all active linked attributes
2615 static int replmd_modify_la_delete(struct ldb_module *module,
2616 struct replmd_private *replmd_private,
2617 const struct dsdb_schema *schema,
2618 struct ldb_message *msg,
2619 struct ldb_message_element *el,
2620 struct ldb_message_element *old_el,
2621 const struct dsdb_attribute *schema_attr,
2624 struct GUID *msg_guid,
2625 struct ldb_request *parent)
2628 struct parsed_dn *dns, *old_dns;
2629 TALLOC_CTX *tmp_ctx = NULL;
2631 struct ldb_context *ldb = ldb_module_get_ctx(module);
2632 struct ldb_control *vanish_links_ctrl = NULL;
2633 bool vanish_links = false;
2634 unsigned int num_to_delete = el->num_values;
2636 const struct GUID *invocation_id;
2639 unix_to_nt_time(&now, t);
2641 invocation_id = samdb_ntds_invocation_id(ldb);
2642 if (!invocation_id) {
2643 return LDB_ERR_OPERATIONS_ERROR;
2646 if (old_el == NULL || old_el->num_values == 0) {
2647 /* there is nothing to delete... */
2648 if (num_to_delete == 0) {
2649 /* and we're deleting nothing, so that's OK */
2652 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2655 tmp_ctx = talloc_new(msg);
2656 if (tmp_ctx == NULL) {
2657 return LDB_ERR_OPERATIONS_ERROR;
2660 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2661 schema_attr->syntax->ldap_oid, parent);
2662 if (ret != LDB_SUCCESS) {
2663 talloc_free(tmp_ctx);
2667 ret = get_parsed_dns_trusted(module, replmd_private,
2668 tmp_ctx, old_el, &old_dns,
2669 schema_attr->syntax->ldap_oid, parent);
2671 if (ret != LDB_SUCCESS) {
2672 talloc_free(tmp_ctx);
2677 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2678 if (vanish_links_ctrl) {
2679 vanish_links = true;
2680 vanish_links_ctrl->critical = false;
2684 /* we empty out el->values here to avoid damage if we return early. */
2689 * If vanish links is set, we are actually removing members of
2690 * old_el->values; otherwise we are just marking them deleted.
2692 * There is a special case when no values are given: we remove them
2693 * all. When we have the vanish_links control we just have to remove
2694 * the backlinks and change our element to replace the existing values
2695 * with the empty list.
2698 if (num_to_delete == 0) {
2699 for (i = 0; i < old_el->num_values; i++) {
2700 struct parsed_dn *p = &old_dns[i];
2701 if (p->dsdb_dn == NULL) {
2702 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2703 schema_attr->syntax->ldap_oid);
2704 if (ret != LDB_SUCCESS) {
2708 ret = replmd_add_backlink(module, replmd_private,
2709 schema, msg_guid, &p->guid,
2710 false, schema_attr, true);
2711 if (ret != LDB_SUCCESS) {
2712 talloc_free(tmp_ctx);
2719 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2720 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2724 ret = replmd_update_la_val(old_el->values, p->v,
2725 p->dsdb_dn, p->dsdb_dn,
2726 invocation_id, seq_num,
2727 seq_num, now, 0, true);
2728 if (ret != LDB_SUCCESS) {
2729 talloc_free(tmp_ctx);
2735 el->flags = LDB_FLAG_MOD_REPLACE;
2736 talloc_free(tmp_ctx);
2742 for (i = 0; i < num_to_delete; i++) {
2743 struct parsed_dn *p = &dns[i];
2744 struct parsed_dn *exact = NULL;
2745 struct parsed_dn *next = NULL;
2746 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2750 schema_attr->syntax->ldap_oid);
2751 if (ret != LDB_SUCCESS) {
2752 talloc_free(tmp_ctx);
2755 if (exact == NULL) {
2756 struct GUID_txt_buf buf;
2757 ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2758 "exist for target GUID %s",
2760 GUID_buf_string(&p->guid, &buf));
2761 if (ldb_attr_cmp(el->name, "member") == 0) {
2762 talloc_free(tmp_ctx);
2763 return LDB_ERR_UNWILLING_TO_PERFORM;
2765 talloc_free(tmp_ctx);
2766 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2771 if (CHECK_DEBUGLVL(5)) {
2772 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2773 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2774 struct GUID_txt_buf buf;
2775 const char *guid_str = \
2776 GUID_buf_string(&p->guid, &buf);
2777 DEBUG(5, ("Deleting deleted linked "
2778 "attribute %s to %s, because "
2779 "vanish_links control is set\n",
2780 el->name, guid_str));
2784 /* remove the backlink */
2785 ret = replmd_add_backlink(module,
2791 if (ret != LDB_SUCCESS) {
2792 talloc_free(tmp_ctx);
2796 /* We flag the deletion and tidy it up later. */
2801 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2803 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2804 struct GUID_txt_buf buf;
2805 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2806 ldb_asprintf_errstring(ldb, "Attribute %s already "
2807 "deleted for target GUID %s",
2808 el->name, guid_str);
2809 if (ldb_attr_cmp(el->name, "member") == 0) {
2810 talloc_free(tmp_ctx);
2811 return LDB_ERR_UNWILLING_TO_PERFORM;
2813 talloc_free(tmp_ctx);
2814 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2818 ret = replmd_update_la_val(old_el->values, exact->v,
2819 exact->dsdb_dn, exact->dsdb_dn,
2820 invocation_id, seq_num, seq_num,
2822 if (ret != LDB_SUCCESS) {
2823 talloc_free(tmp_ctx);
2826 ret = replmd_add_backlink(module, replmd_private,
2827 schema, msg_guid, &p->guid,
2828 false, schema_attr, true);
2829 if (ret != LDB_SUCCESS) {
2830 talloc_free(tmp_ctx);
2837 for (i = 0; i < old_el->num_values; i++) {
2838 if (old_dns[i].v != NULL) {
2839 old_el->values[j] = *old_dns[i].v;
2843 old_el->num_values = j;
2846 el->values = talloc_steal(msg->elements, old_el->values);
2847 el->num_values = old_el->num_values;
2849 talloc_free(tmp_ctx);
2851 /* we now tell the backend to replace all existing values
2852 with the one we have constructed */
2853 el->flags = LDB_FLAG_MOD_REPLACE;
2859 handle replacing a linked attribute
2861 static int replmd_modify_la_replace(struct ldb_module *module,
2862 struct replmd_private *replmd_private,
2863 const struct dsdb_schema *schema,
2864 struct ldb_message *msg,
2865 struct ldb_message_element *el,
2866 struct ldb_message_element *old_el,
2867 const struct dsdb_attribute *schema_attr,
2870 struct GUID *msg_guid,
2871 struct ldb_request *parent)
2873 unsigned int i, old_i, new_i;
2874 struct parsed_dn *dns, *old_dns;
2875 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2877 const struct GUID *invocation_id;
2878 struct ldb_context *ldb = ldb_module_get_ctx(module);
2879 struct ldb_val *new_values = NULL;
2880 const char *ldap_oid = schema_attr->syntax->ldap_oid;
2881 unsigned int old_num_values;
2882 unsigned int repl_num_values;
2883 unsigned int max_num_values;
2886 unix_to_nt_time(&now, t);
2888 invocation_id = samdb_ntds_invocation_id(ldb);
2889 if (!invocation_id) {
2890 return LDB_ERR_OPERATIONS_ERROR;
2894 * The replace operation is unlike the replace and delete cases in that
2895 * we need to look at every existing link to see whether it is being
2896 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
2898 * As we are trying to combine two sorted lists, the algorithm we use
2899 * is akin to the merge phase of a merge sort. We interleave the two
2900 * lists, doing different things depending on which side the current
2903 * There are three main cases, with some sub-cases.
2905 * - a DN is in the old list but not the new one. It needs to be
2906 * marked as deleted (but left in the list).
2907 * - maybe it is already deleted, and we have less to do.
2909 * - a DN is in both lists. The old data gets replaced by the new,
2910 * and the list doesn't grow. The old link may have been marked as
2911 * deleted, in which case we undelete it.
2913 * - a DN is in the new list only. We add it in the right place.
2916 old_num_values = old_el ? old_el->num_values : 0;
2917 repl_num_values = el->num_values;
2918 max_num_values = old_num_values + repl_num_values;
2920 if (max_num_values == 0) {
2921 /* There is nothing to do! */
2925 ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
2926 if (ret != LDB_SUCCESS) {
2927 talloc_free(tmp_ctx);
2931 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
2933 if (ret != LDB_SUCCESS) {
2934 talloc_free(tmp_ctx);
2938 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2940 if (ret != LDB_SUCCESS) {
2941 talloc_free(tmp_ctx);
2945 new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
2946 if (new_values == NULL) {
2947 ldb_module_oom(module);
2948 talloc_free(tmp_ctx);
2949 return LDB_ERR_OPERATIONS_ERROR;
2954 for (i = 0; i < max_num_values; i++) {
2956 struct parsed_dn *old_p, *new_p;
2957 if (old_i < old_num_values && new_i < repl_num_values) {
2958 old_p = &old_dns[old_i];
2959 new_p = &dns[new_i];
2960 cmp = parsed_dn_compare(old_p, new_p);
2961 } else if (old_i < old_num_values) {
2962 /* the new list is empty, read the old list */
2963 old_p = &old_dns[old_i];
2966 } else if (new_i < repl_num_values) {
2967 /* the old list is empty, read new list */
2969 new_p = &dns[new_i];
2977 * An old ones that come before the next replacement
2978 * (if any). We mark it as deleted and add it to the
2981 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2982 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
2983 ret = replmd_update_la_val(new_values, old_p->v,
2989 if (ret != LDB_SUCCESS) {
2990 talloc_free(tmp_ctx);
2994 ret = replmd_add_backlink(module, replmd_private,
2996 &old_p->guid, false,
2998 if (ret != LDB_SUCCESS) {
2999 talloc_free(tmp_ctx);
3003 new_values[i] = *old_p->v;
3005 } else if (cmp == 0) {
3007 * We are overwriting one. If it was previously
3008 * deleted, we need to add a backlink.
3010 * Note that if any RMD_FLAGs in an extended new DN
3015 ret = replmd_update_la_val(new_values, old_p->v,
3021 if (ret != LDB_SUCCESS) {
3022 talloc_free(tmp_ctx);
3026 rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
3027 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
3028 ret = replmd_add_backlink(module, replmd_private,
3032 if (ret != LDB_SUCCESS) {
3033 talloc_free(tmp_ctx);
3038 new_values[i] = *old_p->v;
3043 * Replacements that don't match an existing one. We
3044 * just add them to the final list.
3046 ret = replmd_build_la_val(new_values,
3052 if (ret != LDB_SUCCESS) {
3053 talloc_free(tmp_ctx);
3056 ret = replmd_add_backlink(module, replmd_private,
3060 if (ret != LDB_SUCCESS) {
3061 talloc_free(tmp_ctx);
3064 new_values[i] = *new_p->v;
3068 if (old_el != NULL) {
3069 talloc_steal(msg->elements, old_el->values);
3071 el->values = talloc_steal(msg->elements, new_values);
3073 talloc_free(tmp_ctx);
3075 el->flags = LDB_FLAG_MOD_REPLACE;
3082 handle linked attributes in modify requests
3084 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3085 struct replmd_private *replmd_private,
3086 struct ldb_message *msg,
3087 uint64_t seq_num, time_t t,
3088 struct ldb_request *parent)
3090 struct ldb_result *res;
3093 struct ldb_context *ldb = ldb_module_get_ctx(module);
3094 struct ldb_message *old_msg;
3096 const struct dsdb_schema *schema;
3097 struct GUID old_guid;
3099 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3101 * Nothing special is required for modifying or vanishing links
3102 * in fl2000 since they are just strings in a multi-valued
3105 struct ldb_control *ctrl = ldb_request_get_control(parent,
3106 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3108 ctrl->critical = false;
3116 * We should restrict this to the intersection of the list of
3117 * linked attributes in the schema and the list of attributes
3120 * This will help performance a little, as otherwise we have
3121 * to allocate the entire object value-by-value.
3123 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3124 DSDB_FLAG_NEXT_MODULE |
3125 DSDB_SEARCH_SHOW_RECYCLED |
3126 DSDB_SEARCH_REVEAL_INTERNALS |
3127 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3129 if (ret != LDB_SUCCESS) {
3132 schema = dsdb_get_schema(ldb, res);
3134 return LDB_ERR_OPERATIONS_ERROR;
3137 old_msg = res->msgs[0];
3139 old_guid = samdb_result_guid(old_msg, "objectGUID");
3141 for (i=0; i<msg->num_elements; i++) {
3142 struct ldb_message_element *el = &msg->elements[i];
3143 struct ldb_message_element *old_el, *new_el;
3144 const struct dsdb_attribute *schema_attr
3145 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3147 ldb_asprintf_errstring(ldb,
3148 "%s: attribute %s is not a valid attribute in schema",
3149 __FUNCTION__, el->name);
3150 return LDB_ERR_OBJECT_CLASS_VIOLATION;
3152 if (schema_attr->linkID == 0) {
3155 if ((schema_attr->linkID & 1) == 1) {
3156 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
3159 /* Odd is for the target. Illegal to modify */
3160 ldb_asprintf_errstring(ldb,
3161 "attribute %s must not be modified directly, it is a linked attribute", el->name);
3162 return LDB_ERR_UNWILLING_TO_PERFORM;
3164 old_el = ldb_msg_find_element(old_msg, el->name);
3165 switch (el->flags & LDB_FLAG_MOD_MASK) {
3166 case LDB_FLAG_MOD_REPLACE:
3167 ret = replmd_modify_la_replace(module, replmd_private,
3168 schema, msg, el, old_el,
3169 schema_attr, seq_num, t,
3172 case LDB_FLAG_MOD_DELETE:
3173 ret = replmd_modify_la_delete(module, replmd_private,
3174 schema, msg, el, old_el,
3175 schema_attr, seq_num, t,
3178 case LDB_FLAG_MOD_ADD:
3179 ret = replmd_modify_la_add(module, replmd_private,
3180 schema, msg, el, old_el,
3181 schema_attr, seq_num, t,
3185 ldb_asprintf_errstring(ldb,
3186 "invalid flags 0x%x for %s linked attribute",
3187 el->flags, el->name);
3188 return LDB_ERR_UNWILLING_TO_PERFORM;
3190 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3191 ldb_asprintf_errstring(ldb,
3192 "Attribute %s is single valued but more than one value has been supplied",
3194 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3196 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3201 if (ret != LDB_SUCCESS) {
3205 ldb_msg_remove_attr(old_msg, el->name);
3207 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3208 new_el->num_values = el->num_values;
3209 new_el->values = talloc_steal(msg->elements, el->values);
3211 /* TODO: this relises a bit too heavily on the exact
3212 behaviour of ldb_msg_find_element and
3213 ldb_msg_remove_element */
3214 old_el = ldb_msg_find_element(msg, el->name);
3216 ldb_msg_remove_element(msg, old_el);
3227 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3229 struct ldb_context *ldb;
3230 struct replmd_replicated_request *ac;
3231 struct ldb_request *down_req;
3232 struct ldb_message *msg;
3233 time_t t = time(NULL);
3235 bool is_urgent = false, rodc = false;
3236 bool is_schema_nc = false;
3237 unsigned int functional_level;
3238 const struct ldb_message_element *guid_el = NULL;
3239 struct ldb_control *sd_propagation_control;
3240 struct replmd_private *replmd_private =
3241 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3243 /* do not manipulate our control entries */
3244 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3245 return ldb_next_request(module, req);
3248 sd_propagation_control = ldb_request_get_control(req,
3249 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3250 if (sd_propagation_control != NULL) {
3251 if (req->op.mod.message->num_elements != 1) {
3252 return ldb_module_operr(module);
3254 ret = strcmp(req->op.mod.message->elements[0].name,
3255 "nTSecurityDescriptor");
3257 return ldb_module_operr(module);
3260 return ldb_next_request(module, req);
3263 ldb = ldb_module_get_ctx(module);
3265 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3267 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3268 if (guid_el != NULL) {
3269 ldb_set_errstring(ldb,
3270 "replmd_modify: it's not allowed to change the objectGUID!");
3271 return LDB_ERR_CONSTRAINT_VIOLATION;
3274 ac = replmd_ctx_init(module, req);
3276 return ldb_module_oom(module);
3279 functional_level = dsdb_functional_level(ldb);
3281 /* we have to copy the message as the caller might have it as a const */
3282 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3286 return LDB_ERR_OPERATIONS_ERROR;
3289 ldb_msg_remove_attr(msg, "whenChanged");
3290 ldb_msg_remove_attr(msg, "uSNChanged");
3292 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3294 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3295 msg, &ac->seq_num, t, is_schema_nc,
3297 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3298 struct loadparm_context *lp_ctx;
3301 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3302 struct loadparm_context);
3304 referral = talloc_asprintf(req,
3306 lpcfg_dnsdomain(lp_ctx),
3307 ldb_dn_get_linearized(msg->dn));
3308 ret = ldb_module_send_referral(req, referral);
3313 if (ret != LDB_SUCCESS) {
3318 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3319 msg, ac->seq_num, t, req);
3320 if (ret != LDB_SUCCESS) {
3326 * - replace the old object with the newly constructed one
3329 ac->is_urgent = is_urgent;
3331 ret = ldb_build_mod_req(&down_req, ldb, ac,
3334 ac, replmd_op_callback,
3336 LDB_REQ_SET_LOCATION(down_req);
3337 if (ret != LDB_SUCCESS) {
3342 /* current partition control is needed by "replmd_op_callback" */
3343 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3344 ret = ldb_request_add_control(down_req,
3345 DSDB_CONTROL_CURRENT_PARTITION_OID,
3347 if (ret != LDB_SUCCESS) {
3353 /* If we are in functional level 2000, then
3354 * replmd_modify_handle_linked_attribs will have done
3356 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3357 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3358 if (ret != LDB_SUCCESS) {
3364 talloc_steal(down_req, msg);
3366 /* we only change whenChanged and uSNChanged if the seq_num
3368 if (ac->seq_num != 0) {
3369 ret = add_time_element(msg, "whenChanged", t);
3370 if (ret != LDB_SUCCESS) {
3376 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3377 if (ret != LDB_SUCCESS) {
3384 /* go on with the call chain */
3385 return ldb_next_request(module, down_req);
3388 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3391 handle a rename request
3393 On a rename we need to do an extra ldb_modify which sets the
3394 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3396 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3398 struct ldb_context *ldb;
3399 struct replmd_replicated_request *ac;
3401 struct ldb_request *down_req;
3403 /* do not manipulate our control entries */
3404 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3405 return ldb_next_request(module, req);
3408 ldb = ldb_module_get_ctx(module);
3410 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3412 ac = replmd_ctx_init(module, req);
3414 return ldb_module_oom(module);
3417 ret = ldb_build_rename_req(&down_req, ldb, ac,
3418 ac->req->op.rename.olddn,
3419 ac->req->op.rename.newdn,
3421 ac, replmd_rename_callback,
3423 LDB_REQ_SET_LOCATION(down_req);
3424 if (ret != LDB_SUCCESS) {
3429 /* go on with the call chain */
3430 return ldb_next_request(module, down_req);
3433 /* After the rename is compleated, update the whenchanged etc */
3434 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3436 struct ldb_context *ldb;
3437 struct ldb_request *down_req;
3438 struct ldb_message *msg;
3439 const struct dsdb_attribute *rdn_attr;
3440 const char *rdn_name;
3441 const struct ldb_val *rdn_val;
3442 const char *attrs[5] = { NULL, };
3443 time_t t = time(NULL);
3445 bool is_urgent = false, rodc = false;
3447 struct replmd_replicated_request *ac =
3448 talloc_get_type(req->context, struct replmd_replicated_request);
3449 struct replmd_private *replmd_private =
3450 talloc_get_type(ldb_module_get_private(ac->module),
3451 struct replmd_private);
3453 ldb = ldb_module_get_ctx(ac->module);
3455 if (ares->error != LDB_SUCCESS) {
3456 return ldb_module_done(ac->req, ares->controls,
3457 ares->response, ares->error);
3460 if (ares->type != LDB_REPLY_DONE) {
3461 ldb_set_errstring(ldb,
3462 "invalid ldb_reply_type in callback");
3464 return ldb_module_done(ac->req, NULL, NULL,
3465 LDB_ERR_OPERATIONS_ERROR);
3469 * - replace the old object with the newly constructed one
3472 msg = ldb_msg_new(ac);
3475 return LDB_ERR_OPERATIONS_ERROR;
3478 msg->dn = ac->req->op.rename.newdn;
3480 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3482 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3483 if (rdn_name == NULL) {
3485 return ldb_module_done(ac->req, NULL, NULL,
3489 /* normalize the rdn attribute name */
3490 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3491 if (rdn_attr == NULL) {
3493 return ldb_module_done(ac->req, NULL, NULL,
3496 rdn_name = rdn_attr->lDAPDisplayName;
3498 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3499 if (rdn_val == NULL) {
3501 return ldb_module_done(ac->req, NULL, NULL,
3505 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3507 return ldb_module_done(ac->req, NULL, NULL,
3510 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3512 return ldb_module_done(ac->req, NULL, NULL,
3515 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3517 return ldb_module_done(ac->req, NULL, NULL,
3520 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3522 return ldb_module_done(ac->req, NULL, NULL,
3527 * here we let replmd_update_rpmd() only search for
3528 * the existing "replPropertyMetaData" and rdn_name attributes.
3530 * We do not want the existing "name" attribute as
3531 * the "name" attribute needs to get the version
3532 * updated on rename even if the rdn value hasn't changed.
3534 * This is the diff of the meta data, for a moved user
3535 * on a w2k8r2 server:
3538 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3539 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3540 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3541 * version : 0x00000001 (1)
3542 * reserved : 0x00000000 (0)
3543 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3544 * local_usn : 0x00000000000037a5 (14245)
3545 * array: struct replPropertyMetaData1
3546 * attid : DRSUAPI_ATTID_name (0x90001)
3547 * - version : 0x00000001 (1)
3548 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3549 * + version : 0x00000002 (2)
3550 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3551 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3552 * - originating_usn : 0x00000000000037a5 (14245)
3553 * - local_usn : 0x00000000000037a5 (14245)
3554 * + originating_usn : 0x0000000000003834 (14388)
3555 * + local_usn : 0x0000000000003834 (14388)
3556 * array: struct replPropertyMetaData1
3557 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3558 * version : 0x00000004 (4)
3560 attrs[0] = "replPropertyMetaData";
3561 attrs[1] = "objectClass";
3562 attrs[2] = "instanceType";
3563 attrs[3] = rdn_name;
3566 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3567 msg, &ac->seq_num, t,
3568 is_schema_nc, &is_urgent, &rodc);
3569 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3570 struct ldb_dn *olddn = ac->req->op.rename.olddn;
3571 struct loadparm_context *lp_ctx;
3574 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3575 struct loadparm_context);
3577 referral = talloc_asprintf(req,
3579 lpcfg_dnsdomain(lp_ctx),
3580 ldb_dn_get_linearized(olddn));
3581 ret = ldb_module_send_referral(req, referral);
3583 return ldb_module_done(req, NULL, NULL, ret);
3586 if (ret != LDB_SUCCESS) {
3588 return ldb_module_done(ac->req, NULL, NULL, ret);
3591 if (ac->seq_num == 0) {
3593 return ldb_module_done(ac->req, NULL, NULL,
3595 "internal error seq_num == 0"));
3597 ac->is_urgent = is_urgent;
3599 ret = ldb_build_mod_req(&down_req, ldb, ac,
3602 ac, replmd_op_callback,
3604 LDB_REQ_SET_LOCATION(down_req);
3605 if (ret != LDB_SUCCESS) {
3610 /* current partition control is needed by "replmd_op_callback" */
3611 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3612 ret = ldb_request_add_control(down_req,
3613 DSDB_CONTROL_CURRENT_PARTITION_OID,
3615 if (ret != LDB_SUCCESS) {
3621 talloc_steal(down_req, msg);
3623 ret = add_time_element(msg, "whenChanged", t);
3624 if (ret != LDB_SUCCESS) {
3630 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3631 if (ret != LDB_SUCCESS) {
3637 /* go on with the call chain - do the modify after the rename */
3638 return ldb_next_request(ac->module, down_req);
3642 * remove links from objects that point at this object when an object
3643 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3644 * RemoveObj which states that link removal due to the object being
3645 * deleted is NOT an originating update - they just go away!
3648 static int replmd_delete_remove_link(struct ldb_module *module,
3649 const struct dsdb_schema *schema,
3651 struct ldb_message_element *el,
3652 const struct dsdb_attribute *sa,
3653 struct ldb_request *parent)
3656 TALLOC_CTX *tmp_ctx = talloc_new(module);
3657 struct ldb_context *ldb = ldb_module_get_ctx(module);
3659 for (i=0; i<el->num_values; i++) {
3660 struct dsdb_dn *dsdb_dn;
3664 struct ldb_message *msg;
3665 const struct dsdb_attribute *target_attr;
3666 struct ldb_message_element *el2;
3667 struct ldb_val dn_val;
3668 uint32_t dsdb_flags = 0;
3670 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3674 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3676 talloc_free(tmp_ctx);
3677 return LDB_ERR_OPERATIONS_ERROR;
3680 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
3681 if (!NT_STATUS_IS_OK(status)) {
3682 talloc_free(tmp_ctx);
3683 return LDB_ERR_OPERATIONS_ERROR;
3686 /* remove the link */
3687 msg = ldb_msg_new(tmp_ctx);
3689 ldb_module_oom(module);
3690 talloc_free(tmp_ctx);
3691 return LDB_ERR_OPERATIONS_ERROR;
3695 msg->dn = dsdb_dn->dn;
3697 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3698 if (target_attr == NULL) {
3702 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
3703 if (ret != LDB_SUCCESS) {
3704 ldb_module_oom(module);
3705 talloc_free(tmp_ctx);
3706 return LDB_ERR_OPERATIONS_ERROR;
3708 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
3709 el2->values = &dn_val;
3710 el2->num_values = 1;
3713 * Ensure that we tell the modification to vanish any linked
3714 * attributes (not simply mark them as isDeleted = TRUE)
3716 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3718 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3719 if (ret != LDB_SUCCESS) {
3720 talloc_free(tmp_ctx);
3724 talloc_free(tmp_ctx);
3730 handle update of replication meta data for deletion of objects
3732 This also handles the mapping of delete to a rename operation
3733 to allow deletes to be replicated.
3735 It also handles the incoming deleted objects, to ensure they are
3736 fully deleted here. In that case re_delete is true, and we do not
3737 use this as a signal to change the deleted state, just reinforce it.
3740 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3742 int ret = LDB_ERR_OTHER;
3743 bool retb, disallow_move_on_delete;
3744 struct ldb_dn *old_dn, *new_dn;
3745 const char *rdn_name;
3746 const struct ldb_val *rdn_value, *new_rdn_value;
3748 struct ldb_context *ldb = ldb_module_get_ctx(module);
3749 const struct dsdb_schema *schema;
3750 struct ldb_message *msg, *old_msg;
3751 struct ldb_message_element *el;
3752 TALLOC_CTX *tmp_ctx;
3753 struct ldb_result *res, *parent_res;
3754 static const char * const preserved_attrs[] = {
3755 /* yes, this really is a hard coded list. See MS-ADTS
3756 section 3.1.1.5.5.1.1 */
3759 "dNReferenceUpdate",
3770 "msDS-LastKnownRDN",
3776 "distinguishedName",
3780 "proxiedObjectName",
3782 "nTSecurityDescriptor",
3783 "replPropertyMetaData",
3785 "securityIdentifier",
3793 "userAccountControl",
3800 static const char * const all_attrs[] = {
3801 DSDB_SECRET_ATTRIBUTES,
3805 unsigned int i, el_count = 0;
3806 uint32_t dsdb_flags = 0;
3807 enum deletion_state deletion_state, next_deletion_state;
3809 if (ldb_dn_is_special(req->op.del.dn)) {
3810 return ldb_next_request(module, req);
3814 * We have to allow dbcheck to remove an object that
3815 * is beyond repair, and to do so totally. This could
3816 * mean we we can get a partial object from the other
3817 * DC, causing havoc, so dbcheck suggests
3818 * re-replication first. dbcheck sets both DBCHECK
3819 * and RELAX in this situation.
3821 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3822 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3823 /* really, really remove it */
3824 return ldb_next_request(module, req);
3827 tmp_ctx = talloc_new(ldb);
3830 return LDB_ERR_OPERATIONS_ERROR;
3833 schema = dsdb_get_schema(ldb, tmp_ctx);
3835 talloc_free(tmp_ctx);
3836 return LDB_ERR_OPERATIONS_ERROR;
3839 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3841 /* we need the complete msg off disk, so we can work out which
3842 attributes need to be removed */
3843 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3844 DSDB_FLAG_NEXT_MODULE |
3845 DSDB_SEARCH_SHOW_RECYCLED |
3846 DSDB_SEARCH_REVEAL_INTERNALS |
3847 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3848 if (ret != LDB_SUCCESS) {
3849 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3850 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3851 re_delete ? "re-delete" : "delete",
3852 ldb_dn_get_linearized(old_dn),
3853 ldb_errstring(ldb_module_get_ctx(module)));
3854 talloc_free(tmp_ctx);
3857 old_msg = res->msgs[0];
3859 replmd_deletion_state(module, old_msg,
3861 &next_deletion_state);
3863 /* This supports us noticing an incoming isDeleted and acting on it */
3865 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3866 next_deletion_state = deletion_state;
3869 if (next_deletion_state == OBJECT_REMOVED) {
3871 * We have to prevent objects being deleted, even if
3872 * the administrator really wants them gone, as
3873 * without the tombstone, we can get a partial object
3874 * from the other DC, causing havoc.
3876 * The only other valid case is when the 180 day
3877 * timeout has expired, when relax is specified.
3879 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3880 /* it is already deleted - really remove it this time */
3881 talloc_free(tmp_ctx);
3882 return ldb_next_request(module, req);
3885 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3886 "This check is to prevent corruption of the replicated state.",
3887 ldb_dn_get_linearized(old_msg->dn));
3888 return LDB_ERR_UNWILLING_TO_PERFORM;
3891 rdn_name = ldb_dn_get_rdn_name(old_dn);
3892 rdn_value = ldb_dn_get_rdn_val(old_dn);
3893 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3894 talloc_free(tmp_ctx);
3895 return ldb_operr(ldb);
3898 msg = ldb_msg_new(tmp_ctx);
3900 ldb_module_oom(module);
3901 talloc_free(tmp_ctx);
3902 return LDB_ERR_OPERATIONS_ERROR;
3907 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3908 disallow_move_on_delete =
3909 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3910 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3912 /* work out where we will be renaming this object to */
3913 if (!disallow_move_on_delete) {
3914 struct ldb_dn *deleted_objects_dn;
3915 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3916 &deleted_objects_dn);
3919 * We should not move objects if we can't find the
3920 * deleted objects DN. Not moving (or otherwise
3921 * harming) the Deleted Objects DN itself is handled
3924 if (re_delete && (ret != LDB_SUCCESS)) {
3925 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3926 if (new_dn == NULL) {
3927 ldb_module_oom(module);
3928 talloc_free(tmp_ctx);
3929 return LDB_ERR_OPERATIONS_ERROR;
3931 } else if (ret != LDB_SUCCESS) {
3932 /* this is probably an attempted delete on a partition
3933 * that doesn't allow delete operations, such as the
3934 * schema partition */
3935 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3936 ldb_dn_get_linearized(old_dn));
3937 talloc_free(tmp_ctx);
3938 return LDB_ERR_UNWILLING_TO_PERFORM;
3940 new_dn = deleted_objects_dn;
3943 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3944 if (new_dn == NULL) {
3945 ldb_module_oom(module);
3946 talloc_free(tmp_ctx);
3947 return LDB_ERR_OPERATIONS_ERROR;
3951 if (deletion_state == OBJECT_NOT_DELETED) {
3952 /* get the objects GUID from the search we just did */
3953 guid = samdb_result_guid(old_msg, "objectGUID");
3955 /* Add a formatted child */
3956 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3958 ldb_dn_escape_value(tmp_ctx, *rdn_value),
3959 GUID_string(tmp_ctx, &guid));
3961 ldb_asprintf_errstring(ldb, __location__
3962 ": Unable to add a formatted child to dn: %s",
3963 ldb_dn_get_linearized(new_dn));
3964 talloc_free(tmp_ctx);
3965 return LDB_ERR_OPERATIONS_ERROR;
3968 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
3969 if (ret != LDB_SUCCESS) {
3970 ldb_asprintf_errstring(ldb, __location__
3971 ": Failed to add isDeleted string to the msg");
3972 talloc_free(tmp_ctx);
3975 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3978 * No matter what has happened with other renames etc, try again to
3979 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
3982 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
3983 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
3985 ldb_asprintf_errstring(ldb, __location__
3986 ": Unable to add a prepare rdn of %s",
3987 ldb_dn_get_linearized(rdn));
3988 talloc_free(tmp_ctx);
3989 return LDB_ERR_OPERATIONS_ERROR;
3991 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
3993 retb = ldb_dn_add_child(new_dn, rdn);
3995 ldb_asprintf_errstring(ldb, __location__
3996 ": Unable to add rdn %s to base dn: %s",
3997 ldb_dn_get_linearized(rdn),
3998 ldb_dn_get_linearized(new_dn));
3999 talloc_free(tmp_ctx);
4000 return LDB_ERR_OPERATIONS_ERROR;
4005 now we need to modify the object in the following ways:
4007 - add isDeleted=TRUE
4008 - update rDN and name, with new rDN
4009 - remove linked attributes
4010 - remove objectCategory and sAMAccountType
4011 - remove attribs not on the preserved list
4012 - preserved if in above list, or is rDN
4013 - remove all linked attribs from this object
4014 - remove all links from other objects to this object
4015 - add lastKnownParent
4016 - update replPropertyMetaData?
4018 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4021 if (deletion_state == OBJECT_NOT_DELETED) {
4022 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4023 char *parent_dn_str = NULL;
4025 /* we need the storage form of the parent GUID */
4026 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
4028 DSDB_FLAG_NEXT_MODULE |
4029 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4030 DSDB_SEARCH_REVEAL_INTERNALS|
4031 DSDB_SEARCH_SHOW_RECYCLED, req);
4032 if (ret != LDB_SUCCESS) {
4033 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4034 "repmd_delete: Failed to %s %s, "
4035 "because we failed to find it's parent (%s): %s",
4036 re_delete ? "re-delete" : "delete",
4037 ldb_dn_get_linearized(old_dn),
4038 ldb_dn_get_linearized(parent_dn),
4039 ldb_errstring(ldb_module_get_ctx(module)));
4040 talloc_free(tmp_ctx);
4045 * Now we can use the DB version,
4046 * it will have the extended DN info in it
4048 parent_dn = parent_res->msgs[0]->dn;
4049 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4052 if (parent_dn_str == NULL) {
4053 talloc_free(tmp_ctx);
4054 return ldb_module_oom(module);
4057 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4059 if (ret != LDB_SUCCESS) {
4060 ldb_asprintf_errstring(ldb, __location__
4061 ": Failed to add lastKnownParent "
4062 "string when deleting %s",
4063 ldb_dn_get_linearized(old_dn));
4064 talloc_free(tmp_ctx);
4067 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4069 if (next_deletion_state == OBJECT_DELETED) {
4070 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4071 if (ret != LDB_SUCCESS) {
4072 ldb_asprintf_errstring(ldb, __location__
4073 ": Failed to add msDS-LastKnownRDN "
4074 "string when deleting %s",
4075 ldb_dn_get_linearized(old_dn));
4076 talloc_free(tmp_ctx);
4079 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
4083 switch (next_deletion_state) {
4085 case OBJECT_RECYCLED:
4086 case OBJECT_TOMBSTONE:
4089 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4090 * describes what must be removed from a tombstone
4093 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4094 * describes what must be removed from a recycled
4100 * we also mark it as recycled, meaning this object can't be
4101 * recovered (we are stripping its attributes).
4102 * This is done only if we have this schema object of course ...
4103 * This behavior is identical to the one of Windows 2008R2 which
4104 * always set the isRecycled attribute, even if the recycle-bin is
4105 * not activated and what ever the forest level is.
4107 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4108 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
4109 if (ret != LDB_SUCCESS) {
4110 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4111 ldb_module_oom(module);
4112 talloc_free(tmp_ctx);
4115 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4118 /* work out which of the old attributes we will be removing */
4119 for (i=0; i<old_msg->num_elements; i++) {
4120 const struct dsdb_attribute *sa;
4121 el = &old_msg->elements[i];
4122 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4124 talloc_free(tmp_ctx);
4125 return LDB_ERR_OPERATIONS_ERROR;
4127 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4128 /* don't remove the rDN */
4131 if (sa->linkID && (sa->linkID & 1)) {
4133 we have a backlink in this object
4134 that needs to be removed. We're not
4135 allowed to remove it directly
4136 however, so we instead setup a
4137 modify to delete the corresponding
4140 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
4141 if (ret != LDB_SUCCESS) {
4142 const char *old_dn_str
4143 = ldb_dn_get_linearized(old_dn);
4144 ldb_asprintf_errstring(ldb,
4146 ": Failed to remove backlink of "
4147 "%s when deleting %s: %s",
4150 ldb_errstring(ldb));
4151 talloc_free(tmp_ctx);
4152 return LDB_ERR_OPERATIONS_ERROR;
4154 /* now we continue, which means we
4155 won't remove this backlink
4161 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4164 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4169 * Ensure that we tell the modification to vanish any linked
4170 * attributes (not simply mark them as isDeleted = TRUE)
4172 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4174 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4175 if (ret != LDB_SUCCESS) {
4176 talloc_free(tmp_ctx);
4177 ldb_module_oom(module);
4184 case OBJECT_DELETED:
4186 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4187 * describes what must be removed from a deleted
4191 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4192 if (ret != LDB_SUCCESS) {
4193 talloc_free(tmp_ctx);
4194 ldb_module_oom(module);
4198 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4199 if (ret != LDB_SUCCESS) {
4200 talloc_free(tmp_ctx);
4201 ldb_module_oom(module);
4211 if (deletion_state == OBJECT_NOT_DELETED) {
4212 const struct dsdb_attribute *sa;
4214 /* work out what the new rdn value is, for updating the
4215 rDN and name fields */
4216 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4217 if (new_rdn_value == NULL) {
4218 talloc_free(tmp_ctx);
4219 return ldb_operr(ldb);
4222 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4224 talloc_free(tmp_ctx);
4225 return LDB_ERR_OPERATIONS_ERROR;
4228 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4230 if (ret != LDB_SUCCESS) {
4231 talloc_free(tmp_ctx);
4234 el->flags = LDB_FLAG_MOD_REPLACE;
4236 el = ldb_msg_find_element(old_msg, "name");
4238 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4239 if (ret != LDB_SUCCESS) {
4240 talloc_free(tmp_ctx);
4243 el->flags = LDB_FLAG_MOD_REPLACE;
4248 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4253 * No matter what has happned with other renames, try again to
4254 * get this to be under the deleted DN.
4256 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4257 /* now rename onto the new DN */
4258 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4259 if (ret != LDB_SUCCESS){
4260 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4261 ldb_dn_get_linearized(old_dn),
4262 ldb_dn_get_linearized(new_dn),
4263 ldb_errstring(ldb)));
4264 talloc_free(tmp_ctx);
4270 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4271 if (ret != LDB_SUCCESS) {
4272 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4273 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4274 talloc_free(tmp_ctx);
4278 talloc_free(tmp_ctx);
4280 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4283 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4285 return replmd_delete_internals(module, req, false);
4289 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4294 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4296 int ret = LDB_ERR_OTHER;
4297 /* TODO: do some error mapping */
4299 /* Let the caller know the full WERROR */
4300 ar->objs->error = status;
4306 static struct replPropertyMetaData1 *
4307 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4308 enum drsuapi_DsAttributeId attid)
4311 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4313 for (i = 0; i < rpmd_ctr->count; i++) {
4314 if (rpmd_ctr->array[i].attid == attid) {
4315 return &rpmd_ctr->array[i];
4323 return true if an update is newer than an existing entry
4324 see section 5.11 of MS-ADTS
4326 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4327 const struct GUID *update_invocation_id,
4328 uint32_t current_version,
4329 uint32_t update_version,
4330 NTTIME current_change_time,
4331 NTTIME update_change_time)
4333 if (update_version != current_version) {
4334 return update_version > current_version;
4336 if (update_change_time != current_change_time) {
4337 return update_change_time > current_change_time;
4339 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4342 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4343 struct replPropertyMetaData1 *new_m)
4345 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4346 &new_m->originating_invocation_id,
4349 cur_m->originating_change_time,
4350 new_m->originating_change_time);
4353 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4354 struct replPropertyMetaData1 *cur_m,
4355 struct replPropertyMetaData1 *new_m)
4360 * If the new replPropertyMetaData entry for this attribute is
4361 * not provided (this happens in the case where we look for
4362 * ATTID_name, but the name was not changed), then the local
4363 * state is clearly still current, as the remote
4364 * server didn't send it due to being older the high watermark
4367 if (new_m == NULL) {
4371 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4373 * if we compare equal then do an
4374 * update. This is used when a client
4375 * asks for a FULL_SYNC, and can be
4376 * used to recover a corrupt
4379 * This call is a bit tricky, what we
4380 * are doing it turning the 'is_newer'
4381 * call into a 'not is older' by
4382 * swapping cur_m and new_m, and negating the
4385 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4388 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4398 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4400 const struct ldb_val *rdn_val;
4401 const char *rdn_name;
4402 struct ldb_dn *new_dn;
4404 rdn_val = ldb_dn_get_rdn_val(dn);
4405 rdn_name = ldb_dn_get_rdn_name(dn);
4406 if (!rdn_val || !rdn_name) {
4410 new_dn = ldb_dn_copy(mem_ctx, dn);
4415 if (!ldb_dn_remove_child_components(new_dn, 1)) {
4419 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4421 ldb_dn_escape_value(new_dn, *rdn_val),
4422 GUID_string(new_dn, guid))) {
4431 perform a modify operation which sets the rDN and name attributes to
4432 their current values. This has the effect of changing these
4433 attributes to have been last updated by the current DC. This is
4434 needed to ensure that renames performed as part of conflict
4435 resolution are propogated to other DCs
4437 static int replmd_name_modify(struct replmd_replicated_request *ar,
4438 struct ldb_request *req, struct ldb_dn *dn)
4440 struct ldb_message *msg;
4441 const char *rdn_name;
4442 const struct ldb_val *rdn_val;
4443 const struct dsdb_attribute *rdn_attr;
4446 msg = ldb_msg_new(req);
4452 rdn_name = ldb_dn_get_rdn_name(dn);
4453 if (rdn_name == NULL) {
4457 /* normalize the rdn attribute name */
4458 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4459 if (rdn_attr == NULL) {
4462 rdn_name = rdn_attr->lDAPDisplayName;
4464 rdn_val = ldb_dn_get_rdn_val(dn);
4465 if (rdn_val == NULL) {
4469 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4472 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4475 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4478 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4482 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4483 if (ret != LDB_SUCCESS) {
4484 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
4485 ldb_dn_get_linearized(dn),
4486 ldb_errstring(ldb_module_get_ctx(ar->module))));
4496 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
4497 ldb_dn_get_linearized(dn)));
4498 return LDB_ERR_OPERATIONS_ERROR;
4503 callback for conflict DN handling where we have renamed the incoming
4504 record. After renaming it, we need to ensure the change of name and
4505 rDN for the incoming record is seen as an originating update by this DC.
4507 This also handles updating lastKnownParent for entries sent to lostAndFound
4509 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4511 struct replmd_replicated_request *ar =
4512 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4513 struct ldb_dn *conflict_dn = NULL;
4516 if (ares->error != LDB_SUCCESS) {
4517 /* call the normal callback for everything except success */
4518 return replmd_op_callback(req, ares);
4521 switch (req->operation) {
4523 conflict_dn = req->op.add.message->dn;
4526 conflict_dn = req->op.mod.message->dn;
4529 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4532 /* perform a modify of the rDN and name of the record */
4533 ret = replmd_name_modify(ar, req, conflict_dn);
4534 if (ret != LDB_SUCCESS) {
4536 return replmd_op_callback(req, ares);
4539 if (ar->objs->objects[ar->index_current].last_known_parent) {
4540 struct ldb_message *msg = ldb_msg_new(req);
4542 ldb_module_oom(ar->module);
4543 return LDB_ERR_OPERATIONS_ERROR;
4546 msg->dn = req->op.add.message->dn;
4548 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4549 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4550 if (ret != LDB_SUCCESS) {
4551 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4552 ldb_module_oom(ar->module);
4555 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4557 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4558 if (ret != LDB_SUCCESS) {
4559 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4560 ldb_dn_get_linearized(msg->dn),
4561 ldb_errstring(ldb_module_get_ctx(ar->module))));
4567 return replmd_op_callback(req, ares);
4571 callback for replmd_replicated_apply_add()
4572 This copes with the creation of conflict records in the case where
4573 the DN exists, but with a different objectGUID
4575 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))
4577 struct ldb_dn *conflict_dn;
4578 struct replmd_replicated_request *ar =
4579 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4580 struct ldb_result *res;
4581 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4583 const struct ldb_val *omd_value;
4584 struct replPropertyMetaDataBlob omd, *rmd;
4585 enum ndr_err_code ndr_err;
4586 bool rename_incoming_record, rodc;
4587 struct replPropertyMetaData1 *rmd_name, *omd_name;
4588 struct ldb_message *msg;
4589 struct ldb_request *down_req = NULL;
4591 /* call the normal callback for success */
4592 if (ares->error == LDB_SUCCESS) {
4593 return callback(req, ares);
4597 * we have a conflict, and need to decide if we will keep the
4598 * new record or the old record
4601 msg = ar->objs->objects[ar->index_current].msg;
4602 conflict_dn = msg->dn;
4604 /* For failures other than conflicts, fail the whole operation here */
4605 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4606 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4607 ldb_dn_get_linearized(conflict_dn),
4608 ldb_errstring(ldb_module_get_ctx(ar->module)));
4610 return ldb_module_done(ar->req, NULL, NULL,
4611 LDB_ERR_OPERATIONS_ERROR);
4614 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4615 if (ret != LDB_SUCCESS) {
4616 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)));
4617 return ldb_module_done(ar->req, NULL, NULL,
4618 LDB_ERR_OPERATIONS_ERROR);
4624 * We are on an RODC, or were a GC for this
4625 * partition, so we have to fail this until
4626 * someone who owns the partition sorts it
4629 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4630 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
4631 " - We must fail the operation until a master for this partition resolves the conflict",
4632 ldb_dn_get_linearized(conflict_dn));
4637 * first we need the replPropertyMetaData attribute from the
4638 * local, conflicting record
4640 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4642 DSDB_FLAG_NEXT_MODULE |
4643 DSDB_SEARCH_SHOW_DELETED |
4644 DSDB_SEARCH_SHOW_RECYCLED, req);
4645 if (ret != LDB_SUCCESS) {
4646 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4647 ldb_dn_get_linearized(conflict_dn)));
4651 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4652 if (omd_value == NULL) {
4653 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4654 ldb_dn_get_linearized(conflict_dn)));
4658 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4659 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4660 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4661 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4662 ldb_dn_get_linearized(conflict_dn)));
4666 rmd = ar->objs->objects[ar->index_current].meta_data;
4669 * we decide which is newer based on the RPMD on the name
4670 * attribute. See [MS-DRSR] ResolveNameConflict.
4672 * We expect omd_name to be present, as this is from a local
4673 * search, but while rmd_name should have been given to us by
4674 * the remote server, if it is missing we just prefer the
4676 * replmd_replPropertyMetaData1_new_should_be_taken()
4678 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4679 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4681 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4682 ldb_dn_get_linearized(conflict_dn)));
4687 * Should we preserve the current record, and so rename the
4688 * incoming record to be a conflict?
4690 rename_incoming_record
4691 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4692 omd_name, rmd_name);
4694 if (rename_incoming_record) {
4696 struct ldb_dn *new_dn;
4698 guid = samdb_result_guid(msg, "objectGUID");
4699 if (GUID_all_zero(&guid)) {
4700 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4701 ldb_dn_get_linearized(conflict_dn)));
4704 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4705 if (new_dn == NULL) {
4706 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4707 ldb_dn_get_linearized(conflict_dn)));
4711 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4712 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4714 /* re-submit the request, but with the new DN */
4715 callback = replmd_op_name_modify_callback;
4718 /* we are renaming the existing record */
4720 struct ldb_dn *new_dn;
4722 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4723 if (GUID_all_zero(&guid)) {
4724 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4725 ldb_dn_get_linearized(conflict_dn)));
4729 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4730 if (new_dn == NULL) {
4731 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4732 ldb_dn_get_linearized(conflict_dn)));
4736 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4737 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4739 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4740 DSDB_FLAG_OWN_MODULE, req);
4741 if (ret != LDB_SUCCESS) {
4742 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4743 ldb_dn_get_linearized(conflict_dn),
4744 ldb_dn_get_linearized(new_dn),
4745 ldb_errstring(ldb_module_get_ctx(ar->module))));
4750 * now we need to ensure that the rename is seen as an
4751 * originating update. We do that with a modify.
4753 ret = replmd_name_modify(ar, req, new_dn);
4754 if (ret != LDB_SUCCESS) {
4758 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4759 ldb_dn_get_linearized(req->op.add.message->dn)));
4762 ret = ldb_build_add_req(&down_req,
4763 ldb_module_get_ctx(ar->module),
4770 if (ret != LDB_SUCCESS) {
4773 LDB_REQ_SET_LOCATION(down_req);
4775 /* current partition control needed by "repmd_op_callback" */
4776 ret = ldb_request_add_control(down_req,
4777 DSDB_CONTROL_CURRENT_PARTITION_OID,
4779 if (ret != LDB_SUCCESS) {
4780 return replmd_replicated_request_error(ar, ret);
4783 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4784 /* this tells the partition module to make it a
4785 partial replica if creating an NC */
4786 ret = ldb_request_add_control(down_req,
4787 DSDB_CONTROL_PARTIAL_REPLICA,
4789 if (ret != LDB_SUCCESS) {
4790 return replmd_replicated_request_error(ar, ret);
4795 * Finally we re-run the add, otherwise the new record won't
4796 * exist, as we are here because of that exact failure!
4798 return ldb_next_request(ar->module, down_req);
4801 /* on failure make the caller get the error. This means
4802 * replication will stop with an error, but there is not much
4805 return ldb_module_done(ar->req, NULL, NULL,
4810 callback for replmd_replicated_apply_add()
4811 This copes with the creation of conflict records in the case where
4812 the DN exists, but with a different objectGUID
4814 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4816 struct replmd_replicated_request *ar =
4817 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4819 if (ar->objs->objects[ar->index_current].last_known_parent) {
4820 /* This is like a conflict DN, where we put the object in LostAndFound
4821 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4822 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4825 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4829 this is called when a new object comes in over DRS
4831 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4833 struct ldb_context *ldb;
4834 struct ldb_request *change_req;
4835 enum ndr_err_code ndr_err;
4836 struct ldb_message *msg;
4837 struct replPropertyMetaDataBlob *md;
4838 struct ldb_val md_value;
4841 bool remote_isDeleted = false;
4844 time_t t = time(NULL);
4845 const struct ldb_val *rdn_val;
4846 struct replmd_private *replmd_private =
4847 talloc_get_type(ldb_module_get_private(ar->module),
4848 struct replmd_private);
4849 unix_to_nt_time(&now, t);
4851 ldb = ldb_module_get_ctx(ar->module);
4852 msg = ar->objs->objects[ar->index_current].msg;
4853 md = ar->objs->objects[ar->index_current].meta_data;
4854 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4856 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4857 if (ret != LDB_SUCCESS) {
4858 return replmd_replicated_request_error(ar, ret);
4861 ret = dsdb_msg_add_guid(msg,
4862 &ar->objs->objects[ar->index_current].object_guid,
4864 if (ret != LDB_SUCCESS) {
4865 return replmd_replicated_request_error(ar, ret);
4868 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4869 if (ret != LDB_SUCCESS) {
4870 return replmd_replicated_request_error(ar, ret);
4873 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4874 if (ret != LDB_SUCCESS) {
4875 return replmd_replicated_request_error(ar, ret);
4878 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4879 if (ret != LDB_SUCCESS) {
4880 return replmd_replicated_request_error(ar, ret);
4883 /* remove any message elements that have zero values */
4884 for (i=0; i<msg->num_elements; i++) {
4885 struct ldb_message_element *el = &msg->elements[i];
4887 if (el->num_values == 0) {
4888 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4889 ldb_asprintf_errstring(ldb, __location__
4890 ": empty objectClass sent on %s, aborting replication\n",
4891 ldb_dn_get_linearized(msg->dn));
4892 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4895 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4897 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4898 msg->num_elements--;
4905 struct GUID_txt_buf guid_txt;
4907 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4908 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4909 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4914 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4915 "isDeleted", false);
4918 * the meta data array is already sorted by the caller, except
4919 * for the RDN, which needs to be added.
4923 rdn_val = ldb_dn_get_rdn_val(msg->dn);
4924 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4925 md, ar, now, is_schema_nc);
4926 if (ret != LDB_SUCCESS) {
4927 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4928 return replmd_replicated_request_error(ar, ret);
4931 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4932 if (ret != LDB_SUCCESS) {
4933 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4934 return replmd_replicated_request_error(ar, ret);
4937 for (i=0; i < md->ctr.ctr1.count; i++) {
4938 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4940 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4941 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4942 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4943 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4944 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4946 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4947 if (ret != LDB_SUCCESS) {
4948 return replmd_replicated_request_error(ar, ret);
4951 replmd_ldb_message_sort(msg, ar->schema);
4953 if (!remote_isDeleted) {
4954 ret = dsdb_module_schedule_sd_propagation(ar->module,
4955 ar->objs->partition_dn,
4957 if (ret != LDB_SUCCESS) {
4958 return replmd_replicated_request_error(ar, ret);
4962 ar->isDeleted = remote_isDeleted;
4964 ret = ldb_build_add_req(&change_req,
4970 replmd_op_add_callback,
4972 LDB_REQ_SET_LOCATION(change_req);
4973 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4975 /* current partition control needed by "repmd_op_callback" */
4976 ret = ldb_request_add_control(change_req,
4977 DSDB_CONTROL_CURRENT_PARTITION_OID,
4979 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4981 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4982 /* this tells the partition module to make it a
4983 partial replica if creating an NC */
4984 ret = ldb_request_add_control(change_req,
4985 DSDB_CONTROL_PARTIAL_REPLICA,
4987 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4990 return ldb_next_request(ar->module, change_req);
4993 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
4994 struct ldb_reply *ares)
4996 struct replmd_replicated_request *ar = talloc_get_type(req->context,
4997 struct replmd_replicated_request);
5001 return ldb_module_done(ar->req, NULL, NULL,
5002 LDB_ERR_OPERATIONS_ERROR);
5006 * The error NO_SUCH_OBJECT is not expected, unless the search
5007 * base is the partition DN, and that case doesn't happen here
5008 * because then we wouldn't get a parent_guid_value in any
5011 if (ares->error != LDB_SUCCESS) {
5012 return ldb_module_done(ar->req, ares->controls,
5013 ares->response, ares->error);
5016 switch (ares->type) {
5017 case LDB_REPLY_ENTRY:
5019 struct ldb_message *parent_msg = ares->message;
5020 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5021 struct ldb_dn *parent_dn;
5024 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
5025 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
5026 /* Per MS-DRSR 4.1.10.6.10
5027 * FindBestParentObject we need to move this
5028 * new object under a deleted object to
5030 struct ldb_dn *nc_root;
5032 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
5033 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
5034 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5035 "No suitable NC root found for %s. "
5036 "We need to move this object because parent object %s "
5037 "is deleted, but this object is not.",
5038 ldb_dn_get_linearized(msg->dn),
5039 ldb_dn_get_linearized(parent_msg->dn));
5040 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5041 } else if (ret != LDB_SUCCESS) {
5042 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5043 "Unable to find NC root for %s: %s. "
5044 "We need to move this object because parent object %s "
5045 "is deleted, but this object is not.",
5046 ldb_dn_get_linearized(msg->dn),
5047 ldb_errstring(ldb_module_get_ctx(ar->module)),
5048 ldb_dn_get_linearized(parent_msg->dn));
5049 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5052 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5054 DS_GUID_LOSTANDFOUND_CONTAINER,
5056 if (ret != LDB_SUCCESS) {
5057 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5058 "Unable to find LostAndFound Container for %s "
5059 "in partition %s: %s. "
5060 "We need to move this object because parent object %s "
5061 "is deleted, but this object is not.",
5062 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5063 ldb_errstring(ldb_module_get_ctx(ar->module)),
5064 ldb_dn_get_linearized(parent_msg->dn));
5065 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5067 ar->objs->objects[ar->index_current].last_known_parent
5068 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5072 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5075 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5077 comp_num = ldb_dn_get_comp_num(msg->dn);
5079 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5081 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5084 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5086 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5090 case LDB_REPLY_REFERRAL:
5091 /* we ignore referrals */
5094 case LDB_REPLY_DONE:
5096 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5097 struct GUID_txt_buf str_buf;
5098 if (ar->search_msg != NULL) {
5099 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5100 "No parent with GUID %s found for object locally known as %s",
5101 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5102 ldb_dn_get_linearized(ar->search_msg->dn));
5104 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5105 "No parent with GUID %s found for object remotely known as %s",
5106 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5107 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5111 * This error code is really important, as it
5112 * is the flag back to the callers to retry
5113 * this with DRSUAPI_DRS_GET_ANC, and so get
5114 * the parent objects before the child
5117 return ldb_module_done(ar->req, NULL, NULL,
5118 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5121 if (ar->search_msg != NULL) {
5122 ret = replmd_replicated_apply_merge(ar);
5124 ret = replmd_replicated_apply_add(ar);
5126 if (ret != LDB_SUCCESS) {
5127 return ldb_module_done(ar->req, NULL, NULL, ret);
5136 * Look for the parent object, so we put the new object in the right
5137 * place This is akin to NameObject in MS-DRSR - this routine and the
5138 * callbacks find the right parent name, and correct name for this
5142 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5144 struct ldb_context *ldb;
5148 struct ldb_request *search_req;
5149 static const char *attrs[] = {"isDeleted", NULL};
5150 struct GUID_txt_buf guid_str_buf;
5152 ldb = ldb_module_get_ctx(ar->module);
5154 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5155 if (ar->search_msg != NULL) {
5156 return replmd_replicated_apply_merge(ar);
5158 return replmd_replicated_apply_add(ar);
5162 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5165 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5166 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5168 ret = ldb_build_search_req(&search_req,
5171 ar->objs->partition_dn,
5177 replmd_replicated_apply_search_for_parent_callback,
5179 LDB_REQ_SET_LOCATION(search_req);
5181 ret = dsdb_request_add_controls(search_req,
5182 DSDB_SEARCH_SHOW_RECYCLED|
5183 DSDB_SEARCH_SHOW_DELETED|
5184 DSDB_SEARCH_SHOW_EXTENDED_DN);
5185 if (ret != LDB_SUCCESS) {
5189 return ldb_next_request(ar->module, search_req);
5193 handle renames that come in over DRS replication
5195 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5196 struct ldb_message *msg,
5197 struct ldb_request *parent,
5201 TALLOC_CTX *tmp_ctx = talloc_new(msg);
5202 struct ldb_result *res;
5203 struct ldb_dn *conflict_dn;
5204 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5205 const struct ldb_val *omd_value;
5206 struct replPropertyMetaDataBlob omd, *rmd;
5207 enum ndr_err_code ndr_err;
5208 bool rename_incoming_record, rodc;
5209 struct replPropertyMetaData1 *rmd_name, *omd_name;
5210 struct ldb_dn *new_dn;
5213 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5214 ldb_dn_get_linearized(ar->search_msg->dn),
5215 ldb_dn_get_linearized(msg->dn)));
5218 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5219 DSDB_FLAG_NEXT_MODULE, ar->req);
5220 if (ret == LDB_SUCCESS) {
5221 talloc_free(tmp_ctx);
5226 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5227 talloc_free(tmp_ctx);
5228 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5229 ldb_dn_get_linearized(ar->search_msg->dn),
5230 ldb_dn_get_linearized(msg->dn),
5231 ldb_errstring(ldb_module_get_ctx(ar->module)));
5235 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5236 if (ret != LDB_SUCCESS) {
5237 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5238 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5239 ldb_errstring(ldb_module_get_ctx(ar->module)));
5240 return LDB_ERR_OPERATIONS_ERROR;
5243 * we have a conflict, and need to decide if we will keep the
5244 * new record or the old record
5247 conflict_dn = msg->dn;
5251 * We are on an RODC, or were a GC for this
5252 * partition, so we have to fail this until
5253 * someone who owns the partition sorts it
5256 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5257 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5258 " - We must fail the operation until a master for this partition resolves the conflict",
5259 ldb_dn_get_linearized(conflict_dn));
5264 * first we need the replPropertyMetaData attribute from the
5267 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5269 DSDB_FLAG_NEXT_MODULE |
5270 DSDB_SEARCH_SHOW_DELETED |
5271 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5272 if (ret != LDB_SUCCESS) {
5273 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5274 ldb_dn_get_linearized(conflict_dn)));
5278 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5279 if (omd_value == NULL) {
5280 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5281 ldb_dn_get_linearized(conflict_dn)));
5285 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5286 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5287 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5288 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5289 ldb_dn_get_linearized(conflict_dn)));
5293 rmd = ar->objs->objects[ar->index_current].meta_data;
5296 * we decide which is newer based on the RPMD on the name
5297 * attribute. See [MS-DRSR] ResolveNameConflict.
5299 * We expect omd_name to be present, as this is from a local
5300 * search, but while rmd_name should have been given to us by
5301 * the remote server, if it is missing we just prefer the
5303 * replmd_replPropertyMetaData1_new_should_be_taken()
5305 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5306 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5308 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5309 ldb_dn_get_linearized(conflict_dn)));
5314 * Should we preserve the current record, and so rename the
5315 * incoming record to be a conflict?
5317 rename_incoming_record =
5318 !replmd_replPropertyMetaData1_new_should_be_taken(
5319 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5320 omd_name, rmd_name);
5322 if (rename_incoming_record) {
5324 new_dn = replmd_conflict_dn(msg, msg->dn,
5325 &ar->objs->objects[ar->index_current].object_guid);
5326 if (new_dn == NULL) {
5327 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5328 "Failed to form conflict DN for %s\n",
5329 ldb_dn_get_linearized(msg->dn));
5331 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5334 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5335 DSDB_FLAG_NEXT_MODULE, ar->req);
5336 if (ret != LDB_SUCCESS) {
5337 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5338 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5339 ldb_dn_get_linearized(conflict_dn),
5340 ldb_dn_get_linearized(ar->search_msg->dn),
5341 ldb_dn_get_linearized(new_dn),
5342 ldb_errstring(ldb_module_get_ctx(ar->module)));
5343 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5351 /* we are renaming the existing record */
5353 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5354 if (GUID_all_zero(&guid)) {
5355 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5356 ldb_dn_get_linearized(conflict_dn)));
5360 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5361 if (new_dn == NULL) {
5362 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5363 ldb_dn_get_linearized(conflict_dn)));
5367 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5368 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5370 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5371 DSDB_FLAG_OWN_MODULE, ar->req);
5372 if (ret != LDB_SUCCESS) {
5373 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5374 ldb_dn_get_linearized(conflict_dn),
5375 ldb_dn_get_linearized(new_dn),
5376 ldb_errstring(ldb_module_get_ctx(ar->module))));
5381 * now we need to ensure that the rename is seen as an
5382 * originating update. We do that with a modify.
5384 ret = replmd_name_modify(ar, ar->req, new_dn);
5385 if (ret != LDB_SUCCESS) {
5389 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5390 ldb_dn_get_linearized(ar->search_msg->dn),
5391 ldb_dn_get_linearized(msg->dn)));
5394 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5395 DSDB_FLAG_NEXT_MODULE, ar->req);
5396 if (ret != LDB_SUCCESS) {
5397 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5398 ldb_dn_get_linearized(ar->search_msg->dn),
5399 ldb_dn_get_linearized(msg->dn),
5400 ldb_errstring(ldb_module_get_ctx(ar->module))));
5406 * On failure make the caller get the error
5407 * This means replication will stop with an error,
5408 * but there is not much else we can do. In the
5409 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5413 talloc_free(tmp_ctx);
5418 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5420 struct ldb_context *ldb;
5421 struct ldb_request *change_req;
5422 enum ndr_err_code ndr_err;
5423 struct ldb_message *msg;
5424 struct replPropertyMetaDataBlob *rmd;
5425 struct replPropertyMetaDataBlob omd;
5426 const struct ldb_val *omd_value;
5427 struct replPropertyMetaDataBlob nmd;
5428 struct ldb_val nmd_value;
5429 struct GUID remote_parent_guid;
5432 unsigned int removed_attrs = 0;
5434 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5435 bool isDeleted = false;
5436 bool local_isDeleted = false;
5437 bool remote_isDeleted = false;
5438 bool take_remote_isDeleted = false;
5439 bool sd_updated = false;
5440 bool renamed = false;
5441 bool is_schema_nc = false;
5443 const struct ldb_val *old_rdn, *new_rdn;
5444 struct replmd_private *replmd_private =
5445 talloc_get_type(ldb_module_get_private(ar->module),
5446 struct replmd_private);
5448 time_t t = time(NULL);
5449 unix_to_nt_time(&now, t);
5451 ldb = ldb_module_get_ctx(ar->module);
5452 msg = ar->objs->objects[ar->index_current].msg;
5454 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5456 rmd = ar->objs->objects[ar->index_current].meta_data;
5460 /* find existing meta data */
5461 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5463 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5464 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5465 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5466 nt_status = ndr_map_error2ntstatus(ndr_err);
5467 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5470 if (omd.version != 1) {
5471 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5476 struct GUID_txt_buf guid_txt;
5478 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5479 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
5482 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5484 ndr_print_struct_string(s,
5485 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5486 "existing replPropertyMetaData",
5488 ndr_print_struct_string(s,
5489 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5490 "incoming replPropertyMetaData",
5495 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5496 "isDeleted", false);
5497 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5498 "isDeleted", false);
5501 * Fill in the remote_parent_guid with the GUID or an all-zero
5504 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5505 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5507 remote_parent_guid = GUID_zero();
5511 * To ensure we follow a complex rename chain around, we have
5512 * to confirm that the DN is the same (mostly to confirm the
5513 * RDN) and the parentGUID is the same.
5515 * This ensures we keep things under the correct parent, which
5516 * replmd_replicated_handle_rename() will do.
5519 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5520 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5524 * handle renames, even just by case that come in over
5525 * DRS. Changes in the parent DN don't hit us here,
5526 * because the search for a parent will clean up those
5529 * We also have already filtered out the case where
5530 * the peer has an older name to what we have (see
5531 * replmd_replicated_apply_search_callback())
5533 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5536 if (ret != LDB_SUCCESS) {
5537 ldb_debug(ldb, LDB_DEBUG_FATAL,
5538 "replmd_replicated_request rename %s => %s failed - %s\n",
5539 ldb_dn_get_linearized(ar->search_msg->dn),
5540 ldb_dn_get_linearized(msg->dn),
5541 ldb_errstring(ldb));
5542 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5545 if (renamed == true) {
5547 * Set the callback to one that will fix up the name
5548 * metadata on the new conflict DN
5550 callback = replmd_op_name_modify_callback;
5555 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5556 nmd.ctr.ctr1.array = talloc_array(ar,
5557 struct replPropertyMetaData1,
5558 nmd.ctr.ctr1.count);
5559 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5561 /* first copy the old meta data */
5562 for (i=0; i < omd.ctr.ctr1.count; i++) {
5563 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5568 /* now merge in the new meta data */
5569 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5572 for (j=0; j < ni; j++) {
5575 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5579 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5580 ar->objs->dsdb_repl_flags,
5581 &nmd.ctr.ctr1.array[j],
5582 &rmd->ctr.ctr1.array[i]);
5584 /* replace the entry */
5585 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5586 if (ar->seq_num == 0) {
5587 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5588 if (ret != LDB_SUCCESS) {
5589 return replmd_replicated_request_error(ar, ret);
5592 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5593 switch (nmd.ctr.ctr1.array[j].attid) {
5594 case DRSUAPI_ATTID_ntSecurityDescriptor:
5597 case DRSUAPI_ATTID_isDeleted:
5598 take_remote_isDeleted = true;
5607 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5608 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5609 msg->elements[i-removed_attrs].name,
5610 ldb_dn_get_linearized(msg->dn),
5611 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5614 /* we don't want to apply this change so remove the attribute */
5615 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5622 if (found) continue;
5624 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5625 if (ar->seq_num == 0) {
5626 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5627 if (ret != LDB_SUCCESS) {
5628 return replmd_replicated_request_error(ar, ret);
5631 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5632 switch (nmd.ctr.ctr1.array[ni].attid) {
5633 case DRSUAPI_ATTID_ntSecurityDescriptor:
5636 case DRSUAPI_ATTID_isDeleted:
5637 take_remote_isDeleted = true;
5646 * finally correct the size of the meta_data array
5648 nmd.ctr.ctr1.count = ni;
5650 new_rdn = ldb_dn_get_rdn_val(msg->dn);
5651 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5654 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5655 &nmd, ar, now, is_schema_nc);
5656 if (ret != LDB_SUCCESS) {
5657 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5658 return replmd_replicated_request_error(ar, ret);
5662 * sort the new meta data array
5664 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5665 if (ret != LDB_SUCCESS) {
5666 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5671 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
5674 * This also controls SD propagation below
5676 if (take_remote_isDeleted) {
5677 isDeleted = remote_isDeleted;
5679 isDeleted = local_isDeleted;
5682 ar->isDeleted = isDeleted;
5685 * check if some replicated attributes left, otherwise skip the ldb_modify() call
5687 if (msg->num_elements == 0) {
5688 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5691 return replmd_replicated_apply_isDeleted(ar);
5694 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5695 ar->index_current, msg->num_elements);
5701 if (sd_updated && !isDeleted) {
5702 ret = dsdb_module_schedule_sd_propagation(ar->module,
5703 ar->objs->partition_dn,
5705 if (ret != LDB_SUCCESS) {
5706 return ldb_operr(ldb);
5710 /* create the meta data value */
5711 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5712 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5713 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5714 nt_status = ndr_map_error2ntstatus(ndr_err);
5715 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5719 * when we know that we'll modify the record, add the whenChanged, uSNChanged
5720 * and replPopertyMetaData attributes
5722 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5723 if (ret != LDB_SUCCESS) {
5724 return replmd_replicated_request_error(ar, ret);
5726 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5727 if (ret != LDB_SUCCESS) {
5728 return replmd_replicated_request_error(ar, ret);
5730 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5731 if (ret != LDB_SUCCESS) {
5732 return replmd_replicated_request_error(ar, ret);
5735 replmd_ldb_message_sort(msg, ar->schema);
5737 /* we want to replace the old values */
5738 for (i=0; i < msg->num_elements; i++) {
5739 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5740 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5741 if (msg->elements[i].num_values == 0) {
5742 ldb_asprintf_errstring(ldb, __location__
5743 ": objectClass removed on %s, aborting replication\n",
5744 ldb_dn_get_linearized(msg->dn));
5745 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5751 struct GUID_txt_buf guid_txt;
5753 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5754 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5755 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5760 ret = ldb_build_mod_req(&change_req,
5768 LDB_REQ_SET_LOCATION(change_req);
5769 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5771 /* current partition control needed by "repmd_op_callback" */
5772 ret = ldb_request_add_control(change_req,
5773 DSDB_CONTROL_CURRENT_PARTITION_OID,
5775 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5777 return ldb_next_request(ar->module, change_req);
5780 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5781 struct ldb_reply *ares)
5783 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5784 struct replmd_replicated_request);
5788 return ldb_module_done(ar->req, NULL, NULL,
5789 LDB_ERR_OPERATIONS_ERROR);
5791 if (ares->error != LDB_SUCCESS &&
5792 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5793 return ldb_module_done(ar->req, ares->controls,
5794 ares->response, ares->error);
5797 switch (ares->type) {
5798 case LDB_REPLY_ENTRY:
5799 ar->search_msg = talloc_steal(ar, ares->message);
5802 case LDB_REPLY_REFERRAL:
5803 /* we ignore referrals */
5806 case LDB_REPLY_DONE:
5808 struct replPropertyMetaData1 *md_remote;
5809 struct replPropertyMetaData1 *md_local;
5811 struct replPropertyMetaDataBlob omd;
5812 const struct ldb_val *omd_value;
5813 struct replPropertyMetaDataBlob *rmd;
5814 struct ldb_message *msg;
5816 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5817 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5820 * This is the ADD case, find the appropriate parent,
5821 * as this object doesn't exist locally:
5823 if (ar->search_msg == NULL) {
5824 ret = replmd_replicated_apply_search_for_parent(ar);
5825 if (ret != LDB_SUCCESS) {
5826 return ldb_module_done(ar->req, NULL, NULL, ret);
5833 * Otherwise, in the MERGE case, work out if we are
5834 * attempting a rename, and if so find the parent the
5835 * newly renamed object wants to belong under (which
5836 * may not be the parent in it's attached string DN
5838 rmd = ar->objs->objects[ar->index_current].meta_data;
5842 /* find existing meta data */
5843 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5845 enum ndr_err_code ndr_err;
5846 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5847 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5848 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5849 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5850 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5853 if (omd.version != 1) {
5854 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5858 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5860 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5861 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5862 && GUID_all_zero(&ar->local_parent_guid)) {
5863 DEBUG(0, ("Refusing to replicate new version of %s "
5864 "as local object has an all-zero parentGUID attribute, "
5865 "despite not being an NC root\n",
5866 ldb_dn_get_linearized(ar->search_msg->dn)));
5867 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5871 * now we need to check for double renames. We could have a
5872 * local rename pending which our replication partner hasn't
5873 * received yet. We choose which one wins by looking at the
5874 * attribute stamps on the two objects, the newer one wins.
5876 * This also simply applies the correct algorithms for
5877 * determining if a change was made to name at all, or
5878 * if the object has just been renamed under the same
5881 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5882 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5884 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5885 ldb_dn_get_linearized(ar->search_msg->dn)));
5886 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5890 * if there is no name attribute given then we have to assume the
5891 * object we've received has the older name
5893 if (replmd_replPropertyMetaData1_new_should_be_taken(
5894 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5895 md_local, md_remote)) {
5896 struct GUID_txt_buf p_guid_local;
5897 struct GUID_txt_buf p_guid_remote;
5898 msg = ar->objs->objects[ar->index_current].msg;
5900 /* Merge on the existing object, with rename */
5902 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5903 "as incoming object changing to %s under %s\n",
5904 ldb_dn_get_linearized(ar->search_msg->dn),
5905 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5906 ldb_dn_get_linearized(msg->dn),
5907 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5909 ret = replmd_replicated_apply_search_for_parent(ar);
5911 struct GUID_txt_buf p_guid_local;
5912 struct GUID_txt_buf p_guid_remote;
5913 msg = ar->objs->objects[ar->index_current].msg;
5916 * Merge on the existing object, force no
5917 * rename (code below just to explain why in
5921 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5922 ldb_dn_get_linearized(msg->dn)) == 0) {
5923 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5924 GUID_equal(&ar->local_parent_guid,
5925 ar->objs->objects[ar->index_current].parent_guid)
5927 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5928 "despite incoming object changing parent to %s\n",
5929 ldb_dn_get_linearized(ar->search_msg->dn),
5930 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5931 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5935 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5936 " and rejecting older rename to %s under %s\n",
5937 ldb_dn_get_linearized(ar->search_msg->dn),
5938 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5939 ldb_dn_get_linearized(msg->dn),
5940 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5944 * This assignment ensures that the strcmp()
5945 * and GUID_equal() calls in
5946 * replmd_replicated_apply_merge() avoids the
5949 ar->objs->objects[ar->index_current].parent_guid =
5950 &ar->local_parent_guid;
5952 msg->dn = ar->search_msg->dn;
5953 ret = replmd_replicated_apply_merge(ar);
5955 if (ret != LDB_SUCCESS) {
5956 return ldb_module_done(ar->req, NULL, NULL, ret);
5965 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
5967 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
5969 struct ldb_context *ldb;
5973 struct ldb_request *search_req;
5974 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
5975 "parentGUID", "instanceType",
5976 "replPropertyMetaData", "nTSecurityDescriptor",
5977 "isDeleted", NULL };
5978 struct GUID_txt_buf guid_str_buf;
5980 if (ar->index_current >= ar->objs->num_objects) {
5981 /* done with it, go to next stage */
5982 return replmd_replicated_uptodate_vector(ar);
5985 ldb = ldb_module_get_ctx(ar->module);
5986 ar->search_msg = NULL;
5987 ar->isDeleted = false;
5989 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5992 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5993 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5995 ret = ldb_build_search_req(&search_req,
5998 ar->objs->partition_dn,
6004 replmd_replicated_apply_search_callback,
6006 LDB_REQ_SET_LOCATION(search_req);
6008 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
6010 if (ret != LDB_SUCCESS) {
6014 return ldb_next_request(ar->module, search_req);
6018 * This is essentially a wrapper for replmd_replicated_apply_next()
6020 * This is needed to ensure that both codepaths call this handler.
6022 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
6024 struct ldb_dn *deleted_objects_dn;
6025 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
6026 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
6027 &deleted_objects_dn);
6028 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
6030 * Do a delete here again, so that if there is
6031 * anything local that conflicts with this
6032 * object being deleted, it is removed. This
6033 * includes links. See MS-DRSR 4.1.10.6.9
6036 * If the object is already deleted, and there
6037 * is no more work required, it doesn't do
6041 /* This has been updated to point to the DN we eventually did the modify on */
6043 struct ldb_request *del_req;
6044 struct ldb_result *res;
6046 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6048 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6052 res = talloc_zero(tmp_ctx, struct ldb_result);
6054 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6055 talloc_free(tmp_ctx);
6059 /* Build a delete request, which hopefully will artually turn into nothing */
6060 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6064 ldb_modify_default_callback,
6066 LDB_REQ_SET_LOCATION(del_req);
6067 if (ret != LDB_SUCCESS) {
6068 talloc_free(tmp_ctx);
6073 * This is the guts of the call, call back
6074 * into our delete code, but setting the
6075 * re_delete flag so we delete anything that
6076 * shouldn't be there on a deleted or recycled
6079 ret = replmd_delete_internals(ar->module, del_req, true);
6080 if (ret == LDB_SUCCESS) {
6081 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6084 talloc_free(tmp_ctx);
6085 if (ret != LDB_SUCCESS) {
6090 ar->index_current++;
6091 return replmd_replicated_apply_next(ar);
6094 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6095 struct ldb_reply *ares)
6097 struct ldb_context *ldb;
6098 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6099 struct replmd_replicated_request);
6100 ldb = ldb_module_get_ctx(ar->module);
6103 return ldb_module_done(ar->req, NULL, NULL,
6104 LDB_ERR_OPERATIONS_ERROR);
6106 if (ares->error != LDB_SUCCESS) {
6107 return ldb_module_done(ar->req, ares->controls,
6108 ares->response, ares->error);
6111 if (ares->type != LDB_REPLY_DONE) {
6112 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6113 return ldb_module_done(ar->req, NULL, NULL,
6114 LDB_ERR_OPERATIONS_ERROR);
6119 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6122 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6124 struct ldb_context *ldb;
6125 struct ldb_request *change_req;
6126 enum ndr_err_code ndr_err;
6127 struct ldb_message *msg;
6128 struct replUpToDateVectorBlob ouv;
6129 const struct ldb_val *ouv_value;
6130 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6131 struct replUpToDateVectorBlob nuv;
6132 struct ldb_val nuv_value;
6133 struct ldb_message_element *nuv_el = NULL;
6134 struct ldb_message_element *orf_el = NULL;
6135 struct repsFromToBlob nrf;
6136 struct ldb_val *nrf_value = NULL;
6137 struct ldb_message_element *nrf_el = NULL;
6141 time_t t = time(NULL);
6144 uint32_t instanceType;
6146 ldb = ldb_module_get_ctx(ar->module);
6147 ruv = ar->objs->uptodateness_vector;
6153 unix_to_nt_time(&now, t);
6155 if (ar->search_msg == NULL) {
6156 /* this happens for a REPL_OBJ call where we are
6157 creating the target object by replicating it. The
6158 subdomain join code does this for the partition DN
6160 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6161 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6164 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6165 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6166 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6167 ldb_dn_get_linearized(ar->search_msg->dn)));
6168 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6172 * first create the new replUpToDateVector
6174 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6176 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6177 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6178 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6179 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6180 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6183 if (ouv.version != 2) {
6184 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6189 * the new uptodateness vector will at least
6190 * contain 1 entry, one for the source_dsa
6192 * plus optional values from our old vector and the one from the source_dsa
6194 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6195 if (ruv) nuv.ctr.ctr2.count += ruv->count;
6196 nuv.ctr.ctr2.cursors = talloc_array(ar,
6197 struct drsuapi_DsReplicaCursor2,
6198 nuv.ctr.ctr2.count);
6199 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6201 /* first copy the old vector */
6202 for (i=0; i < ouv.ctr.ctr2.count; i++) {
6203 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6207 /* merge in the source_dsa vector is available */
6208 for (i=0; (ruv && i < ruv->count); i++) {
6211 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6212 &ar->our_invocation_id)) {
6216 for (j=0; j < ni; j++) {
6217 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6218 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6224 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6225 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6230 if (found) continue;
6232 /* if it's not there yet, add it */
6233 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6238 * finally correct the size of the cursors array
6240 nuv.ctr.ctr2.count = ni;
6245 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6248 * create the change ldb_message
6250 msg = ldb_msg_new(ar);
6251 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6252 msg->dn = ar->search_msg->dn;
6254 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6255 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6256 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6257 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6258 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6260 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6261 if (ret != LDB_SUCCESS) {
6262 return replmd_replicated_request_error(ar, ret);
6264 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6267 * now create the new repsFrom value from the given repsFromTo1 structure
6271 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6272 nrf.ctr.ctr1.last_attempt = now;
6273 nrf.ctr.ctr1.last_success = now;
6274 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6277 * first see if we already have a repsFrom value for the current source dsa
6278 * if so we'll later replace this value
6280 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6282 for (i=0; i < orf_el->num_values; i++) {
6283 struct repsFromToBlob *trf;
6285 trf = talloc(ar, struct repsFromToBlob);
6286 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6288 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6289 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6290 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6291 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6292 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6295 if (trf->version != 1) {
6296 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6300 * we compare the source dsa objectGUID not the invocation_id
6301 * because we want only one repsFrom value per source dsa
6302 * and when the invocation_id of the source dsa has changed we don't need
6303 * the old repsFrom with the old invocation_id
6305 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6306 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6312 nrf_value = &orf_el->values[i];
6317 * copy over all old values to the new ldb_message
6319 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6320 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6325 * if we haven't found an old repsFrom value for the current source dsa
6326 * we'll add a new value
6329 struct ldb_val zero_value;
6330 ZERO_STRUCT(zero_value);
6331 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6332 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6334 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6337 /* we now fill the value which is already attached to ldb_message */
6338 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6340 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6341 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6342 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6343 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6347 * the ldb_message_element for the attribute, has all the old values and the new one
6348 * so we'll replace the whole attribute with all values
6350 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6352 if (CHECK_DEBUGLVL(4)) {
6353 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
6354 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6358 /* prepare the ldb_modify() request */
6359 ret = ldb_build_mod_req(&change_req,
6365 replmd_replicated_uptodate_modify_callback,
6367 LDB_REQ_SET_LOCATION(change_req);
6368 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6370 return ldb_next_request(ar->module, change_req);
6373 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6374 struct ldb_reply *ares)
6376 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6377 struct replmd_replicated_request);
6381 return ldb_module_done(ar->req, NULL, NULL,
6382 LDB_ERR_OPERATIONS_ERROR);
6384 if (ares->error != LDB_SUCCESS &&
6385 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6386 return ldb_module_done(ar->req, ares->controls,
6387 ares->response, ares->error);
6390 switch (ares->type) {
6391 case LDB_REPLY_ENTRY:
6392 ar->search_msg = talloc_steal(ar, ares->message);
6395 case LDB_REPLY_REFERRAL:
6396 /* we ignore referrals */
6399 case LDB_REPLY_DONE:
6400 ret = replmd_replicated_uptodate_modify(ar);
6401 if (ret != LDB_SUCCESS) {
6402 return ldb_module_done(ar->req, NULL, NULL, ret);
6411 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6413 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6414 struct replmd_private *replmd_private =
6415 talloc_get_type_abort(ldb_module_get_private(ar->module),
6416 struct replmd_private);
6418 static const char *attrs[] = {
6419 "replUpToDateVector",
6424 struct ldb_request *search_req;
6426 ar->search_msg = NULL;
6429 * Let the caller know that we did an originating updates
6431 ar->objs->originating_updates = replmd_private->originating_updates;
6433 ret = ldb_build_search_req(&search_req,
6436 ar->objs->partition_dn,
6442 replmd_replicated_uptodate_search_callback,
6444 LDB_REQ_SET_LOCATION(search_req);
6445 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6447 return ldb_next_request(ar->module, search_req);
6452 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6454 struct ldb_context *ldb;
6455 struct dsdb_extended_replicated_objects *objs;
6456 struct replmd_replicated_request *ar;
6457 struct ldb_control **ctrls;
6460 struct replmd_private *replmd_private =
6461 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6463 ldb = ldb_module_get_ctx(module);
6465 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6467 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6469 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6470 return LDB_ERR_PROTOCOL_ERROR;
6473 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6474 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6475 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6476 return LDB_ERR_PROTOCOL_ERROR;
6479 ar = replmd_ctx_init(module, req);
6481 return LDB_ERR_OPERATIONS_ERROR;
6483 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6484 ar->apply_mode = true;
6486 ar->schema = dsdb_get_schema(ldb, ar);
6488 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6490 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6491 return LDB_ERR_CONSTRAINT_VIOLATION;
6494 ctrls = req->controls;
6496 if (req->controls) {
6497 req->controls = talloc_memdup(ar, req->controls,
6498 talloc_get_size(req->controls));
6499 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6502 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6503 if (ret != LDB_SUCCESS) {
6507 /* If this change contained linked attributes in the body
6508 * (rather than in the links section) we need to update
6509 * backlinks in linked_attributes */
6510 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6511 if (ret != LDB_SUCCESS) {
6515 ar->controls = req->controls;
6516 req->controls = ctrls;
6518 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
6520 /* save away the linked attributes for the end of the
6522 for (i=0; i<ar->objs->linked_attributes_count; i++) {
6523 struct la_entry *la_entry;
6525 if (replmd_private->la_ctx == NULL) {
6526 replmd_private->la_ctx = talloc_new(replmd_private);
6528 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6529 if (la_entry == NULL) {
6531 return LDB_ERR_OPERATIONS_ERROR;
6533 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6534 if (la_entry->la == NULL) {
6535 talloc_free(la_entry);
6537 return LDB_ERR_OPERATIONS_ERROR;
6539 *la_entry->la = ar->objs->linked_attributes[i];
6541 /* we need to steal the non-scalars so they stay
6542 around until the end of the transaction */
6543 talloc_steal(la_entry->la, la_entry->la->identifier);
6544 talloc_steal(la_entry->la, la_entry->la->value.blob);
6546 DLIST_ADD(replmd_private->la_list, la_entry);
6549 return replmd_replicated_apply_next(ar);
6553 process one linked attribute structure
6555 static int replmd_process_linked_attribute(struct ldb_module *module,
6556 struct replmd_private *replmd_private,
6557 struct la_entry *la_entry,
6558 struct ldb_request *parent)
6560 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6561 struct ldb_context *ldb = ldb_module_get_ctx(module);
6562 struct ldb_message *msg;
6563 struct ldb_message *target_msg = NULL;
6564 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6565 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
6567 const struct dsdb_attribute *attr;
6568 struct dsdb_dn *dsdb_dn;
6569 uint64_t seq_num = 0;
6570 struct ldb_message_element *old_el;
6572 time_t t = time(NULL);
6573 struct ldb_result *res;
6574 struct ldb_result *target_res;
6575 const char *attrs[4];
6576 const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
6577 struct parsed_dn *pdn_list, *pdn, *next;
6578 struct GUID guid = GUID_zero();
6580 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
6582 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
6583 enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
6586 linked_attributes[0]:
6587 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6589 identifier: struct drsuapi_DsReplicaObjectIdentifier
6590 __ndr_size : 0x0000003a (58)
6591 __ndr_size_sid : 0x00000000 (0)
6592 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6594 __ndr_size_dn : 0x00000000 (0)
6596 attid : DRSUAPI_ATTID_member (0x1F)
6597 value: struct drsuapi_DsAttributeValue
6598 __ndr_size : 0x0000007e (126)
6600 blob : DATA_BLOB length=126
6601 flags : 0x00000001 (1)
6602 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6603 originating_add_time : Wed Sep 2 22:20:01 2009 EST
6604 meta_data: struct drsuapi_DsReplicaMetaData
6605 version : 0x00000015 (21)
6606 originating_change_time : Wed Sep 2 23:39:07 2009 EST
6607 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6608 originating_usn : 0x000000000001e19c (123292)
6610 (for cases where the link is to a normal DN)
6611 &target: struct drsuapi_DsReplicaObjectIdentifier3
6612 __ndr_size : 0x0000007e (126)
6613 __ndr_size_sid : 0x0000001c (28)
6614 guid : 7639e594-db75-4086-b0d4-67890ae46031
6615 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
6616 __ndr_size_dn : 0x00000022 (34)
6617 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
6620 /* find the attribute being modified */
6621 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
6623 struct GUID_txt_buf guid_str;
6624 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
6626 GUID_buf_string(&la->identifier->guid,
6628 talloc_free(tmp_ctx);
6629 return LDB_ERR_OPERATIONS_ERROR;
6632 attrs[0] = attr->lDAPDisplayName;
6633 attrs[1] = "isDeleted";
6634 attrs[2] = "isRecycled";
6637 /* get the existing message from the db for the object with
6638 this GUID, returning attribute being modified. We will then
6639 use this msg as the basis for a modify call */
6640 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
6641 DSDB_FLAG_NEXT_MODULE |
6642 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6643 DSDB_SEARCH_SHOW_RECYCLED |
6644 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
6645 DSDB_SEARCH_REVEAL_INTERNALS,
6647 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
6648 if (ret != LDB_SUCCESS) {
6649 talloc_free(tmp_ctx);
6652 if (res->count != 1) {
6653 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
6654 GUID_string(tmp_ctx, &la->identifier->guid));
6655 talloc_free(tmp_ctx);
6656 return LDB_ERR_NO_SUCH_OBJECT;
6661 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6662 * ProcessLinkValue, because link updates are not applied to
6663 * recycled and tombstone objects. We don't have to delete
6664 * any existing link, that should have happened when the
6665 * object deletion was replicated or initiated.
6668 replmd_deletion_state(module, msg, &deletion_state, NULL);
6670 if (deletion_state >= OBJECT_RECYCLED) {
6671 talloc_free(tmp_ctx);
6675 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6676 if (old_el == NULL) {
6677 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
6678 if (ret != LDB_SUCCESS) {
6679 ldb_module_oom(module);
6680 talloc_free(tmp_ctx);
6681 return LDB_ERR_OPERATIONS_ERROR;
6684 old_el->flags = LDB_FLAG_MOD_REPLACE;
6687 /* parse the existing links */
6688 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
6689 attr->syntax->ldap_oid, parent);
6691 if (ret != LDB_SUCCESS) {
6692 talloc_free(tmp_ctx);
6696 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
6697 if (!W_ERROR_IS_OK(status)) {
6698 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
6699 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
6700 talloc_free(tmp_ctx);
6701 return LDB_ERR_OPERATIONS_ERROR;
6704 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
6705 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6707 * This strange behaviour (allowing a NULL/missing
6708 * GUID) originally comes from:
6710 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6711 * Author: Andrew Tridgell <tridge@samba.org>
6712 * Date: Mon Dec 21 21:21:55 2009 +1100
6714 * s4-drs: cope better with NULL GUIDS from DRS
6716 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
6717 * need to match by DN if possible when seeing if we should update an
6720 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6723 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6724 dsdb_dn->dn, attrs2,
6725 DSDB_FLAG_NEXT_MODULE |
6726 DSDB_SEARCH_SHOW_RECYCLED |
6727 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6728 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6730 } else if (!NT_STATUS_IS_OK(ntstatus)) {
6731 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
6733 ldb_dn_get_linearized(dsdb_dn->dn),
6734 ldb_dn_get_linearized(msg->dn));
6735 talloc_free(tmp_ctx);
6736 return LDB_ERR_OPERATIONS_ERROR;
6738 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6739 NULL, LDB_SCOPE_SUBTREE,
6741 DSDB_FLAG_NEXT_MODULE |
6742 DSDB_SEARCH_SHOW_RECYCLED |
6743 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6744 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6747 GUID_string(tmp_ctx, &guid));
6750 if (ret != LDB_SUCCESS) {
6751 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6752 GUID_string(tmp_ctx, &guid),
6753 ldb_errstring(ldb_module_get_ctx(module)));
6754 talloc_free(tmp_ctx);
6758 if (target_res->count == 0) {
6759 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6760 GUID_string(tmp_ctx, &guid),
6761 ldb_dn_get_linearized(dsdb_dn->dn)));
6762 } else if (target_res->count != 1) {
6763 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6764 GUID_string(tmp_ctx, &guid));
6765 talloc_free(tmp_ctx);
6766 return LDB_ERR_OPERATIONS_ERROR;
6768 target_msg = target_res->msgs[0];
6769 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6773 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6774 * ProcessLinkValue, because link updates are not applied to
6775 * recycled and tombstone objects. We don't have to delete
6776 * any existing link, that should have happened when the
6777 * object deletion was replicated or initiated.
6779 replmd_deletion_state(module, target_msg,
6780 &target_deletion_state, NULL);
6782 if (target_deletion_state >= OBJECT_RECYCLED) {
6783 talloc_free(tmp_ctx);
6787 /* see if this link already exists */
6788 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
6792 attr->syntax->ldap_oid);
6793 if (ret != LDB_SUCCESS) {
6794 talloc_free(tmp_ctx);
6800 /* see if this update is newer than what we have already */
6801 struct GUID invocation_id = GUID_zero();
6802 uint32_t version = 0;
6803 uint32_t originating_usn = 0;
6804 NTTIME change_time = 0;
6805 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6807 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6808 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6809 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6810 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6812 if (!replmd_update_is_newer(&invocation_id,
6813 &la->meta_data.originating_invocation_id,
6815 la->meta_data.version,
6817 la->meta_data.originating_change_time)) {
6818 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6819 old_el->name, ldb_dn_get_linearized(msg->dn),
6820 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6821 talloc_free(tmp_ctx);
6825 /* get a seq_num for this change */
6826 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6827 if (ret != LDB_SUCCESS) {
6828 talloc_free(tmp_ctx);
6832 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6833 /* remove the existing backlink */
6834 ret = replmd_add_backlink(module, replmd_private,
6835 schema, &la->identifier->guid,
6836 &guid, false, attr, true);
6837 if (ret != LDB_SUCCESS) {
6838 talloc_free(tmp_ctx);
6843 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6844 &la->meta_data.originating_invocation_id,
6845 la->meta_data.originating_usn, seq_num,
6846 la->meta_data.originating_change_time,
6847 la->meta_data.version,
6849 if (ret != LDB_SUCCESS) {
6850 talloc_free(tmp_ctx);
6855 /* add the new backlink */
6856 ret = replmd_add_backlink(module, replmd_private,
6857 schema, &la->identifier->guid,
6858 &guid, true, attr, true);
6859 if (ret != LDB_SUCCESS) {
6860 talloc_free(tmp_ctx);
6866 /* get a seq_num for this change */
6867 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6868 if (ret != LDB_SUCCESS) {
6869 talloc_free(tmp_ctx);
6873 * We know where the new one needs to be, from the *next
6874 * pointer into pdn_list.
6877 offset = old_el->num_values;
6879 if (next->dsdb_dn == NULL) {
6880 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
6881 attr->syntax->ldap_oid);
6882 if (ret != LDB_SUCCESS) {
6886 offset = next - pdn_list;
6887 if (offset > old_el->num_values) {
6888 talloc_free(tmp_ctx);
6889 return LDB_ERR_OPERATIONS_ERROR;
6893 old_el->values = talloc_realloc(msg->elements, old_el->values,
6894 struct ldb_val, old_el->num_values+1);
6895 if (!old_el->values) {
6896 ldb_module_oom(module);
6897 return LDB_ERR_OPERATIONS_ERROR;
6900 if (offset != old_el->num_values) {
6901 memmove(&old_el->values[offset + 1], &old_el->values[offset],
6902 (old_el->num_values - offset) * sizeof(old_el->values[0]));
6905 old_el->num_values++;
6907 ret = replmd_build_la_val(tmp_ctx, &old_el->values[offset], dsdb_dn,
6908 &la->meta_data.originating_invocation_id,
6909 la->meta_data.originating_usn, seq_num,
6910 la->meta_data.originating_change_time,
6911 la->meta_data.version,
6913 if (ret != LDB_SUCCESS) {
6914 talloc_free(tmp_ctx);
6919 ret = replmd_add_backlink(module, replmd_private,
6920 schema, &la->identifier->guid,
6921 &guid, true, attr, true);
6922 if (ret != LDB_SUCCESS) {
6923 talloc_free(tmp_ctx);
6929 /* we only change whenChanged and uSNChanged if the seq_num
6931 ret = add_time_element(msg, "whenChanged", t);
6932 if (ret != LDB_SUCCESS) {
6933 talloc_free(tmp_ctx);
6938 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
6939 if (ret != LDB_SUCCESS) {
6940 talloc_free(tmp_ctx);
6945 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6946 if (old_el == NULL) {
6947 talloc_free(tmp_ctx);
6948 return ldb_operr(ldb);
6951 ret = dsdb_check_single_valued_link(attr, old_el);
6952 if (ret != LDB_SUCCESS) {
6953 talloc_free(tmp_ctx);
6957 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
6959 ret = linked_attr_modify(module, msg, parent);
6960 if (ret != LDB_SUCCESS) {
6961 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
6963 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
6964 talloc_free(tmp_ctx);
6968 talloc_free(tmp_ctx);
6973 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
6975 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
6976 return replmd_extended_replicated_objects(module, req);
6979 return ldb_next_request(module, req);
6984 we hook into the transaction operations to allow us to
6985 perform the linked attribute updates at the end of the whole
6986 transaction. This allows a forward linked attribute to be created
6987 before the object is created. During a vampire, w2k8 sends us linked
6988 attributes before the objects they are part of.
6990 static int replmd_start_transaction(struct ldb_module *module)
6992 /* create our private structure for this transaction */
6993 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
6994 struct replmd_private);
6995 replmd_txn_cleanup(replmd_private);
6997 /* free any leftover mod_usn records from cancelled
6999 while (replmd_private->ncs) {
7000 struct nc_entry *e = replmd_private->ncs;
7001 DLIST_REMOVE(replmd_private->ncs, e);
7005 replmd_private->originating_updates = false;
7007 return ldb_next_start_trans(module);
7011 on prepare commit we loop over our queued la_context structures and
7014 static int replmd_prepare_commit(struct ldb_module *module)
7016 struct replmd_private *replmd_private =
7017 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7018 struct la_entry *la, *prev;
7019 struct la_backlink *bl;
7022 /* walk the list backwards, to do the first entry first, as we
7023 * added the entries with DLIST_ADD() which puts them at the
7024 * start of the list */
7025 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
7026 prev = DLIST_PREV(la);
7027 DLIST_REMOVE(replmd_private->la_list, la);
7028 ret = replmd_process_linked_attribute(module, replmd_private,
7030 if (ret != LDB_SUCCESS) {
7031 replmd_txn_cleanup(replmd_private);
7036 /* process our backlink list, creating and deleting backlinks
7038 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
7039 ret = replmd_process_backlink(module, bl, NULL);
7040 if (ret != LDB_SUCCESS) {
7041 replmd_txn_cleanup(replmd_private);
7046 replmd_txn_cleanup(replmd_private);
7048 /* possibly change @REPLCHANGED */
7049 ret = replmd_notify_store(module, NULL);
7050 if (ret != LDB_SUCCESS) {
7054 return ldb_next_prepare_commit(module);
7057 static int replmd_del_transaction(struct ldb_module *module)
7059 struct replmd_private *replmd_private =
7060 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7061 replmd_txn_cleanup(replmd_private);
7063 return ldb_next_del_trans(module);
7067 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
7068 .name = "repl_meta_data",
7069 .init_context = replmd_init,
7071 .modify = replmd_modify,
7072 .rename = replmd_rename,
7073 .del = replmd_delete,
7074 .extended = replmd_extended,
7075 .start_transaction = replmd_start_transaction,
7076 .prepare_commit = replmd_prepare_commit,
7077 .del_transaction = replmd_del_transaction,
7080 int ldb_repl_meta_data_module_init(const char *version)
7082 LDB_MODULE_CHECK_VERSION(version);
7083 return ldb_register_module(&ldb_repl_meta_data_module_ops);