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, 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, 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)) {
622 talloc_free(tmp_ctx);
623 return LDB_ERR_OPERATIONS_ERROR;
626 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
627 if (ret != LDB_SUCCESS) {
628 talloc_free(tmp_ctx);
633 talloc_free(tmp_ctx);
639 intercept add requests
641 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
643 struct ldb_context *ldb;
644 struct ldb_control *control;
645 struct replmd_replicated_request *ac;
646 enum ndr_err_code ndr_err;
647 struct ldb_request *down_req;
648 struct ldb_message *msg;
649 const DATA_BLOB *guid_blob;
651 struct replPropertyMetaDataBlob nmd;
652 struct ldb_val nmd_value;
653 const struct GUID *our_invocation_id;
654 time_t t = time(NULL);
659 bool allow_add_guid = false;
660 bool remove_current_guid = false;
662 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
663 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
668 /* do not manipulate our control entries */
669 if (ldb_dn_is_special(req->op.add.message->dn)) {
670 return ldb_next_request(module, req);
673 ldb = ldb_module_get_ctx(module);
675 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
677 ac = replmd_ctx_init(module, req);
679 return LDB_ERR_OPERATIONS_ERROR;
682 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
683 if ( guid_blob != NULL ) {
684 if( !allow_add_guid ) {
685 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
686 "replmd_add: it's not allowed to add an object with objectGUID\n");
688 return LDB_ERR_UNWILLING_TO_PERFORM;
690 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
691 if ( !NT_STATUS_IS_OK(status)) {
692 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
693 "replmd_add: Unable to parse as a GUID the attribute objectGUID\n");
695 return LDB_ERR_UNWILLING_TO_PERFORM;
697 /* we remove this attribute as it can be a string and will not be treated
698 correctly and then we will readd it latter on in the good format*/
699 remove_current_guid = true;
703 guid = GUID_random();
706 /* Get a sequence number from the backend */
707 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
708 if (ret != LDB_SUCCESS) {
713 /* get our invocationId */
714 our_invocation_id = samdb_ntds_invocation_id(ldb);
715 if (!our_invocation_id) {
716 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
717 "replmd_add: unable to find invocationId\n");
719 return LDB_ERR_OPERATIONS_ERROR;
722 /* we have to copy the message as the caller might have it as a const */
723 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
727 return LDB_ERR_OPERATIONS_ERROR;
730 /* generated times */
731 unix_to_nt_time(&now, t);
732 time_str = ldb_timestring(msg, t);
736 return LDB_ERR_OPERATIONS_ERROR;
738 if (remove_current_guid) {
739 ldb_msg_remove_attr(msg,"objectGUID");
743 * remove autogenerated attributes
745 ldb_msg_remove_attr(msg, "whenCreated");
746 ldb_msg_remove_attr(msg, "whenChanged");
747 ldb_msg_remove_attr(msg, "uSNCreated");
748 ldb_msg_remove_attr(msg, "uSNChanged");
749 ldb_msg_remove_attr(msg, "replPropertyMetaData");
752 * readd replicated attributes
754 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
755 if (ret != LDB_SUCCESS) {
761 /* build the replication meta_data */
764 nmd.ctr.ctr1.count = msg->num_elements;
765 nmd.ctr.ctr1.array = talloc_array(msg,
766 struct replPropertyMetaData1,
768 if (!nmd.ctr.ctr1.array) {
771 return LDB_ERR_OPERATIONS_ERROR;
774 for (i=0; i < msg->num_elements; i++) {
775 struct ldb_message_element *e = &msg->elements[i];
776 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
777 const struct dsdb_attribute *sa;
779 if (e->name[0] == '@') continue;
781 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
783 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
784 "replmd_add: attribute '%s' not defined in schema\n",
787 return LDB_ERR_NO_SUCH_ATTRIBUTE;
790 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
791 /* if the attribute is not replicated (0x00000001)
792 * or constructed (0x00000004) it has no metadata
797 #if W2K3_LINKED_ATTRIBUTES
798 if (sa->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
799 ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa);
800 if (ret != LDB_SUCCESS) {
804 /* linked attributes are not stored in
805 replPropertyMetaData in FL above w2k */
810 m->attid = sa->attributeID_id;
812 m->originating_change_time = now;
813 m->originating_invocation_id = *our_invocation_id;
814 m->originating_usn = ac->seq_num;
815 m->local_usn = ac->seq_num;
819 /* fix meta data count */
820 nmd.ctr.ctr1.count = ni;
823 * sort meta data array, and move the rdn attribute entry to the end
825 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
826 if (ret != LDB_SUCCESS) {
831 /* generated NDR encoded values */
832 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
833 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
835 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
836 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
839 return LDB_ERR_OPERATIONS_ERROR;
843 * add the autogenerated values
845 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
846 if (ret != LDB_SUCCESS) {
851 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
852 if (ret != LDB_SUCCESS) {
857 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
858 if (ret != LDB_SUCCESS) {
863 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
864 if (ret != LDB_SUCCESS) {
869 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
870 if (ret != LDB_SUCCESS) {
877 * sort the attributes by attid before storing the object
879 replmd_ldb_message_sort(msg, ac->schema);
881 ret = ldb_build_add_req(&down_req, ldb, ac,
884 ac, replmd_op_callback,
886 if (ret != LDB_SUCCESS) {
891 /* mark the control done */
893 control->critical = 0;
896 /* go on with the call chain */
897 return ldb_next_request(module, down_req);
902 * update the replPropertyMetaData for one element
904 static int replmd_update_rpmd_element(struct ldb_context *ldb,
905 struct ldb_message *msg,
906 struct ldb_message_element *el,
907 struct replPropertyMetaDataBlob *omd,
908 const struct dsdb_schema *schema,
910 const struct GUID *our_invocation_id,
914 const struct dsdb_attribute *a;
915 struct replPropertyMetaData1 *md1;
917 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
919 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
921 return LDB_ERR_OPERATIONS_ERROR;
924 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
928 for (i=0; i<omd->ctr.ctr1.count; i++) {
929 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
932 #if W2K3_LINKED_ATTRIBUTES
933 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
934 /* linked attributes are not stored in
935 replPropertyMetaData in FL above w2k, but we do
936 raise the seqnum for the object */
938 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
939 return LDB_ERR_OPERATIONS_ERROR;
945 if (i == omd->ctr.ctr1.count) {
946 /* we need to add a new one */
947 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
948 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
949 if (omd->ctr.ctr1.array == NULL) {
951 return LDB_ERR_OPERATIONS_ERROR;
953 omd->ctr.ctr1.count++;
954 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
957 /* Get a new sequence number from the backend. We only do this
958 * if we have a change that requires a new
959 * replPropertyMetaData element
962 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
963 if (ret != LDB_SUCCESS) {
964 return LDB_ERR_OPERATIONS_ERROR;
968 md1 = &omd->ctr.ctr1.array[i];
970 md1->attid = a->attributeID_id;
971 md1->originating_change_time = now;
972 md1->originating_invocation_id = *our_invocation_id;
973 md1->originating_usn = *seq_num;
974 md1->local_usn = *seq_num;
980 * update the replPropertyMetaData object each time we modify an
981 * object. This is needed for DRS replication, as the merge on the
982 * client is based on this object
984 static int replmd_update_rpmd(struct ldb_module *module,
985 const struct dsdb_schema *schema,
986 struct ldb_message *msg, uint64_t *seq_num,
989 const struct ldb_val *omd_value;
990 enum ndr_err_code ndr_err;
991 struct replPropertyMetaDataBlob omd;
994 const struct GUID *our_invocation_id;
996 const char *attrs[] = { "replPropertyMetaData" , NULL };
997 struct ldb_result *res;
998 struct ldb_context *ldb;
1000 ldb = ldb_module_get_ctx(module);
1002 our_invocation_id = samdb_ntds_invocation_id(ldb);
1003 if (!our_invocation_id) {
1004 /* this happens during an initial vampire while
1005 updating the schema */
1006 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1010 unix_to_nt_time(&now, t);
1012 /* search for the existing replPropertyMetaDataBlob */
1013 ret = dsdb_search_dn_with_deleted(ldb, msg, &res, msg->dn, attrs);
1014 if (ret != LDB_SUCCESS || res->count != 1) {
1015 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1016 ldb_dn_get_linearized(msg->dn)));
1017 return LDB_ERR_OPERATIONS_ERROR;
1021 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1023 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1024 ldb_dn_get_linearized(msg->dn)));
1025 return LDB_ERR_OPERATIONS_ERROR;
1028 ndr_err = ndr_pull_struct_blob(omd_value, msg,
1029 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
1030 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1031 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1032 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1033 ldb_dn_get_linearized(msg->dn)));
1034 return LDB_ERR_OPERATIONS_ERROR;
1037 if (omd.version != 1) {
1038 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1039 omd.version, ldb_dn_get_linearized(msg->dn)));
1040 return LDB_ERR_OPERATIONS_ERROR;
1043 for (i=0; i<msg->num_elements; i++) {
1044 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], &omd, schema, seq_num,
1045 our_invocation_id, now);
1046 if (ret != LDB_SUCCESS) {
1052 * replmd_update_rpmd_element has done an update if the
1055 if (*seq_num != 0) {
1056 struct ldb_val *md_value;
1057 struct ldb_message_element *el;
1059 md_value = talloc(msg, struct ldb_val);
1060 if (md_value == NULL) {
1062 return LDB_ERR_OPERATIONS_ERROR;
1065 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1066 if (ret != LDB_SUCCESS) {
1070 ndr_err = ndr_push_struct_blob(md_value, msg,
1071 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1073 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1074 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1075 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1076 ldb_dn_get_linearized(msg->dn)));
1077 return LDB_ERR_OPERATIONS_ERROR;
1080 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1081 if (ret != LDB_SUCCESS) {
1082 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1083 ldb_dn_get_linearized(msg->dn)));
1088 el->values = md_value;
1096 struct dsdb_dn *dsdb_dn;
1101 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1103 return GUID_compare(pdn1->guid, pdn2->guid);
1106 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid)
1108 struct parsed_dn *ret;
1109 BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1114 get a series of message element values as an array of DNs and GUIDs
1115 the result is sorted by GUID
1117 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1118 struct ldb_message_element *el, struct parsed_dn **pdn,
1119 const char *ldap_oid)
1122 struct ldb_context *ldb = ldb_module_get_ctx(module);
1129 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1131 ldb_module_oom(module);
1132 return LDB_ERR_OPERATIONS_ERROR;
1135 for (i=0; i<el->num_values; i++) {
1136 struct ldb_val *v = &el->values[i];
1139 struct parsed_dn *p;
1143 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1144 if (p->dsdb_dn == NULL) {
1145 return LDB_ERR_INVALID_DN_SYNTAX;
1148 dn = p->dsdb_dn->dn;
1150 p->guid = talloc(*pdn, struct GUID);
1151 if (p->guid == NULL) {
1152 ldb_module_oom(module);
1153 return LDB_ERR_OPERATIONS_ERROR;
1156 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1157 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1158 /* we got a DN without a GUID - go find the GUID */
1159 int ret = dsdb_find_guid_by_dn(ldb, dn, p->guid);
1160 if (ret != LDB_SUCCESS) {
1161 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1162 ldb_dn_get_linearized(dn));
1165 } else if (!NT_STATUS_IS_OK(status)) {
1166 return LDB_ERR_OPERATIONS_ERROR;
1169 /* keep a pointer to the original ldb_val */
1173 qsort(*pdn, el->num_values, sizeof((*pdn)[0]), (comparison_fn_t)parsed_dn_compare);
1179 build a new extended DN, including all meta data fields
1181 DELETED = 1 or missing
1182 RMD_ADDTIME = originating_add_time
1183 RMD_INVOCID = originating_invocation_id
1184 RMD_CHANGETIME = originating_change_time
1185 RMD_ORIGINATING_USN = originating_usn
1186 RMD_LOCAL_USN = local_usn
1187 RMD_VERSION = version
1189 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1190 const struct GUID *invocation_id, uint64_t seq_num,
1191 uint64_t local_usn, NTTIME nttime, bool deleted)
1193 struct ldb_dn *dn = dsdb_dn->dn;
1194 const char *tstring, *usn_string;
1195 struct ldb_val tval;
1197 struct ldb_val usnv, local_usnv;
1198 struct ldb_val vers;
1201 const char *dnstring;
1203 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1205 return LDB_ERR_OPERATIONS_ERROR;
1207 tval = data_blob_string_const(tstring);
1209 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1211 return LDB_ERR_OPERATIONS_ERROR;
1213 usnv = data_blob_string_const(usn_string);
1215 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1217 return LDB_ERR_OPERATIONS_ERROR;
1219 local_usnv = data_blob_string_const(usn_string);
1221 vers = data_blob_string_const("0");
1223 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1224 if (!NT_STATUS_IS_OK(status)) {
1225 return LDB_ERR_OPERATIONS_ERROR;
1230 dv = data_blob_string_const("1");
1231 ret = ldb_dn_set_extended_component(dn, "DELETED", &dv);
1233 ret = ldb_dn_set_extended_component(dn, "DELETED", NULL);
1235 if (ret != LDB_SUCCESS) return ret;
1236 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1237 if (ret != LDB_SUCCESS) return ret;
1238 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1239 if (ret != LDB_SUCCESS) return ret;
1240 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1241 if (ret != LDB_SUCCESS) return ret;
1242 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1243 if (ret != LDB_SUCCESS) return ret;
1244 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1245 if (ret != LDB_SUCCESS) return ret;
1246 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1247 if (ret != LDB_SUCCESS) return ret;
1249 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1250 if (dnstring == NULL) {
1251 return LDB_ERR_OPERATIONS_ERROR;
1253 *v = data_blob_string_const(dnstring);
1260 update an extended DN, including all meta data fields
1262 see replmd_build_la_val for value names
1264 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1265 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1266 uint64_t seq_num, uint64_t local_usn, NTTIME nttime, bool deleted)
1268 struct ldb_dn *dn = dsdb_dn->dn;
1269 const char *tstring, *usn_string;
1270 struct ldb_val tval;
1272 struct ldb_val usnv, local_usnv;
1273 struct ldb_val vers;
1274 const struct ldb_val *old_addtime, *old_version;
1277 const char *dnstring;
1279 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1281 return LDB_ERR_OPERATIONS_ERROR;
1283 tval = data_blob_string_const(tstring);
1285 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1287 return LDB_ERR_OPERATIONS_ERROR;
1289 usnv = data_blob_string_const(usn_string);
1291 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1293 return LDB_ERR_OPERATIONS_ERROR;
1295 local_usnv = data_blob_string_const(usn_string);
1297 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1298 if (!NT_STATUS_IS_OK(status)) {
1299 return LDB_ERR_OPERATIONS_ERROR;
1304 dv = data_blob_string_const("1");
1305 ret = ldb_dn_set_extended_component(dn, "DELETED", &dv);
1307 ret = ldb_dn_set_extended_component(dn, "DELETED", NULL);
1309 if (ret != LDB_SUCCESS) return ret;
1311 /* get the ADDTIME from the original */
1312 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1313 if (old_addtime == NULL) {
1314 old_addtime = &tval;
1316 if (dsdb_dn != old_dsdb_dn) {
1317 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1318 if (ret != LDB_SUCCESS) return ret;
1321 /* use our invocation id */
1322 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1323 if (ret != LDB_SUCCESS) return ret;
1325 /* changetime is the current time */
1326 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1327 if (ret != LDB_SUCCESS) return ret;
1329 /* update the USN */
1330 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1331 if (ret != LDB_SUCCESS) return ret;
1333 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1334 if (ret != LDB_SUCCESS) return ret;
1336 /* increase the version by 1 */
1337 old_version = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_VERSION");
1338 if (old_version == NULL) {
1339 vers = data_blob_string_const("0");
1342 vstring = talloc_strndup(dn, (const char *)old_version->data, old_version->length);
1344 return LDB_ERR_OPERATIONS_ERROR;
1346 vstring = talloc_asprintf(dn, "%lu",
1347 (unsigned long)strtoul(vstring, NULL, 0)+1);
1348 vers = data_blob_string_const(vstring);
1350 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1351 if (ret != LDB_SUCCESS) return ret;
1353 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1354 if (dnstring == NULL) {
1355 return LDB_ERR_OPERATIONS_ERROR;
1357 *v = data_blob_string_const(dnstring);
1363 handle adding a linked attribute
1365 static int replmd_modify_la_add(struct ldb_module *module,
1366 struct dsdb_schema *schema,
1367 struct ldb_message *msg,
1368 struct ldb_message_element *el,
1369 struct ldb_message_element *old_el,
1370 const struct dsdb_attribute *schema_attr,
1373 struct GUID *msg_guid)
1376 struct parsed_dn *dns, *old_dns;
1377 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1379 struct ldb_val *new_values = NULL;
1380 unsigned int num_new_values = 0;
1381 unsigned old_num_values = old_el?old_el->num_values:0;
1382 const struct GUID *invocation_id;
1383 struct ldb_context *ldb = ldb_module_get_ctx(module);
1386 unix_to_nt_time(&now, t);
1388 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1389 if (ret != LDB_SUCCESS) {
1390 talloc_free(tmp_ctx);
1394 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1395 if (ret != LDB_SUCCESS) {
1396 talloc_free(tmp_ctx);
1400 invocation_id = samdb_ntds_invocation_id(ldb);
1401 if (!invocation_id) {
1402 return LDB_ERR_OPERATIONS_ERROR;
1405 /* for each new value, see if it exists already with the same GUID */
1406 for (i=0; i<el->num_values; i++) {
1407 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid);
1409 /* this is a new linked attribute value */
1410 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1411 if (new_values == NULL) {
1412 ldb_module_oom(module);
1413 talloc_free(tmp_ctx);
1414 return LDB_ERR_OPERATIONS_ERROR;
1416 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1417 invocation_id, seq_num, seq_num, now, false);
1418 if (ret != LDB_SUCCESS) {
1419 talloc_free(tmp_ctx);
1424 /* this is only allowed if the GUID was
1425 previously deleted. */
1426 const struct ldb_val *v;
1427 v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED");
1429 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1430 el->name, GUID_string(tmp_ctx, p->guid));
1431 talloc_free(tmp_ctx);
1432 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1434 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1435 invocation_id, seq_num, seq_num, now, false);
1436 if (ret != LDB_SUCCESS) {
1437 talloc_free(tmp_ctx);
1442 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1443 if (ret != LDB_SUCCESS) {
1444 talloc_free(tmp_ctx);
1449 /* add the new ones on to the end of the old values, constructing a new el->values */
1450 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1452 old_num_values+num_new_values);
1453 if (el->values == NULL) {
1454 ldb_module_oom(module);
1455 return LDB_ERR_OPERATIONS_ERROR;
1458 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1459 el->num_values = old_num_values + num_new_values;
1461 talloc_steal(msg->elements, el->values);
1462 talloc_steal(el->values, new_values);
1464 talloc_free(tmp_ctx);
1466 /* we now tell the backend to replace all existing values
1467 with the one we have constructed */
1468 el->flags = LDB_FLAG_MOD_REPLACE;
1475 handle deleting all active linked attributes
1477 static int replmd_modify_la_delete(struct ldb_module *module,
1478 struct dsdb_schema *schema,
1479 struct ldb_message *msg,
1480 struct ldb_message_element *el,
1481 struct ldb_message_element *old_el,
1482 const struct dsdb_attribute *schema_attr,
1485 struct GUID *msg_guid)
1488 struct parsed_dn *dns, *old_dns;
1489 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1491 const struct GUID *invocation_id;
1492 struct ldb_context *ldb = ldb_module_get_ctx(module);
1495 unix_to_nt_time(&now, t);
1497 /* check if there is nothing to delete */
1498 if ((!old_el || old_el->num_values == 0) &&
1499 el->num_values == 0) {
1503 if (!old_el || old_el->num_values == 0) {
1504 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1507 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1508 if (ret != LDB_SUCCESS) {
1509 talloc_free(tmp_ctx);
1513 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1514 if (ret != LDB_SUCCESS) {
1515 talloc_free(tmp_ctx);
1519 invocation_id = samdb_ntds_invocation_id(ldb);
1520 if (!invocation_id) {
1521 return LDB_ERR_OPERATIONS_ERROR;
1526 /* see if we are being asked to delete any links that
1527 don't exist or are already deleted */
1528 for (i=0; i<el->num_values; i++) {
1529 struct parsed_dn *p = &dns[i];
1530 struct parsed_dn *p2;
1531 const struct ldb_val *v;
1533 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid);
1535 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1536 el->name, GUID_string(tmp_ctx, p->guid));
1537 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1539 v = ldb_dn_get_extended_component(p2->dsdb_dn->dn, "DELETED");
1541 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1542 el->name, GUID_string(tmp_ctx, p->guid));
1543 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1547 /* for each new value, see if it exists already with the same GUID
1548 if it is not already deleted and matches the delete list then delete it
1550 for (i=0; i<old_el->num_values; i++) {
1551 struct parsed_dn *p = &old_dns[i];
1552 const struct ldb_val *v;
1554 if (dns && parsed_dn_find(dns, el->num_values, p->guid) == NULL) {
1558 v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED");
1559 if (v != NULL) continue;
1561 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1562 invocation_id, seq_num, seq_num, now, true);
1563 if (ret != LDB_SUCCESS) {
1564 talloc_free(tmp_ctx);
1568 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1569 if (ret != LDB_SUCCESS) {
1570 talloc_free(tmp_ctx);
1575 el->values = talloc_steal(msg->elements, old_el->values);
1576 el->num_values = old_el->num_values;
1578 talloc_free(tmp_ctx);
1580 /* we now tell the backend to replace all existing values
1581 with the one we have constructed */
1582 el->flags = LDB_FLAG_MOD_REPLACE;
1588 handle replacing a linked attribute
1590 static int replmd_modify_la_replace(struct ldb_module *module,
1591 struct dsdb_schema *schema,
1592 struct ldb_message *msg,
1593 struct ldb_message_element *el,
1594 struct ldb_message_element *old_el,
1595 const struct dsdb_attribute *schema_attr,
1598 struct GUID *msg_guid)
1601 struct parsed_dn *dns, *old_dns;
1602 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1604 const struct GUID *invocation_id;
1605 struct ldb_context *ldb = ldb_module_get_ctx(module);
1606 struct ldb_val *new_values = NULL;
1607 uint32_t num_new_values = 0;
1608 unsigned old_num_values = old_el?old_el->num_values:0;
1611 unix_to_nt_time(&now, t);
1613 /* check if there is nothing to replace */
1614 if ((!old_el || old_el->num_values == 0) &&
1615 el->num_values == 0) {
1619 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1620 if (ret != LDB_SUCCESS) {
1621 talloc_free(tmp_ctx);
1625 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1626 if (ret != LDB_SUCCESS) {
1627 talloc_free(tmp_ctx);
1631 invocation_id = samdb_ntds_invocation_id(ldb);
1632 if (!invocation_id) {
1633 return LDB_ERR_OPERATIONS_ERROR;
1636 /* mark all the old ones as deleted */
1637 for (i=0; i<old_num_values; i++) {
1638 struct parsed_dn *old_p = &old_dns[i];
1639 struct parsed_dn *p;
1640 const struct ldb_val *v;
1642 v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED");
1645 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1646 if (ret != LDB_SUCCESS) {
1647 talloc_free(tmp_ctx);
1651 p = parsed_dn_find(dns, el->num_values, old_p->guid);
1653 /* we don't delete it if we are re-adding it */
1657 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
1658 invocation_id, seq_num, seq_num, now, true);
1659 if (ret != LDB_SUCCESS) {
1660 talloc_free(tmp_ctx);
1665 /* for each new value, either update its meta-data, or add it
1668 for (i=0; i<el->num_values; i++) {
1669 struct parsed_dn *p = &dns[i], *old_p;
1672 (old_p = parsed_dn_find(old_dns,
1673 old_num_values, p->guid)) != NULL) {
1674 /* update in place */
1675 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
1676 old_p->dsdb_dn, invocation_id,
1677 seq_num, seq_num, now, false);
1678 if (ret != LDB_SUCCESS) {
1679 talloc_free(tmp_ctx);
1684 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
1686 if (new_values == NULL) {
1687 ldb_module_oom(module);
1688 talloc_free(tmp_ctx);
1689 return LDB_ERR_OPERATIONS_ERROR;
1691 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1692 invocation_id, seq_num, seq_num, now, false);
1693 if (ret != LDB_SUCCESS) {
1694 talloc_free(tmp_ctx);
1700 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
1701 if (ret != LDB_SUCCESS) {
1702 talloc_free(tmp_ctx);
1707 /* add the new values to the end of old_el */
1708 if (num_new_values != 0) {
1709 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1710 struct ldb_val, old_num_values+num_new_values);
1711 if (el->values == NULL) {
1712 ldb_module_oom(module);
1713 return LDB_ERR_OPERATIONS_ERROR;
1715 memcpy(&el->values[old_num_values], &new_values[0],
1716 sizeof(struct ldb_val)*num_new_values);
1717 el->num_values = old_num_values + num_new_values;
1718 talloc_steal(msg->elements, new_values);
1720 el->values = old_el->values;
1721 el->num_values = old_el->num_values;
1722 talloc_steal(msg->elements, el->values);
1725 talloc_free(tmp_ctx);
1727 /* we now tell the backend to replace all existing values
1728 with the one we have constructed */
1729 el->flags = LDB_FLAG_MOD_REPLACE;
1736 handle linked attributes in modify requests
1738 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
1739 struct ldb_message *msg,
1740 uint64_t seq_num, time_t t)
1742 struct ldb_result *res;
1744 struct ldb_context *ldb = ldb_module_get_ctx(module);
1745 struct ldb_message *old_msg;
1746 struct dsdb_schema *schema = dsdb_get_schema(ldb);
1747 struct GUID old_guid;
1750 /* there the replmd_update_rpmd code has already
1751 * checked and saw that there are no linked
1756 #if !W2K3_LINKED_ATTRIBUTES
1760 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
1761 /* don't do anything special for linked attributes */
1765 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
1766 DSDB_SEARCH_SHOW_DELETED |
1767 DSDB_SEARCH_REVEAL_INTERNALS |
1768 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
1769 if (ret != LDB_SUCCESS) {
1772 old_msg = res->msgs[0];
1774 old_guid = samdb_result_guid(old_msg, "objectGUID");
1776 for (i=0; i<msg->num_elements; i++) {
1777 struct ldb_message_element *el = &msg->elements[i];
1778 struct ldb_message_element *old_el, *new_el;
1779 const struct dsdb_attribute *schema_attr
1780 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1782 ldb_asprintf_errstring(ldb,
1783 "attribute %s is not a valid attribute in schema", el->name);
1784 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1786 if (schema_attr->linkID == 0) {
1789 if ((schema_attr->linkID & 1) == 1) {
1790 /* Odd is for the target. Illegal to modify */
1791 ldb_asprintf_errstring(ldb,
1792 "attribute %s must not be modified directly, it is a linked attribute", el->name);
1793 return LDB_ERR_UNWILLING_TO_PERFORM;
1795 old_el = ldb_msg_find_element(old_msg, el->name);
1796 switch (el->flags & LDB_FLAG_MOD_MASK) {
1797 case LDB_FLAG_MOD_REPLACE:
1798 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1800 case LDB_FLAG_MOD_DELETE:
1801 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1803 case LDB_FLAG_MOD_ADD:
1804 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1807 ldb_asprintf_errstring(ldb,
1808 "invalid flags 0x%x for %s linked attribute",
1809 el->flags, el->name);
1810 return LDB_ERR_UNWILLING_TO_PERFORM;
1812 if (ret != LDB_SUCCESS) {
1816 ldb_msg_remove_attr(old_msg, el->name);
1818 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
1819 new_el->num_values = el->num_values;
1820 new_el->values = el->values;
1822 /* TODO: this relises a bit too heavily on the exact
1823 behaviour of ldb_msg_find_element and
1824 ldb_msg_remove_element */
1825 old_el = ldb_msg_find_element(msg, el->name);
1827 ldb_msg_remove_element(msg, old_el);
1838 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
1840 struct ldb_context *ldb;
1841 struct replmd_replicated_request *ac;
1842 struct ldb_request *down_req;
1843 struct ldb_message *msg;
1844 time_t t = time(NULL);
1847 /* do not manipulate our control entries */
1848 if (ldb_dn_is_special(req->op.mod.message->dn)) {
1849 return ldb_next_request(module, req);
1852 ldb = ldb_module_get_ctx(module);
1854 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
1856 ac = replmd_ctx_init(module, req);
1858 return LDB_ERR_OPERATIONS_ERROR;
1861 /* we have to copy the message as the caller might have it as a const */
1862 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
1866 return LDB_ERR_OPERATIONS_ERROR;
1869 ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num, t);
1870 if (ret != LDB_SUCCESS) {
1875 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t);
1876 if (ret != LDB_SUCCESS) {
1882 * - replace the old object with the newly constructed one
1885 ret = ldb_build_mod_req(&down_req, ldb, ac,
1888 ac, replmd_op_callback,
1890 if (ret != LDB_SUCCESS) {
1894 talloc_steal(down_req, msg);
1896 /* we only change whenChanged and uSNChanged if the seq_num
1898 if (ac->seq_num != 0) {
1899 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
1904 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
1910 /* go on with the call chain */
1911 return ldb_next_request(module, down_req);
1914 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
1917 handle a rename request
1919 On a rename we need to do an extra ldb_modify which sets the
1920 whenChanged and uSNChanged attributes. We do this in a callback after the success.
1922 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
1924 struct ldb_context *ldb;
1925 struct replmd_replicated_request *ac;
1927 struct ldb_request *down_req;
1929 /* do not manipulate our control entries */
1930 if (ldb_dn_is_special(req->op.mod.message->dn)) {
1931 return ldb_next_request(module, req);
1934 ldb = ldb_module_get_ctx(module);
1936 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
1938 ac = replmd_ctx_init(module, req);
1940 return LDB_ERR_OPERATIONS_ERROR;
1942 ret = ldb_build_rename_req(&down_req, ldb, ac,
1943 ac->req->op.rename.olddn,
1944 ac->req->op.rename.newdn,
1946 ac, replmd_rename_callback,
1949 if (ret != LDB_SUCCESS) {
1954 /* go on with the call chain */
1955 return ldb_next_request(module, down_req);
1958 /* After the rename is compleated, update the whenchanged etc */
1959 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
1961 struct ldb_context *ldb;
1962 struct replmd_replicated_request *ac;
1963 struct ldb_request *down_req;
1964 struct ldb_message *msg;
1965 time_t t = time(NULL);
1968 ac = talloc_get_type(req->context, struct replmd_replicated_request);
1969 ldb = ldb_module_get_ctx(ac->module);
1971 if (ares->error != LDB_SUCCESS) {
1972 return ldb_module_done(ac->req, ares->controls,
1973 ares->response, ares->error);
1976 if (ares->type != LDB_REPLY_DONE) {
1977 ldb_set_errstring(ldb,
1978 "invalid ldb_reply_type in callback");
1980 return ldb_module_done(ac->req, NULL, NULL,
1981 LDB_ERR_OPERATIONS_ERROR);
1984 /* Get a sequence number from the backend */
1985 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1986 if (ret != LDB_SUCCESS) {
1991 * - replace the old object with the newly constructed one
1994 msg = ldb_msg_new(ac);
1997 return LDB_ERR_OPERATIONS_ERROR;
2000 msg->dn = ac->req->op.rename.newdn;
2002 ret = ldb_build_mod_req(&down_req, ldb, ac,
2005 ac, replmd_op_callback,
2008 if (ret != LDB_SUCCESS) {
2012 talloc_steal(down_req, msg);
2014 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2019 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
2024 /* go on with the call chain - do the modify after the rename */
2025 return ldb_next_request(ac->module, down_req);
2028 /* remove forwards and backlinks as needed when an object
2030 static int replmd_delete_remove_link(struct ldb_module *module,
2031 struct dsdb_schema *schema,
2033 struct ldb_message_element *el,
2034 const struct dsdb_attribute *sa)
2037 TALLOC_CTX *tmp_ctx = talloc_new(module);
2038 struct ldb_context *ldb = ldb_module_get_ctx(module);
2040 for (i=0; i<el->num_values; i++) {
2041 struct dsdb_dn *dsdb_dn;
2045 struct ldb_message *msg;
2046 const struct dsdb_attribute *target_attr;
2047 struct ldb_message_element *el2;
2048 struct ldb_val dn_val;
2050 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2054 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2056 talloc_free(tmp_ctx);
2057 return LDB_ERR_OPERATIONS_ERROR;
2060 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2061 if (!NT_STATUS_IS_OK(status)) {
2062 talloc_free(tmp_ctx);
2063 return LDB_ERR_OPERATIONS_ERROR;
2066 /* remove the link */
2067 msg = ldb_msg_new(tmp_ctx);
2069 ldb_module_oom(module);
2070 talloc_free(tmp_ctx);
2071 return LDB_ERR_OPERATIONS_ERROR;
2075 msg->dn = dsdb_dn->dn;
2077 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2078 if (target_attr == NULL) {
2082 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2083 if (ret != LDB_SUCCESS) {
2084 ldb_module_oom(module);
2085 talloc_free(tmp_ctx);
2086 return LDB_ERR_OPERATIONS_ERROR;
2088 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2089 el2->values = &dn_val;
2090 el2->num_values = 1;
2092 ret = dsdb_module_modify(module, msg, 0);
2093 if (ret != LDB_SUCCESS) {
2094 talloc_free(tmp_ctx);
2098 talloc_free(tmp_ctx);
2104 handle update of replication meta data for deletion of objects
2106 This also handles the mapping of delete to a rename operation
2107 to allow deletes to be replicated.
2109 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2111 int ret = LDB_ERR_OTHER;
2113 struct ldb_dn *old_dn, *new_dn;
2114 const char *rdn_name;
2115 const struct ldb_val *rdn_value, *new_rdn_value;
2117 struct ldb_context *ldb = ldb_module_get_ctx(module);
2118 struct dsdb_schema *schema = dsdb_get_schema(ldb);
2119 struct ldb_message *msg, *old_msg;
2120 struct ldb_message_element *el;
2121 TALLOC_CTX *tmp_ctx;
2122 struct ldb_result *res, *parent_res;
2123 const char *preserved_attrs[] = {
2124 /* yes, this really is a hard coded list. See MS-ADTS
2125 section 3.1.1.5.5.1.1 */
2126 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2127 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2128 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2129 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2130 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2131 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2132 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreate",
2134 uint32_t el_count = 0;
2137 tmp_ctx = talloc_new(ldb);
2139 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2141 /* we need the complete msg off disk, so we can work out which
2142 attributes need to be removed */
2143 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2144 DSDB_SEARCH_SHOW_DELETED |
2145 DSDB_SEARCH_REVEAL_INTERNALS |
2146 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
2147 if (ret != LDB_SUCCESS) {
2148 talloc_free(tmp_ctx);
2151 old_msg = res->msgs[0];
2153 /* work out where we will be renaming this object to */
2154 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn, &new_dn);
2155 if (ret != LDB_SUCCESS) {
2156 /* this is probably an attempted delete on a partition
2157 * that doesn't allow delete operations, such as the
2158 * schema partition */
2159 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2160 ldb_dn_get_linearized(old_dn));
2161 talloc_free(tmp_ctx);
2162 return LDB_ERR_UNWILLING_TO_PERFORM;
2165 rdn_name = ldb_dn_get_rdn_name(old_dn);
2166 rdn_value = ldb_dn_get_rdn_val(old_dn);
2168 /* get the objects GUID from the search we just did */
2169 guid = samdb_result_guid(old_msg, "objectGUID");
2171 /* Add a formatted child */
2172 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2175 GUID_string(tmp_ctx, &guid));
2177 DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2178 ldb_dn_get_linearized(new_dn)));
2179 talloc_free(tmp_ctx);
2180 return LDB_ERR_OPERATIONS_ERROR;
2184 now we need to modify the object in the following ways:
2186 - add isDeleted=TRUE
2187 - update rDN and name, with new rDN
2188 - remove linked attributes
2189 - remove objectCategory and sAMAccountType
2190 - remove attribs not on the preserved list
2191 - preserved if in above list, or is rDN
2192 - remove all linked attribs from this object
2193 - remove all links from other objects to this object
2194 - add lastKnownParent
2195 - update replPropertyMetaData?
2197 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2200 msg = ldb_msg_new(tmp_ctx);
2202 ldb_module_oom(module);
2203 talloc_free(tmp_ctx);
2204 return LDB_ERR_OPERATIONS_ERROR;
2209 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2210 if (ret != LDB_SUCCESS) {
2211 DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2212 ldb_module_oom(module);
2213 talloc_free(tmp_ctx);
2216 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2218 /* we need the storage form of the parent GUID */
2219 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2220 ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2221 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2222 DSDB_SEARCH_REVEAL_INTERNALS);
2223 if (ret != LDB_SUCCESS) {
2224 talloc_free(tmp_ctx);
2228 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2229 ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2230 if (ret != LDB_SUCCESS) {
2231 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2232 ldb_module_oom(module);
2233 talloc_free(tmp_ctx);
2236 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2238 /* work out which of the old attributes we will be removing */
2239 for (i=0; i<old_msg->num_elements; i++) {
2240 const struct dsdb_attribute *sa;
2241 el = &old_msg->elements[i];
2242 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2244 talloc_free(tmp_ctx);
2245 return LDB_ERR_OPERATIONS_ERROR;
2247 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2248 /* don't remove the rDN */
2253 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa);
2254 if (ret != LDB_SUCCESS) {
2255 talloc_free(tmp_ctx);
2256 return LDB_ERR_OPERATIONS_ERROR;
2260 if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2264 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2265 if (ret != LDB_SUCCESS) {
2266 talloc_free(tmp_ctx);
2267 ldb_module_oom(module);
2272 /* work out what the new rdn value is, for updating the
2273 rDN and name fields */
2274 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2275 ret = ldb_msg_add_value(msg, rdn_name, new_rdn_value, &el);
2276 if (ret != LDB_SUCCESS) {
2277 talloc_free(tmp_ctx);
2280 el->flags = LDB_FLAG_MOD_REPLACE;
2282 el = ldb_msg_find_element(old_msg, "name");
2284 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2285 if (ret != LDB_SUCCESS) {
2286 talloc_free(tmp_ctx);
2289 el->flags = LDB_FLAG_MOD_REPLACE;
2292 ret = dsdb_module_modify(module, msg, 0);
2293 if (ret != LDB_SUCCESS){
2294 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
2295 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
2296 talloc_free(tmp_ctx);
2300 /* now rename onto the new DN */
2301 ret = dsdb_module_rename(module, old_dn, new_dn, 0);
2302 if (ret != LDB_SUCCESS){
2303 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
2304 ldb_dn_get_linearized(old_dn),
2305 ldb_dn_get_linearized(new_dn),
2306 ldb_errstring(ldb)));
2307 talloc_free(tmp_ctx);
2311 talloc_free(tmp_ctx);
2313 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
2318 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
2323 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
2325 int ret = LDB_ERR_OTHER;
2326 /* TODO: do some error mapping */
2330 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
2332 struct ldb_context *ldb;
2333 struct ldb_request *change_req;
2334 enum ndr_err_code ndr_err;
2335 struct ldb_message *msg;
2336 struct replPropertyMetaDataBlob *md;
2337 struct ldb_val md_value;
2342 * TODO: check if the parent object exist
2346 * TODO: handle the conflict case where an object with the
2350 ldb = ldb_module_get_ctx(ar->module);
2351 msg = ar->objs->objects[ar->index_current].msg;
2352 md = ar->objs->objects[ar->index_current].meta_data;
2354 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2355 if (ret != LDB_SUCCESS) {
2356 return replmd_replicated_request_error(ar, ret);
2359 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
2360 if (ret != LDB_SUCCESS) {
2361 return replmd_replicated_request_error(ar, ret);
2364 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2365 if (ret != LDB_SUCCESS) {
2366 return replmd_replicated_request_error(ar, ret);
2369 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
2370 if (ret != LDB_SUCCESS) {
2371 return replmd_replicated_request_error(ar, ret);
2374 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2375 if (ret != LDB_SUCCESS) {
2376 return replmd_replicated_request_error(ar, ret);
2379 /* remove any message elements that have zero values */
2380 for (i=0; i<msg->num_elements; i++) {
2381 struct ldb_message_element *el = &msg->elements[i];
2383 if (el->num_values == 0) {
2384 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
2386 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
2387 msg->num_elements--;
2394 * the meta data array is already sorted by the caller
2396 for (i=0; i < md->ctr.ctr1.count; i++) {
2397 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
2399 ndr_err = ndr_push_struct_blob(&md_value, msg,
2400 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2402 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2403 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2404 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2405 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2407 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
2408 if (ret != LDB_SUCCESS) {
2409 return replmd_replicated_request_error(ar, ret);
2412 replmd_ldb_message_sort(msg, ar->schema);
2415 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
2416 DEBUG(4, ("DRS replication add message:\n%s\n", s));
2420 ret = ldb_build_add_req(&change_req,
2428 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2430 return ldb_next_request(ar->module, change_req);
2434 return true if an update is newer than an existing entry
2435 see section 5.11 of MS-ADTS
2437 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
2438 const struct GUID *update_invocation_id,
2439 uint32_t current_version,
2440 uint32_t update_version,
2441 NTTIME current_change_time,
2442 NTTIME update_change_time)
2444 if (update_version != current_version) {
2445 return update_version > current_version;
2447 if (update_change_time > current_change_time) {
2450 if (update_change_time == current_change_time) {
2451 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
2456 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
2457 struct replPropertyMetaData1 *new_m)
2459 return replmd_update_is_newer(&cur_m->originating_invocation_id,
2460 &new_m->originating_invocation_id,
2463 cur_m->originating_change_time,
2464 new_m->originating_change_time);
2467 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
2469 struct ldb_context *ldb;
2470 struct ldb_request *change_req;
2471 enum ndr_err_code ndr_err;
2472 struct ldb_message *msg;
2473 struct replPropertyMetaDataBlob *rmd;
2474 struct replPropertyMetaDataBlob omd;
2475 const struct ldb_val *omd_value;
2476 struct replPropertyMetaDataBlob nmd;
2477 struct ldb_val nmd_value;
2479 uint32_t removed_attrs = 0;
2482 ldb = ldb_module_get_ctx(ar->module);
2483 msg = ar->objs->objects[ar->index_current].msg;
2484 rmd = ar->objs->objects[ar->index_current].meta_data;
2489 * TODO: check repl data is correct after a rename
2491 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
2492 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
2493 ldb_dn_get_linearized(ar->search_msg->dn),
2494 ldb_dn_get_linearized(msg->dn));
2495 /* we can't use dsdb_module_rename() here as we need
2496 the rename call to be intercepted by this module, to
2497 allow it to process linked attribute changes */
2498 if (ldb_rename(ldb, ar->search_msg->dn, msg->dn) != LDB_SUCCESS) {
2499 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
2500 ldb_dn_get_linearized(ar->search_msg->dn),
2501 ldb_dn_get_linearized(msg->dn),
2502 ldb_errstring(ldb));
2503 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
2507 /* find existing meta data */
2508 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
2510 ndr_err = ndr_pull_struct_blob(omd_value, ar,
2511 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
2512 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
2513 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2514 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2515 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2518 if (omd.version != 1) {
2519 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2525 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
2526 nmd.ctr.ctr1.array = talloc_array(ar,
2527 struct replPropertyMetaData1,
2528 nmd.ctr.ctr1.count);
2529 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2531 /* first copy the old meta data */
2532 for (i=0; i < omd.ctr.ctr1.count; i++) {
2533 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
2537 /* now merge in the new meta data */
2538 for (i=0; i < rmd->ctr.ctr1.count; i++) {
2541 for (j=0; j < ni; j++) {
2544 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
2548 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
2549 &rmd->ctr.ctr1.array[i]);
2551 /* replace the entry */
2552 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
2557 DEBUG(1,("Discarding older DRS attribute update to %s on %s from %s\n",
2558 msg->elements[i-removed_attrs].name,
2559 ldb_dn_get_linearized(msg->dn),
2560 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
2562 /* we don't want to apply this change so remove the attribute */
2563 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
2570 if (found) continue;
2572 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
2577 * finally correct the size of the meta_data array
2579 nmd.ctr.ctr1.count = ni;
2582 * the rdn attribute (the alias for the name attribute),
2583 * 'cn' for most objects is the last entry in the meta data array
2586 * sort the new meta data array
2588 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
2589 if (ret != LDB_SUCCESS) {
2594 * check if some replicated attributes left, otherwise skip the ldb_modify() call
2596 if (msg->num_elements == 0) {
2597 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
2600 ar->index_current++;
2601 return replmd_replicated_apply_next(ar);
2604 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
2605 ar->index_current, msg->num_elements);
2607 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2608 if (ret != LDB_SUCCESS) {
2609 return replmd_replicated_request_error(ar, ret);
2612 for (i=0; i<ni; i++) {
2613 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
2616 /* create the meta data value */
2617 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
2618 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2620 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2621 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2622 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2623 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2627 * when we know that we'll modify the record, add the whenChanged, uSNChanged
2628 * and replPopertyMetaData attributes
2630 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2631 if (ret != LDB_SUCCESS) {
2632 return replmd_replicated_request_error(ar, ret);
2634 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2635 if (ret != LDB_SUCCESS) {
2636 return replmd_replicated_request_error(ar, ret);
2638 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
2639 if (ret != LDB_SUCCESS) {
2640 return replmd_replicated_request_error(ar, ret);
2643 replmd_ldb_message_sort(msg, ar->schema);
2645 /* we want to replace the old values */
2646 for (i=0; i < msg->num_elements; i++) {
2647 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2651 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
2652 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
2656 ret = ldb_build_mod_req(&change_req,
2664 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2666 return ldb_next_request(ar->module, change_req);
2669 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
2670 struct ldb_reply *ares)
2672 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2673 struct replmd_replicated_request);
2677 return ldb_module_done(ar->req, NULL, NULL,
2678 LDB_ERR_OPERATIONS_ERROR);
2680 if (ares->error != LDB_SUCCESS &&
2681 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
2682 return ldb_module_done(ar->req, ares->controls,
2683 ares->response, ares->error);
2686 switch (ares->type) {
2687 case LDB_REPLY_ENTRY:
2688 ar->search_msg = talloc_steal(ar, ares->message);
2691 case LDB_REPLY_REFERRAL:
2692 /* we ignore referrals */
2695 case LDB_REPLY_DONE:
2696 if (ar->search_msg != NULL) {
2697 ret = replmd_replicated_apply_merge(ar);
2699 ret = replmd_replicated_apply_add(ar);
2701 if (ret != LDB_SUCCESS) {
2702 return ldb_module_done(ar->req, NULL, NULL, ret);
2710 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
2712 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
2714 struct ldb_context *ldb;
2718 struct ldb_request *search_req;
2719 struct ldb_search_options_control *options;
2721 if (ar->index_current >= ar->objs->num_objects) {
2722 /* done with it, go to next stage */
2723 return replmd_replicated_uptodate_vector(ar);
2726 ldb = ldb_module_get_ctx(ar->module);
2727 ar->search_msg = NULL;
2729 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
2730 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2732 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
2733 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2734 talloc_free(tmp_str);
2736 ret = ldb_build_search_req(&search_req,
2745 replmd_replicated_apply_search_callback,
2748 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2749 if (ret != LDB_SUCCESS) {
2753 /* we need to cope with cross-partition links, so search for
2754 the GUID over all partitions */
2755 options = talloc(search_req, struct ldb_search_options_control);
2756 if (options == NULL) {
2757 DEBUG(0, (__location__ ": out of memory\n"));
2758 return LDB_ERR_OPERATIONS_ERROR;
2760 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2762 ret = ldb_request_add_control(search_req,
2763 LDB_CONTROL_SEARCH_OPTIONS_OID,
2765 if (ret != LDB_SUCCESS) {
2769 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2771 return ldb_next_request(ar->module, search_req);
2774 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
2775 struct ldb_reply *ares)
2777 struct ldb_context *ldb;
2778 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2779 struct replmd_replicated_request);
2780 ldb = ldb_module_get_ctx(ar->module);
2783 return ldb_module_done(ar->req, NULL, NULL,
2784 LDB_ERR_OPERATIONS_ERROR);
2786 if (ares->error != LDB_SUCCESS) {
2787 return ldb_module_done(ar->req, ares->controls,
2788 ares->response, ares->error);
2791 if (ares->type != LDB_REPLY_DONE) {
2792 ldb_set_errstring(ldb, "Invalid reply type\n!");
2793 return ldb_module_done(ar->req, NULL, NULL,
2794 LDB_ERR_OPERATIONS_ERROR);
2799 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
2802 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
2804 struct ldb_context *ldb;
2805 struct ldb_request *change_req;
2806 enum ndr_err_code ndr_err;
2807 struct ldb_message *msg;
2808 struct replUpToDateVectorBlob ouv;
2809 const struct ldb_val *ouv_value;
2810 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
2811 struct replUpToDateVectorBlob nuv;
2812 struct ldb_val nuv_value;
2813 struct ldb_message_element *nuv_el = NULL;
2814 const struct GUID *our_invocation_id;
2815 struct ldb_message_element *orf_el = NULL;
2816 struct repsFromToBlob nrf;
2817 struct ldb_val *nrf_value = NULL;
2818 struct ldb_message_element *nrf_el = NULL;
2821 time_t t = time(NULL);
2825 ldb = ldb_module_get_ctx(ar->module);
2826 ruv = ar->objs->uptodateness_vector;
2832 unix_to_nt_time(&now, t);
2835 * first create the new replUpToDateVector
2837 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
2839 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
2840 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
2841 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
2842 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2843 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2844 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2847 if (ouv.version != 2) {
2848 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2853 * the new uptodateness vector will at least
2854 * contain 1 entry, one for the source_dsa
2856 * plus optional values from our old vector and the one from the source_dsa
2858 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
2859 if (ruv) nuv.ctr.ctr2.count += ruv->count;
2860 nuv.ctr.ctr2.cursors = talloc_array(ar,
2861 struct drsuapi_DsReplicaCursor2,
2862 nuv.ctr.ctr2.count);
2863 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2865 /* first copy the old vector */
2866 for (i=0; i < ouv.ctr.ctr2.count; i++) {
2867 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
2871 /* get our invocation_id if we have one already attached to the ldb */
2872 our_invocation_id = samdb_ntds_invocation_id(ldb);
2874 /* merge in the source_dsa vector is available */
2875 for (i=0; (ruv && i < ruv->count); i++) {
2878 if (our_invocation_id &&
2879 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
2880 our_invocation_id)) {
2884 for (j=0; j < ni; j++) {
2885 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
2886 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
2893 * we update only the highest_usn and not the latest_sync_success time,
2894 * because the last success stands for direct replication
2896 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
2897 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
2902 if (found) continue;
2904 /* if it's not there yet, add it */
2905 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
2910 * merge in the current highwatermark for the source_dsa
2913 for (j=0; j < ni; j++) {
2914 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
2915 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
2922 * here we update the highest_usn and last_sync_success time
2923 * because we're directly replicating from the source_dsa
2925 * and use the tmp_highest_usn because this is what we have just applied
2928 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
2929 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
2934 * here we update the highest_usn and last_sync_success time
2935 * because we're directly replicating from the source_dsa
2937 * and use the tmp_highest_usn because this is what we have just applied
2940 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
2941 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
2942 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
2947 * finally correct the size of the cursors array
2949 nuv.ctr.ctr2.count = ni;
2954 qsort(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count,
2955 sizeof(struct drsuapi_DsReplicaCursor2),
2956 (comparison_fn_t)drsuapi_DsReplicaCursor2_compare);
2959 * create the change ldb_message
2961 msg = ldb_msg_new(ar);
2962 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2963 msg->dn = ar->search_msg->dn;
2965 ndr_err = ndr_push_struct_blob(&nuv_value, msg,
2966 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2968 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
2969 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2970 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2971 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2973 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
2974 if (ret != LDB_SUCCESS) {
2975 return replmd_replicated_request_error(ar, ret);
2977 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
2980 * now create the new repsFrom value from the given repsFromTo1 structure
2984 nrf.ctr.ctr1 = *ar->objs->source_dsa;
2985 /* and fix some values... */
2986 nrf.ctr.ctr1.consecutive_sync_failures = 0;
2987 nrf.ctr.ctr1.last_success = now;
2988 nrf.ctr.ctr1.last_attempt = now;
2989 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
2990 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
2993 * first see if we already have a repsFrom value for the current source dsa
2994 * if so we'll later replace this value
2996 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
2998 for (i=0; i < orf_el->num_values; i++) {
2999 struct repsFromToBlob *trf;
3001 trf = talloc(ar, struct repsFromToBlob);
3002 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3004 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
3005 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3006 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3007 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3008 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3011 if (trf->version != 1) {
3012 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3016 * we compare the source dsa objectGUID not the invocation_id
3017 * because we want only one repsFrom value per source dsa
3018 * and when the invocation_id of the source dsa has changed we don't need
3019 * the old repsFrom with the old invocation_id
3021 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
3022 &ar->objs->source_dsa->source_dsa_obj_guid)) {
3028 nrf_value = &orf_el->values[i];
3033 * copy over all old values to the new ldb_message
3035 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
3036 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3041 * if we haven't found an old repsFrom value for the current source dsa
3042 * we'll add a new value
3045 struct ldb_val zero_value;
3046 ZERO_STRUCT(zero_value);
3047 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
3048 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3050 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
3053 /* we now fill the value which is already attached to ldb_message */
3054 ndr_err = ndr_push_struct_blob(nrf_value, msg,
3055 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3057 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3058 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3059 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3060 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3064 * the ldb_message_element for the attribute, has all the old values and the new one
3065 * so we'll replace the whole attribute with all values
3067 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
3070 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3071 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
3075 /* prepare the ldb_modify() request */
3076 ret = ldb_build_mod_req(&change_req,
3082 replmd_replicated_uptodate_modify_callback,
3084 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3086 return ldb_next_request(ar->module, change_req);
3089 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
3090 struct ldb_reply *ares)
3092 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3093 struct replmd_replicated_request);
3097 return ldb_module_done(ar->req, NULL, NULL,
3098 LDB_ERR_OPERATIONS_ERROR);
3100 if (ares->error != LDB_SUCCESS &&
3101 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3102 return ldb_module_done(ar->req, ares->controls,
3103 ares->response, ares->error);
3106 switch (ares->type) {
3107 case LDB_REPLY_ENTRY:
3108 ar->search_msg = talloc_steal(ar, ares->message);
3111 case LDB_REPLY_REFERRAL:
3112 /* we ignore referrals */
3115 case LDB_REPLY_DONE:
3116 if (ar->search_msg == NULL) {
3117 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3119 ret = replmd_replicated_uptodate_modify(ar);
3121 if (ret != LDB_SUCCESS) {
3122 return ldb_module_done(ar->req, NULL, NULL, ret);
3131 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
3133 struct ldb_context *ldb;
3135 static const char *attrs[] = {
3136 "replUpToDateVector",
3140 struct ldb_request *search_req;
3142 ldb = ldb_module_get_ctx(ar->module);
3143 ar->search_msg = NULL;
3145 ret = ldb_build_search_req(&search_req,
3148 ar->objs->partition_dn,
3154 replmd_replicated_uptodate_search_callback,
3156 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3158 return ldb_next_request(ar->module, search_req);
3163 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
3165 struct ldb_context *ldb;
3166 struct dsdb_extended_replicated_objects *objs;
3167 struct replmd_replicated_request *ar;
3168 struct ldb_control **ctrls;
3170 struct replmd_private *replmd_private =
3171 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3173 ldb = ldb_module_get_ctx(module);
3175 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
3177 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
3179 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
3180 return LDB_ERR_PROTOCOL_ERROR;
3183 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
3184 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
3185 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
3186 return LDB_ERR_PROTOCOL_ERROR;
3189 ar = replmd_ctx_init(module, req);
3191 return LDB_ERR_OPERATIONS_ERROR;
3193 /* Set the flags to have the replmd_op_callback run over the full set of objects */
3194 ar->apply_mode = true;
3196 ar->schema = dsdb_get_schema(ldb);
3198 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
3200 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3201 return LDB_ERR_CONSTRAINT_VIOLATION;
3204 ctrls = req->controls;
3206 if (req->controls) {
3207 req->controls = talloc_memdup(ar, req->controls,
3208 talloc_get_size(req->controls));
3209 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3212 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
3213 if (ret != LDB_SUCCESS) {
3217 ar->controls = req->controls;
3218 req->controls = ctrls;
3220 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
3222 /* save away the linked attributes for the end of the
3224 for (i=0; i<ar->objs->linked_attributes_count; i++) {
3225 struct la_entry *la_entry;
3227 if (replmd_private->la_ctx == NULL) {
3228 replmd_private->la_ctx = talloc_new(replmd_private);
3230 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
3231 if (la_entry == NULL) {
3233 return LDB_ERR_OPERATIONS_ERROR;
3235 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
3236 if (la_entry->la == NULL) {
3237 talloc_free(la_entry);
3239 return LDB_ERR_OPERATIONS_ERROR;
3241 *la_entry->la = ar->objs->linked_attributes[i];
3243 /* we need to steal the non-scalars so they stay
3244 around until the end of the transaction */
3245 talloc_steal(la_entry->la, la_entry->la->identifier);
3246 talloc_steal(la_entry->la, la_entry->la->value.blob);
3248 DLIST_ADD(replmd_private->la_list, la_entry);
3251 return replmd_replicated_apply_next(ar);
3255 process one linked attribute structure
3257 static int replmd_process_linked_attribute(struct ldb_module *module,
3258 struct la_entry *la_entry)
3260 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
3261 struct ldb_context *ldb = ldb_module_get_ctx(module);
3262 struct dsdb_schema *schema = dsdb_get_schema(ldb);
3263 struct ldb_message *msg;
3264 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
3266 const struct dsdb_attribute *attr;
3267 struct dsdb_dn *dsdb_dn;
3268 uint64_t seq_num = 0;
3269 struct drsuapi_DsReplicaAttribute drs;
3270 struct drsuapi_DsAttributeValue val;
3271 struct ldb_message_element new_el, *old_el;
3273 time_t t = time(NULL);
3274 struct ldb_result *res;
3275 const char *attrs[2];
3276 struct parsed_dn *pdn_list, *pdn;
3279 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
3281 drs.value_ctr.num_values = 1;
3282 drs.value_ctr.values = &val;
3283 val.blob = la->value.blob;
3286 linked_attributes[0]:
3287 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
3289 identifier: struct drsuapi_DsReplicaObjectIdentifier
3290 __ndr_size : 0x0000003a (58)
3291 __ndr_size_sid : 0x00000000 (0)
3292 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
3294 __ndr_size_dn : 0x00000000 (0)
3296 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
3297 value: struct drsuapi_DsAttributeValue
3298 __ndr_size : 0x0000007e (126)
3300 blob : DATA_BLOB length=126
3301 flags : 0x00000001 (1)
3302 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
3303 originating_add_time : Wed Sep 2 22:20:01 2009 EST
3304 meta_data: struct drsuapi_DsReplicaMetaData
3305 version : 0x00000015 (21)
3306 originating_change_time : Wed Sep 2 23:39:07 2009 EST
3307 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
3308 originating_usn : 0x000000000001e19c (123292)
3310 (for cases where the link is to a normal DN)
3311 &target: struct drsuapi_DsReplicaObjectIdentifier3
3312 __ndr_size : 0x0000007e (126)
3313 __ndr_size_sid : 0x0000001c (28)
3314 guid : 7639e594-db75-4086-b0d4-67890ae46031
3315 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
3316 __ndr_size_dn : 0x00000022 (34)
3317 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
3320 /* find the attribute being modified */
3321 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
3323 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
3324 talloc_free(tmp_ctx);
3325 return LDB_ERR_OPERATIONS_ERROR;
3328 attrs[0] = attr->lDAPDisplayName;
3331 /* get the existing message from the db for the object with
3332 this GUID, returning attribute being modified. We will then
3333 use this msg as the basis for a modify call */
3334 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3335 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3336 DSDB_SEARCH_SHOW_DELETED |
3337 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3338 DSDB_SEARCH_REVEAL_INTERNALS,
3339 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
3340 if (ret != LDB_SUCCESS) {
3341 talloc_free(tmp_ctx);
3344 if (res->count != 1) {
3345 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
3346 GUID_string(tmp_ctx, &la->identifier->guid));
3347 talloc_free(tmp_ctx);
3348 return LDB_ERR_NO_SUCH_OBJECT;
3352 if (msg->num_elements == 0) {
3353 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
3354 if (ret != LDB_SUCCESS) {
3355 ldb_module_oom(module);
3356 talloc_free(tmp_ctx);
3357 return LDB_ERR_OPERATIONS_ERROR;
3360 old_el = &msg->elements[0];
3361 old_el->flags = LDB_FLAG_MOD_REPLACE;
3364 /* parse the existing links */
3365 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid);
3366 if (ret != LDB_SUCCESS) {
3367 talloc_free(tmp_ctx);
3371 status = attr->syntax->drsuapi_to_ldb(ldb, schema, attr, &drs, tmp_ctx, &new_el);
3372 if (!W_ERROR_IS_OK(status)) {
3373 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s\n",
3374 old_el->name, ldb_dn_get_linearized(msg->dn));
3375 return LDB_ERR_OPERATIONS_ERROR;
3378 if (new_el.num_values != 1) {
3379 ldb_asprintf_errstring(ldb, "Failed to find value in linked attribute blob for %s on %s\n",
3380 old_el->name, ldb_dn_get_linearized(msg->dn));
3381 return LDB_ERR_OPERATIONS_ERROR;
3384 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &new_el.values[0], attr->syntax->ldap_oid);
3386 ldb_asprintf_errstring(ldb, "Failed to parse DN in linked attribute blob for %s on %s\n",
3387 old_el->name, ldb_dn_get_linearized(msg->dn));
3388 return LDB_ERR_OPERATIONS_ERROR;
3391 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
3392 if (!NT_STATUS_IS_OK(ntstatus)) {
3393 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s\n",
3394 old_el->name, ldb_dn_get_linearized(msg->dn));
3395 return LDB_ERR_OPERATIONS_ERROR;
3398 /* see if this link already exists */
3399 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid);
3401 /* see if this update is newer than what we have already */
3402 struct GUID invocation_id = GUID_zero();
3403 uint32_t version = 0;
3404 NTTIME change_time = 0;
3405 bool was_active = ldb_dn_get_extended_component(pdn->dsdb_dn->dn, "DELETED") == NULL;
3407 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
3408 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
3409 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
3411 if (!replmd_update_is_newer(&invocation_id,
3412 &la->meta_data.originating_invocation_id,
3414 la->meta_data.version,
3416 la->meta_data.originating_change_time)) {
3417 DEBUG(1,("Discarding older DRS linked attribute update to %s on %s from %s\n",
3418 old_el->name, ldb_dn_get_linearized(msg->dn),
3419 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
3420 talloc_free(tmp_ctx);
3424 /* get a seq_num for this change */
3425 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3426 if (ret != LDB_SUCCESS) {
3427 talloc_free(tmp_ctx);
3432 /* remove the existing backlink */
3433 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
3434 if (ret != LDB_SUCCESS) {
3435 talloc_free(tmp_ctx);
3440 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
3441 &la->meta_data.originating_invocation_id,
3442 la->meta_data.originating_usn, seq_num,
3443 la->meta_data.originating_change_time,
3445 if (ret != LDB_SUCCESS) {
3446 talloc_free(tmp_ctx);
3451 /* add the new backlink */
3452 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
3453 if (ret != LDB_SUCCESS) {
3454 talloc_free(tmp_ctx);
3459 /* get a seq_num for this change */
3460 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3461 if (ret != LDB_SUCCESS) {
3462 talloc_free(tmp_ctx);
3466 old_el->values = talloc_realloc(msg->elements, old_el->values,
3467 struct ldb_val, old_el->num_values+1);
3468 if (!old_el->values) {
3469 ldb_module_oom(module);
3470 return LDB_ERR_OPERATIONS_ERROR;
3472 old_el->num_values++;
3474 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
3475 &la->meta_data.originating_invocation_id,
3476 la->meta_data.originating_usn, seq_num,
3477 la->meta_data.originating_change_time,
3478 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
3479 if (ret != LDB_SUCCESS) {
3480 talloc_free(tmp_ctx);
3485 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
3487 if (ret != LDB_SUCCESS) {
3488 talloc_free(tmp_ctx);
3494 /* we only change whenChanged and uSNChanged if the seq_num
3496 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
3497 talloc_free(tmp_ctx);
3498 return LDB_ERR_OPERATIONS_ERROR;
3501 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
3502 talloc_free(tmp_ctx);
3503 return LDB_ERR_OPERATIONS_ERROR;
3506 ret = dsdb_module_modify(module, msg, 0);
3507 if (ret != LDB_SUCCESS) {
3508 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n",
3510 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
3511 talloc_free(tmp_ctx);
3515 talloc_free(tmp_ctx);
3520 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
3522 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
3523 return replmd_extended_replicated_objects(module, req);
3526 return ldb_next_request(module, req);
3531 we hook into the transaction operations to allow us to
3532 perform the linked attribute updates at the end of the whole
3533 transaction. This allows a forward linked attribute to be created
3534 before the object is created. During a vampire, w2k8 sends us linked
3535 attributes before the objects they are part of.
3537 static int replmd_start_transaction(struct ldb_module *module)
3539 /* create our private structure for this transaction */
3540 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
3541 struct replmd_private);
3542 replmd_txn_cleanup(replmd_private);
3544 /* free any leftover mod_usn records from cancelled
3546 while (replmd_private->ncs) {
3547 struct nc_entry *e = replmd_private->ncs;
3548 DLIST_REMOVE(replmd_private->ncs, e);
3552 return ldb_next_start_trans(module);
3556 on prepare commit we loop over our queued la_context structures and
3559 static int replmd_prepare_commit(struct ldb_module *module)
3561 struct replmd_private *replmd_private =
3562 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3563 struct la_entry *la, *prev;
3564 struct la_backlink *bl;
3567 /* walk the list backwards, to do the first entry first, as we
3568 * added the entries with DLIST_ADD() which puts them at the
3569 * start of the list */
3570 for (la = replmd_private->la_list; la && la->next; la=la->next) ;
3572 for (; la; la=prev) {
3574 DLIST_REMOVE(replmd_private->la_list, la);
3575 ret = replmd_process_linked_attribute(module, la);
3576 if (ret != LDB_SUCCESS) {
3577 replmd_txn_cleanup(replmd_private);
3582 /* process our backlink list, creating and deleting backlinks
3584 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
3585 ret = replmd_process_backlink(module, bl);
3586 if (ret != LDB_SUCCESS) {
3587 replmd_txn_cleanup(replmd_private);
3592 replmd_txn_cleanup(replmd_private);
3594 /* possibly change @REPLCHANGED */
3595 ret = replmd_notify_store(module);
3596 if (ret != LDB_SUCCESS) {
3600 return ldb_next_prepare_commit(module);
3603 static int replmd_del_transaction(struct ldb_module *module)
3605 struct replmd_private *replmd_private =
3606 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3607 replmd_txn_cleanup(replmd_private);
3609 return ldb_next_del_trans(module);
3613 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
3614 .name = "repl_meta_data",
3615 .init_context = replmd_init,
3617 .modify = replmd_modify,
3618 .rename = replmd_rename,
3619 .del = replmd_delete,
3620 .extended = replmd_extended,
3621 .start_transaction = replmd_start_transaction,
3622 .prepare_commit = replmd_prepare_commit,
3623 .del_transaction = replmd_del_transaction,