4 Copyright (C) Simo Sorce 2004-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8 Copyright (C) Matthieu Patou <mat@samba.org> 2010
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 "libcli/security/session.h"
52 #include "lib/util/tsort.h"
54 struct replmd_private {
56 struct la_entry *la_list;
58 struct la_backlink *la_backlinks;
60 struct nc_entry *prev, *next;
63 uint64_t mod_usn_urgent;
68 struct la_entry *next, *prev;
69 struct drsuapi_DsReplicaLinkedAttribute *la;
72 struct replmd_replicated_request {
73 struct ldb_module *module;
74 struct ldb_request *req;
76 const struct dsdb_schema *schema;
78 /* the controls we pass down */
79 struct ldb_control **controls;
81 /* details for the mode where we apply a bunch of inbound replication meessages */
83 uint32_t index_current;
84 struct dsdb_extended_replicated_objects *objs;
86 struct ldb_message *search_msg;
92 enum urgent_situation {
93 REPL_URGENT_ON_CREATE = 1,
94 REPL_URGENT_ON_UPDATE = 2,
95 REPL_URGENT_ON_DELETE = 4
100 const char *update_name;
101 enum urgent_situation repl_situation;
102 } urgent_objects[] = {
103 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
104 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
105 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
106 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
107 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
108 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
112 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
113 static const char *urgent_attrs[] = {
116 "userAccountControl",
121 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
122 enum urgent_situation situation)
125 for (i=0; urgent_objects[i].update_name; i++) {
127 if ((situation & urgent_objects[i].repl_situation) == 0) {
131 for (j=0; j<objectclass_el->num_values; j++) {
132 const struct ldb_val *v = &objectclass_el->values[j];
133 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
141 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
143 if (ldb_attr_in_list(urgent_attrs, el->name)) {
150 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
153 initialise the module
154 allocate the private structure and build the list
155 of partition DNs for use by replmd_notify()
157 static int replmd_init(struct ldb_module *module)
159 struct replmd_private *replmd_private;
160 struct ldb_context *ldb = ldb_module_get_ctx(module);
162 replmd_private = talloc_zero(module, struct replmd_private);
163 if (replmd_private == NULL) {
165 return LDB_ERR_OPERATIONS_ERROR;
167 ldb_module_set_private(module, replmd_private);
169 return ldb_next_init(module);
173 cleanup our per-transaction contexts
175 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
177 talloc_free(replmd_private->la_ctx);
178 replmd_private->la_list = NULL;
179 replmd_private->la_ctx = NULL;
181 talloc_free(replmd_private->bl_ctx);
182 replmd_private->la_backlinks = NULL;
183 replmd_private->bl_ctx = NULL;
188 struct la_backlink *next, *prev;
189 const char *attr_name;
190 struct GUID forward_guid, target_guid;
195 process a backlinks we accumulated during a transaction, adding and
196 deleting the backlinks from the target objects
198 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
200 struct ldb_dn *target_dn, *source_dn;
202 struct ldb_context *ldb = ldb_module_get_ctx(module);
203 struct ldb_message *msg;
204 TALLOC_CTX *tmp_ctx = talloc_new(bl);
210 - construct ldb_message
211 - either an add or a delete
213 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn, parent);
214 if (ret != LDB_SUCCESS) {
215 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
216 GUID_string(bl, &bl->target_guid)));
220 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn, parent);
221 if (ret != LDB_SUCCESS) {
222 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
223 GUID_string(bl, &bl->forward_guid));
224 talloc_free(tmp_ctx);
228 msg = ldb_msg_new(tmp_ctx);
230 ldb_module_oom(module);
231 talloc_free(tmp_ctx);
232 return LDB_ERR_OPERATIONS_ERROR;
235 /* construct a ldb_message for adding/deleting the backlink */
237 dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
239 ldb_module_oom(module);
240 talloc_free(tmp_ctx);
241 return LDB_ERR_OPERATIONS_ERROR;
243 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
244 if (ret != LDB_SUCCESS) {
245 talloc_free(tmp_ctx);
248 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
250 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
251 if (ret != LDB_SUCCESS) {
252 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
253 bl->active?"add":"remove",
254 ldb_dn_get_linearized(source_dn),
255 ldb_dn_get_linearized(target_dn),
257 talloc_free(tmp_ctx);
260 talloc_free(tmp_ctx);
265 add a backlink to the list of backlinks to add/delete in the prepare
268 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
269 struct GUID *forward_guid, struct GUID *target_guid,
270 bool active, const struct dsdb_attribute *schema_attr, bool immediate)
272 const struct dsdb_attribute *target_attr;
273 struct la_backlink *bl;
274 struct replmd_private *replmd_private =
275 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
277 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
280 * windows 2003 has a broken schema where the
281 * definition of msDS-IsDomainFor is missing (which is
282 * supposed to be the backlink of the
283 * msDS-HasDomainNCs attribute
288 /* see if its already in the list */
289 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
290 if (GUID_equal(forward_guid, &bl->forward_guid) &&
291 GUID_equal(target_guid, &bl->target_guid) &&
292 (target_attr->lDAPDisplayName == bl->attr_name ||
293 strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
299 /* we found an existing one */
300 if (bl->active == active) {
303 DLIST_REMOVE(replmd_private->la_backlinks, bl);
308 if (replmd_private->bl_ctx == NULL) {
309 replmd_private->bl_ctx = talloc_new(replmd_private);
310 if (replmd_private->bl_ctx == NULL) {
311 ldb_module_oom(module);
312 return LDB_ERR_OPERATIONS_ERROR;
317 bl = talloc(replmd_private->bl_ctx, struct la_backlink);
319 ldb_module_oom(module);
320 return LDB_ERR_OPERATIONS_ERROR;
323 /* Ensure the schema does not go away before the bl->attr_name is used */
324 if (!talloc_reference(bl, schema)) {
326 ldb_module_oom(module);
327 return LDB_ERR_OPERATIONS_ERROR;
330 bl->attr_name = target_attr->lDAPDisplayName;
331 bl->forward_guid = *forward_guid;
332 bl->target_guid = *target_guid;
335 /* the caller may ask for this backlink to be processed
338 int ret = replmd_process_backlink(module, bl, NULL);
343 DLIST_ADD(replmd_private->la_backlinks, bl);
350 * Callback for most write operations in this module:
352 * notify the repl task that a object has changed. The notifies are
353 * gathered up in the replmd_private structure then written to the
354 * @REPLCHANGED object in each partition during the prepare_commit
356 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
359 struct replmd_replicated_request *ac =
360 talloc_get_type_abort(req->context, struct replmd_replicated_request);
361 struct replmd_private *replmd_private =
362 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
363 struct nc_entry *modified_partition;
364 struct ldb_control *partition_ctrl;
365 const struct dsdb_control_current_partition *partition;
367 struct ldb_control **controls;
369 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
371 /* Remove the 'partition' control from what we pass up the chain */
372 controls = ldb_controls_except_specified(ares->controls, ares, partition_ctrl);
374 if (ares->error != LDB_SUCCESS) {
375 DEBUG(0,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
376 return ldb_module_done(ac->req, controls,
377 ares->response, ares->error);
380 if (ares->type != LDB_REPLY_DONE) {
381 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
382 return ldb_module_done(ac->req, NULL,
383 NULL, LDB_ERR_OPERATIONS_ERROR);
386 if (!partition_ctrl) {
387 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
388 return ldb_module_done(ac->req, NULL,
389 NULL, LDB_ERR_OPERATIONS_ERROR);
392 partition = talloc_get_type_abort(partition_ctrl->data,
393 struct dsdb_control_current_partition);
395 if (ac->seq_num > 0) {
396 for (modified_partition = replmd_private->ncs; modified_partition;
397 modified_partition = modified_partition->next) {
398 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
403 if (modified_partition == NULL) {
404 modified_partition = talloc_zero(replmd_private, struct nc_entry);
405 if (!modified_partition) {
406 ldb_oom(ldb_module_get_ctx(ac->module));
407 return ldb_module_done(ac->req, NULL,
408 NULL, LDB_ERR_OPERATIONS_ERROR);
410 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
411 if (!modified_partition->dn) {
412 ldb_oom(ldb_module_get_ctx(ac->module));
413 return ldb_module_done(ac->req, NULL,
414 NULL, LDB_ERR_OPERATIONS_ERROR);
416 DLIST_ADD(replmd_private->ncs, modified_partition);
419 if (ac->seq_num > modified_partition->mod_usn) {
420 modified_partition->mod_usn = ac->seq_num;
422 modified_partition->mod_usn_urgent = ac->seq_num;
427 if (ac->apply_mode) {
431 ret = replmd_replicated_apply_next(ac);
432 if (ret != LDB_SUCCESS) {
433 return ldb_module_done(ac->req, NULL, NULL, ret);
437 /* free the partition control container here, for the
438 * common path. Other cases will have it cleaned up
439 * eventually with the ares */
440 talloc_free(partition_ctrl);
441 return ldb_module_done(ac->req,
442 ldb_controls_except_specified(controls, ares, partition_ctrl),
443 ares->response, LDB_SUCCESS);
449 * update a @REPLCHANGED record in each partition if there have been
450 * any writes of replicated data in the partition
452 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
454 struct replmd_private *replmd_private =
455 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
457 while (replmd_private->ncs) {
459 struct nc_entry *modified_partition = replmd_private->ncs;
461 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
462 modified_partition->mod_usn,
463 modified_partition->mod_usn_urgent, parent);
464 if (ret != LDB_SUCCESS) {
465 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
466 ldb_dn_get_linearized(modified_partition->dn)));
469 DLIST_REMOVE(replmd_private->ncs, modified_partition);
470 talloc_free(modified_partition);
478 created a replmd_replicated_request context
480 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
481 struct ldb_request *req)
483 struct ldb_context *ldb;
484 struct replmd_replicated_request *ac;
486 ldb = ldb_module_get_ctx(module);
488 ac = talloc_zero(req, struct replmd_replicated_request);
497 ac->schema = dsdb_get_schema(ldb, ac);
499 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
500 "replmd_modify: no dsdb_schema loaded");
501 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
509 add a time element to a record
511 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
513 struct ldb_message_element *el;
517 if (ldb_msg_find_element(msg, attr) != NULL) {
521 s = ldb_timestring(msg, t);
523 return LDB_ERR_OPERATIONS_ERROR;
526 ret = ldb_msg_add_string(msg, attr, s);
527 if (ret != LDB_SUCCESS) {
531 el = ldb_msg_find_element(msg, attr);
532 /* always set as replace. This works because on add ops, the flag
534 el->flags = LDB_FLAG_MOD_REPLACE;
540 add a uint64_t element to a record
542 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
543 const char *attr, uint64_t v)
545 struct ldb_message_element *el;
548 if (ldb_msg_find_element(msg, attr) != NULL) {
552 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
553 if (ret != LDB_SUCCESS) {
557 el = ldb_msg_find_element(msg, attr);
558 /* always set as replace. This works because on add ops, the flag
560 el->flags = LDB_FLAG_MOD_REPLACE;
565 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
566 const struct replPropertyMetaData1 *m2,
567 const uint32_t *rdn_attid)
569 if (m1->attid == m2->attid) {
574 * the rdn attribute should be at the end!
575 * so we need to return a value greater than zero
576 * which means m1 is greater than m2
578 if (m1->attid == *rdn_attid) {
583 * the rdn attribute should be at the end!
584 * so we need to return a value less than zero
585 * which means m2 is greater than m1
587 if (m2->attid == *rdn_attid) {
591 return m1->attid > m2->attid ? 1 : -1;
594 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
595 const struct dsdb_schema *schema,
598 const char *rdn_name;
599 const struct dsdb_attribute *rdn_sa;
601 rdn_name = ldb_dn_get_rdn_name(dn);
603 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
604 return LDB_ERR_OPERATIONS_ERROR;
607 rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
608 if (rdn_sa == NULL) {
609 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
610 return LDB_ERR_OPERATIONS_ERROR;
613 DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
614 rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
616 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, &rdn_sa->attributeID_id, replmd_replPropertyMetaData1_attid_sort);
621 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
622 const struct ldb_message_element *e2,
623 const struct dsdb_schema *schema)
625 const struct dsdb_attribute *a1;
626 const struct dsdb_attribute *a2;
629 * TODO: make this faster by caching the dsdb_attribute pointer
630 * on the ldb_messag_element
633 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
634 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
637 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
641 return strcasecmp(e1->name, e2->name);
643 if (a1->attributeID_id == a2->attributeID_id) {
646 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
649 static void replmd_ldb_message_sort(struct ldb_message *msg,
650 const struct dsdb_schema *schema)
652 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
655 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
656 const struct GUID *invocation_id, uint64_t seq_num,
657 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
661 fix up linked attributes in replmd_add.
662 This involves setting up the right meta-data in extended DN
663 components, and creating backlinks to the object
665 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
666 uint64_t seq_num, const struct GUID *invocationId, time_t t,
667 struct GUID *guid, const struct dsdb_attribute *sa, struct ldb_request *parent)
670 TALLOC_CTX *tmp_ctx = talloc_new(el->values);
671 struct ldb_context *ldb = ldb_module_get_ctx(module);
673 /* We will take a reference to the schema in replmd_add_backlink */
674 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
677 unix_to_nt_time(&now, t);
679 for (i=0; i<el->num_values; i++) {
680 struct ldb_val *v = &el->values[i];
681 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
682 struct GUID target_guid;
686 /* note that the DN already has the extended
687 components from the extended_dn_store module */
688 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
689 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
690 ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
691 if (ret != LDB_SUCCESS) {
692 talloc_free(tmp_ctx);
695 ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
696 if (ret != LDB_SUCCESS) {
697 talloc_free(tmp_ctx);
702 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
703 seq_num, seq_num, now, 0, false);
704 if (ret != LDB_SUCCESS) {
705 talloc_free(tmp_ctx);
709 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
710 if (ret != LDB_SUCCESS) {
711 talloc_free(tmp_ctx);
716 talloc_free(tmp_ctx);
722 intercept add requests
724 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
726 struct ldb_context *ldb;
727 struct ldb_control *control;
728 struct replmd_replicated_request *ac;
729 enum ndr_err_code ndr_err;
730 struct ldb_request *down_req;
731 struct ldb_message *msg;
732 const DATA_BLOB *guid_blob;
734 struct replPropertyMetaDataBlob nmd;
735 struct ldb_val nmd_value;
736 const struct GUID *our_invocation_id;
737 time_t t = time(NULL);
742 unsigned int functional_level;
744 bool allow_add_guid = false;
745 bool remove_current_guid = false;
746 bool is_urgent = false;
747 struct ldb_message_element *objectclass_el;
749 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
750 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
752 allow_add_guid = true;
755 /* do not manipulate our control entries */
756 if (ldb_dn_is_special(req->op.add.message->dn)) {
757 return ldb_next_request(module, req);
760 ldb = ldb_module_get_ctx(module);
762 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
764 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
765 if (guid_blob != NULL) {
766 if (!allow_add_guid) {
767 ldb_set_errstring(ldb,
768 "replmd_add: it's not allowed to add an object with objectGUID!");
769 return LDB_ERR_UNWILLING_TO_PERFORM;
771 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
772 if (!NT_STATUS_IS_OK(status)) {
773 ldb_set_errstring(ldb,
774 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
775 return LDB_ERR_UNWILLING_TO_PERFORM;
777 /* we remove this attribute as it can be a string and
778 * will not be treated correctly and then we will re-add
779 * it later on in the good format */
780 remove_current_guid = true;
784 guid = GUID_random();
787 ac = replmd_ctx_init(module, req);
789 return ldb_module_oom(module);
792 functional_level = dsdb_functional_level(ldb);
794 /* Get a sequence number from the backend */
795 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
796 if (ret != LDB_SUCCESS) {
801 /* get our invocationId */
802 our_invocation_id = samdb_ntds_invocation_id(ldb);
803 if (!our_invocation_id) {
804 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
805 "replmd_add: unable to find invocationId\n");
807 return LDB_ERR_OPERATIONS_ERROR;
810 /* we have to copy the message as the caller might have it as a const */
811 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
815 return LDB_ERR_OPERATIONS_ERROR;
818 /* generated times */
819 unix_to_nt_time(&now, t);
820 time_str = ldb_timestring(msg, t);
824 return LDB_ERR_OPERATIONS_ERROR;
826 if (remove_current_guid) {
827 ldb_msg_remove_attr(msg,"objectGUID");
831 * remove autogenerated attributes
833 ldb_msg_remove_attr(msg, "whenCreated");
834 ldb_msg_remove_attr(msg, "whenChanged");
835 ldb_msg_remove_attr(msg, "uSNCreated");
836 ldb_msg_remove_attr(msg, "uSNChanged");
837 ldb_msg_remove_attr(msg, "replPropertyMetaData");
840 * readd replicated attributes
842 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
843 if (ret != LDB_SUCCESS) {
849 /* build the replication meta_data */
852 nmd.ctr.ctr1.count = msg->num_elements;
853 nmd.ctr.ctr1.array = talloc_array(msg,
854 struct replPropertyMetaData1,
856 if (!nmd.ctr.ctr1.array) {
859 return LDB_ERR_OPERATIONS_ERROR;
862 for (i=0; i < msg->num_elements; i++) {
863 struct ldb_message_element *e = &msg->elements[i];
864 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
865 const struct dsdb_attribute *sa;
867 if (e->name[0] == '@') continue;
869 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
871 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
872 "replmd_add: attribute '%s' not defined in schema\n",
875 return LDB_ERR_NO_SUCH_ATTRIBUTE;
878 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
879 /* if the attribute is not replicated (0x00000001)
880 * or constructed (0x00000004) it has no metadata
885 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
886 ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa, req);
887 if (ret != LDB_SUCCESS) {
891 /* linked attributes are not stored in
892 replPropertyMetaData in FL above w2k */
896 m->attid = sa->attributeID_id;
898 m->originating_change_time = now;
899 m->originating_invocation_id = *our_invocation_id;
900 m->originating_usn = ac->seq_num;
901 m->local_usn = ac->seq_num;
905 /* fix meta data count */
906 nmd.ctr.ctr1.count = ni;
909 * sort meta data array, and move the rdn attribute entry to the end
911 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
912 if (ret != LDB_SUCCESS) {
917 /* generated NDR encoded values */
918 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
920 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
921 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
924 return LDB_ERR_OPERATIONS_ERROR;
928 * add the autogenerated values
930 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
931 if (ret != LDB_SUCCESS) {
936 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
937 if (ret != LDB_SUCCESS) {
942 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
943 if (ret != LDB_SUCCESS) {
948 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
949 if (ret != LDB_SUCCESS) {
954 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
955 if (ret != LDB_SUCCESS) {
962 * sort the attributes by attid before storing the object
964 replmd_ldb_message_sort(msg, ac->schema);
966 objectclass_el = ldb_msg_find_element(msg, "objectClass");
967 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
968 REPL_URGENT_ON_CREATE);
970 ac->is_urgent = is_urgent;
971 ret = ldb_build_add_req(&down_req, ldb, ac,
974 ac, replmd_op_callback,
977 LDB_REQ_SET_LOCATION(down_req);
978 if (ret != LDB_SUCCESS) {
983 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
984 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
985 if (ret != LDB_SUCCESS) {
991 /* mark the control done */
993 control->critical = 0;
996 /* go on with the call chain */
997 return ldb_next_request(module, down_req);
1002 * update the replPropertyMetaData for one element
1004 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1005 struct ldb_message *msg,
1006 struct ldb_message_element *el,
1007 struct ldb_message_element *old_el,
1008 struct replPropertyMetaDataBlob *omd,
1009 const struct dsdb_schema *schema,
1011 const struct GUID *our_invocation_id,
1015 const struct dsdb_attribute *a;
1016 struct replPropertyMetaData1 *md1;
1018 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1020 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1022 return LDB_ERR_OPERATIONS_ERROR;
1025 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1029 /* if the attribute's value haven't changed then return LDB_SUCCESS */
1030 if (old_el != NULL && ldb_msg_element_compare(el, old_el) == 0) {
1034 for (i=0; i<omd->ctr.ctr1.count; i++) {
1035 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
1038 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1039 /* linked attributes are not stored in
1040 replPropertyMetaData in FL above w2k, but we do
1041 raise the seqnum for the object */
1042 if (*seq_num == 0 &&
1043 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1044 return LDB_ERR_OPERATIONS_ERROR;
1049 if (i == omd->ctr.ctr1.count) {
1050 /* we need to add a new one */
1051 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1052 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1053 if (omd->ctr.ctr1.array == NULL) {
1055 return LDB_ERR_OPERATIONS_ERROR;
1057 omd->ctr.ctr1.count++;
1058 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1061 /* Get a new sequence number from the backend. We only do this
1062 * if we have a change that requires a new
1063 * replPropertyMetaData element
1065 if (*seq_num == 0) {
1066 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1067 if (ret != LDB_SUCCESS) {
1068 return LDB_ERR_OPERATIONS_ERROR;
1072 md1 = &omd->ctr.ctr1.array[i];
1074 md1->attid = a->attributeID_id;
1075 md1->originating_change_time = now;
1076 md1->originating_invocation_id = *our_invocation_id;
1077 md1->originating_usn = *seq_num;
1078 md1->local_usn = *seq_num;
1083 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1085 uint32_t count = omd.ctr.ctr1.count;
1088 for (i=0; i < count; i++) {
1089 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1090 if (max < m.local_usn) {
1098 * update the replPropertyMetaData object each time we modify an
1099 * object. This is needed for DRS replication, as the merge on the
1100 * client is based on this object
1102 static int replmd_update_rpmd(struct ldb_module *module,
1103 const struct dsdb_schema *schema,
1104 struct ldb_request *req,
1105 struct ldb_message *msg, uint64_t *seq_num,
1109 const struct ldb_val *omd_value;
1110 enum ndr_err_code ndr_err;
1111 struct replPropertyMetaDataBlob omd;
1114 const struct GUID *our_invocation_id;
1116 const char *attrs[] = { "replPropertyMetaData", "*", NULL };
1117 const char *attrs2[] = { "uSNChanged", "objectClass", NULL };
1118 struct ldb_result *res;
1119 struct ldb_context *ldb;
1120 struct ldb_message_element *objectclass_el;
1121 enum urgent_situation situation;
1122 bool rodc, rmd_is_provided;
1124 ldb = ldb_module_get_ctx(module);
1126 our_invocation_id = samdb_ntds_invocation_id(ldb);
1127 if (!our_invocation_id) {
1128 /* this happens during an initial vampire while
1129 updating the schema */
1130 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1134 unix_to_nt_time(&now, t);
1136 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1137 rmd_is_provided = true;
1139 rmd_is_provided = false;
1142 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1143 * otherwise we consider we are updating */
1144 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1145 situation = REPL_URGENT_ON_DELETE;
1147 situation = REPL_URGENT_ON_UPDATE;
1150 if (rmd_is_provided) {
1151 /* In this case the change_replmetadata control was supplied */
1152 /* We check that it's the only attribute that is provided
1153 * (it's a rare case so it's better to keep the code simplier)
1154 * We also check that the highest local_usn is bigger than
1157 if( msg->num_elements != 1 ||
1158 strncmp(msg->elements[0].name,
1159 "replPropertyMetaData", 20) ) {
1160 DEBUG(0,(__location__ ": changereplmetada control called without "\
1161 "a specified replPropertyMetaData attribute or with others\n"));
1162 return LDB_ERR_OPERATIONS_ERROR;
1164 if (situation == REPL_URGENT_ON_DELETE) {
1165 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1166 return LDB_ERR_OPERATIONS_ERROR;
1168 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1170 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1171 ldb_dn_get_linearized(msg->dn)));
1172 return LDB_ERR_OPERATIONS_ERROR;
1174 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1175 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1176 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1177 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1178 ldb_dn_get_linearized(msg->dn)));
1179 return LDB_ERR_OPERATIONS_ERROR;
1181 *seq_num = find_max_local_usn(omd);
1183 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1184 DSDB_FLAG_NEXT_MODULE |
1185 DSDB_SEARCH_SHOW_RECYCLED |
1186 DSDB_SEARCH_SHOW_EXTENDED_DN |
1187 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1188 DSDB_SEARCH_REVEAL_INTERNALS, req);
1190 if (ret != LDB_SUCCESS || res->count != 1) {
1191 DEBUG(0,(__location__ ": Object %s failed to find uSNChanged\n",
1192 ldb_dn_get_linearized(msg->dn)));
1193 return LDB_ERR_OPERATIONS_ERROR;
1196 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1197 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1202 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1203 if (*seq_num <= db_seq) {
1204 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)"\
1205 " is less or equal to uSNChanged (max = %lld uSNChanged = %lld)\n",
1206 (long long)*seq_num, (long long)db_seq));
1207 return LDB_ERR_OPERATIONS_ERROR;
1211 /* search for the existing replPropertyMetaDataBlob. We need
1212 * to use REVEAL and ask for DNs in storage format to support
1213 * the check for values being the same in
1214 * replmd_update_rpmd_element()
1216 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1217 DSDB_FLAG_NEXT_MODULE |
1218 DSDB_SEARCH_SHOW_RECYCLED |
1219 DSDB_SEARCH_SHOW_EXTENDED_DN |
1220 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1221 DSDB_SEARCH_REVEAL_INTERNALS, req);
1222 if (ret != LDB_SUCCESS || res->count != 1) {
1223 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1224 ldb_dn_get_linearized(msg->dn)));
1225 return LDB_ERR_OPERATIONS_ERROR;
1228 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1229 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1234 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1236 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1237 ldb_dn_get_linearized(msg->dn)));
1238 return LDB_ERR_OPERATIONS_ERROR;
1241 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1242 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1243 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1244 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1245 ldb_dn_get_linearized(msg->dn)));
1246 return LDB_ERR_OPERATIONS_ERROR;
1249 if (omd.version != 1) {
1250 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1251 omd.version, ldb_dn_get_linearized(msg->dn)));
1252 return LDB_ERR_OPERATIONS_ERROR;
1255 for (i=0; i<msg->num_elements; i++) {
1256 struct ldb_message_element *old_el;
1257 old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1258 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1259 our_invocation_id, now);
1260 if (ret != LDB_SUCCESS) {
1264 if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1265 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1271 * replmd_update_rpmd_element has done an update if the
1274 if (*seq_num != 0) {
1275 struct ldb_val *md_value;
1276 struct ldb_message_element *el;
1278 /*if we are RODC and this is a DRSR update then its ok*/
1279 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
1280 ret = samdb_rodc(ldb, &rodc);
1281 if (ret != LDB_SUCCESS) {
1282 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1284 ldb_asprintf_errstring(ldb, "RODC modify is forbidden\n");
1285 return LDB_ERR_REFERRAL;
1289 md_value = talloc(msg, struct ldb_val);
1290 if (md_value == NULL) {
1292 return LDB_ERR_OPERATIONS_ERROR;
1295 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1296 if (ret != LDB_SUCCESS) {
1300 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1301 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1302 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1303 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1304 ldb_dn_get_linearized(msg->dn)));
1305 return LDB_ERR_OPERATIONS_ERROR;
1308 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1309 if (ret != LDB_SUCCESS) {
1310 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1311 ldb_dn_get_linearized(msg->dn)));
1316 el->values = md_value;
1323 struct dsdb_dn *dsdb_dn;
1328 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1330 return GUID_compare(pdn1->guid, pdn2->guid);
1333 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1334 unsigned int count, struct GUID *guid,
1337 struct parsed_dn *ret;
1339 if (dn && GUID_all_zero(guid)) {
1340 /* when updating a link using DRS, we sometimes get a
1341 NULL GUID. We then need to try and match by DN */
1342 for (i=0; i<count; i++) {
1343 if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1344 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1350 BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1355 get a series of message element values as an array of DNs and GUIDs
1356 the result is sorted by GUID
1358 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1359 struct ldb_message_element *el, struct parsed_dn **pdn,
1360 const char *ldap_oid, struct ldb_request *parent)
1363 struct ldb_context *ldb = ldb_module_get_ctx(module);
1370 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1372 ldb_module_oom(module);
1373 return LDB_ERR_OPERATIONS_ERROR;
1376 for (i=0; i<el->num_values; i++) {
1377 struct ldb_val *v = &el->values[i];
1380 struct parsed_dn *p;
1384 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1385 if (p->dsdb_dn == NULL) {
1386 return LDB_ERR_INVALID_DN_SYNTAX;
1389 dn = p->dsdb_dn->dn;
1391 p->guid = talloc(*pdn, struct GUID);
1392 if (p->guid == NULL) {
1393 ldb_module_oom(module);
1394 return LDB_ERR_OPERATIONS_ERROR;
1397 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1398 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1399 /* we got a DN without a GUID - go find the GUID */
1400 int ret = dsdb_module_guid_by_dn(module, dn, p->guid, parent);
1401 if (ret != LDB_SUCCESS) {
1402 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1403 ldb_dn_get_linearized(dn));
1406 ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1407 if (ret != LDB_SUCCESS) {
1410 } else if (!NT_STATUS_IS_OK(status)) {
1411 return LDB_ERR_OPERATIONS_ERROR;
1414 /* keep a pointer to the original ldb_val */
1418 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1424 build a new extended DN, including all meta data fields
1426 RMD_FLAGS = DSDB_RMD_FLAG_* bits
1427 RMD_ADDTIME = originating_add_time
1428 RMD_INVOCID = originating_invocation_id
1429 RMD_CHANGETIME = originating_change_time
1430 RMD_ORIGINATING_USN = originating_usn
1431 RMD_LOCAL_USN = local_usn
1432 RMD_VERSION = version
1434 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1435 const struct GUID *invocation_id, uint64_t seq_num,
1436 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1438 struct ldb_dn *dn = dsdb_dn->dn;
1439 const char *tstring, *usn_string, *flags_string;
1440 struct ldb_val tval;
1442 struct ldb_val usnv, local_usnv;
1443 struct ldb_val vers, flagsv;
1446 const char *dnstring;
1448 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1450 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1452 return LDB_ERR_OPERATIONS_ERROR;
1454 tval = data_blob_string_const(tstring);
1456 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1458 return LDB_ERR_OPERATIONS_ERROR;
1460 usnv = data_blob_string_const(usn_string);
1462 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1464 return LDB_ERR_OPERATIONS_ERROR;
1466 local_usnv = data_blob_string_const(usn_string);
1468 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1470 return LDB_ERR_OPERATIONS_ERROR;
1472 vers = data_blob_string_const(vstring);
1474 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1475 if (!NT_STATUS_IS_OK(status)) {
1476 return LDB_ERR_OPERATIONS_ERROR;
1479 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1480 if (!flags_string) {
1481 return LDB_ERR_OPERATIONS_ERROR;
1483 flagsv = data_blob_string_const(flags_string);
1485 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1486 if (ret != LDB_SUCCESS) return ret;
1487 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1488 if (ret != LDB_SUCCESS) return ret;
1489 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1490 if (ret != LDB_SUCCESS) return ret;
1491 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1492 if (ret != LDB_SUCCESS) return ret;
1493 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1494 if (ret != LDB_SUCCESS) return ret;
1495 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1496 if (ret != LDB_SUCCESS) return ret;
1497 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1498 if (ret != LDB_SUCCESS) return ret;
1500 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1501 if (dnstring == NULL) {
1502 return LDB_ERR_OPERATIONS_ERROR;
1504 *v = data_blob_string_const(dnstring);
1509 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1510 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1511 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1512 uint32_t version, bool deleted);
1515 check if any links need upgrading from w2k format
1517 The parent_ctx is the ldb_message_element which contains the values array that dns[i].v points at, and which should be used for allocating any new value.
1519 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1522 for (i=0; i<count; i++) {
1527 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1528 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1532 /* it's an old one that needs upgrading */
1533 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1535 if (ret != LDB_SUCCESS) {
1543 update an extended DN, including all meta data fields
1545 see replmd_build_la_val for value names
1547 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1548 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1549 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1550 uint32_t version, bool deleted)
1552 struct ldb_dn *dn = dsdb_dn->dn;
1553 const char *tstring, *usn_string, *flags_string;
1554 struct ldb_val tval;
1556 struct ldb_val usnv, local_usnv;
1557 struct ldb_val vers, flagsv;
1558 const struct ldb_val *old_addtime;
1559 uint32_t old_version;
1562 const char *dnstring;
1564 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1566 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1568 return LDB_ERR_OPERATIONS_ERROR;
1570 tval = data_blob_string_const(tstring);
1572 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1574 return LDB_ERR_OPERATIONS_ERROR;
1576 usnv = data_blob_string_const(usn_string);
1578 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1580 return LDB_ERR_OPERATIONS_ERROR;
1582 local_usnv = data_blob_string_const(usn_string);
1584 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1585 if (!NT_STATUS_IS_OK(status)) {
1586 return LDB_ERR_OPERATIONS_ERROR;
1589 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1590 if (!flags_string) {
1591 return LDB_ERR_OPERATIONS_ERROR;
1593 flagsv = data_blob_string_const(flags_string);
1595 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1596 if (ret != LDB_SUCCESS) return ret;
1598 /* get the ADDTIME from the original */
1599 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1600 if (old_addtime == NULL) {
1601 old_addtime = &tval;
1603 if (dsdb_dn != old_dsdb_dn) {
1604 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1605 if (ret != LDB_SUCCESS) return ret;
1608 /* use our invocation id */
1609 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1610 if (ret != LDB_SUCCESS) return ret;
1612 /* changetime is the current time */
1613 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1614 if (ret != LDB_SUCCESS) return ret;
1616 /* update the USN */
1617 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1618 if (ret != LDB_SUCCESS) return ret;
1620 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1621 if (ret != LDB_SUCCESS) return ret;
1623 /* increase the version by 1 */
1624 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1625 if (NT_STATUS_IS_OK(status) && old_version >= version) {
1626 version = old_version+1;
1628 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1629 vers = data_blob_string_const(vstring);
1630 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1631 if (ret != LDB_SUCCESS) return ret;
1633 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1634 if (dnstring == NULL) {
1635 return LDB_ERR_OPERATIONS_ERROR;
1637 *v = data_blob_string_const(dnstring);
1643 handle adding a linked attribute
1645 static int replmd_modify_la_add(struct ldb_module *module,
1646 const struct dsdb_schema *schema,
1647 struct ldb_message *msg,
1648 struct ldb_message_element *el,
1649 struct ldb_message_element *old_el,
1650 const struct dsdb_attribute *schema_attr,
1653 struct GUID *msg_guid,
1654 struct ldb_request *parent)
1657 struct parsed_dn *dns, *old_dns;
1658 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1660 struct ldb_val *new_values = NULL;
1661 unsigned int num_new_values = 0;
1662 unsigned old_num_values = old_el?old_el->num_values:0;
1663 const struct GUID *invocation_id;
1664 struct ldb_context *ldb = ldb_module_get_ctx(module);
1667 unix_to_nt_time(&now, t);
1669 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1670 if (ret != LDB_SUCCESS) {
1671 talloc_free(tmp_ctx);
1675 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1676 if (ret != LDB_SUCCESS) {
1677 talloc_free(tmp_ctx);
1681 invocation_id = samdb_ntds_invocation_id(ldb);
1682 if (!invocation_id) {
1683 talloc_free(tmp_ctx);
1684 return LDB_ERR_OPERATIONS_ERROR;
1687 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1688 if (ret != LDB_SUCCESS) {
1689 talloc_free(tmp_ctx);
1693 /* for each new value, see if it exists already with the same GUID */
1694 for (i=0; i<el->num_values; i++) {
1695 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1697 /* this is a new linked attribute value */
1698 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1699 if (new_values == NULL) {
1700 ldb_module_oom(module);
1701 talloc_free(tmp_ctx);
1702 return LDB_ERR_OPERATIONS_ERROR;
1704 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1705 invocation_id, seq_num, seq_num, now, 0, false);
1706 if (ret != LDB_SUCCESS) {
1707 talloc_free(tmp_ctx);
1712 /* this is only allowed if the GUID was
1713 previously deleted. */
1714 uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1716 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
1717 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1718 el->name, GUID_string(tmp_ctx, p->guid));
1719 talloc_free(tmp_ctx);
1720 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1722 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1723 invocation_id, seq_num, seq_num, now, 0, false);
1724 if (ret != LDB_SUCCESS) {
1725 talloc_free(tmp_ctx);
1730 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1731 if (ret != LDB_SUCCESS) {
1732 talloc_free(tmp_ctx);
1737 /* add the new ones on to the end of the old values, constructing a new el->values */
1738 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1740 old_num_values+num_new_values);
1741 if (el->values == NULL) {
1742 ldb_module_oom(module);
1743 return LDB_ERR_OPERATIONS_ERROR;
1746 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1747 el->num_values = old_num_values + num_new_values;
1749 talloc_steal(msg->elements, el->values);
1750 talloc_steal(el->values, new_values);
1752 talloc_free(tmp_ctx);
1754 /* we now tell the backend to replace all existing values
1755 with the one we have constructed */
1756 el->flags = LDB_FLAG_MOD_REPLACE;
1763 handle deleting all active linked attributes
1765 static int replmd_modify_la_delete(struct ldb_module *module,
1766 const struct dsdb_schema *schema,
1767 struct ldb_message *msg,
1768 struct ldb_message_element *el,
1769 struct ldb_message_element *old_el,
1770 const struct dsdb_attribute *schema_attr,
1773 struct GUID *msg_guid,
1774 struct ldb_request *parent)
1777 struct parsed_dn *dns, *old_dns;
1778 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1780 const struct GUID *invocation_id;
1781 struct ldb_context *ldb = ldb_module_get_ctx(module);
1784 unix_to_nt_time(&now, t);
1786 /* check if there is nothing to delete */
1787 if ((!old_el || old_el->num_values == 0) &&
1788 el->num_values == 0) {
1792 if (!old_el || old_el->num_values == 0) {
1793 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1796 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1797 if (ret != LDB_SUCCESS) {
1798 talloc_free(tmp_ctx);
1802 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1803 if (ret != LDB_SUCCESS) {
1804 talloc_free(tmp_ctx);
1808 invocation_id = samdb_ntds_invocation_id(ldb);
1809 if (!invocation_id) {
1810 return LDB_ERR_OPERATIONS_ERROR;
1813 ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
1814 if (ret != LDB_SUCCESS) {
1815 talloc_free(tmp_ctx);
1821 /* see if we are being asked to delete any links that
1822 don't exist or are already deleted */
1823 for (i=0; i<el->num_values; i++) {
1824 struct parsed_dn *p = &dns[i];
1825 struct parsed_dn *p2;
1828 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
1830 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1831 el->name, GUID_string(tmp_ctx, p->guid));
1832 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1834 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
1835 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
1836 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1837 el->name, GUID_string(tmp_ctx, p->guid));
1838 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1842 /* for each new value, see if it exists already with the same GUID
1843 if it is not already deleted and matches the delete list then delete it
1845 for (i=0; i<old_el->num_values; i++) {
1846 struct parsed_dn *p = &old_dns[i];
1849 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
1853 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1854 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1856 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1857 invocation_id, seq_num, seq_num, now, 0, true);
1858 if (ret != LDB_SUCCESS) {
1859 talloc_free(tmp_ctx);
1863 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1864 if (ret != LDB_SUCCESS) {
1865 talloc_free(tmp_ctx);
1870 el->values = talloc_steal(msg->elements, old_el->values);
1871 el->num_values = old_el->num_values;
1873 talloc_free(tmp_ctx);
1875 /* we now tell the backend to replace all existing values
1876 with the one we have constructed */
1877 el->flags = LDB_FLAG_MOD_REPLACE;
1883 handle replacing a linked attribute
1885 static int replmd_modify_la_replace(struct ldb_module *module,
1886 const struct dsdb_schema *schema,
1887 struct ldb_message *msg,
1888 struct ldb_message_element *el,
1889 struct ldb_message_element *old_el,
1890 const struct dsdb_attribute *schema_attr,
1893 struct GUID *msg_guid,
1894 struct ldb_request *parent)
1897 struct parsed_dn *dns, *old_dns;
1898 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1900 const struct GUID *invocation_id;
1901 struct ldb_context *ldb = ldb_module_get_ctx(module);
1902 struct ldb_val *new_values = NULL;
1903 unsigned int num_new_values = 0;
1904 unsigned int old_num_values = old_el?old_el->num_values:0;
1907 unix_to_nt_time(&now, t);
1909 /* check if there is nothing to replace */
1910 if ((!old_el || old_el->num_values == 0) &&
1911 el->num_values == 0) {
1915 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1916 if (ret != LDB_SUCCESS) {
1917 talloc_free(tmp_ctx);
1921 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1922 if (ret != LDB_SUCCESS) {
1923 talloc_free(tmp_ctx);
1927 invocation_id = samdb_ntds_invocation_id(ldb);
1928 if (!invocation_id) {
1929 return LDB_ERR_OPERATIONS_ERROR;
1932 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1933 if (ret != LDB_SUCCESS) {
1934 talloc_free(tmp_ctx);
1938 /* mark all the old ones as deleted */
1939 for (i=0; i<old_num_values; i++) {
1940 struct parsed_dn *old_p = &old_dns[i];
1941 struct parsed_dn *p;
1942 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
1944 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1946 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1947 if (ret != LDB_SUCCESS) {
1948 talloc_free(tmp_ctx);
1952 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
1954 /* we don't delete it if we are re-adding it */
1958 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
1959 invocation_id, seq_num, seq_num, now, 0, true);
1960 if (ret != LDB_SUCCESS) {
1961 talloc_free(tmp_ctx);
1966 /* for each new value, either update its meta-data, or add it
1969 for (i=0; i<el->num_values; i++) {
1970 struct parsed_dn *p = &dns[i], *old_p;
1973 (old_p = parsed_dn_find(old_dns,
1974 old_num_values, p->guid, NULL)) != NULL) {
1975 /* update in place */
1976 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
1977 old_p->dsdb_dn, invocation_id,
1978 seq_num, seq_num, now, 0, false);
1979 if (ret != LDB_SUCCESS) {
1980 talloc_free(tmp_ctx);
1985 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
1987 if (new_values == NULL) {
1988 ldb_module_oom(module);
1989 talloc_free(tmp_ctx);
1990 return LDB_ERR_OPERATIONS_ERROR;
1992 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1993 invocation_id, seq_num, seq_num, now, 0, false);
1994 if (ret != LDB_SUCCESS) {
1995 talloc_free(tmp_ctx);
2001 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
2002 if (ret != LDB_SUCCESS) {
2003 talloc_free(tmp_ctx);
2008 /* add the new values to the end of old_el */
2009 if (num_new_values != 0) {
2010 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2011 struct ldb_val, old_num_values+num_new_values);
2012 if (el->values == NULL) {
2013 ldb_module_oom(module);
2014 return LDB_ERR_OPERATIONS_ERROR;
2016 memcpy(&el->values[old_num_values], &new_values[0],
2017 sizeof(struct ldb_val)*num_new_values);
2018 el->num_values = old_num_values + num_new_values;
2019 talloc_steal(msg->elements, new_values);
2021 el->values = old_el->values;
2022 el->num_values = old_el->num_values;
2023 talloc_steal(msg->elements, el->values);
2026 talloc_free(tmp_ctx);
2028 /* we now tell the backend to replace all existing values
2029 with the one we have constructed */
2030 el->flags = LDB_FLAG_MOD_REPLACE;
2037 handle linked attributes in modify requests
2039 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2040 struct ldb_message *msg,
2041 uint64_t seq_num, time_t t,
2042 struct ldb_request *parent)
2044 struct ldb_result *res;
2047 struct ldb_context *ldb = ldb_module_get_ctx(module);
2048 struct ldb_message *old_msg;
2050 const struct dsdb_schema *schema;
2051 struct GUID old_guid;
2054 /* there the replmd_update_rpmd code has already
2055 * checked and saw that there are no linked
2060 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2061 /* don't do anything special for linked attributes */
2065 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2066 DSDB_FLAG_NEXT_MODULE |
2067 DSDB_SEARCH_SHOW_RECYCLED |
2068 DSDB_SEARCH_REVEAL_INTERNALS |
2069 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2071 if (ret != LDB_SUCCESS) {
2074 schema = dsdb_get_schema(ldb, res);
2076 return LDB_ERR_OPERATIONS_ERROR;
2079 old_msg = res->msgs[0];
2081 old_guid = samdb_result_guid(old_msg, "objectGUID");
2083 for (i=0; i<msg->num_elements; i++) {
2084 struct ldb_message_element *el = &msg->elements[i];
2085 struct ldb_message_element *old_el, *new_el;
2086 const struct dsdb_attribute *schema_attr
2087 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2089 ldb_asprintf_errstring(ldb,
2090 "%s: attribute %s is not a valid attribute in schema",
2091 __FUNCTION__, el->name);
2092 return LDB_ERR_OBJECT_CLASS_VIOLATION;
2094 if (schema_attr->linkID == 0) {
2097 if ((schema_attr->linkID & 1) == 1) {
2098 /* Odd is for the target. Illegal to modify */
2099 ldb_asprintf_errstring(ldb,
2100 "attribute %s must not be modified directly, it is a linked attribute", el->name);
2101 return LDB_ERR_UNWILLING_TO_PERFORM;
2103 old_el = ldb_msg_find_element(old_msg, el->name);
2104 switch (el->flags & LDB_FLAG_MOD_MASK) {
2105 case LDB_FLAG_MOD_REPLACE:
2106 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2108 case LDB_FLAG_MOD_DELETE:
2109 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2111 case LDB_FLAG_MOD_ADD:
2112 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2115 ldb_asprintf_errstring(ldb,
2116 "invalid flags 0x%x for %s linked attribute",
2117 el->flags, el->name);
2118 return LDB_ERR_UNWILLING_TO_PERFORM;
2120 if (ret != LDB_SUCCESS) {
2124 ldb_msg_remove_attr(old_msg, el->name);
2126 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2127 new_el->num_values = el->num_values;
2128 new_el->values = talloc_steal(msg->elements, el->values);
2130 /* TODO: this relises a bit too heavily on the exact
2131 behaviour of ldb_msg_find_element and
2132 ldb_msg_remove_element */
2133 old_el = ldb_msg_find_element(msg, el->name);
2135 ldb_msg_remove_element(msg, old_el);
2146 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2148 struct ldb_context *ldb;
2149 struct replmd_replicated_request *ac;
2150 struct ldb_request *down_req;
2151 struct ldb_message *msg;
2152 time_t t = time(NULL);
2154 bool is_urgent = false;
2155 struct loadparm_context *lp_ctx;
2157 unsigned int functional_level;
2158 const DATA_BLOB *guid_blob;
2160 /* do not manipulate our control entries */
2161 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2162 return ldb_next_request(module, req);
2165 ldb = ldb_module_get_ctx(module);
2167 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2169 guid_blob = ldb_msg_find_ldb_val(req->op.mod.message, "objectGUID");
2170 if ( guid_blob != NULL ) {
2171 ldb_set_errstring(ldb,
2172 "replmd_modify: it's not allowed to change the objectGUID!");
2173 return LDB_ERR_CONSTRAINT_VIOLATION;
2176 ac = replmd_ctx_init(module, req);
2178 return ldb_module_oom(module);
2181 functional_level = dsdb_functional_level(ldb);
2183 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2184 struct loadparm_context);
2186 /* we have to copy the message as the caller might have it as a const */
2187 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2191 return LDB_ERR_OPERATIONS_ERROR;
2194 ldb_msg_remove_attr(msg, "whenChanged");
2195 ldb_msg_remove_attr(msg, "uSNChanged");
2197 ret = replmd_update_rpmd(module, ac->schema, req, msg, &ac->seq_num, t, &is_urgent);
2198 if (ret == LDB_ERR_REFERRAL) {
2199 referral = talloc_asprintf(req,
2201 lpcfg_dnsdomain(lp_ctx),
2202 ldb_dn_get_linearized(msg->dn));
2203 ret = ldb_module_send_referral(req, referral);
2205 return ldb_module_done(req, NULL, NULL, ret);
2208 if (ret != LDB_SUCCESS) {
2213 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2214 if (ret != LDB_SUCCESS) {
2220 * - replace the old object with the newly constructed one
2223 ac->is_urgent = is_urgent;
2225 ret = ldb_build_mod_req(&down_req, ldb, ac,
2228 ac, replmd_op_callback,
2230 LDB_REQ_SET_LOCATION(down_req);
2231 if (ret != LDB_SUCCESS) {
2236 /* If we are in functional level 2000, then
2237 * replmd_modify_handle_linked_attribs will have done
2239 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2240 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2241 if (ret != LDB_SUCCESS) {
2247 talloc_steal(down_req, msg);
2249 /* we only change whenChanged and uSNChanged if the seq_num
2251 if (ac->seq_num != 0) {
2252 ret = add_time_element(msg, "whenChanged", t);
2253 if (ret != LDB_SUCCESS) {
2258 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2259 if (ret != LDB_SUCCESS) {
2265 /* go on with the call chain */
2266 return ldb_next_request(module, down_req);
2269 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2272 handle a rename request
2274 On a rename we need to do an extra ldb_modify which sets the
2275 whenChanged and uSNChanged attributes. We do this in a callback after the success.
2277 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2279 struct ldb_context *ldb;
2280 struct replmd_replicated_request *ac;
2282 struct ldb_request *down_req;
2284 /* do not manipulate our control entries */
2285 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2286 return ldb_next_request(module, req);
2289 ldb = ldb_module_get_ctx(module);
2291 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2293 ac = replmd_ctx_init(module, req);
2295 return ldb_module_oom(module);
2298 ret = ldb_build_rename_req(&down_req, ldb, ac,
2299 ac->req->op.rename.olddn,
2300 ac->req->op.rename.newdn,
2302 ac, replmd_rename_callback,
2304 LDB_REQ_SET_LOCATION(down_req);
2305 if (ret != LDB_SUCCESS) {
2310 /* go on with the call chain */
2311 return ldb_next_request(module, down_req);
2314 /* After the rename is compleated, update the whenchanged etc */
2315 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2317 struct ldb_context *ldb;
2318 struct replmd_replicated_request *ac;
2319 struct ldb_request *down_req;
2320 struct ldb_message *msg;
2321 time_t t = time(NULL);
2324 ac = talloc_get_type(req->context, struct replmd_replicated_request);
2325 ldb = ldb_module_get_ctx(ac->module);
2327 if (ares->error != LDB_SUCCESS) {
2328 return ldb_module_done(ac->req, ares->controls,
2329 ares->response, ares->error);
2332 if (ares->type != LDB_REPLY_DONE) {
2333 ldb_set_errstring(ldb,
2334 "invalid ldb_reply_type in callback");
2336 return ldb_module_done(ac->req, NULL, NULL,
2337 LDB_ERR_OPERATIONS_ERROR);
2340 /* Get a sequence number from the backend */
2341 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
2342 if (ret != LDB_SUCCESS) {
2347 * - replace the old object with the newly constructed one
2350 msg = ldb_msg_new(ac);
2353 return LDB_ERR_OPERATIONS_ERROR;
2356 msg->dn = ac->req->op.rename.newdn;
2358 ret = ldb_build_mod_req(&down_req, ldb, ac,
2361 ac, replmd_op_callback,
2363 LDB_REQ_SET_LOCATION(down_req);
2364 if (ret != LDB_SUCCESS) {
2368 talloc_steal(down_req, msg);
2370 ret = add_time_element(msg, "whenChanged", t);
2371 if (ret != LDB_SUCCESS) {
2376 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2377 if (ret != LDB_SUCCESS) {
2382 /* go on with the call chain - do the modify after the rename */
2383 return ldb_next_request(ac->module, down_req);
2387 remove links from objects that point at this object when an object
2390 static int replmd_delete_remove_link(struct ldb_module *module,
2391 const struct dsdb_schema *schema,
2393 struct ldb_message_element *el,
2394 const struct dsdb_attribute *sa,
2395 struct ldb_request *parent)
2398 TALLOC_CTX *tmp_ctx = talloc_new(module);
2399 struct ldb_context *ldb = ldb_module_get_ctx(module);
2401 for (i=0; i<el->num_values; i++) {
2402 struct dsdb_dn *dsdb_dn;
2406 struct ldb_message *msg;
2407 const struct dsdb_attribute *target_attr;
2408 struct ldb_message_element *el2;
2409 struct ldb_val dn_val;
2411 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2415 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2417 talloc_free(tmp_ctx);
2418 return LDB_ERR_OPERATIONS_ERROR;
2421 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2422 if (!NT_STATUS_IS_OK(status)) {
2423 talloc_free(tmp_ctx);
2424 return LDB_ERR_OPERATIONS_ERROR;
2427 /* remove the link */
2428 msg = ldb_msg_new(tmp_ctx);
2430 ldb_module_oom(module);
2431 talloc_free(tmp_ctx);
2432 return LDB_ERR_OPERATIONS_ERROR;
2436 msg->dn = dsdb_dn->dn;
2438 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2439 if (target_attr == NULL) {
2443 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2444 if (ret != LDB_SUCCESS) {
2445 ldb_module_oom(module);
2446 talloc_free(tmp_ctx);
2447 return LDB_ERR_OPERATIONS_ERROR;
2449 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2450 el2->values = &dn_val;
2451 el2->num_values = 1;
2453 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
2454 if (ret != LDB_SUCCESS) {
2455 talloc_free(tmp_ctx);
2459 talloc_free(tmp_ctx);
2465 handle update of replication meta data for deletion of objects
2467 This also handles the mapping of delete to a rename operation
2468 to allow deletes to be replicated.
2470 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2472 int ret = LDB_ERR_OTHER;
2473 bool retb, disallow_move_on_delete;
2474 struct ldb_dn *old_dn, *new_dn;
2475 const char *rdn_name;
2476 const struct ldb_val *rdn_value, *new_rdn_value;
2478 struct ldb_context *ldb = ldb_module_get_ctx(module);
2479 const struct dsdb_schema *schema;
2480 struct ldb_message *msg, *old_msg;
2481 struct ldb_message_element *el;
2482 TALLOC_CTX *tmp_ctx;
2483 struct ldb_result *res, *parent_res;
2484 const char *preserved_attrs[] = {
2485 /* yes, this really is a hard coded list. See MS-ADTS
2486 section 3.1.1.5.5.1.1 */
2487 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2488 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2489 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2490 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2491 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2492 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2493 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2494 "whenChanged", NULL};
2495 unsigned int i, el_count = 0;
2496 enum deletion_state { OBJECT_NOT_DELETED=1, OBJECT_DELETED=2, OBJECT_RECYCLED=3,
2497 OBJECT_TOMBSTONE=4, OBJECT_REMOVED=5 };
2498 enum deletion_state deletion_state, next_deletion_state;
2501 if (ldb_dn_is_special(req->op.del.dn)) {
2502 return ldb_next_request(module, req);
2505 tmp_ctx = talloc_new(ldb);
2508 return LDB_ERR_OPERATIONS_ERROR;
2511 schema = dsdb_get_schema(ldb, tmp_ctx);
2513 return LDB_ERR_OPERATIONS_ERROR;
2516 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2518 /* we need the complete msg off disk, so we can work out which
2519 attributes need to be removed */
2520 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2521 DSDB_FLAG_NEXT_MODULE |
2522 DSDB_SEARCH_SHOW_RECYCLED |
2523 DSDB_SEARCH_REVEAL_INTERNALS |
2524 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
2525 if (ret != LDB_SUCCESS) {
2526 talloc_free(tmp_ctx);
2529 old_msg = res->msgs[0];
2532 ret = dsdb_recyclebin_enabled(module, &enabled);
2533 if (ret != LDB_SUCCESS) {
2534 talloc_free(tmp_ctx);
2538 if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2540 deletion_state = OBJECT_TOMBSTONE;
2541 next_deletion_state = OBJECT_REMOVED;
2542 } else if (ldb_msg_check_string_attribute(old_msg, "isRecycled", "TRUE")) {
2543 deletion_state = OBJECT_RECYCLED;
2544 next_deletion_state = OBJECT_REMOVED;
2546 deletion_state = OBJECT_DELETED;
2547 next_deletion_state = OBJECT_RECYCLED;
2550 deletion_state = OBJECT_NOT_DELETED;
2552 next_deletion_state = OBJECT_DELETED;
2554 next_deletion_state = OBJECT_TOMBSTONE;
2558 if (next_deletion_state == OBJECT_REMOVED) {
2559 struct auth_session_info *session_info =
2560 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2561 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
2562 ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2563 ldb_dn_get_linearized(old_msg->dn));
2564 return LDB_ERR_UNWILLING_TO_PERFORM;
2567 /* it is already deleted - really remove it this time */
2568 talloc_free(tmp_ctx);
2569 return ldb_next_request(module, req);
2572 rdn_name = ldb_dn_get_rdn_name(old_dn);
2573 rdn_value = ldb_dn_get_rdn_val(old_dn);
2574 if ((rdn_name == NULL) || (rdn_value == NULL)) {
2575 talloc_free(tmp_ctx);
2576 return ldb_operr(ldb);
2579 msg = ldb_msg_new(tmp_ctx);
2581 ldb_module_oom(module);
2582 talloc_free(tmp_ctx);
2583 return LDB_ERR_OPERATIONS_ERROR;
2588 if (deletion_state == OBJECT_NOT_DELETED){
2589 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
2590 disallow_move_on_delete =
2591 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
2592 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
2594 /* work out where we will be renaming this object to */
2595 if (!disallow_move_on_delete) {
2596 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
2598 if (ret != LDB_SUCCESS) {
2599 /* this is probably an attempted delete on a partition
2600 * that doesn't allow delete operations, such as the
2601 * schema partition */
2602 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2603 ldb_dn_get_linearized(old_dn));
2604 talloc_free(tmp_ctx);
2605 return LDB_ERR_UNWILLING_TO_PERFORM;
2608 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
2609 if (new_dn == NULL) {
2610 ldb_module_oom(module);
2611 talloc_free(tmp_ctx);
2612 return LDB_ERR_OPERATIONS_ERROR;
2616 /* get the objects GUID from the search we just did */
2617 guid = samdb_result_guid(old_msg, "objectGUID");
2619 /* Add a formatted child */
2620 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2622 ldb_dn_escape_value(tmp_ctx, *rdn_value),
2623 GUID_string(tmp_ctx, &guid));
2625 DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2626 ldb_dn_get_linearized(new_dn)));
2627 talloc_free(tmp_ctx);
2628 return LDB_ERR_OPERATIONS_ERROR;
2631 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2632 if (ret != LDB_SUCCESS) {
2633 DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2634 ldb_module_oom(module);
2635 talloc_free(tmp_ctx);
2638 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
2642 now we need to modify the object in the following ways:
2644 - add isDeleted=TRUE
2645 - update rDN and name, with new rDN
2646 - remove linked attributes
2647 - remove objectCategory and sAMAccountType
2648 - remove attribs not on the preserved list
2649 - preserved if in above list, or is rDN
2650 - remove all linked attribs from this object
2651 - remove all links from other objects to this object
2652 - add lastKnownParent
2653 - update replPropertyMetaData?
2655 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2658 /* we need the storage form of the parent GUID */
2659 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2660 ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2661 DSDB_FLAG_NEXT_MODULE |
2662 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2663 DSDB_SEARCH_REVEAL_INTERNALS|
2664 DSDB_SEARCH_SHOW_RECYCLED, req);
2665 if (ret != LDB_SUCCESS) {
2666 talloc_free(tmp_ctx);
2670 if (deletion_state == OBJECT_NOT_DELETED){
2671 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2672 ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2673 if (ret != LDB_SUCCESS) {
2674 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2675 ldb_module_oom(module);
2676 talloc_free(tmp_ctx);
2679 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2682 switch (next_deletion_state){
2684 case OBJECT_DELETED:
2686 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
2687 if (ret != LDB_SUCCESS) {
2688 DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n"));
2689 ldb_module_oom(module);
2690 talloc_free(tmp_ctx);
2693 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2695 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_DELETE, NULL);
2696 if (ret != LDB_SUCCESS) {
2697 talloc_free(tmp_ctx);
2698 ldb_module_oom(module);
2702 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_DELETE, NULL);
2703 if (ret != LDB_SUCCESS) {
2704 talloc_free(tmp_ctx);
2705 ldb_module_oom(module);
2711 case OBJECT_RECYCLED:
2712 case OBJECT_TOMBSTONE:
2714 /* we also mark it as recycled, meaning this object can't be
2715 recovered (we are stripping its attributes) */
2716 if (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008_R2) {
2717 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
2718 if (ret != LDB_SUCCESS) {
2719 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
2720 ldb_module_oom(module);
2721 talloc_free(tmp_ctx);
2724 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2727 /* work out which of the old attributes we will be removing */
2728 for (i=0; i<old_msg->num_elements; i++) {
2729 const struct dsdb_attribute *sa;
2730 el = &old_msg->elements[i];
2731 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2733 talloc_free(tmp_ctx);
2734 return LDB_ERR_OPERATIONS_ERROR;
2736 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2737 /* don't remove the rDN */
2740 if (sa->linkID && sa->linkID & 1) {
2741 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
2742 if (ret != LDB_SUCCESS) {
2743 talloc_free(tmp_ctx);
2744 return LDB_ERR_OPERATIONS_ERROR;
2748 if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2751 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2752 if (ret != LDB_SUCCESS) {
2753 talloc_free(tmp_ctx);
2754 ldb_module_oom(module);
2764 if (deletion_state == OBJECT_NOT_DELETED) {
2765 const struct dsdb_attribute *sa;
2767 /* work out what the new rdn value is, for updating the
2768 rDN and name fields */
2769 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2770 if (new_rdn_value == NULL) {
2771 talloc_free(tmp_ctx);
2772 return ldb_operr(ldb);
2775 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
2777 talloc_free(tmp_ctx);
2778 return LDB_ERR_OPERATIONS_ERROR;
2781 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
2783 if (ret != LDB_SUCCESS) {
2784 talloc_free(tmp_ctx);
2787 el->flags = LDB_FLAG_MOD_REPLACE;
2789 el = ldb_msg_find_element(old_msg, "name");
2791 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2792 if (ret != LDB_SUCCESS) {
2793 talloc_free(tmp_ctx);
2796 el->flags = LDB_FLAG_MOD_REPLACE;
2800 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
2801 if (ret != LDB_SUCCESS) {
2802 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
2803 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
2804 talloc_free(tmp_ctx);
2808 if (deletion_state == OBJECT_NOT_DELETED) {
2809 /* now rename onto the new DN */
2810 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
2811 if (ret != LDB_SUCCESS){
2812 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
2813 ldb_dn_get_linearized(old_dn),
2814 ldb_dn_get_linearized(new_dn),
2815 ldb_errstring(ldb)));
2816 talloc_free(tmp_ctx);
2821 talloc_free(tmp_ctx);
2823 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
2828 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
2833 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
2835 int ret = LDB_ERR_OTHER;
2836 /* TODO: do some error mapping */
2840 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
2842 struct ldb_context *ldb;
2843 struct ldb_request *change_req;
2844 enum ndr_err_code ndr_err;
2845 struct ldb_message *msg;
2846 struct replPropertyMetaDataBlob *md;
2847 struct ldb_val md_value;
2852 * TODO: check if the parent object exist
2856 * TODO: handle the conflict case where an object with the
2860 ldb = ldb_module_get_ctx(ar->module);
2861 msg = ar->objs->objects[ar->index_current].msg;
2862 md = ar->objs->objects[ar->index_current].meta_data;
2864 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2865 if (ret != LDB_SUCCESS) {
2866 return replmd_replicated_request_error(ar, ret);
2869 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
2870 if (ret != LDB_SUCCESS) {
2871 return replmd_replicated_request_error(ar, ret);
2874 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2875 if (ret != LDB_SUCCESS) {
2876 return replmd_replicated_request_error(ar, ret);
2879 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
2880 if (ret != LDB_SUCCESS) {
2881 return replmd_replicated_request_error(ar, ret);
2884 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2885 if (ret != LDB_SUCCESS) {
2886 return replmd_replicated_request_error(ar, ret);
2889 /* remove any message elements that have zero values */
2890 for (i=0; i<msg->num_elements; i++) {
2891 struct ldb_message_element *el = &msg->elements[i];
2893 if (el->num_values == 0) {
2894 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
2896 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
2897 msg->num_elements--;
2904 * the meta data array is already sorted by the caller
2906 for (i=0; i < md->ctr.ctr1.count; i++) {
2907 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
2909 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
2910 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2911 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2912 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2913 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2915 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
2916 if (ret != LDB_SUCCESS) {
2917 return replmd_replicated_request_error(ar, ret);
2920 replmd_ldb_message_sort(msg, ar->schema);
2923 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
2924 DEBUG(4, ("DRS replication add message:\n%s\n", s));
2928 ret = ldb_build_add_req(&change_req,
2936 LDB_REQ_SET_LOCATION(change_req);
2937 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2939 return ldb_next_request(ar->module, change_req);
2943 return true if an update is newer than an existing entry
2944 see section 5.11 of MS-ADTS
2946 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
2947 const struct GUID *update_invocation_id,
2948 uint32_t current_version,
2949 uint32_t update_version,
2950 NTTIME current_change_time,
2951 NTTIME update_change_time)
2953 if (update_version != current_version) {
2954 return update_version > current_version;
2956 if (update_change_time != current_change_time) {
2957 return update_change_time > current_change_time;
2959 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
2962 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
2963 struct replPropertyMetaData1 *new_m)
2965 return replmd_update_is_newer(&cur_m->originating_invocation_id,
2966 &new_m->originating_invocation_id,
2969 cur_m->originating_change_time,
2970 new_m->originating_change_time);
2973 static struct replPropertyMetaData1 *
2974 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
2975 enum drsuapi_DsAttributeId attid)
2978 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
2980 for (i = 0; i < rpmd_ctr->count; i++) {
2981 if (rpmd_ctr->array[i].attid == attid) {
2982 return &rpmd_ctr->array[i];
2990 handle renames that come in over DRS replication
2992 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
2993 struct ldb_message *msg,
2994 struct replPropertyMetaDataBlob *rmd,
2995 struct replPropertyMetaDataBlob *omd,
2996 struct ldb_request *parent)
2998 struct replPropertyMetaData1 *md_remote;
2999 struct replPropertyMetaData1 *md_local;
3001 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) == 0) {
3006 /* now we need to check for double renames. We could have a
3007 * local rename pending which our replication partner hasn't
3008 * received yet. We choose which one wins by looking at the
3009 * attribute stamps on the two objects, the newer one wins
3011 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3012 md_local = replmd_replPropertyMetaData1_find_attid(omd, DRSUAPI_ATTID_name);
3013 /* if there is no name attribute then we have to assume the
3014 object we've received is in fact newer */
3015 if (!md_remote || !md_local ||
3016 replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
3017 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
3018 ldb_dn_get_linearized(ar->search_msg->dn),
3019 ldb_dn_get_linearized(msg->dn)));
3020 /* pass rename to the next module
3021 * so it doesn't appear as an originating update */
3022 return dsdb_module_rename(ar->module,
3023 ar->search_msg->dn, msg->dn,
3024 DSDB_FLAG_NEXT_MODULE | DSDB_MODIFY_RELAX, parent);
3027 /* we're going to keep our old object */
3028 DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
3029 ldb_dn_get_linearized(ar->search_msg->dn),
3030 ldb_dn_get_linearized(msg->dn)));
3035 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
3037 struct ldb_context *ldb;
3038 struct ldb_request *change_req;
3039 enum ndr_err_code ndr_err;
3040 struct ldb_message *msg;
3041 struct replPropertyMetaDataBlob *rmd;
3042 struct replPropertyMetaDataBlob omd;
3043 const struct ldb_val *omd_value;
3044 struct replPropertyMetaDataBlob nmd;
3045 struct ldb_val nmd_value;
3048 unsigned int removed_attrs = 0;
3051 ldb = ldb_module_get_ctx(ar->module);
3052 msg = ar->objs->objects[ar->index_current].msg;
3053 rmd = ar->objs->objects[ar->index_current].meta_data;
3057 /* find existing meta data */
3058 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
3060 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
3061 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3062 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3063 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3064 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3067 if (omd.version != 1) {
3068 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3072 /* handle renames that come in over DRS */
3073 ret = replmd_replicated_handle_rename(ar, msg, rmd, &omd, ar->req);
3074 if (ret != LDB_SUCCESS) {
3075 ldb_debug(ldb, LDB_DEBUG_FATAL,
3076 "replmd_replicated_request rename %s => %s failed - %s\n",
3077 ldb_dn_get_linearized(ar->search_msg->dn),
3078 ldb_dn_get_linearized(msg->dn),
3079 ldb_errstring(ldb));
3080 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
3085 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
3086 nmd.ctr.ctr1.array = talloc_array(ar,
3087 struct replPropertyMetaData1,
3088 nmd.ctr.ctr1.count);
3089 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3091 /* first copy the old meta data */
3092 for (i=0; i < omd.ctr.ctr1.count; i++) {
3093 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
3097 /* now merge in the new meta data */
3098 for (i=0; i < rmd->ctr.ctr1.count; i++) {
3101 for (j=0; j < ni; j++) {
3104 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
3108 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
3109 &rmd->ctr.ctr1.array[i]);
3111 /* replace the entry */
3112 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
3117 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
3118 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
3119 msg->elements[i-removed_attrs].name,
3120 ldb_dn_get_linearized(msg->dn),
3121 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
3124 /* we don't want to apply this change so remove the attribute */
3125 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
3132 if (found) continue;
3134 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
3139 * finally correct the size of the meta_data array
3141 nmd.ctr.ctr1.count = ni;
3144 * the rdn attribute (the alias for the name attribute),
3145 * 'cn' for most objects is the last entry in the meta data array
3148 * sort the new meta data array
3150 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
3151 if (ret != LDB_SUCCESS) {
3156 * check if some replicated attributes left, otherwise skip the ldb_modify() call
3158 if (msg->num_elements == 0) {
3159 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
3162 ar->index_current++;
3163 return replmd_replicated_apply_next(ar);
3166 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
3167 ar->index_current, msg->num_elements);
3169 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3170 if (ret != LDB_SUCCESS) {
3171 return replmd_replicated_request_error(ar, ret);
3174 for (i=0; i<ni; i++) {
3175 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
3178 /* create the meta data value */
3179 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
3180 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3181 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3182 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3183 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3187 * when we know that we'll modify the record, add the whenChanged, uSNChanged
3188 * and replPopertyMetaData attributes
3190 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3191 if (ret != LDB_SUCCESS) {
3192 return replmd_replicated_request_error(ar, ret);
3194 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3195 if (ret != LDB_SUCCESS) {
3196 return replmd_replicated_request_error(ar, ret);
3198 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
3199 if (ret != LDB_SUCCESS) {
3200 return replmd_replicated_request_error(ar, ret);
3203 replmd_ldb_message_sort(msg, ar->schema);
3205 /* we want to replace the old values */
3206 for (i=0; i < msg->num_elements; i++) {
3207 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3211 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3212 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
3216 ret = ldb_build_mod_req(&change_req,
3224 LDB_REQ_SET_LOCATION(change_req);
3225 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3227 return ldb_next_request(ar->module, change_req);
3230 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
3231 struct ldb_reply *ares)
3233 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3234 struct replmd_replicated_request);
3238 return ldb_module_done(ar->req, NULL, NULL,
3239 LDB_ERR_OPERATIONS_ERROR);
3241 if (ares->error != LDB_SUCCESS &&
3242 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3243 return ldb_module_done(ar->req, ares->controls,
3244 ares->response, ares->error);
3247 switch (ares->type) {
3248 case LDB_REPLY_ENTRY:
3249 ar->search_msg = talloc_steal(ar, ares->message);
3252 case LDB_REPLY_REFERRAL:
3253 /* we ignore referrals */
3256 case LDB_REPLY_DONE:
3257 if (ar->search_msg != NULL) {
3258 ret = replmd_replicated_apply_merge(ar);
3260 ret = replmd_replicated_apply_add(ar);
3262 if (ret != LDB_SUCCESS) {
3263 return ldb_module_done(ar->req, NULL, NULL, ret);
3271 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
3273 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
3275 struct ldb_context *ldb;
3279 struct ldb_request *search_req;
3280 struct ldb_search_options_control *options;
3282 if (ar->index_current >= ar->objs->num_objects) {
3283 /* done with it, go to next stage */
3284 return replmd_replicated_uptodate_vector(ar);
3287 ldb = ldb_module_get_ctx(ar->module);
3288 ar->search_msg = NULL;
3290 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
3291 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3293 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
3294 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3295 talloc_free(tmp_str);
3297 ret = ldb_build_search_req(&search_req,
3306 replmd_replicated_apply_search_callback,
3308 LDB_REQ_SET_LOCATION(search_req);
3310 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
3312 if (ret != LDB_SUCCESS) {
3316 /* we need to cope with cross-partition links, so search for
3317 the GUID over all partitions */
3318 options = talloc(search_req, struct ldb_search_options_control);
3319 if (options == NULL) {
3320 DEBUG(0, (__location__ ": out of memory\n"));
3321 return LDB_ERR_OPERATIONS_ERROR;
3323 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3325 ret = ldb_request_add_control(search_req,
3326 LDB_CONTROL_SEARCH_OPTIONS_OID,
3328 if (ret != LDB_SUCCESS) {
3332 return ldb_next_request(ar->module, search_req);
3335 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
3336 struct ldb_reply *ares)
3338 struct ldb_context *ldb;
3339 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3340 struct replmd_replicated_request);
3341 ldb = ldb_module_get_ctx(ar->module);
3344 return ldb_module_done(ar->req, NULL, NULL,
3345 LDB_ERR_OPERATIONS_ERROR);
3347 if (ares->error != LDB_SUCCESS) {
3348 return ldb_module_done(ar->req, ares->controls,
3349 ares->response, ares->error);
3352 if (ares->type != LDB_REPLY_DONE) {
3353 ldb_set_errstring(ldb, "Invalid reply type\n!");
3354 return ldb_module_done(ar->req, NULL, NULL,
3355 LDB_ERR_OPERATIONS_ERROR);
3360 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3363 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
3365 struct ldb_context *ldb;
3366 struct ldb_request *change_req;
3367 enum ndr_err_code ndr_err;
3368 struct ldb_message *msg;
3369 struct replUpToDateVectorBlob ouv;
3370 const struct ldb_val *ouv_value;
3371 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
3372 struct replUpToDateVectorBlob nuv;
3373 struct ldb_val nuv_value;
3374 struct ldb_message_element *nuv_el = NULL;
3375 const struct GUID *our_invocation_id;
3376 struct ldb_message_element *orf_el = NULL;
3377 struct repsFromToBlob nrf;
3378 struct ldb_val *nrf_value = NULL;
3379 struct ldb_message_element *nrf_el = NULL;
3383 time_t t = time(NULL);
3386 uint32_t instanceType;
3388 ldb = ldb_module_get_ctx(ar->module);
3389 ruv = ar->objs->uptodateness_vector;
3395 unix_to_nt_time(&now, t);
3397 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
3398 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
3399 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
3400 ldb_dn_get_linearized(ar->search_msg->dn)));
3401 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3405 * first create the new replUpToDateVector
3407 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
3409 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
3410 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3411 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3412 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3413 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3416 if (ouv.version != 2) {
3417 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3422 * the new uptodateness vector will at least
3423 * contain 1 entry, one for the source_dsa
3425 * plus optional values from our old vector and the one from the source_dsa
3427 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
3428 if (ruv) nuv.ctr.ctr2.count += ruv->count;
3429 nuv.ctr.ctr2.cursors = talloc_array(ar,
3430 struct drsuapi_DsReplicaCursor2,
3431 nuv.ctr.ctr2.count);
3432 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3434 /* first copy the old vector */
3435 for (i=0; i < ouv.ctr.ctr2.count; i++) {
3436 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
3440 /* get our invocation_id if we have one already attached to the ldb */
3441 our_invocation_id = samdb_ntds_invocation_id(ldb);
3443 /* merge in the source_dsa vector is available */
3444 for (i=0; (ruv && i < ruv->count); i++) {
3447 if (our_invocation_id &&
3448 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3449 our_invocation_id)) {
3453 for (j=0; j < ni; j++) {
3454 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3455 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3462 * we update only the highest_usn and not the latest_sync_success time,
3463 * because the last success stands for direct replication
3465 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
3466 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
3471 if (found) continue;
3473 /* if it's not there yet, add it */
3474 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
3479 * merge in the current highwatermark for the source_dsa
3482 for (j=0; j < ni; j++) {
3483 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
3484 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3491 * here we update the highest_usn and last_sync_success time
3492 * because we're directly replicating from the source_dsa
3494 * and use the tmp_highest_usn because this is what we have just applied
3497 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3498 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
3503 * here we update the highest_usn and last_sync_success time
3504 * because we're directly replicating from the source_dsa
3506 * and use the tmp_highest_usn because this is what we have just applied
3509 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
3510 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3511 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
3516 * finally correct the size of the cursors array
3518 nuv.ctr.ctr2.count = ni;
3523 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
3526 * create the change ldb_message
3528 msg = ldb_msg_new(ar);
3529 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3530 msg->dn = ar->search_msg->dn;
3532 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
3533 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
3534 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3535 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3536 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3538 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
3539 if (ret != LDB_SUCCESS) {
3540 return replmd_replicated_request_error(ar, ret);
3542 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
3545 * now create the new repsFrom value from the given repsFromTo1 structure
3549 nrf.ctr.ctr1 = *ar->objs->source_dsa;
3550 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
3553 * first see if we already have a repsFrom value for the current source dsa
3554 * if so we'll later replace this value
3556 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
3558 for (i=0; i < orf_el->num_values; i++) {
3559 struct repsFromToBlob *trf;
3561 trf = talloc(ar, struct repsFromToBlob);
3562 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3564 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
3565 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3566 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3567 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3568 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3571 if (trf->version != 1) {
3572 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3576 * we compare the source dsa objectGUID not the invocation_id
3577 * because we want only one repsFrom value per source dsa
3578 * and when the invocation_id of the source dsa has changed we don't need
3579 * the old repsFrom with the old invocation_id
3581 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
3582 &ar->objs->source_dsa->source_dsa_obj_guid)) {
3588 nrf_value = &orf_el->values[i];
3593 * copy over all old values to the new ldb_message
3595 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
3596 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3601 * if we haven't found an old repsFrom value for the current source dsa
3602 * we'll add a new value
3605 struct ldb_val zero_value;
3606 ZERO_STRUCT(zero_value);
3607 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
3608 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3610 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
3613 /* we now fill the value which is already attached to ldb_message */
3614 ndr_err = ndr_push_struct_blob(nrf_value, msg,
3616 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3617 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3618 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3619 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3623 * the ldb_message_element for the attribute, has all the old values and the new one
3624 * so we'll replace the whole attribute with all values
3626 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
3629 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3630 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
3634 /* prepare the ldb_modify() request */
3635 ret = ldb_build_mod_req(&change_req,
3641 replmd_replicated_uptodate_modify_callback,
3643 LDB_REQ_SET_LOCATION(change_req);
3644 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3646 return ldb_next_request(ar->module, change_req);
3649 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
3650 struct ldb_reply *ares)
3652 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3653 struct replmd_replicated_request);
3657 return ldb_module_done(ar->req, NULL, NULL,
3658 LDB_ERR_OPERATIONS_ERROR);
3660 if (ares->error != LDB_SUCCESS &&
3661 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3662 return ldb_module_done(ar->req, ares->controls,
3663 ares->response, ares->error);
3666 switch (ares->type) {
3667 case LDB_REPLY_ENTRY:
3668 ar->search_msg = talloc_steal(ar, ares->message);
3671 case LDB_REPLY_REFERRAL:
3672 /* we ignore referrals */
3675 case LDB_REPLY_DONE:
3676 if (ar->search_msg == NULL) {
3677 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3679 ret = replmd_replicated_uptodate_modify(ar);
3681 if (ret != LDB_SUCCESS) {
3682 return ldb_module_done(ar->req, NULL, NULL, ret);
3691 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
3693 struct ldb_context *ldb;
3695 static const char *attrs[] = {
3696 "replUpToDateVector",
3701 struct ldb_request *search_req;
3703 ldb = ldb_module_get_ctx(ar->module);
3704 ar->search_msg = NULL;
3706 ret = ldb_build_search_req(&search_req,
3709 ar->objs->partition_dn,
3715 replmd_replicated_uptodate_search_callback,
3717 LDB_REQ_SET_LOCATION(search_req);
3718 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3720 return ldb_next_request(ar->module, search_req);
3725 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
3727 struct ldb_context *ldb;
3728 struct dsdb_extended_replicated_objects *objs;
3729 struct replmd_replicated_request *ar;
3730 struct ldb_control **ctrls;
3733 struct replmd_private *replmd_private =
3734 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3736 ldb = ldb_module_get_ctx(module);
3738 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
3740 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
3742 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
3743 return LDB_ERR_PROTOCOL_ERROR;
3746 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
3747 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
3748 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
3749 return LDB_ERR_PROTOCOL_ERROR;
3752 ar = replmd_ctx_init(module, req);
3754 return LDB_ERR_OPERATIONS_ERROR;
3756 /* Set the flags to have the replmd_op_callback run over the full set of objects */
3757 ar->apply_mode = true;
3759 ar->schema = dsdb_get_schema(ldb, ar);
3761 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
3763 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3764 return LDB_ERR_CONSTRAINT_VIOLATION;
3767 ctrls = req->controls;
3769 if (req->controls) {
3770 req->controls = talloc_memdup(ar, req->controls,
3771 talloc_get_size(req->controls));
3772 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3775 /* This allows layers further down to know if a change came in over replication */
3776 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
3777 if (ret != LDB_SUCCESS) {
3781 /* If this change contained linked attributes in the body
3782 * (rather than in the links section) we need to update
3783 * backlinks in linked_attributes */
3784 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3785 if (ret != LDB_SUCCESS) {
3789 ar->controls = req->controls;
3790 req->controls = ctrls;
3792 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
3794 /* save away the linked attributes for the end of the
3796 for (i=0; i<ar->objs->linked_attributes_count; i++) {
3797 struct la_entry *la_entry;
3799 if (replmd_private->la_ctx == NULL) {
3800 replmd_private->la_ctx = talloc_new(replmd_private);
3802 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
3803 if (la_entry == NULL) {
3805 return LDB_ERR_OPERATIONS_ERROR;
3807 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
3808 if (la_entry->la == NULL) {
3809 talloc_free(la_entry);
3811 return LDB_ERR_OPERATIONS_ERROR;
3813 *la_entry->la = ar->objs->linked_attributes[i];
3815 /* we need to steal the non-scalars so they stay
3816 around until the end of the transaction */
3817 talloc_steal(la_entry->la, la_entry->la->identifier);
3818 talloc_steal(la_entry->la, la_entry->la->value.blob);
3820 DLIST_ADD(replmd_private->la_list, la_entry);
3823 return replmd_replicated_apply_next(ar);
3827 process one linked attribute structure
3829 static int replmd_process_linked_attribute(struct ldb_module *module,
3830 struct la_entry *la_entry,
3831 struct ldb_request *parent)
3833 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
3834 struct ldb_context *ldb = ldb_module_get_ctx(module);
3835 struct ldb_message *msg;
3836 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
3837 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
3839 const struct dsdb_attribute *attr;
3840 struct dsdb_dn *dsdb_dn;
3841 uint64_t seq_num = 0;
3842 struct ldb_message_element *old_el;
3844 time_t t = time(NULL);
3845 struct ldb_result *res;
3846 const char *attrs[2];
3847 struct parsed_dn *pdn_list, *pdn;
3848 struct GUID guid = GUID_zero();
3850 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
3851 const struct GUID *our_invocation_id;
3854 linked_attributes[0]:
3855 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
3857 identifier: struct drsuapi_DsReplicaObjectIdentifier
3858 __ndr_size : 0x0000003a (58)
3859 __ndr_size_sid : 0x00000000 (0)
3860 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
3862 __ndr_size_dn : 0x00000000 (0)
3864 attid : DRSUAPI_ATTID_member (0x1F)
3865 value: struct drsuapi_DsAttributeValue
3866 __ndr_size : 0x0000007e (126)
3868 blob : DATA_BLOB length=126
3869 flags : 0x00000001 (1)
3870 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
3871 originating_add_time : Wed Sep 2 22:20:01 2009 EST
3872 meta_data: struct drsuapi_DsReplicaMetaData
3873 version : 0x00000015 (21)
3874 originating_change_time : Wed Sep 2 23:39:07 2009 EST
3875 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
3876 originating_usn : 0x000000000001e19c (123292)
3878 (for cases where the link is to a normal DN)
3879 &target: struct drsuapi_DsReplicaObjectIdentifier3
3880 __ndr_size : 0x0000007e (126)
3881 __ndr_size_sid : 0x0000001c (28)
3882 guid : 7639e594-db75-4086-b0d4-67890ae46031
3883 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
3884 __ndr_size_dn : 0x00000022 (34)
3885 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
3888 /* find the attribute being modified */
3889 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
3891 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
3892 talloc_free(tmp_ctx);
3893 return LDB_ERR_OPERATIONS_ERROR;
3896 attrs[0] = attr->lDAPDisplayName;
3899 /* get the existing message from the db for the object with
3900 this GUID, returning attribute being modified. We will then
3901 use this msg as the basis for a modify call */
3902 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3903 DSDB_FLAG_NEXT_MODULE |
3904 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3905 DSDB_SEARCH_SHOW_RECYCLED |
3906 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3907 DSDB_SEARCH_REVEAL_INTERNALS,
3909 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
3910 if (ret != LDB_SUCCESS) {
3911 talloc_free(tmp_ctx);
3914 if (res->count != 1) {
3915 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
3916 GUID_string(tmp_ctx, &la->identifier->guid));
3917 talloc_free(tmp_ctx);
3918 return LDB_ERR_NO_SUCH_OBJECT;
3922 if (msg->num_elements == 0) {
3923 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
3924 if (ret != LDB_SUCCESS) {
3925 ldb_module_oom(module);
3926 talloc_free(tmp_ctx);
3927 return LDB_ERR_OPERATIONS_ERROR;
3930 old_el = &msg->elements[0];
3931 old_el->flags = LDB_FLAG_MOD_REPLACE;
3934 /* parse the existing links */
3935 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
3936 if (ret != LDB_SUCCESS) {
3937 talloc_free(tmp_ctx);
3941 /* get our invocationId */
3942 our_invocation_id = samdb_ntds_invocation_id(ldb);
3943 if (!our_invocation_id) {
3944 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
3945 talloc_free(tmp_ctx);
3946 return LDB_ERR_OPERATIONS_ERROR;
3949 ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
3950 if (ret != LDB_SUCCESS) {
3951 talloc_free(tmp_ctx);
3955 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
3956 if (!W_ERROR_IS_OK(status)) {
3957 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
3958 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
3959 return LDB_ERR_OPERATIONS_ERROR;
3962 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
3963 if (!NT_STATUS_IS_OK(ntstatus) && active) {
3964 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
3966 ldb_dn_get_linearized(dsdb_dn->dn),
3967 ldb_dn_get_linearized(msg->dn));
3968 return LDB_ERR_OPERATIONS_ERROR;
3971 /* re-resolve the DN by GUID, as the DRS server may give us an
3973 ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn, parent);
3974 if (ret != LDB_SUCCESS) {
3975 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s",
3976 GUID_string(tmp_ctx, &guid),
3977 ldb_dn_get_linearized(dsdb_dn->dn)));
3980 /* see if this link already exists */
3981 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
3983 /* see if this update is newer than what we have already */
3984 struct GUID invocation_id = GUID_zero();
3985 uint32_t version = 0;
3986 uint32_t originating_usn = 0;
3987 NTTIME change_time = 0;
3988 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
3990 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
3991 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
3992 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
3993 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
3995 if (!replmd_update_is_newer(&invocation_id,
3996 &la->meta_data.originating_invocation_id,
3998 la->meta_data.version,
4000 la->meta_data.originating_change_time)) {
4001 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
4002 old_el->name, ldb_dn_get_linearized(msg->dn),
4003 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
4004 talloc_free(tmp_ctx);
4008 /* get a seq_num for this change */
4009 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4010 if (ret != LDB_SUCCESS) {
4011 talloc_free(tmp_ctx);
4015 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
4016 /* remove the existing backlink */
4017 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
4018 if (ret != LDB_SUCCESS) {
4019 talloc_free(tmp_ctx);
4024 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
4025 &la->meta_data.originating_invocation_id,
4026 la->meta_data.originating_usn, seq_num,
4027 la->meta_data.originating_change_time,
4028 la->meta_data.version,
4030 if (ret != LDB_SUCCESS) {
4031 talloc_free(tmp_ctx);
4036 /* add the new backlink */
4037 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
4038 if (ret != LDB_SUCCESS) {
4039 talloc_free(tmp_ctx);
4044 /* get a seq_num for this change */
4045 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4046 if (ret != LDB_SUCCESS) {
4047 talloc_free(tmp_ctx);
4051 old_el->values = talloc_realloc(msg->elements, old_el->values,
4052 struct ldb_val, old_el->num_values+1);
4053 if (!old_el->values) {
4054 ldb_module_oom(module);
4055 return LDB_ERR_OPERATIONS_ERROR;
4057 old_el->num_values++;
4059 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
4060 &la->meta_data.originating_invocation_id,
4061 la->meta_data.originating_usn, seq_num,
4062 la->meta_data.originating_change_time,
4063 la->meta_data.version,
4064 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
4065 if (ret != LDB_SUCCESS) {
4066 talloc_free(tmp_ctx);
4071 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
4073 if (ret != LDB_SUCCESS) {
4074 talloc_free(tmp_ctx);
4080 /* we only change whenChanged and uSNChanged if the seq_num
4082 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
4083 talloc_free(tmp_ctx);
4084 return ldb_operr(ldb);
4087 if (add_uint64_element(ldb, msg, "uSNChanged",
4088 seq_num) != LDB_SUCCESS) {
4089 talloc_free(tmp_ctx);
4090 return ldb_operr(ldb);
4093 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
4094 if (old_el == NULL) {
4095 talloc_free(tmp_ctx);
4096 return ldb_operr(ldb);
4099 ret = dsdb_check_single_valued_link(attr, old_el);
4100 if (ret != LDB_SUCCESS) {
4101 talloc_free(tmp_ctx);
4105 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
4107 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
4108 if (ret != LDB_SUCCESS) {
4109 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
4111 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
4112 talloc_free(tmp_ctx);
4116 talloc_free(tmp_ctx);
4121 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
4123 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
4124 return replmd_extended_replicated_objects(module, req);
4127 return ldb_next_request(module, req);
4132 we hook into the transaction operations to allow us to
4133 perform the linked attribute updates at the end of the whole
4134 transaction. This allows a forward linked attribute to be created
4135 before the object is created. During a vampire, w2k8 sends us linked
4136 attributes before the objects they are part of.
4138 static int replmd_start_transaction(struct ldb_module *module)
4140 /* create our private structure for this transaction */
4141 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
4142 struct replmd_private);
4143 replmd_txn_cleanup(replmd_private);
4145 /* free any leftover mod_usn records from cancelled
4147 while (replmd_private->ncs) {
4148 struct nc_entry *e = replmd_private->ncs;
4149 DLIST_REMOVE(replmd_private->ncs, e);
4153 return ldb_next_start_trans(module);
4157 on prepare commit we loop over our queued la_context structures and
4160 static int replmd_prepare_commit(struct ldb_module *module)
4162 struct replmd_private *replmd_private =
4163 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4164 struct la_entry *la, *prev;
4165 struct la_backlink *bl;
4168 /* walk the list backwards, to do the first entry first, as we
4169 * added the entries with DLIST_ADD() which puts them at the
4170 * start of the list */
4171 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
4172 prev = DLIST_PREV(la);
4173 DLIST_REMOVE(replmd_private->la_list, la);
4174 ret = replmd_process_linked_attribute(module, la, NULL);
4175 if (ret != LDB_SUCCESS) {
4176 replmd_txn_cleanup(replmd_private);
4181 /* process our backlink list, creating and deleting backlinks
4183 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
4184 ret = replmd_process_backlink(module, bl, NULL);
4185 if (ret != LDB_SUCCESS) {
4186 replmd_txn_cleanup(replmd_private);
4191 replmd_txn_cleanup(replmd_private);
4193 /* possibly change @REPLCHANGED */
4194 ret = replmd_notify_store(module, NULL);
4195 if (ret != LDB_SUCCESS) {
4199 return ldb_next_prepare_commit(module);
4202 static int replmd_del_transaction(struct ldb_module *module)
4204 struct replmd_private *replmd_private =
4205 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4206 replmd_txn_cleanup(replmd_private);
4208 return ldb_next_del_trans(module);
4212 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
4213 .name = "repl_meta_data",
4214 .init_context = replmd_init,
4216 .modify = replmd_modify,
4217 .rename = replmd_rename,
4218 .del = replmd_delete,
4219 .extended = replmd_extended,
4220 .start_transaction = replmd_start_transaction,
4221 .prepare_commit = replmd_prepare_commit,
4222 .del_transaction = replmd_del_transaction,
4225 int ldb_repl_meta_data_module_init(const char *version)
4227 LDB_MODULE_CHECK_VERSION(version);
4228 return ldb_register_module(&ldb_repl_meta_data_module_ops);