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
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 * Component: ldb repl_meta_data module
28 * Description: - add a unique objectGUID onto every new record,
29 * - handle whenCreated, whenChanged timestamps
30 * - handle uSNCreated, uSNChanged numbers
31 * - handle replPropertyMetaData attribute
34 * Author: Stefan Metzmacher
38 #include "ldb_module.h"
39 #include "dsdb/samdb/samdb.h"
40 #include "dsdb/common/proto.h"
41 #include "../libds/common/flags.h"
42 #include "librpc/gen_ndr/ndr_misc.h"
43 #include "librpc/gen_ndr/ndr_drsuapi.h"
44 #include "librpc/gen_ndr/ndr_drsblobs.h"
45 #include "param/param.h"
46 #include "libcli/security/dom_sid.h"
47 #include "lib/util/dlinklist.h"
48 #include "dsdb/samdb/ldb_modules/util.h"
49 #include "lib/util/binsearch.h"
51 #define W2K3_LINKED_ATTRIBUTES 1
53 struct replmd_private {
55 struct la_entry *la_list;
57 struct la_backlink *la_backlinks;
59 struct nc_entry *prev, *next;
66 struct la_entry *next, *prev;
67 struct drsuapi_DsReplicaLinkedAttribute *la;
70 struct replmd_replicated_request {
71 struct ldb_module *module;
72 struct ldb_request *req;
74 const struct dsdb_schema *schema;
76 /* the controls we pass down */
77 struct ldb_control **controls;
79 /* details for the mode where we apply a bunch of inbound replication meessages */
81 uint32_t index_current;
82 struct dsdb_extended_replicated_objects *objs;
84 struct ldb_message *search_msg;
90 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
95 allocate the private structure and build the list
96 of partition DNs for use by replmd_notify()
98 static int replmd_init(struct ldb_module *module)
100 struct replmd_private *replmd_private;
101 struct ldb_context *ldb = ldb_module_get_ctx(module);
103 replmd_private = talloc_zero(module, struct replmd_private);
104 if (replmd_private == NULL) {
106 return LDB_ERR_OPERATIONS_ERROR;
108 ldb_module_set_private(module, replmd_private);
110 return ldb_next_init(module);
114 cleanup our per-transaction contexts
116 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
118 talloc_free(replmd_private->la_ctx);
119 replmd_private->la_list = NULL;
120 replmd_private->la_ctx = NULL;
122 talloc_free(replmd_private->bl_ctx);
123 replmd_private->la_backlinks = NULL;
124 replmd_private->bl_ctx = NULL;
129 struct la_backlink *next, *prev;
130 const char *attr_name;
131 struct GUID forward_guid, target_guid;
136 process a backlinks we accumulated during a transaction, adding and
137 deleting the backlinks from the target objects
139 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl)
141 struct ldb_dn *target_dn, *source_dn;
143 struct ldb_context *ldb = ldb_module_get_ctx(module);
144 struct ldb_message *msg;
145 TALLOC_CTX *tmp_ctx = talloc_new(bl);
151 - construct ldb_message
152 - either an add or a delete
154 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn);
155 if (ret != LDB_SUCCESS) {
156 ldb_asprintf_errstring(ldb, "Failed to find target DN for linked attribute with GUID %s\n",
157 GUID_string(bl, &bl->target_guid));
158 talloc_free(tmp_ctx);
162 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn);
163 if (ret != LDB_SUCCESS) {
164 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
165 GUID_string(bl, &bl->forward_guid));
166 talloc_free(tmp_ctx);
170 msg = ldb_msg_new(tmp_ctx);
172 ldb_module_oom(module);
173 talloc_free(tmp_ctx);
174 return LDB_ERR_OPERATIONS_ERROR;
177 /* construct a ldb_message for adding/deleting the backlink */
179 dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
181 ldb_module_oom(module);
182 talloc_free(tmp_ctx);
183 return LDB_ERR_OPERATIONS_ERROR;
185 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
186 if (ret != LDB_SUCCESS) {
187 talloc_free(tmp_ctx);
190 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
192 ret = dsdb_module_modify(module, msg, 0);
193 if (ret != LDB_SUCCESS) {
194 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
195 bl->active?"add":"remove",
196 ldb_dn_get_linearized(source_dn),
197 ldb_dn_get_linearized(target_dn),
199 talloc_free(tmp_ctx);
202 talloc_free(tmp_ctx);
207 add a backlink to the list of backlinks to add/delete in the prepare
210 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
211 struct GUID *forward_guid, struct GUID *target_guid,
212 bool active, const struct dsdb_attribute *schema_attr, bool immediate)
214 const struct dsdb_attribute *target_attr;
215 struct la_backlink *bl;
216 struct replmd_private *replmd_private =
217 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
219 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
222 * windows 2003 has a broken schema where the
223 * definition of msDS-IsDomainFor is missing (which is
224 * supposed to be the backlink of the
225 * msDS-HasDomainNCs attribute
230 /* see if its already in the list */
231 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
232 if (GUID_equal(forward_guid, &bl->forward_guid) &&
233 GUID_equal(target_guid, &bl->target_guid) &&
234 (target_attr->lDAPDisplayName == bl->attr_name ||
235 strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
241 /* we found an existing one */
242 if (bl->active == active) {
245 DLIST_REMOVE(replmd_private->la_backlinks, bl);
250 if (replmd_private->bl_ctx == NULL) {
251 replmd_private->bl_ctx = talloc_new(replmd_private);
252 if (replmd_private->bl_ctx == NULL) {
253 ldb_module_oom(module);
254 return LDB_ERR_OPERATIONS_ERROR;
259 bl = talloc(replmd_private->bl_ctx, struct la_backlink);
261 ldb_module_oom(module);
262 return LDB_ERR_OPERATIONS_ERROR;
265 bl->attr_name = target_attr->lDAPDisplayName;
266 bl->forward_guid = *forward_guid;
267 bl->target_guid = *target_guid;
270 /* the caller may ask for this backlink to be processed
273 int ret = replmd_process_backlink(module, bl);
278 DLIST_ADD(replmd_private->la_backlinks, bl);
285 * Callback for most write operations in this module:
287 * notify the repl task that a object has changed. The notifies are
288 * gathered up in the replmd_private structure then written to the
289 * @REPLCHANGED object in each partition during the prepare_commit
291 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
294 struct replmd_replicated_request *ac =
295 talloc_get_type_abort(req->context, struct replmd_replicated_request);
296 struct replmd_private *replmd_private =
297 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
298 struct nc_entry *modified_partition;
299 struct ldb_control *partition_ctrl;
300 const struct dsdb_control_current_partition *partition;
302 struct ldb_control **controls;
304 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
306 /* Remove the 'partition' control from what we pass up the chain */
307 controls = controls_except_specified(ares->controls, ares, partition_ctrl);
309 if (ares->error != LDB_SUCCESS) {
310 return ldb_module_done(ac->req, controls,
311 ares->response, ares->error);
314 if (ares->type != LDB_REPLY_DONE) {
315 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
316 return ldb_module_done(ac->req, NULL,
317 NULL, LDB_ERR_OPERATIONS_ERROR);
320 if (!partition_ctrl) {
321 return ldb_module_done(ac->req, NULL,
322 NULL, LDB_ERR_OPERATIONS_ERROR);
325 partition = talloc_get_type_abort(partition_ctrl->data,
326 struct dsdb_control_current_partition);
328 if (ac->seq_num > 0) {
329 for (modified_partition = replmd_private->ncs; modified_partition;
330 modified_partition = modified_partition->next) {
331 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
336 if (modified_partition == NULL) {
337 modified_partition = talloc_zero(replmd_private, struct nc_entry);
338 if (!modified_partition) {
339 ldb_oom(ldb_module_get_ctx(ac->module));
340 return ldb_module_done(ac->req, NULL,
341 NULL, LDB_ERR_OPERATIONS_ERROR);
343 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
344 if (!modified_partition->dn) {
345 ldb_oom(ldb_module_get_ctx(ac->module));
346 return ldb_module_done(ac->req, NULL,
347 NULL, LDB_ERR_OPERATIONS_ERROR);
349 DLIST_ADD(replmd_private->ncs, modified_partition);
352 if (ac->seq_num > modified_partition->mod_usn) {
353 modified_partition->mod_usn = ac->seq_num;
357 if (ac->apply_mode) {
361 ret = replmd_replicated_apply_next(ac);
362 if (ret != LDB_SUCCESS) {
363 return ldb_module_done(ac->req, NULL, NULL, ret);
367 /* free the partition control container here, for the
368 * common path. Other cases will have it cleaned up
369 * eventually with the ares */
370 talloc_free(partition_ctrl);
371 return ldb_module_done(ac->req,
372 controls_except_specified(controls, ares, partition_ctrl),
373 ares->response, LDB_SUCCESS);
379 * update a @REPLCHANGED record in each partition if there have been
380 * any writes of replicated data in the partition
382 static int replmd_notify_store(struct ldb_module *module)
384 struct replmd_private *replmd_private =
385 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
386 struct ldb_context *ldb = ldb_module_get_ctx(module);
388 while (replmd_private->ncs) {
390 struct nc_entry *modified_partition = replmd_private->ncs;
392 ret = dsdb_save_partition_usn(ldb, modified_partition->dn, modified_partition->mod_usn);
393 if (ret != LDB_SUCCESS) {
394 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
395 ldb_dn_get_linearized(modified_partition->dn)));
398 DLIST_REMOVE(replmd_private->ncs, modified_partition);
399 talloc_free(modified_partition);
407 created a replmd_replicated_request context
409 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
410 struct ldb_request *req)
412 struct ldb_context *ldb;
413 struct replmd_replicated_request *ac;
415 ldb = ldb_module_get_ctx(module);
417 ac = talloc_zero(req, struct replmd_replicated_request);
426 ac->schema = dsdb_get_schema(ldb);
428 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
429 "replmd_modify: no dsdb_schema loaded");
430 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
438 add a time element to a record
440 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
442 struct ldb_message_element *el;
445 if (ldb_msg_find_element(msg, attr) != NULL) {
449 s = ldb_timestring(msg, t);
451 return LDB_ERR_OPERATIONS_ERROR;
454 if (ldb_msg_add_string(msg, attr, s) != LDB_SUCCESS) {
455 return LDB_ERR_OPERATIONS_ERROR;
458 el = ldb_msg_find_element(msg, attr);
459 /* always set as replace. This works because on add ops, the flag
461 el->flags = LDB_FLAG_MOD_REPLACE;
467 add a uint64_t element to a record
469 static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_t v)
471 struct ldb_message_element *el;
473 if (ldb_msg_find_element(msg, attr) != NULL) {
477 if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != LDB_SUCCESS) {
478 return LDB_ERR_OPERATIONS_ERROR;
481 el = ldb_msg_find_element(msg, attr);
482 /* always set as replace. This works because on add ops, the flag
484 el->flags = LDB_FLAG_MOD_REPLACE;
489 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
490 const struct replPropertyMetaData1 *m2,
491 const uint32_t *rdn_attid)
493 if (m1->attid == m2->attid) {
498 * the rdn attribute should be at the end!
499 * so we need to return a value greater than zero
500 * which means m1 is greater than m2
502 if (m1->attid == *rdn_attid) {
507 * the rdn attribute should be at the end!
508 * so we need to return a value less than zero
509 * which means m2 is greater than m1
511 if (m2->attid == *rdn_attid) {
515 return m1->attid > m2->attid ? 1 : -1;
518 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
519 const struct dsdb_schema *schema,
522 const char *rdn_name;
523 const struct dsdb_attribute *rdn_sa;
525 rdn_name = ldb_dn_get_rdn_name(dn);
527 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
528 return LDB_ERR_OPERATIONS_ERROR;
531 rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
532 if (rdn_sa == NULL) {
533 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
534 return LDB_ERR_OPERATIONS_ERROR;
537 DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
538 rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
540 ldb_qsort(ctr1->array, ctr1->count, sizeof(struct replPropertyMetaData1),
541 discard_const_p(void, &rdn_sa->attributeID_id),
542 (ldb_qsort_cmp_fn_t)replmd_replPropertyMetaData1_attid_sort);
547 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
548 const struct ldb_message_element *e2,
549 const struct dsdb_schema *schema)
551 const struct dsdb_attribute *a1;
552 const struct dsdb_attribute *a2;
555 * TODO: make this faster by caching the dsdb_attribute pointer
556 * on the ldb_messag_element
559 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
560 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
563 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
567 return strcasecmp(e1->name, e2->name);
569 if (a1->attributeID_id == a2->attributeID_id) {
572 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
575 static void replmd_ldb_message_sort(struct ldb_message *msg,
576 const struct dsdb_schema *schema)
578 ldb_qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
579 discard_const_p(void, schema), (ldb_qsort_cmp_fn_t)replmd_ldb_message_element_attid_sort);
582 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
583 const struct GUID *invocation_id, uint64_t seq_num,
584 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
588 fix up linked attributes in replmd_add.
589 This involves setting up the right meta-data in extended DN
590 components, and creating backlinks to the object
592 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
593 uint64_t seq_num, const struct GUID *invocationId, time_t t,
594 struct GUID *guid, const struct dsdb_attribute *sa)
597 TALLOC_CTX *tmp_ctx = talloc_new(el->values);
598 struct ldb_context *ldb = ldb_module_get_ctx(module);
599 struct dsdb_schema *schema = dsdb_get_schema(ldb);
602 unix_to_nt_time(&now, t);
604 for (i=0; i<el->num_values; i++) {
605 struct ldb_val *v = &el->values[i];
606 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
607 struct GUID target_guid;
611 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
612 seq_num, seq_num, now, 0, false);
613 if (ret != LDB_SUCCESS) {
614 talloc_free(tmp_ctx);
618 /* note that the DN already has the extended
619 components from the extended_dn_store module */
620 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
621 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
622 ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid);
623 if (ret != LDB_SUCCESS) {
624 talloc_free(tmp_ctx);
629 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
630 if (ret != LDB_SUCCESS) {
631 talloc_free(tmp_ctx);
636 talloc_free(tmp_ctx);
642 intercept add requests
644 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
646 struct ldb_context *ldb;
647 struct ldb_control *control;
648 struct replmd_replicated_request *ac;
649 enum ndr_err_code ndr_err;
650 struct ldb_request *down_req;
651 struct ldb_message *msg;
652 const DATA_BLOB *guid_blob;
654 struct replPropertyMetaDataBlob nmd;
655 struct ldb_val nmd_value;
656 const struct GUID *our_invocation_id;
657 time_t t = time(NULL);
662 bool allow_add_guid = false;
663 bool remove_current_guid = false;
665 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
666 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
671 /* do not manipulate our control entries */
672 if (ldb_dn_is_special(req->op.add.message->dn)) {
673 return ldb_next_request(module, req);
676 ldb = ldb_module_get_ctx(module);
678 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
680 ac = replmd_ctx_init(module, req);
682 return LDB_ERR_OPERATIONS_ERROR;
685 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
686 if ( guid_blob != NULL ) {
687 if( !allow_add_guid ) {
688 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
689 "replmd_add: it's not allowed to add an object with objectGUID\n");
691 return LDB_ERR_UNWILLING_TO_PERFORM;
693 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
694 if ( !NT_STATUS_IS_OK(status)) {
695 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
696 "replmd_add: Unable to parse as a GUID the attribute objectGUID\n");
698 return LDB_ERR_UNWILLING_TO_PERFORM;
700 /* we remove this attribute as it can be a string and will not be treated
701 correctly and then we will readd it latter on in the good format*/
702 remove_current_guid = true;
706 guid = GUID_random();
709 /* Get a sequence number from the backend */
710 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
711 if (ret != LDB_SUCCESS) {
716 /* get our invocationId */
717 our_invocation_id = samdb_ntds_invocation_id(ldb);
718 if (!our_invocation_id) {
719 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
720 "replmd_add: unable to find invocationId\n");
722 return LDB_ERR_OPERATIONS_ERROR;
725 /* we have to copy the message as the caller might have it as a const */
726 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
730 return LDB_ERR_OPERATIONS_ERROR;
733 /* generated times */
734 unix_to_nt_time(&now, t);
735 time_str = ldb_timestring(msg, t);
739 return LDB_ERR_OPERATIONS_ERROR;
741 if (remove_current_guid) {
742 ldb_msg_remove_attr(msg,"objectGUID");
746 * remove autogenerated attributes
748 ldb_msg_remove_attr(msg, "whenCreated");
749 ldb_msg_remove_attr(msg, "whenChanged");
750 ldb_msg_remove_attr(msg, "uSNCreated");
751 ldb_msg_remove_attr(msg, "uSNChanged");
752 ldb_msg_remove_attr(msg, "replPropertyMetaData");
755 * readd replicated attributes
757 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
758 if (ret != LDB_SUCCESS) {
764 /* build the replication meta_data */
767 nmd.ctr.ctr1.count = msg->num_elements;
768 nmd.ctr.ctr1.array = talloc_array(msg,
769 struct replPropertyMetaData1,
771 if (!nmd.ctr.ctr1.array) {
774 return LDB_ERR_OPERATIONS_ERROR;
777 for (i=0; i < msg->num_elements; i++) {
778 struct ldb_message_element *e = &msg->elements[i];
779 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
780 const struct dsdb_attribute *sa;
782 if (e->name[0] == '@') continue;
784 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
786 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
787 "replmd_add: attribute '%s' not defined in schema\n",
790 return LDB_ERR_NO_SUCH_ATTRIBUTE;
793 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
794 /* if the attribute is not replicated (0x00000001)
795 * or constructed (0x00000004) it has no metadata
800 #if W2K3_LINKED_ATTRIBUTES
801 if (sa->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
802 ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa);
803 if (ret != LDB_SUCCESS) {
807 /* linked attributes are not stored in
808 replPropertyMetaData in FL above w2k */
813 m->attid = sa->attributeID_id;
815 m->originating_change_time = now;
816 m->originating_invocation_id = *our_invocation_id;
817 m->originating_usn = ac->seq_num;
818 m->local_usn = ac->seq_num;
822 /* fix meta data count */
823 nmd.ctr.ctr1.count = ni;
826 * sort meta data array, and move the rdn attribute entry to the end
828 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
829 if (ret != LDB_SUCCESS) {
834 /* generated NDR encoded values */
835 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
836 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
838 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
839 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
842 return LDB_ERR_OPERATIONS_ERROR;
846 * add the autogenerated values
848 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
849 if (ret != LDB_SUCCESS) {
854 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
855 if (ret != LDB_SUCCESS) {
860 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
861 if (ret != LDB_SUCCESS) {
866 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
867 if (ret != LDB_SUCCESS) {
872 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
873 if (ret != LDB_SUCCESS) {
880 * sort the attributes by attid before storing the object
882 replmd_ldb_message_sort(msg, ac->schema);
884 ret = ldb_build_add_req(&down_req, ldb, ac,
887 ac, replmd_op_callback,
889 if (ret != LDB_SUCCESS) {
894 /* mark the control done */
896 control->critical = 0;
899 /* go on with the call chain */
900 return ldb_next_request(module, down_req);
905 * update the replPropertyMetaData for one element
907 static int replmd_update_rpmd_element(struct ldb_context *ldb,
908 struct ldb_message *msg,
909 struct ldb_message_element *el,
910 struct replPropertyMetaDataBlob *omd,
911 const struct dsdb_schema *schema,
913 const struct GUID *our_invocation_id,
917 const struct dsdb_attribute *a;
918 struct replPropertyMetaData1 *md1;
920 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
922 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
924 return LDB_ERR_OPERATIONS_ERROR;
927 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
931 for (i=0; i<omd->ctr.ctr1.count; i++) {
932 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
935 #if W2K3_LINKED_ATTRIBUTES
936 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
937 /* linked attributes are not stored in
938 replPropertyMetaData in FL above w2k, but we do
939 raise the seqnum for the object */
941 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
942 return LDB_ERR_OPERATIONS_ERROR;
948 if (i == omd->ctr.ctr1.count) {
949 /* we need to add a new one */
950 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
951 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
952 if (omd->ctr.ctr1.array == NULL) {
954 return LDB_ERR_OPERATIONS_ERROR;
956 omd->ctr.ctr1.count++;
957 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
960 /* Get a new sequence number from the backend. We only do this
961 * if we have a change that requires a new
962 * replPropertyMetaData element
965 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
966 if (ret != LDB_SUCCESS) {
967 return LDB_ERR_OPERATIONS_ERROR;
971 md1 = &omd->ctr.ctr1.array[i];
973 md1->attid = a->attributeID_id;
974 md1->originating_change_time = now;
975 md1->originating_invocation_id = *our_invocation_id;
976 md1->originating_usn = *seq_num;
977 md1->local_usn = *seq_num;
983 * update the replPropertyMetaData object each time we modify an
984 * object. This is needed for DRS replication, as the merge on the
985 * client is based on this object
987 static int replmd_update_rpmd(struct ldb_module *module,
988 const struct dsdb_schema *schema,
989 struct ldb_message *msg, uint64_t *seq_num,
992 const struct ldb_val *omd_value;
993 enum ndr_err_code ndr_err;
994 struct replPropertyMetaDataBlob omd;
997 const struct GUID *our_invocation_id;
999 const char *attrs[] = { "replPropertyMetaData" , NULL };
1000 struct ldb_result *res;
1001 struct ldb_context *ldb;
1003 ldb = ldb_module_get_ctx(module);
1005 our_invocation_id = samdb_ntds_invocation_id(ldb);
1006 if (!our_invocation_id) {
1007 /* this happens during an initial vampire while
1008 updating the schema */
1009 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1013 unix_to_nt_time(&now, t);
1015 /* search for the existing replPropertyMetaDataBlob */
1016 ret = dsdb_search_dn_with_deleted(ldb, msg, &res, msg->dn, attrs);
1017 if (ret != LDB_SUCCESS || res->count != 1) {
1018 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1019 ldb_dn_get_linearized(msg->dn)));
1020 return LDB_ERR_OPERATIONS_ERROR;
1024 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1026 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1027 ldb_dn_get_linearized(msg->dn)));
1028 return LDB_ERR_OPERATIONS_ERROR;
1031 ndr_err = ndr_pull_struct_blob(omd_value, msg,
1032 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
1033 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1034 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1035 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1036 ldb_dn_get_linearized(msg->dn)));
1037 return LDB_ERR_OPERATIONS_ERROR;
1040 if (omd.version != 1) {
1041 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1042 omd.version, ldb_dn_get_linearized(msg->dn)));
1043 return LDB_ERR_OPERATIONS_ERROR;
1046 for (i=0; i<msg->num_elements; i++) {
1047 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], &omd, schema, seq_num,
1048 our_invocation_id, now);
1049 if (ret != LDB_SUCCESS) {
1055 * replmd_update_rpmd_element has done an update if the
1058 if (*seq_num != 0) {
1059 struct ldb_val *md_value;
1060 struct ldb_message_element *el;
1062 md_value = talloc(msg, struct ldb_val);
1063 if (md_value == NULL) {
1065 return LDB_ERR_OPERATIONS_ERROR;
1068 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1069 if (ret != LDB_SUCCESS) {
1073 ndr_err = ndr_push_struct_blob(md_value, msg,
1074 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1076 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1077 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1078 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1079 ldb_dn_get_linearized(msg->dn)));
1080 return LDB_ERR_OPERATIONS_ERROR;
1083 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1084 if (ret != LDB_SUCCESS) {
1085 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1086 ldb_dn_get_linearized(msg->dn)));
1091 el->values = md_value;
1099 struct dsdb_dn *dsdb_dn;
1104 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1106 return GUID_compare(pdn1->guid, pdn2->guid);
1109 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid)
1111 struct parsed_dn *ret;
1112 BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1117 get a series of message element values as an array of DNs and GUIDs
1118 the result is sorted by GUID
1120 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1121 struct ldb_message_element *el, struct parsed_dn **pdn,
1122 const char *ldap_oid)
1125 struct ldb_context *ldb = ldb_module_get_ctx(module);
1132 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1134 ldb_module_oom(module);
1135 return LDB_ERR_OPERATIONS_ERROR;
1138 for (i=0; i<el->num_values; i++) {
1139 struct ldb_val *v = &el->values[i];
1142 struct parsed_dn *p;
1146 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1147 if (p->dsdb_dn == NULL) {
1148 return LDB_ERR_INVALID_DN_SYNTAX;
1151 dn = p->dsdb_dn->dn;
1153 p->guid = talloc(*pdn, struct GUID);
1154 if (p->guid == NULL) {
1155 ldb_module_oom(module);
1156 return LDB_ERR_OPERATIONS_ERROR;
1159 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1160 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1161 /* we got a DN without a GUID - go find the GUID */
1162 int ret = dsdb_find_guid_by_dn(ldb, dn, p->guid);
1163 if (ret != LDB_SUCCESS) {
1164 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1165 ldb_dn_get_linearized(dn));
1168 } else if (!NT_STATUS_IS_OK(status)) {
1169 return LDB_ERR_OPERATIONS_ERROR;
1172 /* keep a pointer to the original ldb_val */
1176 qsort(*pdn, el->num_values, sizeof((*pdn)[0]), (comparison_fn_t)parsed_dn_compare);
1182 build a new extended DN, including all meta data fields
1184 DELETED = 1 or missing
1185 RMD_ADDTIME = originating_add_time
1186 RMD_INVOCID = originating_invocation_id
1187 RMD_CHANGETIME = originating_change_time
1188 RMD_ORIGINATING_USN = originating_usn
1189 RMD_LOCAL_USN = local_usn
1190 RMD_VERSION = version
1192 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1193 const struct GUID *invocation_id, uint64_t seq_num,
1194 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1196 struct ldb_dn *dn = dsdb_dn->dn;
1197 const char *tstring, *usn_string;
1198 struct ldb_val tval;
1200 struct ldb_val usnv, local_usnv;
1201 struct ldb_val vers;
1204 const char *dnstring;
1207 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1209 return LDB_ERR_OPERATIONS_ERROR;
1211 tval = data_blob_string_const(tstring);
1213 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1215 return LDB_ERR_OPERATIONS_ERROR;
1217 usnv = data_blob_string_const(usn_string);
1219 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1221 return LDB_ERR_OPERATIONS_ERROR;
1223 local_usnv = data_blob_string_const(usn_string);
1225 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1226 vers = data_blob_string_const(vstring);
1228 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1229 if (!NT_STATUS_IS_OK(status)) {
1230 return LDB_ERR_OPERATIONS_ERROR;
1235 dv = data_blob_string_const("1");
1236 ret = ldb_dn_set_extended_component(dn, "DELETED", &dv);
1238 ret = ldb_dn_set_extended_component(dn, "DELETED", NULL);
1240 if (ret != LDB_SUCCESS) return ret;
1241 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1242 if (ret != LDB_SUCCESS) return ret;
1243 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1244 if (ret != LDB_SUCCESS) return ret;
1245 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1246 if (ret != LDB_SUCCESS) return ret;
1247 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1248 if (ret != LDB_SUCCESS) return ret;
1249 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1250 if (ret != LDB_SUCCESS) return ret;
1251 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1252 if (ret != LDB_SUCCESS) return ret;
1254 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1255 if (dnstring == NULL) {
1256 return LDB_ERR_OPERATIONS_ERROR;
1258 *v = data_blob_string_const(dnstring);
1263 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1264 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1265 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1266 uint32_t version, bool deleted);
1269 check if any links need upgrading from w2k format
1271 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, const struct GUID *invocation_id)
1274 for (i=0; i<count; i++) {
1279 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1280 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1284 /* it's an old one that needs upgrading */
1285 ret = replmd_update_la_val(dns, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1287 if (ret != LDB_SUCCESS) {
1295 update an extended DN, including all meta data fields
1297 see replmd_build_la_val for value names
1299 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1300 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1301 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1302 uint32_t version, bool deleted)
1304 struct ldb_dn *dn = dsdb_dn->dn;
1305 const char *tstring, *usn_string;
1306 struct ldb_val tval;
1308 struct ldb_val usnv, local_usnv;
1309 struct ldb_val vers;
1310 const struct ldb_val *old_addtime;
1311 uint32_t old_version;
1314 const char *dnstring;
1317 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1319 return LDB_ERR_OPERATIONS_ERROR;
1321 tval = data_blob_string_const(tstring);
1323 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1325 return LDB_ERR_OPERATIONS_ERROR;
1327 usnv = data_blob_string_const(usn_string);
1329 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1331 return LDB_ERR_OPERATIONS_ERROR;
1333 local_usnv = data_blob_string_const(usn_string);
1335 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1336 if (!NT_STATUS_IS_OK(status)) {
1337 return LDB_ERR_OPERATIONS_ERROR;
1342 dv = data_blob_string_const("1");
1343 ret = ldb_dn_set_extended_component(dn, "DELETED", &dv);
1345 ret = ldb_dn_set_extended_component(dn, "DELETED", NULL);
1347 if (ret != LDB_SUCCESS) return ret;
1349 /* get the ADDTIME from the original */
1350 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1351 if (old_addtime == NULL) {
1352 old_addtime = &tval;
1354 if (dsdb_dn != old_dsdb_dn) {
1355 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1356 if (ret != LDB_SUCCESS) return ret;
1359 /* use our invocation id */
1360 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1361 if (ret != LDB_SUCCESS) return ret;
1363 /* changetime is the current time */
1364 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1365 if (ret != LDB_SUCCESS) return ret;
1367 /* update the USN */
1368 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1369 if (ret != LDB_SUCCESS) return ret;
1371 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1372 if (ret != LDB_SUCCESS) return ret;
1374 /* increase the version by 1 */
1375 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1376 if (NT_STATUS_IS_OK(status) && old_version >= version) {
1377 version = old_version+1;
1379 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1380 vers = data_blob_string_const(vstring);
1381 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1382 if (ret != LDB_SUCCESS) return ret;
1384 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1385 if (dnstring == NULL) {
1386 return LDB_ERR_OPERATIONS_ERROR;
1388 *v = data_blob_string_const(dnstring);
1394 handle adding a linked attribute
1396 static int replmd_modify_la_add(struct ldb_module *module,
1397 struct dsdb_schema *schema,
1398 struct ldb_message *msg,
1399 struct ldb_message_element *el,
1400 struct ldb_message_element *old_el,
1401 const struct dsdb_attribute *schema_attr,
1404 struct GUID *msg_guid)
1407 struct parsed_dn *dns, *old_dns;
1408 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1410 struct ldb_val *new_values = NULL;
1411 unsigned int num_new_values = 0;
1412 unsigned old_num_values = old_el?old_el->num_values:0;
1413 const struct GUID *invocation_id;
1414 struct ldb_context *ldb = ldb_module_get_ctx(module);
1417 unix_to_nt_time(&now, t);
1419 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1420 if (ret != LDB_SUCCESS) {
1421 talloc_free(tmp_ctx);
1425 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1426 if (ret != LDB_SUCCESS) {
1427 talloc_free(tmp_ctx);
1431 invocation_id = samdb_ntds_invocation_id(ldb);
1432 if (!invocation_id) {
1433 talloc_free(tmp_ctx);
1434 return LDB_ERR_OPERATIONS_ERROR;
1437 ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
1438 if (ret != LDB_SUCCESS) {
1439 talloc_free(tmp_ctx);
1443 /* for each new value, see if it exists already with the same GUID */
1444 for (i=0; i<el->num_values; i++) {
1445 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid);
1447 /* this is a new linked attribute value */
1448 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1449 if (new_values == NULL) {
1450 ldb_module_oom(module);
1451 talloc_free(tmp_ctx);
1452 return LDB_ERR_OPERATIONS_ERROR;
1454 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1455 invocation_id, seq_num, seq_num, now, 0, false);
1456 if (ret != LDB_SUCCESS) {
1457 talloc_free(tmp_ctx);
1462 /* this is only allowed if the GUID was
1463 previously deleted. */
1464 const struct ldb_val *v;
1465 v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED");
1467 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1468 el->name, GUID_string(tmp_ctx, p->guid));
1469 talloc_free(tmp_ctx);
1470 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1472 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1473 invocation_id, seq_num, seq_num, now, 0, false);
1474 if (ret != LDB_SUCCESS) {
1475 talloc_free(tmp_ctx);
1480 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1481 if (ret != LDB_SUCCESS) {
1482 talloc_free(tmp_ctx);
1487 /* add the new ones on to the end of the old values, constructing a new el->values */
1488 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1490 old_num_values+num_new_values);
1491 if (el->values == NULL) {
1492 ldb_module_oom(module);
1493 return LDB_ERR_OPERATIONS_ERROR;
1496 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1497 el->num_values = old_num_values + num_new_values;
1499 talloc_steal(msg->elements, el->values);
1500 talloc_steal(el->values, new_values);
1502 talloc_free(tmp_ctx);
1504 /* we now tell the backend to replace all existing values
1505 with the one we have constructed */
1506 el->flags = LDB_FLAG_MOD_REPLACE;
1513 handle deleting all active linked attributes
1515 static int replmd_modify_la_delete(struct ldb_module *module,
1516 struct dsdb_schema *schema,
1517 struct ldb_message *msg,
1518 struct ldb_message_element *el,
1519 struct ldb_message_element *old_el,
1520 const struct dsdb_attribute *schema_attr,
1523 struct GUID *msg_guid)
1526 struct parsed_dn *dns, *old_dns;
1527 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1529 const struct GUID *invocation_id;
1530 struct ldb_context *ldb = ldb_module_get_ctx(module);
1533 unix_to_nt_time(&now, t);
1535 /* check if there is nothing to delete */
1536 if ((!old_el || old_el->num_values == 0) &&
1537 el->num_values == 0) {
1541 if (!old_el || old_el->num_values == 0) {
1542 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1545 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1546 if (ret != LDB_SUCCESS) {
1547 talloc_free(tmp_ctx);
1551 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1552 if (ret != LDB_SUCCESS) {
1553 talloc_free(tmp_ctx);
1557 invocation_id = samdb_ntds_invocation_id(ldb);
1558 if (!invocation_id) {
1559 return LDB_ERR_OPERATIONS_ERROR;
1562 ret = replmd_check_upgrade_links(old_dns, old_el->num_values, invocation_id);
1563 if (ret != LDB_SUCCESS) {
1564 talloc_free(tmp_ctx);
1570 /* see if we are being asked to delete any links that
1571 don't exist or are already deleted */
1572 for (i=0; i<el->num_values; i++) {
1573 struct parsed_dn *p = &dns[i];
1574 struct parsed_dn *p2;
1575 const struct ldb_val *v;
1577 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid);
1579 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1580 el->name, GUID_string(tmp_ctx, p->guid));
1581 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1583 v = ldb_dn_get_extended_component(p2->dsdb_dn->dn, "DELETED");
1585 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1586 el->name, GUID_string(tmp_ctx, p->guid));
1587 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1591 /* for each new value, see if it exists already with the same GUID
1592 if it is not already deleted and matches the delete list then delete it
1594 for (i=0; i<old_el->num_values; i++) {
1595 struct parsed_dn *p = &old_dns[i];
1596 const struct ldb_val *v;
1598 if (dns && parsed_dn_find(dns, el->num_values, p->guid) == NULL) {
1602 v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED");
1603 if (v != NULL) continue;
1605 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1606 invocation_id, seq_num, seq_num, now, 0, true);
1607 if (ret != LDB_SUCCESS) {
1608 talloc_free(tmp_ctx);
1612 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1613 if (ret != LDB_SUCCESS) {
1614 talloc_free(tmp_ctx);
1619 el->values = talloc_steal(msg->elements, old_el->values);
1620 el->num_values = old_el->num_values;
1622 talloc_free(tmp_ctx);
1624 /* we now tell the backend to replace all existing values
1625 with the one we have constructed */
1626 el->flags = LDB_FLAG_MOD_REPLACE;
1632 handle replacing a linked attribute
1634 static int replmd_modify_la_replace(struct ldb_module *module,
1635 struct dsdb_schema *schema,
1636 struct ldb_message *msg,
1637 struct ldb_message_element *el,
1638 struct ldb_message_element *old_el,
1639 const struct dsdb_attribute *schema_attr,
1642 struct GUID *msg_guid)
1645 struct parsed_dn *dns, *old_dns;
1646 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1648 const struct GUID *invocation_id;
1649 struct ldb_context *ldb = ldb_module_get_ctx(module);
1650 struct ldb_val *new_values = NULL;
1651 uint32_t num_new_values = 0;
1652 unsigned old_num_values = old_el?old_el->num_values:0;
1655 unix_to_nt_time(&now, t);
1657 /* check if there is nothing to replace */
1658 if ((!old_el || old_el->num_values == 0) &&
1659 el->num_values == 0) {
1663 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1664 if (ret != LDB_SUCCESS) {
1665 talloc_free(tmp_ctx);
1669 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1670 if (ret != LDB_SUCCESS) {
1671 talloc_free(tmp_ctx);
1675 invocation_id = samdb_ntds_invocation_id(ldb);
1676 if (!invocation_id) {
1677 return LDB_ERR_OPERATIONS_ERROR;
1680 ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
1681 if (ret != LDB_SUCCESS) {
1682 talloc_free(tmp_ctx);
1686 /* mark all the old ones as deleted */
1687 for (i=0; i<old_num_values; i++) {
1688 struct parsed_dn *old_p = &old_dns[i];
1689 struct parsed_dn *p;
1690 const struct ldb_val *v;
1692 v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED");
1695 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1696 if (ret != LDB_SUCCESS) {
1697 talloc_free(tmp_ctx);
1701 p = parsed_dn_find(dns, el->num_values, old_p->guid);
1703 /* we don't delete it if we are re-adding it */
1707 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
1708 invocation_id, seq_num, seq_num, now, 0, true);
1709 if (ret != LDB_SUCCESS) {
1710 talloc_free(tmp_ctx);
1715 /* for each new value, either update its meta-data, or add it
1718 for (i=0; i<el->num_values; i++) {
1719 struct parsed_dn *p = &dns[i], *old_p;
1722 (old_p = parsed_dn_find(old_dns,
1723 old_num_values, p->guid)) != NULL) {
1724 /* update in place */
1725 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
1726 old_p->dsdb_dn, invocation_id,
1727 seq_num, seq_num, now, 0, false);
1728 if (ret != LDB_SUCCESS) {
1729 talloc_free(tmp_ctx);
1734 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
1736 if (new_values == NULL) {
1737 ldb_module_oom(module);
1738 talloc_free(tmp_ctx);
1739 return LDB_ERR_OPERATIONS_ERROR;
1741 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1742 invocation_id, seq_num, seq_num, now, 0, false);
1743 if (ret != LDB_SUCCESS) {
1744 talloc_free(tmp_ctx);
1750 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
1751 if (ret != LDB_SUCCESS) {
1752 talloc_free(tmp_ctx);
1757 /* add the new values to the end of old_el */
1758 if (num_new_values != 0) {
1759 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1760 struct ldb_val, old_num_values+num_new_values);
1761 if (el->values == NULL) {
1762 ldb_module_oom(module);
1763 return LDB_ERR_OPERATIONS_ERROR;
1765 memcpy(&el->values[old_num_values], &new_values[0],
1766 sizeof(struct ldb_val)*num_new_values);
1767 el->num_values = old_num_values + num_new_values;
1768 talloc_steal(msg->elements, new_values);
1770 el->values = old_el->values;
1771 el->num_values = old_el->num_values;
1772 talloc_steal(msg->elements, el->values);
1775 talloc_free(tmp_ctx);
1777 /* we now tell the backend to replace all existing values
1778 with the one we have constructed */
1779 el->flags = LDB_FLAG_MOD_REPLACE;
1786 handle linked attributes in modify requests
1788 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
1789 struct ldb_message *msg,
1790 uint64_t seq_num, time_t t)
1792 struct ldb_result *res;
1794 struct ldb_context *ldb = ldb_module_get_ctx(module);
1795 struct ldb_message *old_msg;
1796 struct dsdb_schema *schema = dsdb_get_schema(ldb);
1797 struct GUID old_guid;
1800 /* there the replmd_update_rpmd code has already
1801 * checked and saw that there are no linked
1806 #if !W2K3_LINKED_ATTRIBUTES
1810 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
1811 /* don't do anything special for linked attributes */
1815 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
1816 DSDB_SEARCH_SHOW_DELETED |
1817 DSDB_SEARCH_REVEAL_INTERNALS |
1818 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
1819 if (ret != LDB_SUCCESS) {
1822 old_msg = res->msgs[0];
1824 old_guid = samdb_result_guid(old_msg, "objectGUID");
1826 for (i=0; i<msg->num_elements; i++) {
1827 struct ldb_message_element *el = &msg->elements[i];
1828 struct ldb_message_element *old_el, *new_el;
1829 const struct dsdb_attribute *schema_attr
1830 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1832 ldb_asprintf_errstring(ldb,
1833 "attribute %s is not a valid attribute in schema", el->name);
1834 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1836 if (schema_attr->linkID == 0) {
1839 if ((schema_attr->linkID & 1) == 1) {
1840 /* Odd is for the target. Illegal to modify */
1841 ldb_asprintf_errstring(ldb,
1842 "attribute %s must not be modified directly, it is a linked attribute", el->name);
1843 return LDB_ERR_UNWILLING_TO_PERFORM;
1845 old_el = ldb_msg_find_element(old_msg, el->name);
1846 switch (el->flags & LDB_FLAG_MOD_MASK) {
1847 case LDB_FLAG_MOD_REPLACE:
1848 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1850 case LDB_FLAG_MOD_DELETE:
1851 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1853 case LDB_FLAG_MOD_ADD:
1854 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1857 ldb_asprintf_errstring(ldb,
1858 "invalid flags 0x%x for %s linked attribute",
1859 el->flags, el->name);
1860 return LDB_ERR_UNWILLING_TO_PERFORM;
1862 if (ret != LDB_SUCCESS) {
1866 ldb_msg_remove_attr(old_msg, el->name);
1868 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
1869 new_el->num_values = el->num_values;
1870 new_el->values = el->values;
1872 /* TODO: this relises a bit too heavily on the exact
1873 behaviour of ldb_msg_find_element and
1874 ldb_msg_remove_element */
1875 old_el = ldb_msg_find_element(msg, el->name);
1877 ldb_msg_remove_element(msg, old_el);
1888 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
1890 struct ldb_context *ldb;
1891 struct replmd_replicated_request *ac;
1892 struct ldb_request *down_req;
1893 struct ldb_message *msg;
1894 time_t t = time(NULL);
1897 /* do not manipulate our control entries */
1898 if (ldb_dn_is_special(req->op.mod.message->dn)) {
1899 return ldb_next_request(module, req);
1902 ldb = ldb_module_get_ctx(module);
1904 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
1906 ac = replmd_ctx_init(module, req);
1908 return LDB_ERR_OPERATIONS_ERROR;
1911 /* we have to copy the message as the caller might have it as a const */
1912 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
1916 return LDB_ERR_OPERATIONS_ERROR;
1919 ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num, t);
1920 if (ret != LDB_SUCCESS) {
1925 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t);
1926 if (ret != LDB_SUCCESS) {
1932 * - replace the old object with the newly constructed one
1935 ret = ldb_build_mod_req(&down_req, ldb, ac,
1938 ac, replmd_op_callback,
1940 if (ret != LDB_SUCCESS) {
1944 talloc_steal(down_req, msg);
1946 /* we only change whenChanged and uSNChanged if the seq_num
1948 if (ac->seq_num != 0) {
1949 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
1954 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
1960 /* go on with the call chain */
1961 return ldb_next_request(module, down_req);
1964 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
1967 handle a rename request
1969 On a rename we need to do an extra ldb_modify which sets the
1970 whenChanged and uSNChanged attributes. We do this in a callback after the success.
1972 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
1974 struct ldb_context *ldb;
1975 struct replmd_replicated_request *ac;
1977 struct ldb_request *down_req;
1979 /* do not manipulate our control entries */
1980 if (ldb_dn_is_special(req->op.mod.message->dn)) {
1981 return ldb_next_request(module, req);
1984 ldb = ldb_module_get_ctx(module);
1986 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
1988 ac = replmd_ctx_init(module, req);
1990 return LDB_ERR_OPERATIONS_ERROR;
1992 ret = ldb_build_rename_req(&down_req, ldb, ac,
1993 ac->req->op.rename.olddn,
1994 ac->req->op.rename.newdn,
1996 ac, replmd_rename_callback,
1999 if (ret != LDB_SUCCESS) {
2004 /* go on with the call chain */
2005 return ldb_next_request(module, down_req);
2008 /* After the rename is compleated, update the whenchanged etc */
2009 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2011 struct ldb_context *ldb;
2012 struct replmd_replicated_request *ac;
2013 struct ldb_request *down_req;
2014 struct ldb_message *msg;
2015 time_t t = time(NULL);
2018 ac = talloc_get_type(req->context, struct replmd_replicated_request);
2019 ldb = ldb_module_get_ctx(ac->module);
2021 if (ares->error != LDB_SUCCESS) {
2022 return ldb_module_done(ac->req, ares->controls,
2023 ares->response, ares->error);
2026 if (ares->type != LDB_REPLY_DONE) {
2027 ldb_set_errstring(ldb,
2028 "invalid ldb_reply_type in callback");
2030 return ldb_module_done(ac->req, NULL, NULL,
2031 LDB_ERR_OPERATIONS_ERROR);
2034 /* Get a sequence number from the backend */
2035 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
2036 if (ret != LDB_SUCCESS) {
2041 * - replace the old object with the newly constructed one
2044 msg = ldb_msg_new(ac);
2047 return LDB_ERR_OPERATIONS_ERROR;
2050 msg->dn = ac->req->op.rename.newdn;
2052 ret = ldb_build_mod_req(&down_req, ldb, ac,
2055 ac, replmd_op_callback,
2058 if (ret != LDB_SUCCESS) {
2062 talloc_steal(down_req, msg);
2064 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2069 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
2074 /* go on with the call chain - do the modify after the rename */
2075 return ldb_next_request(ac->module, down_req);
2078 /* remove forwards and backlinks as needed when an object
2080 static int replmd_delete_remove_link(struct ldb_module *module,
2081 struct dsdb_schema *schema,
2083 struct ldb_message_element *el,
2084 const struct dsdb_attribute *sa)
2087 TALLOC_CTX *tmp_ctx = talloc_new(module);
2088 struct ldb_context *ldb = ldb_module_get_ctx(module);
2090 for (i=0; i<el->num_values; i++) {
2091 struct dsdb_dn *dsdb_dn;
2095 struct ldb_message *msg;
2096 const struct dsdb_attribute *target_attr;
2097 struct ldb_message_element *el2;
2098 struct ldb_val dn_val;
2100 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2104 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2106 talloc_free(tmp_ctx);
2107 return LDB_ERR_OPERATIONS_ERROR;
2110 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2111 if (!NT_STATUS_IS_OK(status)) {
2112 talloc_free(tmp_ctx);
2113 return LDB_ERR_OPERATIONS_ERROR;
2116 /* remove the link */
2117 msg = ldb_msg_new(tmp_ctx);
2119 ldb_module_oom(module);
2120 talloc_free(tmp_ctx);
2121 return LDB_ERR_OPERATIONS_ERROR;
2125 msg->dn = dsdb_dn->dn;
2127 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2128 if (target_attr == NULL) {
2132 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2133 if (ret != LDB_SUCCESS) {
2134 ldb_module_oom(module);
2135 talloc_free(tmp_ctx);
2136 return LDB_ERR_OPERATIONS_ERROR;
2138 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2139 el2->values = &dn_val;
2140 el2->num_values = 1;
2142 ret = dsdb_module_modify(module, msg, 0);
2143 if (ret != LDB_SUCCESS) {
2144 talloc_free(tmp_ctx);
2148 talloc_free(tmp_ctx);
2154 handle update of replication meta data for deletion of objects
2156 This also handles the mapping of delete to a rename operation
2157 to allow deletes to be replicated.
2159 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2161 int ret = LDB_ERR_OTHER;
2163 struct ldb_dn *old_dn, *new_dn;
2164 const char *rdn_name;
2165 const struct ldb_val *rdn_value, *new_rdn_value;
2167 struct ldb_context *ldb = ldb_module_get_ctx(module);
2168 struct dsdb_schema *schema = dsdb_get_schema(ldb);
2169 struct ldb_message *msg, *old_msg;
2170 struct ldb_message_element *el;
2171 TALLOC_CTX *tmp_ctx;
2172 struct ldb_result *res, *parent_res;
2173 const char *preserved_attrs[] = {
2174 /* yes, this really is a hard coded list. See MS-ADTS
2175 section 3.1.1.5.5.1.1 */
2176 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2177 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2178 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2179 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2180 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2181 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2182 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreate",
2184 uint32_t el_count = 0;
2187 tmp_ctx = talloc_new(ldb);
2189 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2191 /* we need the complete msg off disk, so we can work out which
2192 attributes need to be removed */
2193 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2194 DSDB_SEARCH_SHOW_DELETED |
2195 DSDB_SEARCH_REVEAL_INTERNALS |
2196 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
2197 if (ret != LDB_SUCCESS) {
2198 talloc_free(tmp_ctx);
2201 old_msg = res->msgs[0];
2203 /* work out where we will be renaming this object to */
2204 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn, &new_dn);
2205 if (ret != LDB_SUCCESS) {
2206 /* this is probably an attempted delete on a partition
2207 * that doesn't allow delete operations, such as the
2208 * schema partition */
2209 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2210 ldb_dn_get_linearized(old_dn));
2211 talloc_free(tmp_ctx);
2212 return LDB_ERR_UNWILLING_TO_PERFORM;
2215 rdn_name = ldb_dn_get_rdn_name(old_dn);
2216 rdn_value = ldb_dn_get_rdn_val(old_dn);
2218 /* get the objects GUID from the search we just did */
2219 guid = samdb_result_guid(old_msg, "objectGUID");
2221 /* Add a formatted child */
2222 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2225 GUID_string(tmp_ctx, &guid));
2227 DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2228 ldb_dn_get_linearized(new_dn)));
2229 talloc_free(tmp_ctx);
2230 return LDB_ERR_OPERATIONS_ERROR;
2234 now we need to modify the object in the following ways:
2236 - add isDeleted=TRUE
2237 - update rDN and name, with new rDN
2238 - remove linked attributes
2239 - remove objectCategory and sAMAccountType
2240 - remove attribs not on the preserved list
2241 - preserved if in above list, or is rDN
2242 - remove all linked attribs from this object
2243 - remove all links from other objects to this object
2244 - add lastKnownParent
2245 - update replPropertyMetaData?
2247 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2250 msg = ldb_msg_new(tmp_ctx);
2252 ldb_module_oom(module);
2253 talloc_free(tmp_ctx);
2254 return LDB_ERR_OPERATIONS_ERROR;
2259 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2260 if (ret != LDB_SUCCESS) {
2261 DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2262 ldb_module_oom(module);
2263 talloc_free(tmp_ctx);
2266 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2268 /* we need the storage form of the parent GUID */
2269 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2270 ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2271 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2272 DSDB_SEARCH_REVEAL_INTERNALS);
2273 if (ret != LDB_SUCCESS) {
2274 talloc_free(tmp_ctx);
2278 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2279 ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2280 if (ret != LDB_SUCCESS) {
2281 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2282 ldb_module_oom(module);
2283 talloc_free(tmp_ctx);
2286 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2288 /* work out which of the old attributes we will be removing */
2289 for (i=0; i<old_msg->num_elements; i++) {
2290 const struct dsdb_attribute *sa;
2291 el = &old_msg->elements[i];
2292 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2294 talloc_free(tmp_ctx);
2295 return LDB_ERR_OPERATIONS_ERROR;
2297 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2298 /* don't remove the rDN */
2303 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa);
2304 if (ret != LDB_SUCCESS) {
2305 talloc_free(tmp_ctx);
2306 return LDB_ERR_OPERATIONS_ERROR;
2310 if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2314 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2315 if (ret != LDB_SUCCESS) {
2316 talloc_free(tmp_ctx);
2317 ldb_module_oom(module);
2322 /* work out what the new rdn value is, for updating the
2323 rDN and name fields */
2324 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2325 ret = ldb_msg_add_value(msg, rdn_name, new_rdn_value, &el);
2326 if (ret != LDB_SUCCESS) {
2327 talloc_free(tmp_ctx);
2330 el->flags = LDB_FLAG_MOD_REPLACE;
2332 el = ldb_msg_find_element(old_msg, "name");
2334 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2335 if (ret != LDB_SUCCESS) {
2336 talloc_free(tmp_ctx);
2339 el->flags = LDB_FLAG_MOD_REPLACE;
2342 ret = dsdb_module_modify(module, msg, 0);
2343 if (ret != LDB_SUCCESS){
2344 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
2345 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
2346 talloc_free(tmp_ctx);
2350 /* now rename onto the new DN */
2351 ret = dsdb_module_rename(module, old_dn, new_dn, 0);
2352 if (ret != LDB_SUCCESS){
2353 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
2354 ldb_dn_get_linearized(old_dn),
2355 ldb_dn_get_linearized(new_dn),
2356 ldb_errstring(ldb)));
2357 talloc_free(tmp_ctx);
2361 talloc_free(tmp_ctx);
2363 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
2368 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
2373 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
2375 int ret = LDB_ERR_OTHER;
2376 /* TODO: do some error mapping */
2380 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
2382 struct ldb_context *ldb;
2383 struct ldb_request *change_req;
2384 enum ndr_err_code ndr_err;
2385 struct ldb_message *msg;
2386 struct replPropertyMetaDataBlob *md;
2387 struct ldb_val md_value;
2392 * TODO: check if the parent object exist
2396 * TODO: handle the conflict case where an object with the
2400 ldb = ldb_module_get_ctx(ar->module);
2401 msg = ar->objs->objects[ar->index_current].msg;
2402 md = ar->objs->objects[ar->index_current].meta_data;
2404 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2405 if (ret != LDB_SUCCESS) {
2406 return replmd_replicated_request_error(ar, ret);
2409 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
2410 if (ret != LDB_SUCCESS) {
2411 return replmd_replicated_request_error(ar, ret);
2414 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2415 if (ret != LDB_SUCCESS) {
2416 return replmd_replicated_request_error(ar, ret);
2419 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
2420 if (ret != LDB_SUCCESS) {
2421 return replmd_replicated_request_error(ar, ret);
2424 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2425 if (ret != LDB_SUCCESS) {
2426 return replmd_replicated_request_error(ar, ret);
2429 /* remove any message elements that have zero values */
2430 for (i=0; i<msg->num_elements; i++) {
2431 struct ldb_message_element *el = &msg->elements[i];
2433 if (el->num_values == 0) {
2434 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
2436 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
2437 msg->num_elements--;
2444 * the meta data array is already sorted by the caller
2446 for (i=0; i < md->ctr.ctr1.count; i++) {
2447 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
2449 ndr_err = ndr_push_struct_blob(&md_value, msg,
2450 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2452 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2453 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2454 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2455 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2457 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
2458 if (ret != LDB_SUCCESS) {
2459 return replmd_replicated_request_error(ar, ret);
2462 replmd_ldb_message_sort(msg, ar->schema);
2465 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
2466 DEBUG(4, ("DRS replication add message:\n%s\n", s));
2470 ret = ldb_build_add_req(&change_req,
2478 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2480 return ldb_next_request(ar->module, change_req);
2484 return true if an update is newer than an existing entry
2485 see section 5.11 of MS-ADTS
2487 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
2488 const struct GUID *update_invocation_id,
2489 uint32_t current_version,
2490 uint32_t update_version,
2491 NTTIME current_change_time,
2492 NTTIME update_change_time)
2494 if (update_version != current_version) {
2495 return update_version > current_version;
2497 if (update_change_time > current_change_time) {
2500 if (update_change_time == current_change_time) {
2501 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
2506 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
2507 struct replPropertyMetaData1 *new_m)
2509 return replmd_update_is_newer(&cur_m->originating_invocation_id,
2510 &new_m->originating_invocation_id,
2513 cur_m->originating_change_time,
2514 new_m->originating_change_time);
2517 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
2519 struct ldb_context *ldb;
2520 struct ldb_request *change_req;
2521 enum ndr_err_code ndr_err;
2522 struct ldb_message *msg;
2523 struct replPropertyMetaDataBlob *rmd;
2524 struct replPropertyMetaDataBlob omd;
2525 const struct ldb_val *omd_value;
2526 struct replPropertyMetaDataBlob nmd;
2527 struct ldb_val nmd_value;
2529 uint32_t removed_attrs = 0;
2532 ldb = ldb_module_get_ctx(ar->module);
2533 msg = ar->objs->objects[ar->index_current].msg;
2534 rmd = ar->objs->objects[ar->index_current].meta_data;
2539 * TODO: check repl data is correct after a rename
2541 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
2542 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
2543 ldb_dn_get_linearized(ar->search_msg->dn),
2544 ldb_dn_get_linearized(msg->dn));
2545 /* we can't use dsdb_module_rename() here as we need
2546 the rename call to be intercepted by this module, to
2547 allow it to process linked attribute changes */
2548 if (ldb_rename(ldb, ar->search_msg->dn, msg->dn) != LDB_SUCCESS) {
2549 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
2550 ldb_dn_get_linearized(ar->search_msg->dn),
2551 ldb_dn_get_linearized(msg->dn),
2552 ldb_errstring(ldb));
2553 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
2557 /* find existing meta data */
2558 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
2560 ndr_err = ndr_pull_struct_blob(omd_value, ar,
2561 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
2562 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
2563 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2564 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2565 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2568 if (omd.version != 1) {
2569 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2575 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
2576 nmd.ctr.ctr1.array = talloc_array(ar,
2577 struct replPropertyMetaData1,
2578 nmd.ctr.ctr1.count);
2579 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2581 /* first copy the old meta data */
2582 for (i=0; i < omd.ctr.ctr1.count; i++) {
2583 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
2587 /* now merge in the new meta data */
2588 for (i=0; i < rmd->ctr.ctr1.count; i++) {
2591 for (j=0; j < ni; j++) {
2594 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
2598 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
2599 &rmd->ctr.ctr1.array[i]);
2601 /* replace the entry */
2602 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
2607 DEBUG(1,("Discarding older DRS attribute update to %s on %s from %s\n",
2608 msg->elements[i-removed_attrs].name,
2609 ldb_dn_get_linearized(msg->dn),
2610 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
2612 /* we don't want to apply this change so remove the attribute */
2613 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
2620 if (found) continue;
2622 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
2627 * finally correct the size of the meta_data array
2629 nmd.ctr.ctr1.count = ni;
2632 * the rdn attribute (the alias for the name attribute),
2633 * 'cn' for most objects is the last entry in the meta data array
2636 * sort the new meta data array
2638 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
2639 if (ret != LDB_SUCCESS) {
2644 * check if some replicated attributes left, otherwise skip the ldb_modify() call
2646 if (msg->num_elements == 0) {
2647 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
2650 ar->index_current++;
2651 return replmd_replicated_apply_next(ar);
2654 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
2655 ar->index_current, msg->num_elements);
2657 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2658 if (ret != LDB_SUCCESS) {
2659 return replmd_replicated_request_error(ar, ret);
2662 for (i=0; i<ni; i++) {
2663 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
2666 /* create the meta data value */
2667 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
2668 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2670 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2671 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2672 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2673 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2677 * when we know that we'll modify the record, add the whenChanged, uSNChanged
2678 * and replPopertyMetaData attributes
2680 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2681 if (ret != LDB_SUCCESS) {
2682 return replmd_replicated_request_error(ar, ret);
2684 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2685 if (ret != LDB_SUCCESS) {
2686 return replmd_replicated_request_error(ar, ret);
2688 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
2689 if (ret != LDB_SUCCESS) {
2690 return replmd_replicated_request_error(ar, ret);
2693 replmd_ldb_message_sort(msg, ar->schema);
2695 /* we want to replace the old values */
2696 for (i=0; i < msg->num_elements; i++) {
2697 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2701 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
2702 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
2706 ret = ldb_build_mod_req(&change_req,
2714 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2716 return ldb_next_request(ar->module, change_req);
2719 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
2720 struct ldb_reply *ares)
2722 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2723 struct replmd_replicated_request);
2727 return ldb_module_done(ar->req, NULL, NULL,
2728 LDB_ERR_OPERATIONS_ERROR);
2730 if (ares->error != LDB_SUCCESS &&
2731 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
2732 return ldb_module_done(ar->req, ares->controls,
2733 ares->response, ares->error);
2736 switch (ares->type) {
2737 case LDB_REPLY_ENTRY:
2738 ar->search_msg = talloc_steal(ar, ares->message);
2741 case LDB_REPLY_REFERRAL:
2742 /* we ignore referrals */
2745 case LDB_REPLY_DONE:
2746 if (ar->search_msg != NULL) {
2747 ret = replmd_replicated_apply_merge(ar);
2749 ret = replmd_replicated_apply_add(ar);
2751 if (ret != LDB_SUCCESS) {
2752 return ldb_module_done(ar->req, NULL, NULL, ret);
2760 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
2762 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
2764 struct ldb_context *ldb;
2768 struct ldb_request *search_req;
2769 struct ldb_search_options_control *options;
2771 if (ar->index_current >= ar->objs->num_objects) {
2772 /* done with it, go to next stage */
2773 return replmd_replicated_uptodate_vector(ar);
2776 ldb = ldb_module_get_ctx(ar->module);
2777 ar->search_msg = NULL;
2779 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
2780 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2782 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
2783 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2784 talloc_free(tmp_str);
2786 ret = ldb_build_search_req(&search_req,
2795 replmd_replicated_apply_search_callback,
2798 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2799 if (ret != LDB_SUCCESS) {
2803 /* we need to cope with cross-partition links, so search for
2804 the GUID over all partitions */
2805 options = talloc(search_req, struct ldb_search_options_control);
2806 if (options == NULL) {
2807 DEBUG(0, (__location__ ": out of memory\n"));
2808 return LDB_ERR_OPERATIONS_ERROR;
2810 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2812 ret = ldb_request_add_control(search_req,
2813 LDB_CONTROL_SEARCH_OPTIONS_OID,
2815 if (ret != LDB_SUCCESS) {
2819 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2821 return ldb_next_request(ar->module, search_req);
2824 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
2825 struct ldb_reply *ares)
2827 struct ldb_context *ldb;
2828 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2829 struct replmd_replicated_request);
2830 ldb = ldb_module_get_ctx(ar->module);
2833 return ldb_module_done(ar->req, NULL, NULL,
2834 LDB_ERR_OPERATIONS_ERROR);
2836 if (ares->error != LDB_SUCCESS) {
2837 return ldb_module_done(ar->req, ares->controls,
2838 ares->response, ares->error);
2841 if (ares->type != LDB_REPLY_DONE) {
2842 ldb_set_errstring(ldb, "Invalid reply type\n!");
2843 return ldb_module_done(ar->req, NULL, NULL,
2844 LDB_ERR_OPERATIONS_ERROR);
2849 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
2852 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
2854 struct ldb_context *ldb;
2855 struct ldb_request *change_req;
2856 enum ndr_err_code ndr_err;
2857 struct ldb_message *msg;
2858 struct replUpToDateVectorBlob ouv;
2859 const struct ldb_val *ouv_value;
2860 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
2861 struct replUpToDateVectorBlob nuv;
2862 struct ldb_val nuv_value;
2863 struct ldb_message_element *nuv_el = NULL;
2864 const struct GUID *our_invocation_id;
2865 struct ldb_message_element *orf_el = NULL;
2866 struct repsFromToBlob nrf;
2867 struct ldb_val *nrf_value = NULL;
2868 struct ldb_message_element *nrf_el = NULL;
2871 time_t t = time(NULL);
2875 ldb = ldb_module_get_ctx(ar->module);
2876 ruv = ar->objs->uptodateness_vector;
2882 unix_to_nt_time(&now, t);
2885 * first create the new replUpToDateVector
2887 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
2889 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
2890 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
2891 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
2892 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2893 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2894 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2897 if (ouv.version != 2) {
2898 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2903 * the new uptodateness vector will at least
2904 * contain 1 entry, one for the source_dsa
2906 * plus optional values from our old vector and the one from the source_dsa
2908 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
2909 if (ruv) nuv.ctr.ctr2.count += ruv->count;
2910 nuv.ctr.ctr2.cursors = talloc_array(ar,
2911 struct drsuapi_DsReplicaCursor2,
2912 nuv.ctr.ctr2.count);
2913 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2915 /* first copy the old vector */
2916 for (i=0; i < ouv.ctr.ctr2.count; i++) {
2917 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
2921 /* get our invocation_id if we have one already attached to the ldb */
2922 our_invocation_id = samdb_ntds_invocation_id(ldb);
2924 /* merge in the source_dsa vector is available */
2925 for (i=0; (ruv && i < ruv->count); i++) {
2928 if (our_invocation_id &&
2929 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
2930 our_invocation_id)) {
2934 for (j=0; j < ni; j++) {
2935 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
2936 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
2943 * we update only the highest_usn and not the latest_sync_success time,
2944 * because the last success stands for direct replication
2946 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
2947 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
2952 if (found) continue;
2954 /* if it's not there yet, add it */
2955 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
2960 * merge in the current highwatermark for the source_dsa
2963 for (j=0; j < ni; j++) {
2964 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
2965 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
2972 * here we update the highest_usn and last_sync_success time
2973 * because we're directly replicating from the source_dsa
2975 * and use the tmp_highest_usn because this is what we have just applied
2978 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
2979 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
2984 * here we update the highest_usn and last_sync_success time
2985 * because we're directly replicating from the source_dsa
2987 * and use the tmp_highest_usn because this is what we have just applied
2990 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
2991 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
2992 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
2997 * finally correct the size of the cursors array
2999 nuv.ctr.ctr2.count = ni;
3004 qsort(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count,
3005 sizeof(struct drsuapi_DsReplicaCursor2),
3006 (comparison_fn_t)drsuapi_DsReplicaCursor2_compare);
3009 * create the change ldb_message
3011 msg = ldb_msg_new(ar);
3012 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3013 msg->dn = ar->search_msg->dn;
3015 ndr_err = ndr_push_struct_blob(&nuv_value, msg,
3016 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3018 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
3019 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3020 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3021 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3023 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
3024 if (ret != LDB_SUCCESS) {
3025 return replmd_replicated_request_error(ar, ret);
3027 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
3030 * now create the new repsFrom value from the given repsFromTo1 structure
3034 nrf.ctr.ctr1 = *ar->objs->source_dsa;
3035 /* and fix some values... */
3036 nrf.ctr.ctr1.consecutive_sync_failures = 0;
3037 nrf.ctr.ctr1.last_success = now;
3038 nrf.ctr.ctr1.last_attempt = now;
3039 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
3040 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
3043 * first see if we already have a repsFrom value for the current source dsa
3044 * if so we'll later replace this value
3046 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
3048 for (i=0; i < orf_el->num_values; i++) {
3049 struct repsFromToBlob *trf;
3051 trf = talloc(ar, struct repsFromToBlob);
3052 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3054 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
3055 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3056 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3057 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3058 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3061 if (trf->version != 1) {
3062 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3066 * we compare the source dsa objectGUID not the invocation_id
3067 * because we want only one repsFrom value per source dsa
3068 * and when the invocation_id of the source dsa has changed we don't need
3069 * the old repsFrom with the old invocation_id
3071 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
3072 &ar->objs->source_dsa->source_dsa_obj_guid)) {
3078 nrf_value = &orf_el->values[i];
3083 * copy over all old values to the new ldb_message
3085 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
3086 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3091 * if we haven't found an old repsFrom value for the current source dsa
3092 * we'll add a new value
3095 struct ldb_val zero_value;
3096 ZERO_STRUCT(zero_value);
3097 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
3098 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3100 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
3103 /* we now fill the value which is already attached to ldb_message */
3104 ndr_err = ndr_push_struct_blob(nrf_value, msg,
3105 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3107 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3108 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3109 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3110 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3114 * the ldb_message_element for the attribute, has all the old values and the new one
3115 * so we'll replace the whole attribute with all values
3117 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
3120 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3121 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
3125 /* prepare the ldb_modify() request */
3126 ret = ldb_build_mod_req(&change_req,
3132 replmd_replicated_uptodate_modify_callback,
3134 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3136 return ldb_next_request(ar->module, change_req);
3139 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
3140 struct ldb_reply *ares)
3142 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3143 struct replmd_replicated_request);
3147 return ldb_module_done(ar->req, NULL, NULL,
3148 LDB_ERR_OPERATIONS_ERROR);
3150 if (ares->error != LDB_SUCCESS &&
3151 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3152 return ldb_module_done(ar->req, ares->controls,
3153 ares->response, ares->error);
3156 switch (ares->type) {
3157 case LDB_REPLY_ENTRY:
3158 ar->search_msg = talloc_steal(ar, ares->message);
3161 case LDB_REPLY_REFERRAL:
3162 /* we ignore referrals */
3165 case LDB_REPLY_DONE:
3166 if (ar->search_msg == NULL) {
3167 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3169 ret = replmd_replicated_uptodate_modify(ar);
3171 if (ret != LDB_SUCCESS) {
3172 return ldb_module_done(ar->req, NULL, NULL, ret);
3181 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
3183 struct ldb_context *ldb;
3185 static const char *attrs[] = {
3186 "replUpToDateVector",
3190 struct ldb_request *search_req;
3192 ldb = ldb_module_get_ctx(ar->module);
3193 ar->search_msg = NULL;
3195 ret = ldb_build_search_req(&search_req,
3198 ar->objs->partition_dn,
3204 replmd_replicated_uptodate_search_callback,
3206 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3208 return ldb_next_request(ar->module, search_req);
3213 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
3215 struct ldb_context *ldb;
3216 struct dsdb_extended_replicated_objects *objs;
3217 struct replmd_replicated_request *ar;
3218 struct ldb_control **ctrls;
3220 struct replmd_private *replmd_private =
3221 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3223 ldb = ldb_module_get_ctx(module);
3225 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
3227 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
3229 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
3230 return LDB_ERR_PROTOCOL_ERROR;
3233 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
3234 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
3235 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
3236 return LDB_ERR_PROTOCOL_ERROR;
3239 ar = replmd_ctx_init(module, req);
3241 return LDB_ERR_OPERATIONS_ERROR;
3243 /* Set the flags to have the replmd_op_callback run over the full set of objects */
3244 ar->apply_mode = true;
3246 ar->schema = dsdb_get_schema(ldb);
3248 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
3250 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3251 return LDB_ERR_CONSTRAINT_VIOLATION;
3254 ctrls = req->controls;
3256 if (req->controls) {
3257 req->controls = talloc_memdup(ar, req->controls,
3258 talloc_get_size(req->controls));
3259 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3262 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
3263 if (ret != LDB_SUCCESS) {
3267 ar->controls = req->controls;
3268 req->controls = ctrls;
3270 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
3272 /* save away the linked attributes for the end of the
3274 for (i=0; i<ar->objs->linked_attributes_count; i++) {
3275 struct la_entry *la_entry;
3277 if (replmd_private->la_ctx == NULL) {
3278 replmd_private->la_ctx = talloc_new(replmd_private);
3280 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
3281 if (la_entry == NULL) {
3283 return LDB_ERR_OPERATIONS_ERROR;
3285 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
3286 if (la_entry->la == NULL) {
3287 talloc_free(la_entry);
3289 return LDB_ERR_OPERATIONS_ERROR;
3291 *la_entry->la = ar->objs->linked_attributes[i];
3293 /* we need to steal the non-scalars so they stay
3294 around until the end of the transaction */
3295 talloc_steal(la_entry->la, la_entry->la->identifier);
3296 talloc_steal(la_entry->la, la_entry->la->value.blob);
3298 DLIST_ADD(replmd_private->la_list, la_entry);
3301 return replmd_replicated_apply_next(ar);
3305 process one linked attribute structure
3307 static int replmd_process_linked_attribute(struct ldb_module *module,
3308 struct la_entry *la_entry)
3310 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
3311 struct ldb_context *ldb = ldb_module_get_ctx(module);
3312 struct dsdb_schema *schema = dsdb_get_schema(ldb);
3313 struct ldb_message *msg;
3314 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
3316 const struct dsdb_attribute *attr;
3317 struct dsdb_dn *dsdb_dn;
3318 uint64_t seq_num = 0;
3319 struct drsuapi_DsReplicaAttribute drs;
3320 struct drsuapi_DsAttributeValue val;
3321 struct ldb_message_element new_el, *old_el;
3323 time_t t = time(NULL);
3324 struct ldb_result *res;
3325 const char *attrs[2];
3326 struct parsed_dn *pdn_list, *pdn;
3329 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
3330 const struct GUID *our_invocation_id;
3332 drs.value_ctr.num_values = 1;
3333 drs.value_ctr.values = &val;
3334 val.blob = la->value.blob;
3337 linked_attributes[0]:
3338 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
3340 identifier: struct drsuapi_DsReplicaObjectIdentifier
3341 __ndr_size : 0x0000003a (58)
3342 __ndr_size_sid : 0x00000000 (0)
3343 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
3345 __ndr_size_dn : 0x00000000 (0)
3347 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
3348 value: struct drsuapi_DsAttributeValue
3349 __ndr_size : 0x0000007e (126)
3351 blob : DATA_BLOB length=126
3352 flags : 0x00000001 (1)
3353 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
3354 originating_add_time : Wed Sep 2 22:20:01 2009 EST
3355 meta_data: struct drsuapi_DsReplicaMetaData
3356 version : 0x00000015 (21)
3357 originating_change_time : Wed Sep 2 23:39:07 2009 EST
3358 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
3359 originating_usn : 0x000000000001e19c (123292)
3361 (for cases where the link is to a normal DN)
3362 &target: struct drsuapi_DsReplicaObjectIdentifier3
3363 __ndr_size : 0x0000007e (126)
3364 __ndr_size_sid : 0x0000001c (28)
3365 guid : 7639e594-db75-4086-b0d4-67890ae46031
3366 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
3367 __ndr_size_dn : 0x00000022 (34)
3368 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
3371 /* find the attribute being modified */
3372 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
3374 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
3375 talloc_free(tmp_ctx);
3376 return LDB_ERR_OPERATIONS_ERROR;
3379 attrs[0] = attr->lDAPDisplayName;
3382 /* get the existing message from the db for the object with
3383 this GUID, returning attribute being modified. We will then
3384 use this msg as the basis for a modify call */
3385 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3386 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3387 DSDB_SEARCH_SHOW_DELETED |
3388 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3389 DSDB_SEARCH_REVEAL_INTERNALS,
3390 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
3391 if (ret != LDB_SUCCESS) {
3392 talloc_free(tmp_ctx);
3395 if (res->count != 1) {
3396 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
3397 GUID_string(tmp_ctx, &la->identifier->guid));
3398 talloc_free(tmp_ctx);
3399 return LDB_ERR_NO_SUCH_OBJECT;
3403 if (msg->num_elements == 0) {
3404 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
3405 if (ret != LDB_SUCCESS) {
3406 ldb_module_oom(module);
3407 talloc_free(tmp_ctx);
3408 return LDB_ERR_OPERATIONS_ERROR;
3411 old_el = &msg->elements[0];
3412 old_el->flags = LDB_FLAG_MOD_REPLACE;
3415 /* parse the existing links */
3416 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid);
3417 if (ret != LDB_SUCCESS) {
3418 talloc_free(tmp_ctx);
3422 /* get our invocationId */
3423 our_invocation_id = samdb_ntds_invocation_id(ldb);
3424 if (!our_invocation_id) {
3425 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
3426 talloc_free(tmp_ctx);
3427 return LDB_ERR_OPERATIONS_ERROR;
3430 ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, our_invocation_id);
3431 if (ret != LDB_SUCCESS) {
3432 talloc_free(tmp_ctx);
3436 status = attr->syntax->drsuapi_to_ldb(ldb, schema, attr, &drs, tmp_ctx, &new_el);
3437 if (!W_ERROR_IS_OK(status)) {
3438 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s\n",
3439 old_el->name, ldb_dn_get_linearized(msg->dn));
3440 return LDB_ERR_OPERATIONS_ERROR;
3443 if (new_el.num_values != 1) {
3444 ldb_asprintf_errstring(ldb, "Failed to find value in linked attribute blob for %s on %s\n",
3445 old_el->name, ldb_dn_get_linearized(msg->dn));
3446 return LDB_ERR_OPERATIONS_ERROR;
3449 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &new_el.values[0], attr->syntax->ldap_oid);
3451 ldb_asprintf_errstring(ldb, "Failed to parse DN in linked attribute blob for %s on %s\n",
3452 old_el->name, ldb_dn_get_linearized(msg->dn));
3453 return LDB_ERR_OPERATIONS_ERROR;
3456 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
3457 if (!NT_STATUS_IS_OK(ntstatus)) {
3458 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s\n",
3459 old_el->name, ldb_dn_get_linearized(msg->dn));
3460 return LDB_ERR_OPERATIONS_ERROR;
3463 /* see if this link already exists */
3464 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid);
3466 /* see if this update is newer than what we have already */
3467 struct GUID invocation_id = GUID_zero();
3468 uint32_t version = 0;
3469 NTTIME change_time = 0;
3470 bool was_active = ldb_dn_get_extended_component(pdn->dsdb_dn->dn, "DELETED") == NULL;
3472 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
3473 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
3474 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
3476 if (!replmd_update_is_newer(&invocation_id,
3477 &la->meta_data.originating_invocation_id,
3479 la->meta_data.version,
3481 la->meta_data.originating_change_time)) {
3482 DEBUG(1,("Discarding older DRS linked attribute update to %s on %s from %s\n",
3483 old_el->name, ldb_dn_get_linearized(msg->dn),
3484 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
3485 talloc_free(tmp_ctx);
3489 /* get a seq_num for this change */
3490 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3491 if (ret != LDB_SUCCESS) {
3492 talloc_free(tmp_ctx);
3497 /* remove the existing backlink */
3498 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
3499 if (ret != LDB_SUCCESS) {
3500 talloc_free(tmp_ctx);
3505 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
3506 &la->meta_data.originating_invocation_id,
3507 la->meta_data.originating_usn, seq_num,
3508 la->meta_data.originating_change_time,
3509 la->meta_data.version,
3511 if (ret != LDB_SUCCESS) {
3512 talloc_free(tmp_ctx);
3517 /* add the new backlink */
3518 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
3519 if (ret != LDB_SUCCESS) {
3520 talloc_free(tmp_ctx);
3525 /* get a seq_num for this change */
3526 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3527 if (ret != LDB_SUCCESS) {
3528 talloc_free(tmp_ctx);
3532 old_el->values = talloc_realloc(msg->elements, old_el->values,
3533 struct ldb_val, old_el->num_values+1);
3534 if (!old_el->values) {
3535 ldb_module_oom(module);
3536 return LDB_ERR_OPERATIONS_ERROR;
3538 old_el->num_values++;
3540 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
3541 &la->meta_data.originating_invocation_id,
3542 la->meta_data.originating_usn, seq_num,
3543 la->meta_data.originating_change_time,
3544 la->meta_data.version,
3545 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
3546 if (ret != LDB_SUCCESS) {
3547 talloc_free(tmp_ctx);
3552 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
3554 if (ret != LDB_SUCCESS) {
3555 talloc_free(tmp_ctx);
3561 /* we only change whenChanged and uSNChanged if the seq_num
3563 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
3564 talloc_free(tmp_ctx);
3565 return LDB_ERR_OPERATIONS_ERROR;
3568 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
3569 talloc_free(tmp_ctx);
3570 return LDB_ERR_OPERATIONS_ERROR;
3573 ret = dsdb_check_single_valued_link(attr, old_el);
3574 if (ret != LDB_SUCCESS) {
3575 talloc_free(tmp_ctx);
3579 ret = dsdb_module_modify(module, msg, DSDB_MODIFY_RELAX);
3580 if (ret != LDB_SUCCESS) {
3581 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
3583 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
3584 talloc_free(tmp_ctx);
3588 talloc_free(tmp_ctx);
3593 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
3595 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
3596 return replmd_extended_replicated_objects(module, req);
3599 return ldb_next_request(module, req);
3604 we hook into the transaction operations to allow us to
3605 perform the linked attribute updates at the end of the whole
3606 transaction. This allows a forward linked attribute to be created
3607 before the object is created. During a vampire, w2k8 sends us linked
3608 attributes before the objects they are part of.
3610 static int replmd_start_transaction(struct ldb_module *module)
3612 /* create our private structure for this transaction */
3613 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
3614 struct replmd_private);
3615 replmd_txn_cleanup(replmd_private);
3617 /* free any leftover mod_usn records from cancelled
3619 while (replmd_private->ncs) {
3620 struct nc_entry *e = replmd_private->ncs;
3621 DLIST_REMOVE(replmd_private->ncs, e);
3625 return ldb_next_start_trans(module);
3629 on prepare commit we loop over our queued la_context structures and
3632 static int replmd_prepare_commit(struct ldb_module *module)
3634 struct replmd_private *replmd_private =
3635 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3636 struct la_entry *la, *prev;
3637 struct la_backlink *bl;
3640 /* walk the list backwards, to do the first entry first, as we
3641 * added the entries with DLIST_ADD() which puts them at the
3642 * start of the list */
3643 for (la = replmd_private->la_list; la && la->next; la=la->next) ;
3645 for (; la; la=prev) {
3647 DLIST_REMOVE(replmd_private->la_list, la);
3648 ret = replmd_process_linked_attribute(module, la);
3649 if (ret != LDB_SUCCESS) {
3650 replmd_txn_cleanup(replmd_private);
3655 /* process our backlink list, creating and deleting backlinks
3657 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
3658 ret = replmd_process_backlink(module, bl);
3659 if (ret != LDB_SUCCESS) {
3660 replmd_txn_cleanup(replmd_private);
3665 replmd_txn_cleanup(replmd_private);
3667 /* possibly change @REPLCHANGED */
3668 ret = replmd_notify_store(module);
3669 if (ret != LDB_SUCCESS) {
3673 return ldb_next_prepare_commit(module);
3676 static int replmd_del_transaction(struct ldb_module *module)
3678 struct replmd_private *replmd_private =
3679 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3680 replmd_txn_cleanup(replmd_private);
3682 return ldb_next_del_trans(module);
3686 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
3687 .name = "repl_meta_data",
3688 .init_context = replmd_init,
3690 .modify = replmd_modify,
3691 .rename = replmd_rename,
3692 .del = replmd_delete,
3693 .extended = replmd_extended,
3694 .start_transaction = replmd_start_transaction,
3695 .prepare_commit = replmd_prepare_commit,
3696 .del_transaction = replmd_del_transaction,