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 "dsdb/common/util.h"
43 #include "../libds/common/flags.h"
44 #include "librpc/gen_ndr/irpc.h"
45 #include "librpc/gen_ndr/ndr_misc.h"
46 #include "librpc/gen_ndr/ndr_drsuapi.h"
47 #include "librpc/gen_ndr/ndr_drsblobs.h"
48 #include "param/param.h"
49 #include "libcli/security/security.h"
50 #include "lib/util/dlinklist.h"
51 #include "dsdb/samdb/ldb_modules/util.h"
52 #include "lib/util/tsort.h"
55 #define DBGC_CLASS DBGC_DRS_REPL
57 /* the RMD_VERSION for linked attributes starts from 1 */
58 #define RMD_VERSION_INITIAL 1
61 * It's 29/12/9999 at 23:59:59 UTC as specified in MS-ADTS 7.1.1.4.2
62 * Deleted Objects Container
64 static const NTTIME DELETED_OBJECT_CONTAINER_CHANGE_TIME = 2650466015990000000ULL;
66 struct replmd_private {
68 struct la_entry *la_list;
70 struct nc_entry *prev, *next;
73 uint64_t mod_usn_urgent;
75 struct ldb_dn *schema_dn;
76 bool originating_updates;
81 struct la_entry *next, *prev;
82 struct drsuapi_DsReplicaLinkedAttribute *la;
83 uint32_t dsdb_repl_flags;
86 struct replmd_replicated_request {
87 struct ldb_module *module;
88 struct ldb_request *req;
90 const struct dsdb_schema *schema;
91 struct GUID our_invocation_id;
93 /* the controls we pass down */
94 struct ldb_control **controls;
97 * Backlinks for the replmd_add() case (we want to create
98 * backlinks after creating the user, but before the end of
101 struct la_backlink *la_backlinks;
103 /* details for the mode where we apply a bunch of inbound replication meessages */
105 uint32_t index_current;
106 struct dsdb_extended_replicated_objects *objs;
108 struct ldb_message *search_msg;
109 struct GUID local_parent_guid;
117 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
118 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
119 static int replmd_check_upgrade_links(struct ldb_context *ldb,
120 struct parsed_dn *dns, uint32_t count,
121 struct ldb_message_element *el,
122 const char *ldap_oid);
123 static int replmd_verify_linked_attribute(struct replmd_replicated_request *ar,
124 struct la_entry *la);
125 static int replmd_set_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
126 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
127 uint64_t usn, uint64_t local_usn, NTTIME nttime,
128 uint32_t version, bool deleted);
130 static int replmd_make_deleted_child_dn(TALLOC_CTX *tmp_ctx,
131 struct ldb_context *ldb,
133 const char *rdn_name,
134 const struct ldb_val *rdn_value,
137 enum urgent_situation {
138 REPL_URGENT_ON_CREATE = 1,
139 REPL_URGENT_ON_UPDATE = 2,
140 REPL_URGENT_ON_DELETE = 4
143 enum deletion_state {
144 OBJECT_NOT_DELETED=1,
151 static void replmd_deletion_state(struct ldb_module *module,
152 const struct ldb_message *msg,
153 enum deletion_state *current_state,
154 enum deletion_state *next_state)
157 bool enabled = false;
160 *current_state = OBJECT_REMOVED;
161 if (next_state != NULL) {
162 *next_state = OBJECT_REMOVED;
167 ret = dsdb_recyclebin_enabled(module, &enabled);
168 if (ret != LDB_SUCCESS) {
172 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
174 *current_state = OBJECT_TOMBSTONE;
175 if (next_state != NULL) {
176 *next_state = OBJECT_REMOVED;
181 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
182 *current_state = OBJECT_RECYCLED;
183 if (next_state != NULL) {
184 *next_state = OBJECT_REMOVED;
189 *current_state = OBJECT_DELETED;
190 if (next_state != NULL) {
191 *next_state = OBJECT_RECYCLED;
196 *current_state = OBJECT_NOT_DELETED;
197 if (next_state == NULL) {
202 *next_state = OBJECT_DELETED;
204 *next_state = OBJECT_TOMBSTONE;
208 static const struct {
209 const char *update_name;
210 enum urgent_situation repl_situation;
211 } urgent_objects[] = {
212 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
213 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
214 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
215 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
216 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
217 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
221 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
222 static const char *urgent_attrs[] = {
225 "userAccountControl",
230 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
231 enum urgent_situation situation)
234 for (i=0; urgent_objects[i].update_name; i++) {
236 if ((situation & urgent_objects[i].repl_situation) == 0) {
240 for (j=0; j<objectclass_el->num_values; j++) {
241 const struct ldb_val *v = &objectclass_el->values[j];
242 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
250 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
252 if (ldb_attr_in_list(urgent_attrs, el->name)) {
258 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
261 initialise the module
262 allocate the private structure and build the list
263 of partition DNs for use by replmd_notify()
265 static int replmd_init(struct ldb_module *module)
267 struct replmd_private *replmd_private;
268 struct ldb_context *ldb = ldb_module_get_ctx(module);
269 static const char *samba_dsdb_attrs[] = { SAMBA_COMPATIBLE_FEATURES_ATTR, NULL };
270 struct ldb_dn *samba_dsdb_dn;
271 struct ldb_result *res;
273 TALLOC_CTX *frame = talloc_stackframe();
274 replmd_private = talloc_zero(module, struct replmd_private);
275 if (replmd_private == NULL) {
278 return LDB_ERR_OPERATIONS_ERROR;
280 ldb_module_set_private(module, replmd_private);
282 replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
284 samba_dsdb_dn = ldb_dn_new(frame, ldb, "@SAMBA_DSDB");
285 if (!samba_dsdb_dn) {
290 ret = dsdb_module_search_dn(module, frame, &res, samba_dsdb_dn,
291 samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
292 if (ret == LDB_SUCCESS) {
293 replmd_private->sorted_links
294 = ldb_msg_check_string_attribute(res->msgs[0],
295 SAMBA_COMPATIBLE_FEATURES_ATTR,
296 SAMBA_SORTED_LINKS_FEATURE);
300 return ldb_next_init(module);
304 cleanup our per-transaction contexts
306 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
308 talloc_free(replmd_private->la_ctx);
309 replmd_private->la_list = NULL;
310 replmd_private->la_ctx = NULL;
316 struct la_backlink *next, *prev;
317 const char *attr_name;
318 struct ldb_dn *forward_dn;
319 struct GUID target_guid;
324 a ldb_modify request operating on modules below the
327 static int linked_attr_modify(struct ldb_module *module,
328 const struct ldb_message *message,
329 struct ldb_request *parent)
331 struct ldb_request *mod_req;
333 struct ldb_context *ldb = ldb_module_get_ctx(module);
334 TALLOC_CTX *tmp_ctx = talloc_new(module);
335 struct ldb_result *res;
337 res = talloc_zero(tmp_ctx, struct ldb_result);
339 talloc_free(tmp_ctx);
340 return ldb_oom(ldb_module_get_ctx(module));
343 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
347 ldb_modify_default_callback,
349 LDB_REQ_SET_LOCATION(mod_req);
350 if (ret != LDB_SUCCESS) {
351 talloc_free(tmp_ctx);
355 ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
357 if (ret != LDB_SUCCESS) {
361 /* Run the new request */
362 ret = ldb_next_request(module, mod_req);
364 if (ret == LDB_SUCCESS) {
365 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
368 talloc_free(tmp_ctx);
373 process a backlinks we accumulated during a transaction, adding and
374 deleting the backlinks from the target objects
376 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
378 struct ldb_dn *target_dn, *source_dn;
380 struct ldb_context *ldb = ldb_module_get_ctx(module);
381 struct ldb_message *msg;
382 TALLOC_CTX *frame = talloc_stackframe();
388 - construct ldb_message
389 - either an add or a delete
391 ret = dsdb_module_dn_by_guid(module, frame, &bl->target_guid, &target_dn, parent);
392 if (ret != LDB_SUCCESS) {
393 struct GUID_txt_buf guid_str;
394 DBG_WARNING("Failed to find target DN for linked attribute with GUID %s\n",
395 GUID_buf_string(&bl->target_guid, &guid_str));
396 DBG_WARNING("Please run 'samba-tool dbcheck' to resolve any missing backlinks.\n");
401 msg = ldb_msg_new(frame);
403 ldb_module_oom(module);
405 return LDB_ERR_OPERATIONS_ERROR;
408 source_dn = ldb_dn_copy(frame, bl->forward_dn);
410 ldb_module_oom(module);
412 return LDB_ERR_OPERATIONS_ERROR;
414 /* Filter down to the attributes we want in the backlink */
415 const char *accept[] = { "GUID", "SID", NULL };
416 ldb_dn_extended_filter(source_dn, accept);
419 /* construct a ldb_message for adding/deleting the backlink */
421 dn_string = ldb_dn_get_extended_linearized(frame, bl->forward_dn, 1);
423 ldb_module_oom(module);
425 return LDB_ERR_OPERATIONS_ERROR;
427 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
428 if (ret != LDB_SUCCESS) {
432 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
434 /* a backlink should never be single valued. Unfortunately the
435 exchange schema has a attribute
436 msExchBridgeheadedLocalConnectorsDNBL which is single
437 valued and a backlink. We need to cope with that by
438 ignoring the single value flag */
439 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
441 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
442 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
443 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
444 cope with possible corruption where the backlink has
445 already been removed */
446 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
447 ldb_dn_get_linearized(target_dn),
448 ldb_dn_get_linearized(source_dn),
449 ldb_errstring(ldb)));
451 } else if (ret != LDB_SUCCESS) {
452 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
453 bl->active?"add":"remove",
454 ldb_dn_get_linearized(source_dn),
455 ldb_dn_get_linearized(target_dn),
465 add a backlink to the list of backlinks to add/delete in the prepare
468 forward_dn is stolen onto the defereed context
470 static int replmd_defer_add_backlink(struct ldb_module *module,
471 struct replmd_private *replmd_private,
472 const struct dsdb_schema *schema,
473 struct replmd_replicated_request *ac,
474 struct ldb_dn *forward_dn,
475 struct GUID *target_guid, bool active,
476 const struct dsdb_attribute *schema_attr,
477 struct ldb_request *parent)
479 const struct dsdb_attribute *target_attr;
480 struct la_backlink *bl;
482 bl = talloc(ac, struct la_backlink);
484 ldb_module_oom(module);
485 return LDB_ERR_OPERATIONS_ERROR;
488 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
491 * windows 2003 has a broken schema where the
492 * definition of msDS-IsDomainFor is missing (which is
493 * supposed to be the backlink of the
494 * msDS-HasDomainNCs attribute
499 bl->attr_name = target_attr->lDAPDisplayName;
500 bl->forward_dn = talloc_steal(bl, forward_dn);
501 bl->target_guid = *target_guid;
504 DLIST_ADD(ac->la_backlinks, bl);
510 add a backlink to the list of backlinks to add/delete in the prepare
513 static int replmd_add_backlink(struct ldb_module *module,
514 struct replmd_private *replmd_private,
515 const struct dsdb_schema *schema,
516 struct ldb_dn *forward_dn,
517 struct GUID *target_guid, bool active,
518 const struct dsdb_attribute *schema_attr,
519 struct ldb_request *parent)
521 const struct dsdb_attribute *target_attr;
522 struct la_backlink bl;
525 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
528 * windows 2003 has a broken schema where the
529 * definition of msDS-IsDomainFor is missing (which is
530 * supposed to be the backlink of the
531 * msDS-HasDomainNCs attribute
536 bl.attr_name = target_attr->lDAPDisplayName;
537 bl.forward_dn = forward_dn;
538 bl.target_guid = *target_guid;
541 ret = replmd_process_backlink(module, &bl, parent);
547 * Callback for most write operations in this module:
549 * notify the repl task that a object has changed. The notifies are
550 * gathered up in the replmd_private structure then written to the
551 * @REPLCHANGED object in each partition during the prepare_commit
553 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
556 struct replmd_replicated_request *ac =
557 talloc_get_type_abort(req->context, struct replmd_replicated_request);
558 struct replmd_private *replmd_private =
559 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
560 struct nc_entry *modified_partition;
561 struct ldb_control *partition_ctrl;
562 const struct dsdb_control_current_partition *partition;
564 struct ldb_control **controls;
566 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
568 controls = ares->controls;
569 if (ldb_request_get_control(ac->req,
570 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
572 * Remove the current partition control from what we pass up
573 * the chain if it hasn't been requested manually.
575 controls = ldb_controls_except_specified(ares->controls, ares,
579 if (ares->error != LDB_SUCCESS) {
580 struct GUID_txt_buf guid_txt;
581 struct ldb_message *msg = NULL;
584 if (ac->apply_mode == false) {
585 DBG_NOTICE("Originating update failure. Error is: %s\n",
586 ldb_strerror(ares->error));
587 return ldb_module_done(ac->req, controls,
588 ares->response, ares->error);
591 msg = ac->objs->objects[ac->index_current].msg;
593 * Set at DBG_NOTICE as once these start to happe, they
594 * will happen a lot until resolved, due to repeated
595 * replication. The caller will probably print the
596 * ldb error string anyway.
598 DBG_NOTICE("DRS replication apply failure for %s. Error is: %s\n",
599 ldb_dn_get_linearized(msg->dn),
600 ldb_strerror(ares->error));
602 s = ldb_ldif_message_redacted_string(ldb_module_get_ctx(ac->module),
607 DBG_INFO("Failing DRS %s replication message was %s:\n%s\n",
608 ac->search_msg == NULL ? "ADD" : "MODIFY",
609 GUID_buf_string(&ac->objs->objects[ac->index_current].object_guid,
613 return ldb_module_done(ac->req, controls,
614 ares->response, ares->error);
617 if (ares->type != LDB_REPLY_DONE) {
618 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
619 return ldb_module_done(ac->req, NULL,
620 NULL, LDB_ERR_OPERATIONS_ERROR);
623 if (ac->apply_mode == false) {
624 struct la_backlink *bl;
626 * process our backlink list after an replmd_add(),
627 * creating and deleting backlinks as necessary (this
628 * code is sync). The other cases are handled inline
631 for (bl=ac->la_backlinks; bl; bl=bl->next) {
632 ret = replmd_process_backlink(ac->module, bl, ac->req);
633 if (ret != LDB_SUCCESS) {
634 return ldb_module_done(ac->req, NULL,
640 if (!partition_ctrl) {
641 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
642 return ldb_module_done(ac->req, NULL,
643 NULL, LDB_ERR_OPERATIONS_ERROR);
646 partition = talloc_get_type_abort(partition_ctrl->data,
647 struct dsdb_control_current_partition);
649 if (ac->seq_num > 0) {
650 for (modified_partition = replmd_private->ncs; modified_partition;
651 modified_partition = modified_partition->next) {
652 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
657 if (modified_partition == NULL) {
658 modified_partition = talloc_zero(replmd_private, struct nc_entry);
659 if (!modified_partition) {
660 ldb_oom(ldb_module_get_ctx(ac->module));
661 return ldb_module_done(ac->req, NULL,
662 NULL, LDB_ERR_OPERATIONS_ERROR);
664 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
665 if (!modified_partition->dn) {
666 ldb_oom(ldb_module_get_ctx(ac->module));
667 return ldb_module_done(ac->req, NULL,
668 NULL, LDB_ERR_OPERATIONS_ERROR);
670 DLIST_ADD(replmd_private->ncs, modified_partition);
673 if (ac->seq_num > modified_partition->mod_usn) {
674 modified_partition->mod_usn = ac->seq_num;
676 modified_partition->mod_usn_urgent = ac->seq_num;
679 if (!ac->apply_mode) {
680 replmd_private->originating_updates = true;
684 if (ac->apply_mode) {
685 ret = replmd_replicated_apply_isDeleted(ac);
686 if (ret != LDB_SUCCESS) {
687 return ldb_module_done(ac->req, NULL, NULL, ret);
691 /* free the partition control container here, for the
692 * common path. Other cases will have it cleaned up
693 * eventually with the ares */
694 talloc_free(partition_ctrl);
695 return ldb_module_done(ac->req, controls,
696 ares->response, LDB_SUCCESS);
702 * update a @REPLCHANGED record in each partition if there have been
703 * any writes of replicated data in the partition
705 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
707 struct replmd_private *replmd_private =
708 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
710 while (replmd_private->ncs) {
712 struct nc_entry *modified_partition = replmd_private->ncs;
714 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
715 modified_partition->mod_usn,
716 modified_partition->mod_usn_urgent, parent);
717 if (ret != LDB_SUCCESS) {
718 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
719 ldb_dn_get_linearized(modified_partition->dn)));
723 if (ldb_dn_compare(modified_partition->dn,
724 replmd_private->schema_dn) == 0) {
725 struct ldb_result *ext_res;
726 ret = dsdb_module_extended(module,
727 replmd_private->schema_dn,
729 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
731 DSDB_FLAG_NEXT_MODULE,
733 if (ret != LDB_SUCCESS) {
736 talloc_free(ext_res);
739 DLIST_REMOVE(replmd_private->ncs, modified_partition);
740 talloc_free(modified_partition);
748 created a replmd_replicated_request context
750 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
751 struct ldb_request *req)
753 struct ldb_context *ldb;
754 struct replmd_replicated_request *ac;
755 const struct GUID *our_invocation_id;
757 ldb = ldb_module_get_ctx(module);
759 ac = talloc_zero(req, struct replmd_replicated_request);
768 ac->schema = dsdb_get_schema(ldb, ac);
770 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
771 "replmd_modify: no dsdb_schema loaded");
772 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
777 /* get our invocationId */
778 our_invocation_id = samdb_ntds_invocation_id(ldb);
779 if (!our_invocation_id) {
780 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
781 "replmd_add: unable to find invocationId\n");
785 ac->our_invocation_id = *our_invocation_id;
791 add a time element to a record
793 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
795 struct ldb_message_element *el;
799 if (ldb_msg_find_element(msg, attr) != NULL) {
803 s = ldb_timestring(msg, t);
805 return LDB_ERR_OPERATIONS_ERROR;
808 ret = ldb_msg_add_string(msg, attr, s);
809 if (ret != LDB_SUCCESS) {
813 el = ldb_msg_find_element(msg, attr);
814 /* always set as replace. This works because on add ops, the flag
816 el->flags = LDB_FLAG_MOD_REPLACE;
822 add a uint64_t element to a record
824 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
825 const char *attr, uint64_t v)
827 struct ldb_message_element *el;
830 if (ldb_msg_find_element(msg, attr) != NULL) {
834 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
835 if (ret != LDB_SUCCESS) {
839 el = ldb_msg_find_element(msg, attr);
840 /* always set as replace. This works because on add ops, the flag
842 el->flags = LDB_FLAG_MOD_REPLACE;
847 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
848 const struct replPropertyMetaData1 *m2,
849 const uint32_t *rdn_attid)
852 * This assignment seems inoccous, but it is critical for the
853 * system, as we need to do the comparisons as a unsigned
854 * quantity, not signed (enums are signed integers)
856 uint32_t attid_1 = m1->attid;
857 uint32_t attid_2 = m2->attid;
859 if (attid_1 == attid_2) {
864 * See above regarding this being an unsigned comparison.
865 * Otherwise when the high bit is set on non-standard
866 * attributes, they would end up first, before objectClass
869 return attid_1 > attid_2 ? 1 : -1;
872 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
873 struct replPropertyMetaDataCtr1 *ctr1,
876 if (ctr1->count == 0) {
877 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
878 "No elements found in replPropertyMetaData for %s!\n",
879 ldb_dn_get_linearized(dn));
880 return LDB_ERR_CONSTRAINT_VIOLATION;
883 /* the objectClass attribute is value 0x00000000, so must be first */
884 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
885 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
886 "No objectClass found in replPropertyMetaData for %s!\n",
887 ldb_dn_get_linearized(dn));
888 return LDB_ERR_OBJECT_CLASS_VIOLATION;
894 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
895 struct replPropertyMetaDataCtr1 *ctr1,
898 /* Note this is O(n^2) for the almost-sorted case, which this is */
899 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
900 replmd_replPropertyMetaData1_attid_sort);
901 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
904 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
905 const struct ldb_message_element *e2,
906 const struct dsdb_schema *schema)
908 const struct dsdb_attribute *a1;
909 const struct dsdb_attribute *a2;
912 * TODO: make this faster by caching the dsdb_attribute pointer
913 * on the ldb_messag_element
916 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
917 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
920 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
924 return strcasecmp(e1->name, e2->name);
926 if (a1->attributeID_id == a2->attributeID_id) {
929 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
932 static void replmd_ldb_message_sort(struct ldb_message *msg,
933 const struct dsdb_schema *schema)
935 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
938 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
939 const struct GUID *invocation_id,
940 uint64_t local_usn, NTTIME nttime);
942 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2);
944 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
945 struct ldb_message_element *el, struct parsed_dn **pdn,
946 const char *ldap_oid, struct ldb_request *parent);
948 static int check_parsed_dn_duplicates(struct ldb_module *module,
949 struct ldb_message_element *el,
950 struct parsed_dn *pdn);
953 fix up linked attributes in replmd_add.
954 This involves setting up the right meta-data in extended DN
955 components, and creating backlinks to the object
957 static int replmd_add_fix_la(struct ldb_module *module, TALLOC_CTX *mem_ctx,
958 struct replmd_private *replmd_private,
959 struct ldb_message_element *el,
960 struct replmd_replicated_request *ac,
962 struct ldb_dn *forward_dn,
963 const struct dsdb_attribute *sa,
964 struct ldb_request *parent)
967 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
968 struct ldb_context *ldb = ldb_module_get_ctx(module);
969 struct parsed_dn *pdn;
970 /* We will take a reference to the schema in replmd_add_backlink */
971 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
972 struct ldb_val *new_values = NULL;
975 if (dsdb_check_single_valued_link(sa, el) == LDB_SUCCESS) {
976 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
978 ldb_asprintf_errstring(ldb,
979 "Attribute %s is single valued but "
980 "more than one value has been supplied",
982 talloc_free(tmp_ctx);
983 return LDB_ERR_CONSTRAINT_VIOLATION;
986 ret = get_parsed_dns(module, tmp_ctx, el, &pdn,
987 sa->syntax->ldap_oid, parent);
988 if (ret != LDB_SUCCESS) {
989 talloc_free(tmp_ctx);
993 ret = check_parsed_dn_duplicates(module, el, pdn);
994 if (ret != LDB_SUCCESS) {
995 talloc_free(tmp_ctx);
999 new_values = talloc_array(tmp_ctx, struct ldb_val, el->num_values);
1000 if (new_values == NULL) {
1001 ldb_module_oom(module);
1002 talloc_free(tmp_ctx);
1003 return LDB_ERR_OPERATIONS_ERROR;
1006 for (i = 0; i < el->num_values; i++) {
1007 struct parsed_dn *p = &pdn[i];
1008 ret = replmd_build_la_val(el->values, p->v, p->dsdb_dn,
1009 &ac->our_invocation_id,
1011 if (ret != LDB_SUCCESS) {
1012 talloc_free(tmp_ctx);
1016 ret = replmd_defer_add_backlink(module, replmd_private,
1018 forward_dn, &p->guid, true, sa,
1020 if (ret != LDB_SUCCESS) {
1021 talloc_free(tmp_ctx);
1025 new_values[i] = *p->v;
1027 el->values = talloc_steal(mem_ctx, new_values);
1029 talloc_free(tmp_ctx);
1033 static int replmd_add_make_extended_dn(struct ldb_request *req,
1034 const DATA_BLOB *guid_blob,
1035 struct ldb_dn **_extended_dn)
1038 const DATA_BLOB *sid_blob;
1039 /* Calculate an extended DN for any linked attributes */
1040 struct ldb_dn *extended_dn = ldb_dn_copy(req, req->op.add.message->dn);
1042 return LDB_ERR_OPERATIONS_ERROR;
1044 ret = ldb_dn_set_extended_component(extended_dn, "GUID", guid_blob);
1045 if (ret != LDB_SUCCESS) {
1049 sid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectSID");
1050 if (sid_blob != NULL) {
1051 ret = ldb_dn_set_extended_component(extended_dn, "SID", sid_blob);
1052 if (ret != LDB_SUCCESS) {
1056 *_extended_dn = extended_dn;
1061 intercept add requests
1063 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
1065 struct ldb_context *ldb;
1066 struct ldb_control *control;
1067 struct replmd_replicated_request *ac;
1068 enum ndr_err_code ndr_err;
1069 struct ldb_request *down_req;
1070 struct ldb_message *msg;
1071 const DATA_BLOB *guid_blob;
1072 DATA_BLOB guid_blob_stack;
1074 uint8_t guid_data[16];
1075 struct replPropertyMetaDataBlob nmd;
1076 struct ldb_val nmd_value;
1077 struct ldb_dn *extended_dn = NULL;
1080 * The use of a time_t here seems odd, but as the NTTIME
1081 * elements are actually declared as NTTIME_1sec in the IDL,
1082 * getting a higher resolution timestamp is not required.
1084 time_t t = time(NULL);
1089 unsigned int functional_level;
1091 bool allow_add_guid = false;
1092 bool remove_current_guid = false;
1093 bool is_urgent = false;
1094 bool is_schema_nc = false;
1095 struct ldb_message_element *objectclass_el;
1096 struct replmd_private *replmd_private =
1097 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
1099 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
1100 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
1102 allow_add_guid = true;
1105 /* do not manipulate our control entries */
1106 if (ldb_dn_is_special(req->op.add.message->dn)) {
1107 return ldb_next_request(module, req);
1110 ldb = ldb_module_get_ctx(module);
1112 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
1114 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
1115 if (guid_blob != NULL) {
1116 if (!allow_add_guid) {
1117 ldb_set_errstring(ldb,
1118 "replmd_add: it's not allowed to add an object with objectGUID!");
1119 return LDB_ERR_UNWILLING_TO_PERFORM;
1121 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
1122 if (!NT_STATUS_IS_OK(status)) {
1123 ldb_set_errstring(ldb,
1124 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1125 return LDB_ERR_UNWILLING_TO_PERFORM;
1127 /* we remove this attribute as it can be a string and
1128 * will not be treated correctly and then we will re-add
1129 * it later on in the good format */
1130 remove_current_guid = true;
1134 guid = GUID_random();
1136 guid_blob_stack = data_blob_const(guid_data, sizeof(guid_data));
1138 /* This can't fail */
1139 ndr_push_struct_into_fixed_blob(&guid_blob_stack, &guid,
1140 (ndr_push_flags_fn_t)ndr_push_GUID);
1141 guid_blob = &guid_blob_stack;
1144 ac = replmd_ctx_init(module, req);
1146 return ldb_module_oom(module);
1149 functional_level = dsdb_functional_level(ldb);
1151 /* Get a sequence number from the backend */
1152 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1153 if (ret != LDB_SUCCESS) {
1158 /* we have to copy the message as the caller might have it as a const */
1159 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1163 return LDB_ERR_OPERATIONS_ERROR;
1166 /* generated times */
1167 unix_to_nt_time(&now, t);
1168 time_str = ldb_timestring(msg, t);
1172 return LDB_ERR_OPERATIONS_ERROR;
1174 if (remove_current_guid) {
1175 ldb_msg_remove_attr(msg,"objectGUID");
1179 * remove autogenerated attributes
1181 ldb_msg_remove_attr(msg, "whenCreated");
1182 ldb_msg_remove_attr(msg, "whenChanged");
1183 ldb_msg_remove_attr(msg, "uSNCreated");
1184 ldb_msg_remove_attr(msg, "uSNChanged");
1185 ldb_msg_remove_attr(msg, "replPropertyMetaData");
1188 * readd replicated attributes
1190 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1191 if (ret != LDB_SUCCESS) {
1197 /* build the replication meta_data */
1200 nmd.ctr.ctr1.count = msg->num_elements;
1201 nmd.ctr.ctr1.array = talloc_array(msg,
1202 struct replPropertyMetaData1,
1203 nmd.ctr.ctr1.count);
1204 if (!nmd.ctr.ctr1.array) {
1207 return LDB_ERR_OPERATIONS_ERROR;
1210 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1212 for (i=0; i < msg->num_elements;) {
1213 struct ldb_message_element *e = &msg->elements[i];
1214 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1215 const struct dsdb_attribute *sa;
1217 if (e->name[0] == '@') {
1222 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1224 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1225 "replmd_add: attribute '%s' not defined in schema\n",
1228 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1231 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1232 /* if the attribute is not replicated (0x00000001)
1233 * or constructed (0x00000004) it has no metadata
1239 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1240 if (extended_dn == NULL) {
1241 ret = replmd_add_make_extended_dn(req,
1244 if (ret != LDB_SUCCESS) {
1251 * Prepare the context for the backlinks and
1252 * create metadata for the forward links. The
1253 * backlinks are created in
1254 * replmd_op_callback() after the successful
1255 * ADD of the object.
1257 ret = replmd_add_fix_la(module, msg->elements,
1262 if (ret != LDB_SUCCESS) {
1266 /* linked attributes are not stored in
1267 replPropertyMetaData in FL above w2k */
1272 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1274 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1275 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1278 if (rdn_val == NULL) {
1281 return LDB_ERR_OPERATIONS_ERROR;
1284 rdn = (const char*)rdn_val->data;
1285 if (strcmp(rdn, "Deleted Objects") == 0) {
1287 * Set the originating_change_time to 29/12/9999 at 23:59:59
1288 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1290 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1292 m->originating_change_time = now;
1295 m->originating_change_time = now;
1297 m->originating_invocation_id = ac->our_invocation_id;
1298 m->originating_usn = ac->seq_num;
1299 m->local_usn = ac->seq_num;
1302 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1307 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1309 if (e->num_values != 0) {
1314 ldb_msg_remove_element(msg, e);
1317 /* fix meta data count */
1318 nmd.ctr.ctr1.count = ni;
1321 * sort meta data array
1323 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1324 if (ret != LDB_SUCCESS) {
1325 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1330 /* generated NDR encoded values */
1331 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1333 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1334 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1337 return LDB_ERR_OPERATIONS_ERROR;
1341 * add the autogenerated values
1343 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1344 if (ret != LDB_SUCCESS) {
1349 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1350 if (ret != LDB_SUCCESS) {
1355 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1356 if (ret != LDB_SUCCESS) {
1361 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1362 if (ret != LDB_SUCCESS) {
1367 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1368 if (ret != LDB_SUCCESS) {
1375 * sort the attributes by attid before storing the object
1377 replmd_ldb_message_sort(msg, ac->schema);
1380 * Assert that we do have an objectClass
1382 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1383 if (objectclass_el == NULL) {
1384 ldb_asprintf_errstring(ldb, __location__
1385 ": objectClass missing on %s\n",
1386 ldb_dn_get_linearized(msg->dn));
1388 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1390 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1391 REPL_URGENT_ON_CREATE);
1393 ac->is_urgent = is_urgent;
1394 ret = ldb_build_add_req(&down_req, ldb, ac,
1397 ac, replmd_op_callback,
1400 LDB_REQ_SET_LOCATION(down_req);
1401 if (ret != LDB_SUCCESS) {
1406 /* current partition control is needed by "replmd_op_callback" */
1407 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1408 ret = ldb_request_add_control(down_req,
1409 DSDB_CONTROL_CURRENT_PARTITION_OID,
1411 if (ret != LDB_SUCCESS) {
1417 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1418 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1419 if (ret != LDB_SUCCESS) {
1425 /* mark the control done */
1427 control->critical = 0;
1429 /* go on with the call chain */
1430 return ldb_next_request(module, down_req);
1435 * update the replPropertyMetaData for one element
1437 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1438 struct ldb_message *msg,
1439 struct ldb_message_element *el,
1440 struct ldb_message_element *old_el,
1441 struct replPropertyMetaDataBlob *omd,
1442 const struct dsdb_schema *schema,
1444 const struct GUID *our_invocation_id,
1447 bool is_forced_rodc,
1448 struct ldb_request *req)
1451 const struct dsdb_attribute *a;
1452 struct replPropertyMetaData1 *md1;
1453 bool may_skip = false;
1456 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1458 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1459 /* allow this to make it possible for dbcheck
1460 to remove bad attributes */
1464 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1466 return LDB_ERR_OPERATIONS_ERROR;
1469 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1471 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1476 * if the attribute's value haven't changed, and this isn't
1477 * just a delete of everything then return LDB_SUCCESS Unless
1478 * we have the provision control or if the attribute is
1479 * interSiteTopologyGenerator as this page explain:
1480 * http://support.microsoft.com/kb/224815 this attribute is
1481 * periodicaly written by the DC responsible for the intersite
1482 * generation in a given site
1484 * Unchanged could be deleting or replacing an already-gone
1485 * thing with an unconstrained delete/empty replace or a
1486 * replace with the same value, but not an add with the same
1487 * value because that could be about adding a duplicate (which
1488 * is for someone else to error out on).
1490 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1491 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1494 } else if (old_el == NULL && el->num_values == 0) {
1495 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1497 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1500 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1501 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1503 * We intentionally skip the version bump when attempting to
1506 * The control is set by dbcheck and expunge-tombstones which
1507 * both attempt to be non-replicating. Otherwise, making an
1508 * alteration to the replication state would trigger a
1509 * broadcast of all expunged objects.
1514 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1516 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1520 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1521 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1523 * allow this to make it possible for dbcheck
1524 * to rebuild broken metadata
1530 for (i=0; i<omd->ctr.ctr1.count; i++) {
1532 * First check if we find it under the msDS-IntID,
1533 * then check if we find it under the OID and
1536 * This allows the administrator to simply re-write
1537 * the attributes and so restore replication, which is
1538 * likely what they will try to do.
1540 if (attid == omd->ctr.ctr1.array[i].attid) {
1544 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1549 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1550 /* linked attributes are not stored in
1551 replPropertyMetaData in FL above w2k, but we do
1552 raise the seqnum for the object */
1553 if (*seq_num == 0 &&
1554 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1555 return LDB_ERR_OPERATIONS_ERROR;
1560 if (i == omd->ctr.ctr1.count) {
1561 /* we need to add a new one */
1562 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1563 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1564 if (omd->ctr.ctr1.array == NULL) {
1566 return LDB_ERR_OPERATIONS_ERROR;
1568 omd->ctr.ctr1.count++;
1569 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1572 /* Get a new sequence number from the backend. We only do this
1573 * if we have a change that requires a new
1574 * replPropertyMetaData element
1576 if (*seq_num == 0) {
1577 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1578 if (ret != LDB_SUCCESS) {
1579 return LDB_ERR_OPERATIONS_ERROR;
1583 md1 = &omd->ctr.ctr1.array[i];
1587 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1588 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1591 if (rdn_val == NULL) {
1593 return LDB_ERR_OPERATIONS_ERROR;
1596 rdn = (const char*)rdn_val->data;
1597 if (strcmp(rdn, "Deleted Objects") == 0) {
1599 * Set the originating_change_time to 29/12/9999 at 23:59:59
1600 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1602 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1604 md1->originating_change_time = now;
1607 md1->originating_change_time = now;
1609 md1->originating_invocation_id = *our_invocation_id;
1610 md1->originating_usn = *seq_num;
1611 md1->local_usn = *seq_num;
1613 if (is_forced_rodc) {
1614 /* Force version to 0 to be overriden later via replication */
1622 * Bump the replPropertyMetaData version on an attribute, and if it
1623 * has changed (or forced by leaving rdn_old NULL), update the value
1626 * This is important, as calling a modify operation may not change the
1627 * version number if the values appear unchanged, but a rename between
1628 * parents bumps this value.
1631 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1632 struct ldb_message *msg,
1633 const struct ldb_val *rdn_new,
1634 const struct ldb_val *rdn_old,
1635 struct replPropertyMetaDataBlob *omd,
1636 struct replmd_replicated_request *ar,
1639 bool is_forced_rodc)
1641 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1642 const struct dsdb_attribute *rdn_attr =
1643 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1644 const char *attr_name = rdn_attr != NULL ?
1645 rdn_attr->lDAPDisplayName :
1647 struct ldb_message_element new_el = {
1648 .flags = LDB_FLAG_MOD_REPLACE,
1651 .values = discard_const_p(struct ldb_val, rdn_new)
1653 struct ldb_message_element old_el = {
1654 .flags = LDB_FLAG_MOD_REPLACE,
1656 .num_values = rdn_old ? 1 : 0,
1657 .values = discard_const_p(struct ldb_val, rdn_old)
1660 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1661 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1662 if (ret != LDB_SUCCESS) {
1663 return ldb_oom(ldb);
1667 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1668 omd, ar->schema, &ar->seq_num,
1669 &ar->our_invocation_id,
1670 now, is_schema_nc, is_forced_rodc,
1675 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1677 uint32_t count = omd.ctr.ctr1.count;
1680 for (i=0; i < count; i++) {
1681 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1682 if (max < m.local_usn) {
1690 * update the replPropertyMetaData object each time we modify an
1691 * object. This is needed for DRS replication, as the merge on the
1692 * client is based on this object
1694 static int replmd_update_rpmd(struct ldb_module *module,
1695 const struct dsdb_schema *schema,
1696 struct ldb_request *req,
1697 const char * const *rename_attrs,
1698 struct ldb_message *msg, uint64_t *seq_num,
1699 time_t t, bool is_schema_nc,
1700 bool *is_urgent, bool *rodc)
1702 const struct ldb_val *omd_value;
1703 enum ndr_err_code ndr_err;
1704 struct replPropertyMetaDataBlob omd;
1707 const struct GUID *our_invocation_id;
1709 const char * const *attrs = NULL;
1710 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1711 struct ldb_result *res;
1712 struct ldb_context *ldb;
1713 struct ldb_message_element *objectclass_el;
1714 enum urgent_situation situation;
1715 bool rmd_is_provided;
1716 bool rmd_is_just_resorted = false;
1717 const char *not_rename_attrs[4 + msg->num_elements];
1718 bool is_forced_rodc = false;
1721 attrs = rename_attrs;
1723 for (i = 0; i < msg->num_elements; i++) {
1724 not_rename_attrs[i] = msg->elements[i].name;
1726 not_rename_attrs[i] = "replPropertyMetaData";
1727 not_rename_attrs[i+1] = "objectClass";
1728 not_rename_attrs[i+2] = "instanceType";
1729 not_rename_attrs[i+3] = NULL;
1730 attrs = not_rename_attrs;
1733 ldb = ldb_module_get_ctx(module);
1735 ret = samdb_rodc(ldb, rodc);
1736 if (ret != LDB_SUCCESS) {
1737 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1742 ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE)) {
1743 is_forced_rodc = true;
1746 our_invocation_id = samdb_ntds_invocation_id(ldb);
1747 if (!our_invocation_id) {
1748 /* this happens during an initial vampire while
1749 updating the schema */
1750 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1754 unix_to_nt_time(&now, t);
1756 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1757 rmd_is_provided = true;
1758 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1759 rmd_is_just_resorted = true;
1762 rmd_is_provided = false;
1765 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1766 * otherwise we consider we are updating */
1767 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1768 situation = REPL_URGENT_ON_DELETE;
1769 } else if (rename_attrs) {
1770 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1772 situation = REPL_URGENT_ON_UPDATE;
1775 if (rmd_is_provided) {
1776 /* In this case the change_replmetadata control was supplied */
1777 /* We check that it's the only attribute that is provided
1778 * (it's a rare case so it's better to keep the code simplier)
1779 * We also check that the highest local_usn is bigger or the same as
1782 if( msg->num_elements != 1 ||
1783 strncmp(msg->elements[0].name,
1784 "replPropertyMetaData", 20) ) {
1785 DEBUG(0,(__location__ ": changereplmetada control called without "\
1786 "a specified replPropertyMetaData attribute or with others\n"));
1787 return LDB_ERR_OPERATIONS_ERROR;
1789 if (situation != REPL_URGENT_ON_UPDATE) {
1790 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1791 return LDB_ERR_OPERATIONS_ERROR;
1793 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1795 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1796 ldb_dn_get_linearized(msg->dn)));
1797 return LDB_ERR_OPERATIONS_ERROR;
1799 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1800 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1801 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1802 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1803 ldb_dn_get_linearized(msg->dn)));
1804 return LDB_ERR_OPERATIONS_ERROR;
1807 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1808 DSDB_FLAG_NEXT_MODULE |
1809 DSDB_SEARCH_SHOW_RECYCLED |
1810 DSDB_SEARCH_SHOW_EXTENDED_DN |
1811 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1812 DSDB_SEARCH_REVEAL_INTERNALS, req);
1814 if (ret != LDB_SUCCESS) {
1818 if (rmd_is_just_resorted == false) {
1819 *seq_num = find_max_local_usn(omd);
1821 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1824 * The test here now allows for a new
1825 * replPropertyMetaData with no change, if was
1826 * just dbcheck re-sorting the values.
1828 if (*seq_num <= db_seq) {
1829 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1830 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1831 (long long)*seq_num, (long long)db_seq));
1832 return LDB_ERR_OPERATIONS_ERROR;
1837 /* search for the existing replPropertyMetaDataBlob. We need
1838 * to use REVEAL and ask for DNs in storage format to support
1839 * the check for values being the same in
1840 * replmd_update_rpmd_element()
1842 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1843 DSDB_FLAG_NEXT_MODULE |
1844 DSDB_SEARCH_SHOW_RECYCLED |
1845 DSDB_SEARCH_SHOW_EXTENDED_DN |
1846 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1847 DSDB_SEARCH_REVEAL_INTERNALS, req);
1848 if (ret != LDB_SUCCESS) {
1852 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1854 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1855 ldb_dn_get_linearized(msg->dn)));
1856 return LDB_ERR_OPERATIONS_ERROR;
1859 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1860 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1861 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1862 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1863 ldb_dn_get_linearized(msg->dn)));
1864 return LDB_ERR_OPERATIONS_ERROR;
1867 if (omd.version != 1) {
1868 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1869 omd.version, ldb_dn_get_linearized(msg->dn)));
1870 return LDB_ERR_OPERATIONS_ERROR;
1873 for (i=0; i<msg->num_elements;) {
1874 struct ldb_message_element *el = &msg->elements[i];
1875 struct ldb_message_element *old_el;
1877 old_el = ldb_msg_find_element(res->msgs[0], el->name);
1878 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1879 &omd, schema, seq_num,
1884 if (ret != LDB_SUCCESS) {
1888 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1889 *is_urgent = replmd_check_urgent_attribute(el);
1892 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1897 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1899 if (el->num_values != 0) {
1904 ldb_msg_remove_element(msg, el);
1909 * Assert that we have an objectClass attribute - this is major
1910 * corruption if we don't have this!
1912 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1913 if (objectclass_el != NULL) {
1915 * Now check if this objectClass means we need to do urgent replication
1917 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1921 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1922 ldb_asprintf_errstring(ldb, __location__
1923 ": objectClass missing on %s\n",
1924 ldb_dn_get_linearized(msg->dn));
1925 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1929 * replmd_update_rpmd_element has done an update if the
1932 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1933 struct ldb_val *md_value;
1934 struct ldb_message_element *el;
1936 /*if we are RODC and this is a DRSR update then its ok*/
1937 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1938 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)
1939 && !is_forced_rodc) {
1940 unsigned instanceType;
1943 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1944 return LDB_ERR_REFERRAL;
1947 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1948 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1949 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1950 "cannot change replicated attribute on partial replica");
1954 md_value = talloc(msg, struct ldb_val);
1955 if (md_value == NULL) {
1957 return LDB_ERR_OPERATIONS_ERROR;
1960 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1961 if (ret != LDB_SUCCESS) {
1962 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1966 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1967 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1968 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1969 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1970 ldb_dn_get_linearized(msg->dn)));
1971 return LDB_ERR_OPERATIONS_ERROR;
1974 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1975 if (ret != LDB_SUCCESS) {
1976 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1977 ldb_dn_get_linearized(msg->dn)));
1982 el->values = md_value;
1988 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1990 int ret = ndr_guid_compare(&pdn1->guid, &pdn2->guid);
1992 return data_blob_cmp(&pdn1->dsdb_dn->extra_part,
1993 &pdn2->dsdb_dn->extra_part);
1999 get a series of message element values as an array of DNs and GUIDs
2000 the result is sorted by GUID
2002 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
2003 struct ldb_message_element *el, struct parsed_dn **pdn,
2004 const char *ldap_oid, struct ldb_request *parent)
2007 bool values_are_sorted = true;
2008 struct ldb_context *ldb = ldb_module_get_ctx(module);
2015 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
2017 ldb_module_oom(module);
2018 return LDB_ERR_OPERATIONS_ERROR;
2021 for (i=0; i<el->num_values; i++) {
2022 struct ldb_val *v = &el->values[i];
2025 struct parsed_dn *p;
2029 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
2030 if (p->dsdb_dn == NULL) {
2031 return LDB_ERR_INVALID_DN_SYNTAX;
2034 dn = p->dsdb_dn->dn;
2036 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
2037 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
2038 unlikely(GUID_all_zero(&p->guid))) {
2039 /* we got a DN without a GUID - go find the GUID */
2040 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
2041 if (ret != LDB_SUCCESS) {
2042 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
2043 ldb_dn_get_linearized(dn));
2044 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
2045 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
2046 ldb_attr_cmp(el->name, "member") == 0) {
2047 return LDB_ERR_UNWILLING_TO_PERFORM;
2051 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
2052 if (ret != LDB_SUCCESS) {
2055 } else if (!NT_STATUS_IS_OK(status)) {
2056 return LDB_ERR_OPERATIONS_ERROR;
2058 if (i > 0 && values_are_sorted) {
2059 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2061 values_are_sorted = false;
2064 /* keep a pointer to the original ldb_val */
2067 if (! values_are_sorted) {
2068 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2074 * Get a series of trusted message element values. The result is sorted by
2075 * GUID, even though the GUIDs might not be known. That works because we trust
2076 * the database to give us the elements like that if the
2077 * replmd_private->sorted_links flag is set.
2079 * We also ensure that the links are in the Functional Level 2003
2080 * linked attributes format.
2082 static int get_parsed_dns_trusted(struct ldb_module *module,
2083 struct replmd_private *replmd_private,
2084 TALLOC_CTX *mem_ctx,
2085 struct ldb_message_element *el,
2086 struct parsed_dn **pdn,
2087 const char *ldap_oid,
2088 struct ldb_request *parent)
2097 if (!replmd_private->sorted_links) {
2098 /* We need to sort the list. This is the slow old path we want
2101 ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2103 if (ret != LDB_SUCCESS) {
2107 /* Here we get a list of 'struct parsed_dns' without the parsing */
2108 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2111 ldb_module_oom(module);
2112 return LDB_ERR_OPERATIONS_ERROR;
2115 for (i = 0; i < el->num_values; i++) {
2116 (*pdn)[i].v = &el->values[i];
2121 * This upgrades links to FL2003 style, and sorts the result
2122 * if that was needed.
2124 * TODO: Add a database feature that asserts we have no FL2000
2125 * style links to avoid this check or add a feature that
2126 * uses a similar check to find sorted/unsorted links
2127 * for an on-the-fly upgrade.
2130 ret = replmd_check_upgrade_links(ldb_module_get_ctx(module),
2131 *pdn, el->num_values,
2134 if (ret != LDB_SUCCESS) {
2142 Return LDB_SUCCESS if a parsed_dn list contains no duplicate values,
2143 otherwise an error code. For compatibility the error code differs depending
2144 on whether or not the attribute is "member".
2146 As always, the parsed_dn list is assumed to be sorted.
2148 static int check_parsed_dn_duplicates(struct ldb_module *module,
2149 struct ldb_message_element *el,
2150 struct parsed_dn *pdn)
2153 struct ldb_context *ldb = ldb_module_get_ctx(module);
2155 for (i = 1; i < el->num_values; i++) {
2156 struct parsed_dn *p = &pdn[i];
2157 if (parsed_dn_compare(p, &pdn[i - 1]) == 0) {
2158 ldb_asprintf_errstring(ldb,
2159 "Linked attribute %s has "
2160 "multiple identical values",
2162 if (ldb_attr_cmp(el->name, "member") == 0) {
2163 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2165 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2173 build a new extended DN, including all meta data fields
2175 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2176 RMD_ADDTIME = originating_add_time
2177 RMD_INVOCID = originating_invocation_id
2178 RMD_CHANGETIME = originating_change_time
2179 RMD_ORIGINATING_USN = originating_usn
2180 RMD_LOCAL_USN = local_usn
2181 RMD_VERSION = version
2183 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v,
2184 struct dsdb_dn *dsdb_dn,
2185 const struct GUID *invocation_id,
2186 uint64_t local_usn, NTTIME nttime)
2188 return replmd_set_la_val(mem_ctx, v, dsdb_dn, NULL, invocation_id,
2189 local_usn, local_usn, nttime,
2190 RMD_VERSION_INITIAL, false);
2193 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2194 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2195 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2199 check if any links need upgrading from w2k format
2201 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2202 struct parsed_dn *dns, uint32_t count,
2203 struct ldb_message_element *el,
2204 const char *ldap_oid)
2207 const struct GUID *invocation_id = NULL;
2208 for (i=0; i<count; i++) {
2212 if (dns[i].dsdb_dn == NULL) {
2213 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2215 if (ret != LDB_SUCCESS) {
2216 return LDB_ERR_INVALID_DN_SYNTAX;
2220 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2221 &version, "RMD_VERSION");
2222 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2224 * We optimistically assume they are all the same; if
2225 * the first one is fixed, they are all fixed.
2227 * If the first one was *not* fixed and we find a
2228 * later one that is, that is an occasion to shout
2234 DEBUG(0, ("Mixed w2k and fixed format "
2235 "linked attributes\n"));
2239 if (invocation_id == NULL) {
2240 invocation_id = samdb_ntds_invocation_id(ldb);
2241 if (invocation_id == NULL) {
2242 return LDB_ERR_OPERATIONS_ERROR;
2247 /* it's an old one that needs upgrading */
2248 ret = replmd_update_la_val(el->values, dns[i].v,
2249 dns[i].dsdb_dn, dns[i].dsdb_dn,
2250 invocation_id, 1, 1, 0, false);
2251 if (ret != LDB_SUCCESS) {
2257 * This sort() is critical for the operation of
2258 * get_parsed_dns_trusted() because callers of this function
2259 * expect a sorted list, and FL2000 style links are not
2260 * sorted. In particular, as well as the upgrade case,
2261 * get_parsed_dns_trusted() is called from
2262 * replmd_delete_remove_link() even in FL2000 mode
2264 * We do not normally pay the cost of the qsort() due to the
2265 * early return in the RMD_VERSION found case.
2267 TYPESAFE_QSORT(dns, count, parsed_dn_compare);
2272 Sets the value for a linked attribute, including all meta data fields
2274 see replmd_build_la_val for value names
2276 static int replmd_set_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2277 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2278 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2279 uint32_t version, bool deleted)
2281 struct ldb_dn *dn = dsdb_dn->dn;
2282 const char *tstring, *usn_string, *flags_string;
2283 struct ldb_val tval;
2285 struct ldb_val usnv, local_usnv;
2286 struct ldb_val vers, flagsv;
2287 const struct ldb_val *old_addtime = NULL;
2290 const char *dnstring;
2292 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2294 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2296 return LDB_ERR_OPERATIONS_ERROR;
2298 tval = data_blob_string_const(tstring);
2300 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2302 return LDB_ERR_OPERATIONS_ERROR;
2304 usnv = data_blob_string_const(usn_string);
2306 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2308 return LDB_ERR_OPERATIONS_ERROR;
2310 local_usnv = data_blob_string_const(usn_string);
2312 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2313 if (!NT_STATUS_IS_OK(status)) {
2314 return LDB_ERR_OPERATIONS_ERROR;
2317 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2318 if (!flags_string) {
2319 return LDB_ERR_OPERATIONS_ERROR;
2321 flagsv = data_blob_string_const(flags_string);
2323 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2324 if (ret != LDB_SUCCESS) return ret;
2326 /* get the ADDTIME from the original */
2327 if (old_dsdb_dn != NULL) {
2328 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn,
2331 if (old_addtime == NULL) {
2332 old_addtime = &tval;
2334 if (dsdb_dn != old_dsdb_dn ||
2335 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2336 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2337 if (ret != LDB_SUCCESS) return ret;
2340 /* use our invocation id */
2341 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2342 if (ret != LDB_SUCCESS) return ret;
2344 /* changetime is the current time */
2345 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2346 if (ret != LDB_SUCCESS) return ret;
2348 /* update the USN */
2349 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2350 if (ret != LDB_SUCCESS) return ret;
2352 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2353 if (ret != LDB_SUCCESS) return ret;
2355 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2356 vers = data_blob_string_const(vstring);
2357 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2358 if (ret != LDB_SUCCESS) return ret;
2360 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2361 if (dnstring == NULL) {
2362 return LDB_ERR_OPERATIONS_ERROR;
2364 *v = data_blob_string_const(dnstring);
2370 * Updates the value for a linked attribute, including all meta data fields
2372 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2373 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2374 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2377 uint32_t old_version;
2378 uint32_t version = RMD_VERSION_INITIAL;
2382 * We're updating the linked attribute locally, so increase the version
2383 * by 1 so that other DCs will see the change when it gets replicated out
2385 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version,
2388 if (NT_STATUS_IS_OK(status)) {
2389 version = old_version + 1;
2392 return replmd_set_la_val(mem_ctx, v, dsdb_dn, old_dsdb_dn, invocation_id,
2393 usn, local_usn, nttime, version, deleted);
2397 handle adding a linked attribute
2399 static int replmd_modify_la_add(struct ldb_module *module,
2400 struct replmd_private *replmd_private,
2401 const struct dsdb_schema *schema,
2402 struct ldb_message *msg,
2403 struct ldb_message_element *el,
2404 struct ldb_message_element *old_el,
2405 const struct dsdb_attribute *schema_attr,
2408 struct ldb_dn *msg_dn,
2409 struct ldb_request *parent)
2412 struct parsed_dn *dns, *old_dns;
2413 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2415 struct ldb_val *new_values = NULL;
2416 unsigned old_num_values = old_el ? old_el->num_values : 0;
2417 unsigned num_values = 0;
2418 unsigned max_num_values;
2419 const struct GUID *invocation_id;
2420 struct ldb_context *ldb = ldb_module_get_ctx(module);
2422 unix_to_nt_time(&now, t);
2424 invocation_id = samdb_ntds_invocation_id(ldb);
2425 if (!invocation_id) {
2426 talloc_free(tmp_ctx);
2427 return LDB_ERR_OPERATIONS_ERROR;
2430 /* get the DNs to be added, fully parsed.
2432 * We need full parsing because they came off the wire and we don't
2433 * trust them, besides which we need their details to know where to put
2436 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2437 schema_attr->syntax->ldap_oid, parent);
2438 if (ret != LDB_SUCCESS) {
2439 talloc_free(tmp_ctx);
2443 /* get the existing DNs, lazily parsed */
2444 ret = get_parsed_dns_trusted(module, replmd_private,
2445 tmp_ctx, old_el, &old_dns,
2446 schema_attr->syntax->ldap_oid, parent);
2448 if (ret != LDB_SUCCESS) {
2449 talloc_free(tmp_ctx);
2453 max_num_values = old_num_values + el->num_values;
2454 if (max_num_values < old_num_values) {
2455 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2456 "old values: %u, new values: %u, sum: %u",
2457 old_num_values, el->num_values, max_num_values));
2458 talloc_free(tmp_ctx);
2459 return LDB_ERR_OPERATIONS_ERROR;
2462 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2464 if (new_values == NULL) {
2465 ldb_module_oom(module);
2466 talloc_free(tmp_ctx);
2467 return LDB_ERR_OPERATIONS_ERROR;
2471 * For each new value, find where it would go in the list. If there is
2472 * a matching GUID there, we update the existing value; otherwise we
2476 for (i = 0; i < el->num_values; i++) {
2477 struct parsed_dn *exact;
2478 struct parsed_dn *next;
2480 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2483 dns[i].dsdb_dn->extra_part, 0,
2485 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, false);
2527 if (ret != LDB_SUCCESS) {
2528 talloc_free(tmp_ctx);
2532 ret = replmd_add_backlink(module, replmd_private,
2539 if (ret != LDB_SUCCESS) {
2540 talloc_free(tmp_ctx);
2546 * Here we don't have an exact match.
2548 * If next is NULL, this one goes beyond the end of the
2549 * existing list, so we need to add all of those ones first.
2551 * If next is not NULL, we need to add all the ones before
2555 offset = old_num_values;
2557 /* next should have been parsed, but let's make sure */
2558 if (next->dsdb_dn == NULL) {
2559 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2560 schema_attr->syntax->ldap_oid);
2561 if (ret != LDB_SUCCESS) {
2565 offset = MIN(next - old_dns, old_num_values);
2568 /* put all the old ones before next on the list */
2569 for (; j < offset; j++) {
2570 new_values[num_values] = *old_dns[j].v;
2574 ret = replmd_add_backlink(module, replmd_private,
2579 /* Make the new linked attribute ldb_val. */
2580 ret = replmd_build_la_val(new_values, &new_values[num_values],
2581 dns[i].dsdb_dn, invocation_id,
2583 if (ret != LDB_SUCCESS) {
2584 talloc_free(tmp_ctx);
2588 if (ret != LDB_SUCCESS) {
2589 talloc_free(tmp_ctx);
2593 /* copy the rest of the old ones (if any) */
2594 for (; j < old_num_values; j++) {
2595 new_values[num_values] = *old_dns[j].v;
2599 talloc_steal(msg->elements, new_values);
2600 if (old_el != NULL) {
2601 talloc_steal(msg->elements, old_el->values);
2603 el->values = new_values;
2604 el->num_values = num_values;
2606 talloc_free(tmp_ctx);
2608 /* we now tell the backend to replace all existing values
2609 with the one we have constructed */
2610 el->flags = LDB_FLAG_MOD_REPLACE;
2617 handle deleting all active linked attributes
2619 static int replmd_modify_la_delete(struct ldb_module *module,
2620 struct replmd_private *replmd_private,
2621 const struct dsdb_schema *schema,
2622 struct ldb_message *msg,
2623 struct ldb_message_element *el,
2624 struct ldb_message_element *old_el,
2625 const struct dsdb_attribute *schema_attr,
2628 struct ldb_dn *msg_dn,
2629 struct ldb_request *parent)
2632 struct parsed_dn *dns, *old_dns;
2633 TALLOC_CTX *tmp_ctx = NULL;
2635 struct ldb_context *ldb = ldb_module_get_ctx(module);
2636 struct ldb_control *vanish_links_ctrl = NULL;
2637 bool vanish_links = false;
2638 unsigned int num_to_delete = el->num_values;
2640 const struct GUID *invocation_id;
2643 unix_to_nt_time(&now, t);
2645 invocation_id = samdb_ntds_invocation_id(ldb);
2646 if (!invocation_id) {
2647 return LDB_ERR_OPERATIONS_ERROR;
2650 if (old_el == NULL || old_el->num_values == 0) {
2651 /* there is nothing to delete... */
2652 if (num_to_delete == 0) {
2653 /* and we're deleting nothing, so that's OK */
2656 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2659 tmp_ctx = talloc_new(msg);
2660 if (tmp_ctx == NULL) {
2661 return LDB_ERR_OPERATIONS_ERROR;
2664 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2665 schema_attr->syntax->ldap_oid, parent);
2666 if (ret != LDB_SUCCESS) {
2667 talloc_free(tmp_ctx);
2671 ret = get_parsed_dns_trusted(module, replmd_private,
2672 tmp_ctx, old_el, &old_dns,
2673 schema_attr->syntax->ldap_oid, parent);
2675 if (ret != LDB_SUCCESS) {
2676 talloc_free(tmp_ctx);
2681 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2682 if (vanish_links_ctrl) {
2683 vanish_links = true;
2684 vanish_links_ctrl->critical = false;
2688 /* we empty out el->values here to avoid damage if we return early. */
2693 * If vanish links is set, we are actually removing members of
2694 * old_el->values; otherwise we are just marking them deleted.
2696 * There is a special case when no values are given: we remove them
2697 * all. When we have the vanish_links control we just have to remove
2698 * the backlinks and change our element to replace the existing values
2699 * with the empty list.
2702 if (num_to_delete == 0) {
2703 for (i = 0; i < old_el->num_values; i++) {
2704 struct parsed_dn *p = &old_dns[i];
2705 if (p->dsdb_dn == NULL) {
2706 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2707 schema_attr->syntax->ldap_oid);
2708 if (ret != LDB_SUCCESS) {
2712 ret = replmd_add_backlink(module, replmd_private,
2713 schema, msg_dn, &p->guid,