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 nc_entry *prev, *next;
66 uint64_t mod_usn_urgent;
68 struct ldb_dn *schema_dn;
69 bool originating_updates;
74 struct la_entry *next, *prev;
75 struct drsuapi_DsReplicaLinkedAttribute *la;
78 struct replmd_replicated_request {
79 struct ldb_module *module;
80 struct ldb_request *req;
82 const struct dsdb_schema *schema;
83 struct GUID our_invocation_id;
85 /* the controls we pass down */
86 struct ldb_control **controls;
89 * Backlinks for the replmd_add() case (we want to create
90 * backlinks after creating the user, but before the end of
93 struct la_backlink *la_backlinks;
95 /* details for the mode where we apply a bunch of inbound replication meessages */
97 uint32_t index_current;
98 struct dsdb_extended_replicated_objects *objs;
100 struct ldb_message *search_msg;
101 struct GUID local_parent_guid;
110 struct dsdb_dn *dsdb_dn;
115 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
116 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
117 static int replmd_check_upgrade_links(struct ldb_context *ldb,
118 struct parsed_dn *dns, uint32_t count,
119 struct ldb_message_element *el,
120 const char *ldap_oid);
122 enum urgent_situation {
123 REPL_URGENT_ON_CREATE = 1,
124 REPL_URGENT_ON_UPDATE = 2,
125 REPL_URGENT_ON_DELETE = 4
128 enum deletion_state {
129 OBJECT_NOT_DELETED=1,
136 static void replmd_deletion_state(struct ldb_module *module,
137 const struct ldb_message *msg,
138 enum deletion_state *current_state,
139 enum deletion_state *next_state)
142 bool enabled = false;
145 *current_state = OBJECT_REMOVED;
146 if (next_state != NULL) {
147 *next_state = OBJECT_REMOVED;
152 ret = dsdb_recyclebin_enabled(module, &enabled);
153 if (ret != LDB_SUCCESS) {
157 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
159 *current_state = OBJECT_TOMBSTONE;
160 if (next_state != NULL) {
161 *next_state = OBJECT_REMOVED;
166 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
167 *current_state = OBJECT_RECYCLED;
168 if (next_state != NULL) {
169 *next_state = OBJECT_REMOVED;
174 *current_state = OBJECT_DELETED;
175 if (next_state != NULL) {
176 *next_state = OBJECT_RECYCLED;
181 *current_state = OBJECT_NOT_DELETED;
182 if (next_state == NULL) {
187 *next_state = OBJECT_DELETED;
189 *next_state = OBJECT_TOMBSTONE;
193 static const struct {
194 const char *update_name;
195 enum urgent_situation repl_situation;
196 } urgent_objects[] = {
197 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
198 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
199 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
200 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
201 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
202 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
206 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
207 static const char *urgent_attrs[] = {
210 "userAccountControl",
215 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
216 enum urgent_situation situation)
219 for (i=0; urgent_objects[i].update_name; i++) {
221 if ((situation & urgent_objects[i].repl_situation) == 0) {
225 for (j=0; j<objectclass_el->num_values; j++) {
226 const struct ldb_val *v = &objectclass_el->values[j];
227 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
235 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
237 if (ldb_attr_in_list(urgent_attrs, el->name)) {
244 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
247 initialise the module
248 allocate the private structure and build the list
249 of partition DNs for use by replmd_notify()
251 static int replmd_init(struct ldb_module *module)
253 struct replmd_private *replmd_private;
254 struct ldb_context *ldb = ldb_module_get_ctx(module);
255 static const char *samba_dsdb_attrs[] = { SAMBA_COMPATIBLE_FEATURES_ATTR, NULL };
256 struct ldb_dn *samba_dsdb_dn;
257 struct ldb_result *res;
259 TALLOC_CTX *frame = talloc_stackframe();
260 replmd_private = talloc_zero(module, struct replmd_private);
261 if (replmd_private == NULL) {
264 return LDB_ERR_OPERATIONS_ERROR;
266 ldb_module_set_private(module, replmd_private);
268 replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
270 samba_dsdb_dn = ldb_dn_new(frame, ldb, "@SAMBA_DSDB");
271 if (!samba_dsdb_dn) {
276 ret = dsdb_module_search_dn(module, frame, &res, samba_dsdb_dn,
277 samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
278 if (ret == LDB_SUCCESS) {
279 replmd_private->sorted_links
280 = ldb_msg_check_string_attribute(res->msgs[0],
281 SAMBA_COMPATIBLE_FEATURES_ATTR,
282 SAMBA_SORTED_LINKS_FEATURE);
286 return ldb_next_init(module);
290 cleanup our per-transaction contexts
292 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
294 talloc_free(replmd_private->la_ctx);
295 replmd_private->la_list = NULL;
296 replmd_private->la_ctx = NULL;
302 struct la_backlink *next, *prev;
303 const char *attr_name;
304 struct ldb_dn *forward_dn;
305 struct GUID target_guid;
310 a ldb_modify request operating on modules below the
313 static int linked_attr_modify(struct ldb_module *module,
314 const struct ldb_message *message,
315 struct ldb_request *parent)
317 struct ldb_request *mod_req;
319 struct ldb_context *ldb = ldb_module_get_ctx(module);
320 TALLOC_CTX *tmp_ctx = talloc_new(module);
321 struct ldb_result *res;
323 res = talloc_zero(tmp_ctx, struct ldb_result);
325 talloc_free(tmp_ctx);
326 return ldb_oom(ldb_module_get_ctx(module));
329 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
333 ldb_modify_default_callback,
335 LDB_REQ_SET_LOCATION(mod_req);
336 if (ret != LDB_SUCCESS) {
337 talloc_free(tmp_ctx);
341 ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
343 if (ret != LDB_SUCCESS) {
347 /* Run the new request */
348 ret = ldb_next_request(module, mod_req);
350 if (ret == LDB_SUCCESS) {
351 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
354 talloc_free(tmp_ctx);
359 process a backlinks we accumulated during a transaction, adding and
360 deleting the backlinks from the target objects
362 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
364 struct ldb_dn *target_dn, *source_dn;
366 struct ldb_context *ldb = ldb_module_get_ctx(module);
367 struct ldb_message *msg;
368 TALLOC_CTX *frame = talloc_stackframe();
374 - construct ldb_message
375 - either an add or a delete
377 ret = dsdb_module_dn_by_guid(module, frame, &bl->target_guid, &target_dn, parent);
378 if (ret != LDB_SUCCESS) {
379 struct GUID_txt_buf guid_str;
380 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
381 GUID_buf_string(&bl->target_guid, &guid_str)));
386 msg = ldb_msg_new(frame);
388 ldb_module_oom(module);
390 return LDB_ERR_OPERATIONS_ERROR;
393 source_dn = ldb_dn_copy(frame, bl->forward_dn);
395 ldb_module_oom(module);
397 return LDB_ERR_OPERATIONS_ERROR;
399 /* Filter down to the attributes we want in the backlink */
400 const char *accept[] = { "GUID", "SID", NULL };
401 ldb_dn_extended_filter(source_dn, accept);
404 /* construct a ldb_message for adding/deleting the backlink */
406 dn_string = ldb_dn_get_extended_linearized(frame, bl->forward_dn, 1);
408 ldb_module_oom(module);
410 return LDB_ERR_OPERATIONS_ERROR;
412 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
413 if (ret != LDB_SUCCESS) {
417 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
419 /* a backlink should never be single valued. Unfortunately the
420 exchange schema has a attribute
421 msExchBridgeheadedLocalConnectorsDNBL which is single
422 valued and a backlink. We need to cope with that by
423 ignoring the single value flag */
424 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
426 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
427 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
428 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
429 cope with possible corruption where the backlink has
430 already been removed */
431 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
432 ldb_dn_get_linearized(target_dn),
433 ldb_dn_get_linearized(source_dn),
434 ldb_errstring(ldb)));
436 } else if (ret != LDB_SUCCESS) {
437 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
438 bl->active?"add":"remove",
439 ldb_dn_get_linearized(source_dn),
440 ldb_dn_get_linearized(target_dn),
450 add a backlink to the list of backlinks to add/delete in the prepare
453 forward_dn is stolen onto the defereed context
455 static int replmd_defer_add_backlink(struct ldb_module *module,
456 struct replmd_private *replmd_private,
457 const struct dsdb_schema *schema,
458 struct replmd_replicated_request *ac,
459 struct ldb_dn *forward_dn,
460 struct GUID *target_guid, bool active,
461 const struct dsdb_attribute *schema_attr,
462 struct ldb_request *parent)
464 const struct dsdb_attribute *target_attr;
465 struct la_backlink *bl;
467 bl = talloc(ac, struct la_backlink);
469 ldb_module_oom(module);
470 return LDB_ERR_OPERATIONS_ERROR;
473 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
476 * windows 2003 has a broken schema where the
477 * definition of msDS-IsDomainFor is missing (which is
478 * supposed to be the backlink of the
479 * msDS-HasDomainNCs attribute
484 bl->attr_name = target_attr->lDAPDisplayName;
485 bl->forward_dn = talloc_steal(bl, forward_dn);
486 bl->target_guid = *target_guid;
489 DLIST_ADD(ac->la_backlinks, bl);
495 add a backlink to the list of backlinks to add/delete in the prepare
498 static int replmd_add_backlink(struct ldb_module *module,
499 struct replmd_private *replmd_private,
500 const struct dsdb_schema *schema,
501 struct ldb_dn *forward_dn,
502 struct GUID *target_guid, bool active,
503 const struct dsdb_attribute *schema_attr,
504 struct ldb_request *parent)
506 const struct dsdb_attribute *target_attr;
507 struct la_backlink bl;
510 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
513 * windows 2003 has a broken schema where the
514 * definition of msDS-IsDomainFor is missing (which is
515 * supposed to be the backlink of the
516 * msDS-HasDomainNCs attribute
521 bl.attr_name = target_attr->lDAPDisplayName;
522 bl.forward_dn = forward_dn;
523 bl.target_guid = *target_guid;
526 ret = replmd_process_backlink(module, &bl, parent);
532 * Callback for most write operations in this module:
534 * notify the repl task that a object has changed. The notifies are
535 * gathered up in the replmd_private structure then written to the
536 * @REPLCHANGED object in each partition during the prepare_commit
538 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
541 struct replmd_replicated_request *ac =
542 talloc_get_type_abort(req->context, struct replmd_replicated_request);
543 struct replmd_private *replmd_private =
544 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
545 struct nc_entry *modified_partition;
546 struct ldb_control *partition_ctrl;
547 const struct dsdb_control_current_partition *partition;
549 struct ldb_control **controls;
551 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
553 controls = ares->controls;
554 if (ldb_request_get_control(ac->req,
555 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
557 * Remove the current partition control from what we pass up
558 * the chain if it hasn't been requested manually.
560 controls = ldb_controls_except_specified(ares->controls, ares,
564 if (ares->error != LDB_SUCCESS) {
565 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
566 return ldb_module_done(ac->req, controls,
567 ares->response, ares->error);
570 if (ares->type != LDB_REPLY_DONE) {
571 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
572 return ldb_module_done(ac->req, NULL,
573 NULL, LDB_ERR_OPERATIONS_ERROR);
576 if (ac->apply_mode == false) {
577 struct la_backlink *bl;
579 * process our backlink list after an replmd_add(),
580 * creating and deleting backlinks as necessary (this
581 * code is sync). The other cases are handled inline
584 for (bl=ac->la_backlinks; bl; bl=bl->next) {
585 ret = replmd_process_backlink(ac->module, bl, ac->req);
586 if (ret != LDB_SUCCESS) {
587 return ldb_module_done(ac->req, NULL,
593 if (!partition_ctrl) {
594 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
595 return ldb_module_done(ac->req, NULL,
596 NULL, LDB_ERR_OPERATIONS_ERROR);
599 partition = talloc_get_type_abort(partition_ctrl->data,
600 struct dsdb_control_current_partition);
602 if (ac->seq_num > 0) {
603 for (modified_partition = replmd_private->ncs; modified_partition;
604 modified_partition = modified_partition->next) {
605 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
610 if (modified_partition == NULL) {
611 modified_partition = talloc_zero(replmd_private, struct nc_entry);
612 if (!modified_partition) {
613 ldb_oom(ldb_module_get_ctx(ac->module));
614 return ldb_module_done(ac->req, NULL,
615 NULL, LDB_ERR_OPERATIONS_ERROR);
617 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
618 if (!modified_partition->dn) {
619 ldb_oom(ldb_module_get_ctx(ac->module));
620 return ldb_module_done(ac->req, NULL,
621 NULL, LDB_ERR_OPERATIONS_ERROR);
623 DLIST_ADD(replmd_private->ncs, modified_partition);
626 if (ac->seq_num > modified_partition->mod_usn) {
627 modified_partition->mod_usn = ac->seq_num;
629 modified_partition->mod_usn_urgent = ac->seq_num;
632 if (!ac->apply_mode) {
633 replmd_private->originating_updates = true;
637 if (ac->apply_mode) {
638 ret = replmd_replicated_apply_isDeleted(ac);
639 if (ret != LDB_SUCCESS) {
640 return ldb_module_done(ac->req, NULL, NULL, ret);
644 /* free the partition control container here, for the
645 * common path. Other cases will have it cleaned up
646 * eventually with the ares */
647 talloc_free(partition_ctrl);
648 return ldb_module_done(ac->req, controls,
649 ares->response, LDB_SUCCESS);
655 * update a @REPLCHANGED record in each partition if there have been
656 * any writes of replicated data in the partition
658 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
660 struct replmd_private *replmd_private =
661 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
663 while (replmd_private->ncs) {
665 struct nc_entry *modified_partition = replmd_private->ncs;
667 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
668 modified_partition->mod_usn,
669 modified_partition->mod_usn_urgent, parent);
670 if (ret != LDB_SUCCESS) {
671 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
672 ldb_dn_get_linearized(modified_partition->dn)));
676 if (ldb_dn_compare(modified_partition->dn,
677 replmd_private->schema_dn) == 0) {
678 struct ldb_result *ext_res;
679 ret = dsdb_module_extended(module,
680 replmd_private->schema_dn,
682 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
684 DSDB_FLAG_NEXT_MODULE,
686 if (ret != LDB_SUCCESS) {
689 talloc_free(ext_res);
692 DLIST_REMOVE(replmd_private->ncs, modified_partition);
693 talloc_free(modified_partition);
701 created a replmd_replicated_request context
703 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
704 struct ldb_request *req)
706 struct ldb_context *ldb;
707 struct replmd_replicated_request *ac;
708 const struct GUID *our_invocation_id;
710 ldb = ldb_module_get_ctx(module);
712 ac = talloc_zero(req, struct replmd_replicated_request);
721 ac->schema = dsdb_get_schema(ldb, ac);
723 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
724 "replmd_modify: no dsdb_schema loaded");
725 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
730 /* get our invocationId */
731 our_invocation_id = samdb_ntds_invocation_id(ldb);
732 if (!our_invocation_id) {
733 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
734 "replmd_add: unable to find invocationId\n");
738 ac->our_invocation_id = *our_invocation_id;
744 add a time element to a record
746 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
748 struct ldb_message_element *el;
752 if (ldb_msg_find_element(msg, attr) != NULL) {
756 s = ldb_timestring(msg, t);
758 return LDB_ERR_OPERATIONS_ERROR;
761 ret = ldb_msg_add_string(msg, attr, s);
762 if (ret != LDB_SUCCESS) {
766 el = ldb_msg_find_element(msg, attr);
767 /* always set as replace. This works because on add ops, the flag
769 el->flags = LDB_FLAG_MOD_REPLACE;
775 add a uint64_t element to a record
777 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
778 const char *attr, uint64_t v)
780 struct ldb_message_element *el;
783 if (ldb_msg_find_element(msg, attr) != NULL) {
787 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
788 if (ret != LDB_SUCCESS) {
792 el = ldb_msg_find_element(msg, attr);
793 /* always set as replace. This works because on add ops, the flag
795 el->flags = LDB_FLAG_MOD_REPLACE;
800 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
801 const struct replPropertyMetaData1 *m2,
802 const uint32_t *rdn_attid)
805 * This assignment seems inoccous, but it is critical for the
806 * system, as we need to do the comparisons as a unsigned
807 * quantity, not signed (enums are signed integers)
809 uint32_t attid_1 = m1->attid;
810 uint32_t attid_2 = m2->attid;
812 if (attid_1 == attid_2) {
817 * See above regarding this being an unsigned comparison.
818 * Otherwise when the high bit is set on non-standard
819 * attributes, they would end up first, before objectClass
822 return attid_1 > attid_2 ? 1 : -1;
825 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
826 struct replPropertyMetaDataCtr1 *ctr1,
829 if (ctr1->count == 0) {
830 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
831 "No elements found in replPropertyMetaData for %s!\n",
832 ldb_dn_get_linearized(dn));
833 return LDB_ERR_CONSTRAINT_VIOLATION;
836 /* the objectClass attribute is value 0x00000000, so must be first */
837 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
838 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
839 "No objectClass found in replPropertyMetaData for %s!\n",
840 ldb_dn_get_linearized(dn));
841 return LDB_ERR_OBJECT_CLASS_VIOLATION;
847 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
848 struct replPropertyMetaDataCtr1 *ctr1,
851 /* Note this is O(n^2) for the almost-sorted case, which this is */
852 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
853 replmd_replPropertyMetaData1_attid_sort);
854 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
857 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
858 const struct ldb_message_element *e2,
859 const struct dsdb_schema *schema)
861 const struct dsdb_attribute *a1;
862 const struct dsdb_attribute *a2;
865 * TODO: make this faster by caching the dsdb_attribute pointer
866 * on the ldb_messag_element
869 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
870 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
873 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
877 return strcasecmp(e1->name, e2->name);
879 if (a1->attributeID_id == a2->attributeID_id) {
882 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
885 static void replmd_ldb_message_sort(struct ldb_message *msg,
886 const struct dsdb_schema *schema)
888 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
891 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
892 const struct GUID *invocation_id, uint64_t seq_num,
893 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
895 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
896 struct ldb_message_element *el, struct parsed_dn **pdn,
897 const char *ldap_oid, struct ldb_request *parent);
900 fix up linked attributes in replmd_add.
901 This involves setting up the right meta-data in extended DN
902 components, and creating backlinks to the object
904 static int replmd_add_fix_la(struct ldb_module *module, TALLOC_CTX *mem_ctx,
905 struct replmd_private *replmd_private,
906 struct ldb_message_element *el,
907 struct replmd_replicated_request *ac,
909 struct ldb_dn *forward_dn,
910 const struct dsdb_attribute *sa,
911 struct ldb_request *parent)
914 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
915 struct ldb_context *ldb = ldb_module_get_ctx(module);
916 struct parsed_dn *pdn;
917 /* We will take a reference to the schema in replmd_add_backlink */
918 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
919 struct ldb_val *new_values = NULL;
921 int ret = get_parsed_dns(module, tmp_ctx, el, &pdn,
922 sa->syntax->ldap_oid, parent);
923 if (ret != LDB_SUCCESS) {
924 talloc_free(tmp_ctx);
928 new_values = talloc_array(tmp_ctx, struct ldb_val, el->num_values);
929 if (new_values == NULL) {
930 ldb_module_oom(module);
931 talloc_free(tmp_ctx);
932 return LDB_ERR_OPERATIONS_ERROR;
935 for (i = 0; i < el->num_values; i++) {
936 struct parsed_dn *p = &pdn[i];
937 ret = replmd_build_la_val(el->values, p->v, p->dsdb_dn,
938 &ac->our_invocation_id,
939 ac->seq_num, ac->seq_num, now, 0, false);
940 if (ret != LDB_SUCCESS) {
941 talloc_free(tmp_ctx);
945 ret = replmd_defer_add_backlink(module, replmd_private,
947 forward_dn, &p->guid, true, sa,
949 if (ret != LDB_SUCCESS) {
950 talloc_free(tmp_ctx);
954 new_values[i] = *p->v;
956 el->values = talloc_steal(mem_ctx, new_values);
958 talloc_free(tmp_ctx);
962 static int replmd_add_make_extended_dn(struct ldb_request *req,
963 const DATA_BLOB *guid_blob,
964 struct ldb_dn **_extended_dn)
967 const DATA_BLOB *sid_blob;
968 /* Calculate an extended DN for any linked attributes */
969 struct ldb_dn *extended_dn = ldb_dn_copy(req, req->op.add.message->dn);
971 return LDB_ERR_OPERATIONS_ERROR;
973 ret = ldb_dn_set_extended_component(extended_dn, "GUID", guid_blob);
974 if (ret != LDB_SUCCESS) {
978 sid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectSID");
979 if (sid_blob != NULL) {
980 ret = ldb_dn_set_extended_component(extended_dn, "SID", sid_blob);
981 if (ret != LDB_SUCCESS) {
985 *_extended_dn = extended_dn;
990 intercept add requests
992 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
994 struct ldb_context *ldb;
995 struct ldb_control *control;
996 struct replmd_replicated_request *ac;
997 enum ndr_err_code ndr_err;
998 struct ldb_request *down_req;
999 struct ldb_message *msg;
1000 const DATA_BLOB *guid_blob;
1001 DATA_BLOB guid_blob_stack;
1003 uint8_t guid_data[16];
1004 struct replPropertyMetaDataBlob nmd;
1005 struct ldb_val nmd_value;
1006 struct ldb_dn *extended_dn = NULL;
1009 * The use of a time_t here seems odd, but as the NTTIME
1010 * elements are actually declared as NTTIME_1sec in the IDL,
1011 * getting a higher resolution timestamp is not required.
1013 time_t t = time(NULL);
1018 unsigned int functional_level;
1020 bool allow_add_guid = false;
1021 bool remove_current_guid = false;
1022 bool is_urgent = false;
1023 bool is_schema_nc = false;
1024 struct ldb_message_element *objectclass_el;
1025 struct replmd_private *replmd_private =
1026 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
1028 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
1029 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
1031 allow_add_guid = true;
1034 /* do not manipulate our control entries */
1035 if (ldb_dn_is_special(req->op.add.message->dn)) {
1036 return ldb_next_request(module, req);
1039 ldb = ldb_module_get_ctx(module);
1041 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
1043 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
1044 if (guid_blob != NULL) {
1045 if (!allow_add_guid) {
1046 ldb_set_errstring(ldb,
1047 "replmd_add: it's not allowed to add an object with objectGUID!");
1048 return LDB_ERR_UNWILLING_TO_PERFORM;
1050 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
1051 if (!NT_STATUS_IS_OK(status)) {
1052 ldb_set_errstring(ldb,
1053 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1054 return LDB_ERR_UNWILLING_TO_PERFORM;
1056 /* we remove this attribute as it can be a string and
1057 * will not be treated correctly and then we will re-add
1058 * it later on in the good format */
1059 remove_current_guid = true;
1063 guid = GUID_random();
1065 guid_blob_stack = data_blob_const(guid_data, sizeof(guid_data));
1067 /* This can't fail */
1068 ndr_push_struct_into_fixed_blob(&guid_blob_stack, &guid,
1069 (ndr_push_flags_fn_t)ndr_push_GUID);
1070 guid_blob = &guid_blob_stack;
1073 ac = replmd_ctx_init(module, req);
1075 return ldb_module_oom(module);
1078 functional_level = dsdb_functional_level(ldb);
1080 /* Get a sequence number from the backend */
1081 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1082 if (ret != LDB_SUCCESS) {
1087 /* we have to copy the message as the caller might have it as a const */
1088 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1092 return LDB_ERR_OPERATIONS_ERROR;
1095 /* generated times */
1096 unix_to_nt_time(&now, t);
1097 time_str = ldb_timestring(msg, t);
1101 return LDB_ERR_OPERATIONS_ERROR;
1103 if (remove_current_guid) {
1104 ldb_msg_remove_attr(msg,"objectGUID");
1108 * remove autogenerated attributes
1110 ldb_msg_remove_attr(msg, "whenCreated");
1111 ldb_msg_remove_attr(msg, "whenChanged");
1112 ldb_msg_remove_attr(msg, "uSNCreated");
1113 ldb_msg_remove_attr(msg, "uSNChanged");
1114 ldb_msg_remove_attr(msg, "replPropertyMetaData");
1117 * readd replicated attributes
1119 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1120 if (ret != LDB_SUCCESS) {
1126 /* build the replication meta_data */
1129 nmd.ctr.ctr1.count = msg->num_elements;
1130 nmd.ctr.ctr1.array = talloc_array(msg,
1131 struct replPropertyMetaData1,
1132 nmd.ctr.ctr1.count);
1133 if (!nmd.ctr.ctr1.array) {
1136 return LDB_ERR_OPERATIONS_ERROR;
1139 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1141 for (i=0; i < msg->num_elements;) {
1142 struct ldb_message_element *e = &msg->elements[i];
1143 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1144 const struct dsdb_attribute *sa;
1146 if (e->name[0] == '@') {
1151 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1153 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1154 "replmd_add: attribute '%s' not defined in schema\n",
1157 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1160 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1161 /* if the attribute is not replicated (0x00000001)
1162 * or constructed (0x00000004) it has no metadata
1168 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1169 if (extended_dn == NULL) {
1170 ret = replmd_add_make_extended_dn(req,
1173 if (ret != LDB_SUCCESS) {
1180 * Prepare the context for the backlinks and
1181 * create metadata for the forward links. The
1182 * backlinks are created in
1183 * replmd_op_callback() after the successful
1184 * ADD of the object.
1186 ret = replmd_add_fix_la(module, msg->elements,
1191 if (ret != LDB_SUCCESS) {
1195 /* linked attributes are not stored in
1196 replPropertyMetaData in FL above w2k */
1201 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1203 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1204 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1207 if (rdn_val == NULL) {
1210 return LDB_ERR_OPERATIONS_ERROR;
1213 rdn = (const char*)rdn_val->data;
1214 if (strcmp(rdn, "Deleted Objects") == 0) {
1216 * Set the originating_change_time to 29/12/9999 at 23:59:59
1217 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1219 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1221 m->originating_change_time = now;
1224 m->originating_change_time = now;
1226 m->originating_invocation_id = ac->our_invocation_id;
1227 m->originating_usn = ac->seq_num;
1228 m->local_usn = ac->seq_num;
1231 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1236 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1238 if (e->num_values != 0) {
1243 ldb_msg_remove_element(msg, e);
1246 /* fix meta data count */
1247 nmd.ctr.ctr1.count = ni;
1250 * sort meta data array
1252 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1253 if (ret != LDB_SUCCESS) {
1254 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1259 /* generated NDR encoded values */
1260 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1262 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1263 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1266 return LDB_ERR_OPERATIONS_ERROR;
1270 * add the autogenerated values
1272 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1273 if (ret != LDB_SUCCESS) {
1278 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1279 if (ret != LDB_SUCCESS) {
1284 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1285 if (ret != LDB_SUCCESS) {
1290 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1291 if (ret != LDB_SUCCESS) {
1296 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1297 if (ret != LDB_SUCCESS) {
1304 * sort the attributes by attid before storing the object
1306 replmd_ldb_message_sort(msg, ac->schema);
1309 * Assert that we do have an objectClass
1311 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1312 if (objectclass_el == NULL) {
1313 ldb_asprintf_errstring(ldb, __location__
1314 ": objectClass missing on %s\n",
1315 ldb_dn_get_linearized(msg->dn));
1317 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1319 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1320 REPL_URGENT_ON_CREATE);
1322 ac->is_urgent = is_urgent;
1323 ret = ldb_build_add_req(&down_req, ldb, ac,
1326 ac, replmd_op_callback,
1329 LDB_REQ_SET_LOCATION(down_req);
1330 if (ret != LDB_SUCCESS) {
1335 /* current partition control is needed by "replmd_op_callback" */
1336 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1337 ret = ldb_request_add_control(down_req,
1338 DSDB_CONTROL_CURRENT_PARTITION_OID,
1340 if (ret != LDB_SUCCESS) {
1346 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1347 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1348 if (ret != LDB_SUCCESS) {
1354 /* mark the control done */
1356 control->critical = 0;
1358 /* go on with the call chain */
1359 return ldb_next_request(module, down_req);
1364 * update the replPropertyMetaData for one element
1366 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1367 struct ldb_message *msg,
1368 struct ldb_message_element *el,
1369 struct ldb_message_element *old_el,
1370 struct replPropertyMetaDataBlob *omd,
1371 const struct dsdb_schema *schema,
1373 const struct GUID *our_invocation_id,
1376 struct ldb_request *req)
1379 const struct dsdb_attribute *a;
1380 struct replPropertyMetaData1 *md1;
1381 bool may_skip = false;
1384 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1386 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1387 /* allow this to make it possible for dbcheck
1388 to remove bad attributes */
1392 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1394 return LDB_ERR_OPERATIONS_ERROR;
1397 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1399 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1404 * if the attribute's value haven't changed, and this isn't
1405 * just a delete of everything then return LDB_SUCCESS Unless
1406 * we have the provision control or if the attribute is
1407 * interSiteTopologyGenerator as this page explain:
1408 * http://support.microsoft.com/kb/224815 this attribute is
1409 * periodicaly written by the DC responsible for the intersite
1410 * generation in a given site
1412 * Unchanged could be deleting or replacing an already-gone
1413 * thing with an unconstrained delete/empty replace or a
1414 * replace with the same value, but not an add with the same
1415 * value because that could be about adding a duplicate (which
1416 * is for someone else to error out on).
1418 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1419 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1422 } else if (old_el == NULL && el->num_values == 0) {
1423 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1425 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1428 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1429 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1431 * We intentionally skip the version bump when attempting to
1434 * The control is set by dbcheck and expunge-tombstones which
1435 * both attempt to be non-replicating. Otherwise, making an
1436 * alteration to the replication state would trigger a
1437 * broadcast of all expunged objects.
1442 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1444 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1448 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1449 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1451 * allow this to make it possible for dbcheck
1452 * to rebuild broken metadata
1458 for (i=0; i<omd->ctr.ctr1.count; i++) {
1460 * First check if we find it under the msDS-IntID,
1461 * then check if we find it under the OID and
1464 * This allows the administrator to simply re-write
1465 * the attributes and so restore replication, which is
1466 * likely what they will try to do.
1468 if (attid == omd->ctr.ctr1.array[i].attid) {
1472 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1477 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1478 /* linked attributes are not stored in
1479 replPropertyMetaData in FL above w2k, but we do
1480 raise the seqnum for the object */
1481 if (*seq_num == 0 &&
1482 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1483 return LDB_ERR_OPERATIONS_ERROR;
1488 if (i == omd->ctr.ctr1.count) {
1489 /* we need to add a new one */
1490 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1491 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1492 if (omd->ctr.ctr1.array == NULL) {
1494 return LDB_ERR_OPERATIONS_ERROR;
1496 omd->ctr.ctr1.count++;
1497 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1500 /* Get a new sequence number from the backend. We only do this
1501 * if we have a change that requires a new
1502 * replPropertyMetaData element
1504 if (*seq_num == 0) {
1505 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1506 if (ret != LDB_SUCCESS) {
1507 return LDB_ERR_OPERATIONS_ERROR;
1511 md1 = &omd->ctr.ctr1.array[i];
1514 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1515 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1518 if (rdn_val == NULL) {
1520 return LDB_ERR_OPERATIONS_ERROR;
1523 rdn = (const char*)rdn_val->data;
1524 if (strcmp(rdn, "Deleted Objects") == 0) {
1526 * Set the originating_change_time to 29/12/9999 at 23:59:59
1527 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1529 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1531 md1->originating_change_time = now;
1534 md1->originating_change_time = now;
1536 md1->originating_invocation_id = *our_invocation_id;
1537 md1->originating_usn = *seq_num;
1538 md1->local_usn = *seq_num;
1544 * Bump the replPropertyMetaData version on an attribute, and if it
1545 * has changed (or forced by leaving rdn_old NULL), update the value
1548 * This is important, as calling a modify operation may not change the
1549 * version number if the values appear unchanged, but a rename between
1550 * parents bumps this value.
1553 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1554 struct ldb_message *msg,
1555 const struct ldb_val *rdn_new,
1556 const struct ldb_val *rdn_old,
1557 struct replPropertyMetaDataBlob *omd,
1558 struct replmd_replicated_request *ar,
1562 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1563 const struct dsdb_attribute *rdn_attr =
1564 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1565 const char *attr_name = rdn_attr != NULL ?
1566 rdn_attr->lDAPDisplayName :
1568 struct ldb_message_element new_el = {
1569 .flags = LDB_FLAG_MOD_REPLACE,
1572 .values = discard_const_p(struct ldb_val, rdn_new)
1574 struct ldb_message_element old_el = {
1575 .flags = LDB_FLAG_MOD_REPLACE,
1577 .num_values = rdn_old ? 1 : 0,
1578 .values = discard_const_p(struct ldb_val, rdn_old)
1581 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1582 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1583 if (ret != LDB_SUCCESS) {
1584 return ldb_oom(ldb);
1588 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1589 omd, ar->schema, &ar->seq_num,
1590 &ar->our_invocation_id,
1591 now, is_schema_nc, ar->req);
1595 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1597 uint32_t count = omd.ctr.ctr1.count;
1600 for (i=0; i < count; i++) {
1601 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1602 if (max < m.local_usn) {
1610 * update the replPropertyMetaData object each time we modify an
1611 * object. This is needed for DRS replication, as the merge on the
1612 * client is based on this object
1614 static int replmd_update_rpmd(struct ldb_module *module,
1615 const struct dsdb_schema *schema,
1616 struct ldb_request *req,
1617 const char * const *rename_attrs,
1618 struct ldb_message *msg, uint64_t *seq_num,
1619 time_t t, bool is_schema_nc,
1620 bool *is_urgent, bool *rodc)
1622 const struct ldb_val *omd_value;
1623 enum ndr_err_code ndr_err;
1624 struct replPropertyMetaDataBlob omd;
1627 const struct GUID *our_invocation_id;
1629 const char * const *attrs = NULL;
1630 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1631 struct ldb_result *res;
1632 struct ldb_context *ldb;
1633 struct ldb_message_element *objectclass_el;
1634 enum urgent_situation situation;
1635 bool rmd_is_provided;
1636 bool rmd_is_just_resorted = false;
1637 const char *not_rename_attrs[4 + msg->num_elements];
1640 attrs = rename_attrs;
1642 for (i = 0; i < msg->num_elements; i++) {
1643 not_rename_attrs[i] = msg->elements[i].name;
1645 not_rename_attrs[i] = "replPropertyMetaData";
1646 not_rename_attrs[i+1] = "objectClass";
1647 not_rename_attrs[i+2] = "instanceType";
1648 not_rename_attrs[i+3] = NULL;
1649 attrs = not_rename_attrs;
1652 ldb = ldb_module_get_ctx(module);
1654 our_invocation_id = samdb_ntds_invocation_id(ldb);
1655 if (!our_invocation_id) {
1656 /* this happens during an initial vampire while
1657 updating the schema */
1658 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1662 unix_to_nt_time(&now, t);
1664 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1665 rmd_is_provided = true;
1666 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1667 rmd_is_just_resorted = true;
1670 rmd_is_provided = false;
1673 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1674 * otherwise we consider we are updating */
1675 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1676 situation = REPL_URGENT_ON_DELETE;
1677 } else if (rename_attrs) {
1678 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1680 situation = REPL_URGENT_ON_UPDATE;
1683 if (rmd_is_provided) {
1684 /* In this case the change_replmetadata control was supplied */
1685 /* We check that it's the only attribute that is provided
1686 * (it's a rare case so it's better to keep the code simplier)
1687 * We also check that the highest local_usn is bigger or the same as
1690 if( msg->num_elements != 1 ||
1691 strncmp(msg->elements[0].name,
1692 "replPropertyMetaData", 20) ) {
1693 DEBUG(0,(__location__ ": changereplmetada control called without "\
1694 "a specified replPropertyMetaData attribute or with others\n"));
1695 return LDB_ERR_OPERATIONS_ERROR;
1697 if (situation != REPL_URGENT_ON_UPDATE) {
1698 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1699 return LDB_ERR_OPERATIONS_ERROR;
1701 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1703 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1704 ldb_dn_get_linearized(msg->dn)));
1705 return LDB_ERR_OPERATIONS_ERROR;
1707 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1708 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1709 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1710 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1711 ldb_dn_get_linearized(msg->dn)));
1712 return LDB_ERR_OPERATIONS_ERROR;
1715 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1716 DSDB_FLAG_NEXT_MODULE |
1717 DSDB_SEARCH_SHOW_RECYCLED |
1718 DSDB_SEARCH_SHOW_EXTENDED_DN |
1719 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1720 DSDB_SEARCH_REVEAL_INTERNALS, req);
1722 if (ret != LDB_SUCCESS) {
1726 if (rmd_is_just_resorted == false) {
1727 *seq_num = find_max_local_usn(omd);
1729 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1732 * The test here now allows for a new
1733 * replPropertyMetaData with no change, if was
1734 * just dbcheck re-sorting the values.
1736 if (*seq_num <= db_seq) {
1737 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1738 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1739 (long long)*seq_num, (long long)db_seq));
1740 return LDB_ERR_OPERATIONS_ERROR;
1745 /* search for the existing replPropertyMetaDataBlob. We need
1746 * to use REVEAL and ask for DNs in storage format to support
1747 * the check for values being the same in
1748 * replmd_update_rpmd_element()
1750 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1751 DSDB_FLAG_NEXT_MODULE |
1752 DSDB_SEARCH_SHOW_RECYCLED |
1753 DSDB_SEARCH_SHOW_EXTENDED_DN |
1754 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1755 DSDB_SEARCH_REVEAL_INTERNALS, req);
1756 if (ret != LDB_SUCCESS) {
1760 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1762 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1763 ldb_dn_get_linearized(msg->dn)));
1764 return LDB_ERR_OPERATIONS_ERROR;
1767 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1768 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1769 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1770 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1771 ldb_dn_get_linearized(msg->dn)));
1772 return LDB_ERR_OPERATIONS_ERROR;
1775 if (omd.version != 1) {
1776 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1777 omd.version, ldb_dn_get_linearized(msg->dn)));
1778 return LDB_ERR_OPERATIONS_ERROR;
1781 for (i=0; i<msg->num_elements;) {
1782 struct ldb_message_element *el = &msg->elements[i];
1783 struct ldb_message_element *old_el;
1785 old_el = ldb_msg_find_element(res->msgs[0], el->name);
1786 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1787 &omd, schema, seq_num,
1791 if (ret != LDB_SUCCESS) {
1795 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1796 *is_urgent = replmd_check_urgent_attribute(el);
1799 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1804 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1806 if (el->num_values != 0) {
1811 ldb_msg_remove_element(msg, el);
1816 * Assert that we have an objectClass attribute - this is major
1817 * corruption if we don't have this!
1819 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1820 if (objectclass_el != NULL) {
1822 * Now check if this objectClass means we need to do urgent replication
1824 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1828 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1829 ldb_asprintf_errstring(ldb, __location__
1830 ": objectClass missing on %s\n",
1831 ldb_dn_get_linearized(msg->dn));
1832 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1836 * replmd_update_rpmd_element has done an update if the
1839 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1840 struct ldb_val *md_value;
1841 struct ldb_message_element *el;
1843 /*if we are RODC and this is a DRSR update then its ok*/
1844 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1845 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
1846 unsigned instanceType;
1848 ret = samdb_rodc(ldb, rodc);
1849 if (ret != LDB_SUCCESS) {
1850 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1852 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1853 return LDB_ERR_REFERRAL;
1856 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1857 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1858 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1859 "cannot change replicated attribute on partial replica");
1863 md_value = talloc(msg, struct ldb_val);
1864 if (md_value == NULL) {
1866 return LDB_ERR_OPERATIONS_ERROR;
1869 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1870 if (ret != LDB_SUCCESS) {
1871 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1875 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1876 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1877 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1878 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1879 ldb_dn_get_linearized(msg->dn)));
1880 return LDB_ERR_OPERATIONS_ERROR;
1883 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1884 if (ret != LDB_SUCCESS) {
1885 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1886 ldb_dn_get_linearized(msg->dn)));
1891 el->values = md_value;
1897 struct compare_ctx {
1899 struct ldb_context *ldb;
1900 TALLOC_CTX *mem_ctx;
1901 const char *ldap_oid;
1903 const struct GUID *invocation_id;
1906 /* When a parsed_dn comes from the database, sometimes it is not really parsed. */
1908 static int really_parse_trusted_dn(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
1909 struct parsed_dn *pdn, const char *ldap_oid)
1912 struct dsdb_dn *dsdb_dn = dsdb_dn_parse_trusted(mem_ctx, ldb, pdn->v,
1914 if (dsdb_dn == NULL) {
1915 return LDB_ERR_INVALID_DN_SYNTAX;
1918 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &pdn->guid, "GUID");
1919 if (!NT_STATUS_IS_OK(status)) {
1920 return LDB_ERR_OPERATIONS_ERROR;
1922 pdn->dsdb_dn = dsdb_dn;
1927 * We choose, as the sort order, the same order as is used in DRS replication,
1928 * which is the memcmp() order of the NDR GUID, not that obtained from
1931 * This means that sorted links will be in the same order as a new DC would
1934 static int ndr_guid_compare(struct GUID *guid1, struct GUID *guid2)
1936 uint8_t v1_data[16];
1937 struct ldb_val v1 = data_blob_const(v1_data, sizeof(v1_data));
1938 uint8_t v2_data[16];
1939 struct ldb_val v2 = data_blob_const(v2_data, sizeof(v2_data));
1941 /* This can't fail */
1942 ndr_push_struct_into_fixed_blob(&v1, guid1,
1943 (ndr_push_flags_fn_t)ndr_push_GUID);
1944 /* This can't fail */
1945 ndr_push_struct_into_fixed_blob(&v2, guid2,
1946 (ndr_push_flags_fn_t)ndr_push_GUID);
1947 return data_blob_cmp(&v1, &v2);
1950 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1952 return ndr_guid_compare(&pdn1->guid, &pdn2->guid);
1955 static int la_guid_compare_with_trusted_dn(struct compare_ctx *ctx,
1956 struct parsed_dn *p)
1959 * This works like a standard compare function in its return values,
1960 * but has an extra trick to deal with errors: zero is returned and
1961 * ctx->err is set to the ldb error code.
1963 * That is, if (as is expected in most cases) you get a non-zero
1964 * result, you don't need to check for errors.
1966 * We assume the second argument refers to a DN is from the database
1967 * and has a GUID -- but this GUID might not have been parsed out yet.
1969 if (p->dsdb_dn == NULL) {
1970 int ret = really_parse_trusted_dn(ctx->mem_ctx, ctx->ldb, p,
1972 if (ret != LDB_SUCCESS) {
1977 return ndr_guid_compare(ctx->guid, &p->guid);
1982 static int parsed_dn_find(struct ldb_context *ldb, struct parsed_dn *pdn,
1985 struct ldb_dn *target_dn,
1986 struct parsed_dn **exact,
1987 struct parsed_dn **next,
1988 const char *ldap_oid)
1991 struct compare_ctx ctx;
1998 if (unlikely(GUID_all_zero(guid))) {
2000 * When updating a link using DRS, we sometimes get a NULL
2001 * GUID when a forward link has been deleted and its GUID has
2002 * for some reason been forgotten. The best we can do is try
2003 * and match by DN via a linear search. Note that this
2004 * probably only happens in the ADD case, in which we only
2005 * allow modification of link if it is already deleted, so
2006 * this seems very close to an elaborate NO-OP, but we are not
2007 * quite prepared to declare it so.
2009 * If the DN is not in our list, we have to add it to the
2010 * beginning of the list, where it would naturally sort.
2012 struct parsed_dn *p;
2013 if (target_dn == NULL) {
2014 /* We don't know the target DN, so we can't search for DN */
2015 DEBUG(1, ("parsed_dn_find has a NULL GUID for a linked "
2016 "attribute but we don't have a DN to compare "
2018 return LDB_ERR_OPERATIONS_ERROR;
2023 DEBUG(3, ("parsed_dn_find has a NULL GUID for a link to DN "
2024 "%s; searching through links for it",
2025 ldb_dn_get_linearized(target_dn)));
2027 for (i = 0; i < count; i++) {
2030 if (p->dsdb_dn == NULL) {
2031 int ret = really_parse_trusted_dn(pdn, ldb, p, ldap_oid);
2032 if (ret != LDB_SUCCESS) {
2033 return LDB_ERR_OPERATIONS_ERROR;
2037 cmp = ldb_dn_compare(p->dsdb_dn->dn, target_dn);
2044 * Here we have a null guid which doesn't match any existing
2045 * link. This is a bit unexpected because null guids occur
2046 * when a forward link has been deleted and we are replicating
2049 * The best thing to do is weep into the logs and add the
2050 * offending link to the beginning of the list which is
2051 * at least the correct sort position.
2053 DEBUG(1, ("parsed_dn_find has been given a NULL GUID for a "
2054 "link to unknown DN %s\n",
2055 ldb_dn_get_linearized(target_dn)));
2063 ctx.ldap_oid = ldap_oid;
2066 BINARY_ARRAY_SEARCH_GTE(pdn, count, &ctx, la_guid_compare_with_trusted_dn,
2076 get a series of message element values as an array of DNs and GUIDs
2077 the result is sorted by GUID
2079 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
2080 struct ldb_message_element *el, struct parsed_dn **pdn,
2081 const char *ldap_oid, struct ldb_request *parent)
2084 bool values_are_sorted = true;
2085 struct ldb_context *ldb = ldb_module_get_ctx(module);
2092 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
2094 ldb_module_oom(module);
2095 return LDB_ERR_OPERATIONS_ERROR;
2098 for (i=0; i<el->num_values; i++) {
2099 struct ldb_val *v = &el->values[i];
2102 struct parsed_dn *p;
2106 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
2107 if (p->dsdb_dn == NULL) {
2108 return LDB_ERR_INVALID_DN_SYNTAX;
2111 dn = p->dsdb_dn->dn;
2113 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
2114 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
2115 unlikely(GUID_all_zero(&p->guid))) {
2116 /* we got a DN without a GUID - go find the GUID */
2117 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
2118 if (ret != LDB_SUCCESS) {
2119 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
2120 ldb_dn_get_linearized(dn));
2121 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
2122 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
2123 ldb_attr_cmp(el->name, "member") == 0) {
2124 return LDB_ERR_UNWILLING_TO_PERFORM;
2128 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
2129 if (ret != LDB_SUCCESS) {
2132 } else if (!NT_STATUS_IS_OK(status)) {
2133 return LDB_ERR_OPERATIONS_ERROR;
2135 if (i > 0 && values_are_sorted) {
2136 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2138 values_are_sorted = false;
2141 /* keep a pointer to the original ldb_val */
2144 if (! values_are_sorted) {
2145 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2151 * Get a series of trusted message element values. The result is sorted by
2152 * GUID, even though the GUIDs might not be known. That works because we trust
2153 * the database to give us the elements like that if the
2154 * replmd_private->sorted_links flag is set.
2156 * We also ensure that the links are in the Functional Level 2003
2157 * linked attributes format.
2159 static int get_parsed_dns_trusted(struct ldb_module *module,
2160 struct replmd_private *replmd_private,
2161 TALLOC_CTX *mem_ctx,
2162 struct ldb_message_element *el,
2163 struct parsed_dn **pdn,
2164 const char *ldap_oid,
2165 struct ldb_request *parent)
2174 if (!replmd_private->sorted_links) {
2175 /* We need to sort the list. This is the slow old path we want
2178 ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2180 if (ret != LDB_SUCCESS) {
2184 /* Here we get a list of 'struct parsed_dns' without the parsing */
2185 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2188 ldb_module_oom(module);
2189 return LDB_ERR_OPERATIONS_ERROR;
2192 for (i = 0; i < el->num_values; i++) {
2193 (*pdn)[i].v = &el->values[i];
2198 * This upgrades links to FL2003 style, and sorts the result
2199 * if that was needed.
2201 * TODO: Add a database feature that asserts we have no FL2000
2202 * style links to avoid this check or add a feature that
2203 * uses a similar check to find sorted/unsorted links
2204 * for an on-the-fly upgrade.
2207 ret = replmd_check_upgrade_links(ldb_module_get_ctx(module),
2208 *pdn, el->num_values,
2211 if (ret != LDB_SUCCESS) {
2219 build a new extended DN, including all meta data fields
2221 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2222 RMD_ADDTIME = originating_add_time
2223 RMD_INVOCID = originating_invocation_id
2224 RMD_CHANGETIME = originating_change_time
2225 RMD_ORIGINATING_USN = originating_usn
2226 RMD_LOCAL_USN = local_usn
2227 RMD_VERSION = version
2229 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2230 const struct GUID *invocation_id, uint64_t seq_num,
2231 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
2233 struct ldb_dn *dn = dsdb_dn->dn;
2234 const char *tstring, *usn_string, *flags_string;
2235 struct ldb_val tval;
2237 struct ldb_val usnv, local_usnv;
2238 struct ldb_val vers, flagsv;
2241 const char *dnstring;
2243 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2245 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2247 return LDB_ERR_OPERATIONS_ERROR;
2249 tval = data_blob_string_const(tstring);
2251 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
2253 return LDB_ERR_OPERATIONS_ERROR;
2255 usnv = data_blob_string_const(usn_string);
2257 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2259 return LDB_ERR_OPERATIONS_ERROR;
2261 local_usnv = data_blob_string_const(usn_string);
2263 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2265 return LDB_ERR_OPERATIONS_ERROR;
2267 vers = data_blob_string_const(vstring);
2269 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2270 if (!NT_STATUS_IS_OK(status)) {
2271 return LDB_ERR_OPERATIONS_ERROR;
2274 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2275 if (!flags_string) {
2276 return LDB_ERR_OPERATIONS_ERROR;
2278 flagsv = data_blob_string_const(flags_string);
2280 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2281 if (ret != LDB_SUCCESS) return ret;
2282 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
2283 if (ret != LDB_SUCCESS) return ret;
2284 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2285 if (ret != LDB_SUCCESS) return ret;
2286 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2287 if (ret != LDB_SUCCESS) return ret;
2288 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2289 if (ret != LDB_SUCCESS) return ret;
2290 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2291 if (ret != LDB_SUCCESS) return ret;
2292 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2293 if (ret != LDB_SUCCESS) return ret;
2295 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2296 if (dnstring == NULL) {
2297 return LDB_ERR_OPERATIONS_ERROR;
2299 *v = data_blob_string_const(dnstring);
2304 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2305 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2306 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2307 uint32_t version, bool deleted);
2310 check if any links need upgrading from w2k format
2312 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2313 struct parsed_dn *dns, uint32_t count,
2314 struct ldb_message_element *el,
2315 const char *ldap_oid)
2318 const struct GUID *invocation_id = NULL;
2319 for (i=0; i<count; i++) {
2323 if (dns[i].dsdb_dn == NULL) {
2324 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2326 if (ret != LDB_SUCCESS) {
2327 return LDB_ERR_INVALID_DN_SYNTAX;
2331 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2332 &version, "RMD_VERSION");
2333 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2335 * We optimistically assume they are all the same; if
2336 * the first one is fixed, they are all fixed.
2338 * If the first one was *not* fixed and we find a
2339 * later one that is, that is an occasion to shout
2345 DEBUG(0, ("Mixed w2k and fixed format "
2346 "linked attributes\n"));
2350 if (invocation_id == NULL) {
2351 invocation_id = samdb_ntds_invocation_id(ldb);
2352 if (invocation_id == NULL) {
2353 return LDB_ERR_OPERATIONS_ERROR;
2358 /* it's an old one that needs upgrading */
2359 ret = replmd_update_la_val(el->values, dns[i].v,
2360 dns[i].dsdb_dn, dns[i].dsdb_dn,
2361 invocation_id, 1, 1, 0, 0, false);
2362 if (ret != LDB_SUCCESS) {
2368 * This sort() is critical for the operation of
2369 * get_parsed_dns_trusted() because callers of this function
2370 * expect a sorted list, and FL2000 style links are not
2371 * sorted. In particular, as well as the upgrade case,
2372 * get_parsed_dns_trusted() is called from
2373 * replmd_delete_remove_link() even in FL2000 mode
2375 * We do not normally pay the cost of the qsort() due to the
2376 * early return in the RMD_VERSION found case.
2378 TYPESAFE_QSORT(dns, count, parsed_dn_compare);
2383 update an extended DN, including all meta data fields
2385 see replmd_build_la_val for value names
2387 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2388 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2389 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2390 uint32_t version, bool deleted)
2392 struct ldb_dn *dn = dsdb_dn->dn;
2393 const char *tstring, *usn_string, *flags_string;
2394 struct ldb_val tval;
2396 struct ldb_val usnv, local_usnv;
2397 struct ldb_val vers, flagsv;
2398 const struct ldb_val *old_addtime;
2399 uint32_t old_version;
2402 const char *dnstring;
2404 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2406 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2408 return LDB_ERR_OPERATIONS_ERROR;
2410 tval = data_blob_string_const(tstring);
2412 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2414 return LDB_ERR_OPERATIONS_ERROR;
2416 usnv = data_blob_string_const(usn_string);
2418 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2420 return LDB_ERR_OPERATIONS_ERROR;
2422 local_usnv = data_blob_string_const(usn_string);
2424 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2425 if (!NT_STATUS_IS_OK(status)) {
2426 return LDB_ERR_OPERATIONS_ERROR;
2429 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2430 if (!flags_string) {
2431 return LDB_ERR_OPERATIONS_ERROR;
2433 flagsv = data_blob_string_const(flags_string);
2435 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2436 if (ret != LDB_SUCCESS) return ret;
2438 /* get the ADDTIME from the original */
2439 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2440 if (old_addtime == NULL) {
2441 old_addtime = &tval;
2443 if (dsdb_dn != old_dsdb_dn ||
2444 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2445 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2446 if (ret != LDB_SUCCESS) return ret;
2449 /* use our invocation id */
2450 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2451 if (ret != LDB_SUCCESS) return ret;
2453 /* changetime is the current time */
2454 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2455 if (ret != LDB_SUCCESS) return ret;
2457 /* update the USN */
2458 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2459 if (ret != LDB_SUCCESS) return ret;
2461 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2462 if (ret != LDB_SUCCESS) return ret;
2464 /* increase the version by 1 */
2465 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2466 if (NT_STATUS_IS_OK(status) && old_version >= version) {
2467 version = old_version+1;
2469 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2470 vers = data_blob_string_const(vstring);
2471 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2472 if (ret != LDB_SUCCESS) return ret;
2474 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2475 if (dnstring == NULL) {
2476 return LDB_ERR_OPERATIONS_ERROR;
2478 *v = data_blob_string_const(dnstring);
2484 handle adding a linked attribute
2486 static int replmd_modify_la_add(struct ldb_module *module,
2487 struct replmd_private *replmd_private,
2488 const struct dsdb_schema *schema,
2489 struct ldb_message *msg,
2490 struct ldb_message_element *el,
2491 struct ldb_message_element *old_el,
2492 const struct dsdb_attribute *schema_attr,
2495 struct ldb_dn *msg_dn,
2496 struct ldb_request *parent)
2499 struct parsed_dn *dns, *old_dns;
2500 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2502 struct ldb_val *new_values = NULL;
2503 unsigned old_num_values = old_el ? old_el->num_values : 0;
2504 unsigned num_values = 0;
2505 unsigned max_num_values;
2506 const struct GUID *invocation_id;
2507 struct ldb_context *ldb = ldb_module_get_ctx(module);
2509 unix_to_nt_time(&now, t);
2511 invocation_id = samdb_ntds_invocation_id(ldb);
2512 if (!invocation_id) {
2513 talloc_free(tmp_ctx);
2514 return LDB_ERR_OPERATIONS_ERROR;
2517 /* get the DNs to be added, fully parsed.
2519 * We need full parsing because they came off the wire and we don't
2520 * trust them, besides which we need their details to know where to put
2523 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2524 schema_attr->syntax->ldap_oid, parent);
2525 if (ret != LDB_SUCCESS) {
2526 talloc_free(tmp_ctx);
2530 /* get the existing DNs, lazily parsed */
2531 ret = get_parsed_dns_trusted(module, replmd_private,
2532 tmp_ctx, old_el, &old_dns,
2533 schema_attr->syntax->ldap_oid, parent);
2535 if (ret != LDB_SUCCESS) {
2536 talloc_free(tmp_ctx);
2540 max_num_values = old_num_values + el->num_values;
2541 if (max_num_values < old_num_values) {
2542 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2543 "old values: %u, new values: %u, sum: %u",
2544 old_num_values, el->num_values, max_num_values));
2545 talloc_free(tmp_ctx);
2546 return LDB_ERR_OPERATIONS_ERROR;
2549 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2551 if (new_values == NULL) {
2552 ldb_module_oom(module);
2553 talloc_free(tmp_ctx);
2554 return LDB_ERR_OPERATIONS_ERROR;
2558 * For each new value, find where it would go in the list. If there is
2559 * a matching GUID there, we update the existing value; otherwise we
2563 for (i = 0; i < el->num_values; i++) {
2564 struct parsed_dn *exact;
2565 struct parsed_dn *next;
2567 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2571 schema_attr->syntax->ldap_oid);
2572 if (err != LDB_SUCCESS) {
2573 talloc_free(tmp_ctx);
2577 if (exact != NULL) {
2579 * We are trying to add one that exists, which is only
2580 * allowed if it was previously deleted.
2582 * When we do undelete a link we change it in place.
2583 * It will be copied across into the right spot in due
2587 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2589 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2590 struct GUID_txt_buf guid_str;
2591 ldb_asprintf_errstring(ldb,
2592 "Attribute %s already "
2593 "exists for target GUID %s",
2595 GUID_buf_string(&exact->guid,
2597 talloc_free(tmp_ctx);
2598 /* error codes for 'member' need to be
2600 if (ldb_attr_cmp(el->name, "member") == 0) {
2601 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2603 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2607 ret = replmd_update_la_val(new_values, exact->v,
2610 invocation_id, seq_num,
2611 seq_num, now, 0, false);
2612 if (ret != LDB_SUCCESS) {
2613 talloc_free(tmp_ctx);
2617 ret = replmd_add_backlink(module, replmd_private,
2624 if (ret != LDB_SUCCESS) {
2625 talloc_free(tmp_ctx);
2631 * Here we don't have an exact match.
2633 * If next is NULL, this one goes beyond the end of the
2634 * existing list, so we need to add all of those ones first.
2636 * If next is not NULL, we need to add all the ones before
2640 offset = old_num_values;
2642 /* next should have been parsed, but let's make sure */
2643 if (next->dsdb_dn == NULL) {
2644 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2645 schema_attr->syntax->ldap_oid);
2646 if (ret != LDB_SUCCESS) {
2650 offset = MIN(next - old_dns, old_num_values);
2653 /* put all the old ones before next on the list */
2654 for (; j < offset; j++) {
2655 new_values[num_values] = *old_dns[j].v;
2659 ret = replmd_add_backlink(module, replmd_private,
2664 /* Make the new linked attribute ldb_val. */
2665 ret = replmd_build_la_val(new_values, &new_values[num_values],
2666 dns[i].dsdb_dn, invocation_id,
2669 if (ret != LDB_SUCCESS) {
2670 talloc_free(tmp_ctx);
2674 if (ret != LDB_SUCCESS) {
2675 talloc_free(tmp_ctx);
2679 /* copy the rest of the old ones (if any) */
2680 for (; j < old_num_values; j++) {
2681 new_values[num_values] = *old_dns[j].v;
2685 talloc_steal(msg->elements, new_values);
2686 if (old_el != NULL) {
2687 talloc_steal(msg->elements, old_el->values);
2689 el->values = new_values;
2690 el->num_values = num_values;
2692 talloc_free(tmp_ctx);
2694 /* we now tell the backend to replace all existing values
2695 with the one we have constructed */
2696 el->flags = LDB_FLAG_MOD_REPLACE;
2703 handle deleting all active linked attributes
2705 static int replmd_modify_la_delete(struct ldb_module *module,
2706 struct replmd_private *replmd_private,
2707 const struct dsdb_schema *schema,
2708 struct ldb_message *msg,
2709 struct ldb_message_element *el,
2710 struct ldb_message_element *old_el,
2711 const struct dsdb_attribute *schema_attr,
2714 struct ldb_dn *msg_dn,
2715 struct ldb_request *parent)
2718 struct parsed_dn *dns, *old_dns;
2719 TALLOC_CTX *tmp_ctx = NULL;
2721 struct ldb_context *ldb = ldb_module_get_ctx(module);
2722 struct ldb_control *vanish_links_ctrl = NULL;
2723 bool vanish_links = false;
2724 unsigned int num_to_delete = el->num_values;
2726 const struct GUID *invocation_id;
2729 unix_to_nt_time(&now, t);
2731 invocation_id = samdb_ntds_invocation_id(ldb);
2732 if (!invocation_id) {
2733 return LDB_ERR_OPERATIONS_ERROR;
2736 if (old_el == NULL || old_el->num_values == 0) {
2737 /* there is nothing to delete... */
2738 if (num_to_delete == 0) {
2739 /* and we're deleting nothing, so that's OK */
2742 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2745 tmp_ctx = talloc_new(msg);
2746 if (tmp_ctx == NULL) {
2747 return LDB_ERR_OPERATIONS_ERROR;
2750 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2751 schema_attr->syntax->ldap_oid, parent);
2752 if (ret != LDB_SUCCESS) {
2753 talloc_free(tmp_ctx);
2757 ret = get_parsed_dns_trusted(module, replmd_private,
2758 tmp_ctx, old_el, &old_dns,
2759 schema_attr->syntax->ldap_oid, parent);
2761 if (ret != LDB_SUCCESS) {
2762 talloc_free(tmp_ctx);
2767 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2768 if (vanish_links_ctrl) {
2769 vanish_links = true;
2770 vanish_links_ctrl->critical = false;
2774 /* we empty out el->values here to avoid damage if we return early. */
2779 * If vanish links is set, we are actually removing members of
2780 * old_el->values; otherwise we are just marking them deleted.
2782 * There is a special case when no values are given: we remove them
2783 * all. When we have the vanish_links control we just have to remove
2784 * the backlinks and change our element to replace the existing values
2785 * with the empty list.
2788 if (num_to_delete == 0) {
2789 for (i = 0; i < old_el->num_values; i++) {
2790 struct parsed_dn *p = &old_dns[i];
2791 if (p->dsdb_dn == NULL) {
2792 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2793 schema_attr->syntax->ldap_oid);
2794 if (ret != LDB_SUCCESS) {
2798 ret = replmd_add_backlink(module, replmd_private,
2799 schema, msg_dn, &p->guid,
2802 if (ret != LDB_SUCCESS) {
2803 talloc_free(tmp_ctx);
2810 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2811 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2815 ret = replmd_update_la_val(old_el->values, p->v,
2816 p->dsdb_dn, p->dsdb_dn,
2817 invocation_id, seq_num,
2818 seq_num, now, 0, true);
2819 if (ret != LDB_SUCCESS) {
2820 talloc_free(tmp_ctx);
2826 el->flags = LDB_FLAG_MOD_REPLACE;
2827 talloc_free(tmp_ctx);
2833 for (i = 0; i < num_to_delete; i++) {
2834 struct parsed_dn *p = &dns[i];
2835 struct parsed_dn *exact = NULL;
2836 struct parsed_dn *next = NULL;
2837 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2841 schema_attr->syntax->ldap_oid);
2842 if (ret != LDB_SUCCESS) {
2843 talloc_free(tmp_ctx);
2846 if (exact == NULL) {
2847 struct GUID_txt_buf buf;
2848 ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2849 "exist for target GUID %s",
2851 GUID_buf_string(&p->guid, &buf));
2852 if (ldb_attr_cmp(el->name, "member") == 0) {
2853 talloc_free(tmp_ctx);
2854 return LDB_ERR_UNWILLING_TO_PERFORM;
2856 talloc_free(tmp_ctx);
2857 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2862 if (CHECK_DEBUGLVL(5)) {
2863 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2864 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2865 struct GUID_txt_buf buf;
2866 const char *guid_str = \
2867 GUID_buf_string(&p->guid, &buf);
2868 DEBUG(5, ("Deleting deleted linked "
2869 "attribute %s to %s, because "
2870 "vanish_links control is set\n",
2871 el->name, guid_str));
2875 /* remove the backlink */
2876 ret = replmd_add_backlink(module,
2883 if (ret != LDB_SUCCESS) {
2884 talloc_free(tmp_ctx);
2888 /* We flag the deletion and tidy it up later. */
2893 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2895 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2896 struct GUID_txt_buf buf;
2897 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2898 ldb_asprintf_errstring(ldb, "Attribute %s already "
2899 "deleted for target GUID %s",
2900 el->name, guid_str);
2901 if (ldb_attr_cmp(el->name, "member") == 0) {
2902 talloc_free(tmp_ctx);
2903 return LDB_ERR_UNWILLING_TO_PERFORM;
2905 talloc_free(tmp_ctx);
2906 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2910 ret = replmd_update_la_val(old_el->values, exact->v,
2911 exact->dsdb_dn, exact->dsdb_dn,
2912 invocation_id, seq_num, seq_num,
2914 if (ret != LDB_SUCCESS) {
2915 talloc_free(tmp_ctx);
2918 ret = replmd_add_backlink(module, replmd_private,
2923 if (ret != LDB_SUCCESS) {
2924 talloc_free(tmp_ctx);
2931 for (i = 0; i < old_el->num_values; i++) {
2932 if (old_dns[i].v != NULL) {
2933 old_el->values[j] = *old_dns[i].v;
2937 old_el->num_values = j;
2940 el->values = talloc_steal(msg->elements, old_el->values);
2941 el->num_values = old_el->num_values;
2943 talloc_free(tmp_ctx);
2945 /* we now tell the backend to replace all existing values
2946 with the one we have constructed */
2947 el->flags = LDB_FLAG_MOD_REPLACE;
2953 handle replacing a linked attribute
2955 static int replmd_modify_la_replace(struct ldb_module *module,
2956 struct replmd_private *replmd_private,
2957 const struct dsdb_schema *schema,
2958 struct ldb_message *msg,
2959 struct ldb_message_element *el,
2960 struct ldb_message_element *old_el,
2961 const struct dsdb_attribute *schema_attr,
2964 struct ldb_dn *msg_dn,
2965 struct ldb_request *parent)
2967 unsigned int i, old_i, new_i;
2968 struct parsed_dn *dns, *old_dns;
2969 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2971 const struct GUID *invocation_id;
2972 struct ldb_context *ldb = ldb_module_get_ctx(module);
2973 struct ldb_val *new_values = NULL;
2974 const char *ldap_oid = schema_attr->syntax->ldap_oid;
2975 unsigned int old_num_values;
2976 unsigned int repl_num_values;
2977 unsigned int max_num_values;
2980 unix_to_nt_time(&now, t);
2982 invocation_id = samdb_ntds_invocation_id(ldb);
2983 if (!invocation_id) {
2984 return LDB_ERR_OPERATIONS_ERROR;
2988 * The replace operation is unlike the replace and delete cases in that
2989 * we need to look at every existing link to see whether it is being
2990 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
2992 * As we are trying to combine two sorted lists, the algorithm we use
2993 * is akin to the merge phase of a merge sort. We interleave the two
2994 * lists, doing different things depending on which side the current
2997 * There are three main cases, with some sub-cases.
2999 * - a DN is in the old list but not the new one. It needs to be
3000 * marked as deleted (but left in the list).
3001 * - maybe it is already deleted, and we have less to do.
3003 * - a DN is in both lists. The old data gets replaced by the new,
3004 * and the list doesn't grow. The old link may have been marked as
3005 * deleted, in which case we undelete it.
3007 * - a DN is in the new list only. We add it in the right place.
3010 old_num_values = old_el ? old_el->num_values : 0;
3011 repl_num_values = el->num_values;
3012 max_num_values = old_num_values + repl_num_values;
3014 if (max_num_values == 0) {
3015 /* There is nothing to do! */
3019 ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
3020 if (ret != LDB_SUCCESS) {
3021 talloc_free(tmp_ctx);
3025 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
3027 if (ret != LDB_SUCCESS) {
3028 talloc_free(tmp_ctx);
3032 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
3034 if (ret != LDB_SUCCESS) {
3035 talloc_free(tmp_ctx);
3039 new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
3040 if (new_values == NULL) {
3041 ldb_module_oom(module);
3042 talloc_free(tmp_ctx);
3043 return LDB_ERR_OPERATIONS_ERROR;
3048 for (i = 0; i < max_num_values; i++) {
3050 struct parsed_dn *old_p, *new_p;
3051 if (old_i < old_num_values && new_i < repl_num_values) {
3052 old_p = &old_dns[old_i];
3053 new_p = &dns[new_i];
3054 cmp = parsed_dn_compare(old_p, new_p);
3055 } else if (old_i < old_num_values) {
3056 /* the new list is empty, read the old list */
3057 old_p = &old_dns[old_i];
3060 } else if (new_i < repl_num_values) {