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 if (msg->elements[i].num_values == 0) {
2382 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
2383 msg->elements[i].name));
2384 memmove(&msg->elements[i],
2385 &msg->elements[i+1],
2386 sizeof(msg->elements[i])*(msg->num_elements - (i+1)));
2387 msg->num_elements--;
2393 * the meta data array is already sorted by the caller
2395 for (i=0; i < md->ctr.ctr1.count; i++) {
2396 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
2398 ndr_err = ndr_push_struct_blob(&md_value, msg,
2399 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2401 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2402 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2403 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2404 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2406 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
2407 if (ret != LDB_SUCCESS) {
2408 return replmd_replicated_request_error(ar, ret);
2411 replmd_ldb_message_sort(msg, ar->schema);
2414 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
2415 DEBUG(4, ("DRS replication add message:\n%s\n", s));
2419 ret = ldb_build_add_req(&change_req,
2427 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2429 return ldb_next_request(ar->module, change_req);
2433 return true if an update is newer than an existing entry
2434 see section 5.11 of MS-ADTS
2436 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
2437 const struct GUID *update_invocation_id,
2438 uint32_t current_version,
2439 uint32_t update_version,
2440 NTTIME current_change_time,
2441 NTTIME update_change_time)
2443 if (update_version != current_version) {
2444 return update_version > current_version;
2446 if (update_change_time > current_change_time) {
2449 if (update_change_time == current_change_time) {
2450 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
2455 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
2456 struct replPropertyMetaData1 *new_m)
2458 return replmd_update_is_newer(&cur_m->originating_invocation_id,
2459 &new_m->originating_invocation_id,
2462 cur_m->originating_change_time,
2463 new_m->originating_change_time);
2466 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
2468 struct ldb_context *ldb;
2469 struct ldb_request *change_req;
2470 enum ndr_err_code ndr_err;
2471 struct ldb_message *msg;
2472 struct replPropertyMetaDataBlob *rmd;
2473 struct replPropertyMetaDataBlob omd;
2474 const struct ldb_val *omd_value;
2475 struct replPropertyMetaDataBlob nmd;
2476 struct ldb_val nmd_value;
2478 uint32_t removed_attrs = 0;
2481 ldb = ldb_module_get_ctx(ar->module);
2482 msg = ar->objs->objects[ar->index_current].msg;
2483 rmd = ar->objs->objects[ar->index_current].meta_data;
2488 * TODO: check repl data is correct after a rename
2490 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
2491 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
2492 ldb_dn_get_linearized(ar->search_msg->dn),
2493 ldb_dn_get_linearized(msg->dn));
2494 /* we can't use dsdb_module_rename() here as we need
2495 the rename call to be intercepted by this module, to
2496 allow it to process linked attribute changes */
2497 if (ldb_rename(ldb, ar->search_msg->dn, msg->dn) != LDB_SUCCESS) {
2498 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
2499 ldb_dn_get_linearized(ar->search_msg->dn),
2500 ldb_dn_get_linearized(msg->dn),
2501 ldb_errstring(ldb));
2502 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
2506 /* find existing meta data */
2507 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
2509 ndr_err = ndr_pull_struct_blob(omd_value, ar,
2510 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
2511 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
2512 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2513 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2514 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2517 if (omd.version != 1) {
2518 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2524 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
2525 nmd.ctr.ctr1.array = talloc_array(ar,
2526 struct replPropertyMetaData1,
2527 nmd.ctr.ctr1.count);
2528 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2530 /* first copy the old meta data */
2531 for (i=0; i < omd.ctr.ctr1.count; i++) {
2532 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
2536 /* now merge in the new meta data */
2537 for (i=0; i < rmd->ctr.ctr1.count; i++) {
2540 for (j=0; j < ni; j++) {
2543 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
2547 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
2548 &rmd->ctr.ctr1.array[i]);
2550 /* replace the entry */
2551 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
2556 DEBUG(1,("Discarding older DRS attribute update to %s on %s from %s\n",
2557 msg->elements[i-removed_attrs].name,
2558 ldb_dn_get_linearized(msg->dn),
2559 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
2561 /* we don't want to apply this change so remove the attribute */
2562 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
2569 if (found) continue;
2571 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
2576 * finally correct the size of the meta_data array
2578 nmd.ctr.ctr1.count = ni;
2581 * the rdn attribute (the alias for the name attribute),
2582 * 'cn' for most objects is the last entry in the meta data array
2585 * sort the new meta data array
2587 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
2588 if (ret != LDB_SUCCESS) {
2593 * check if some replicated attributes left, otherwise skip the ldb_modify() call
2595 if (msg->num_elements == 0) {
2596 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
2599 ar->index_current++;
2600 return replmd_replicated_apply_next(ar);
2603 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
2604 ar->index_current, msg->num_elements);
2606 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2607 if (ret != LDB_SUCCESS) {
2608 return replmd_replicated_request_error(ar, ret);
2611 for (i=0; i<ni; i++) {
2612 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
2615 /* create the meta data value */
2616 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
2617 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2619 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2620 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2621 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2622 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2626 * when we know that we'll modify the record, add the whenChanged, uSNChanged
2627 * and replPopertyMetaData attributes
2629 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2630 if (ret != LDB_SUCCESS) {
2631 return replmd_replicated_request_error(ar, ret);
2633 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2634 if (ret != LDB_SUCCESS) {
2635 return replmd_replicated_request_error(ar, ret);
2637 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
2638 if (ret != LDB_SUCCESS) {
2639 return replmd_replicated_request_error(ar, ret);
2642 replmd_ldb_message_sort(msg, ar->schema);
2644 /* we want to replace the old values */
2645 for (i=0; i < msg->num_elements; i++) {
2646 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2650 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
2651 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
2655 ret = ldb_build_mod_req(&change_req,
2663 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2665 return ldb_next_request(ar->module, change_req);
2668 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
2669 struct ldb_reply *ares)
2671 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2672 struct replmd_replicated_request);
2676 return ldb_module_done(ar->req, NULL, NULL,
2677 LDB_ERR_OPERATIONS_ERROR);
2679 if (ares->error != LDB_SUCCESS &&
2680 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
2681 return ldb_module_done(ar->req, ares->controls,
2682 ares->response, ares->error);
2685 switch (ares->type) {
2686 case LDB_REPLY_ENTRY:
2687 ar->search_msg = talloc_steal(ar, ares->message);
2690 case LDB_REPLY_REFERRAL:
2691 /* we ignore referrals */
2694 case LDB_REPLY_DONE:
2695 if (ar->search_msg != NULL) {
2696 ret = replmd_replicated_apply_merge(ar);
2698 ret = replmd_replicated_apply_add(ar);
2700 if (ret != LDB_SUCCESS) {
2701 return ldb_module_done(ar->req, NULL, NULL, ret);
2709 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
2711 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
2713 struct ldb_context *ldb;
2717 struct ldb_request *search_req;
2718 struct ldb_search_options_control *options;
2720 if (ar->index_current >= ar->objs->num_objects) {
2721 /* done with it, go to next stage */
2722 return replmd_replicated_uptodate_vector(ar);
2725 ldb = ldb_module_get_ctx(ar->module);
2726 ar->search_msg = NULL;
2728 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
2729 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2731 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
2732 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2733 talloc_free(tmp_str);
2735 ret = ldb_build_search_req(&search_req,
2744 replmd_replicated_apply_search_callback,
2747 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2748 if (ret != LDB_SUCCESS) {
2752 /* we need to cope with cross-partition links, so search for
2753 the GUID over all partitions */
2754 options = talloc(search_req, struct ldb_search_options_control);
2755 if (options == NULL) {
2756 DEBUG(0, (__location__ ": out of memory\n"));
2757 return LDB_ERR_OPERATIONS_ERROR;
2759 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2761 ret = ldb_request_add_control(search_req,
2762 LDB_CONTROL_SEARCH_OPTIONS_OID,
2764 if (ret != LDB_SUCCESS) {
2768 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2770 return ldb_next_request(ar->module, search_req);
2773 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
2774 struct ldb_reply *ares)
2776 struct ldb_context *ldb;
2777 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2778 struct replmd_replicated_request);
2779 ldb = ldb_module_get_ctx(ar->module);
2782 return ldb_module_done(ar->req, NULL, NULL,
2783 LDB_ERR_OPERATIONS_ERROR);
2785 if (ares->error != LDB_SUCCESS) {
2786 return ldb_module_done(ar->req, ares->controls,
2787 ares->response, ares->error);
2790 if (ares->type != LDB_REPLY_DONE) {
2791 ldb_set_errstring(ldb, "Invalid reply type\n!");
2792 return ldb_module_done(ar->req, NULL, NULL,
2793 LDB_ERR_OPERATIONS_ERROR);
2798 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
2801 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
2803 struct ldb_context *ldb;
2804 struct ldb_request *change_req;
2805 enum ndr_err_code ndr_err;
2806 struct ldb_message *msg;
2807 struct replUpToDateVectorBlob ouv;
2808 const struct ldb_val *ouv_value;
2809 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
2810 struct replUpToDateVectorBlob nuv;
2811 struct ldb_val nuv_value;
2812 struct ldb_message_element *nuv_el = NULL;
2813 const struct GUID *our_invocation_id;
2814 struct ldb_message_element *orf_el = NULL;
2815 struct repsFromToBlob nrf;
2816 struct ldb_val *nrf_value = NULL;
2817 struct ldb_message_element *nrf_el = NULL;
2820 time_t t = time(NULL);
2824 ldb = ldb_module_get_ctx(ar->module);
2825 ruv = ar->objs->uptodateness_vector;
2831 unix_to_nt_time(&now, t);
2834 * first create the new replUpToDateVector
2836 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
2838 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
2839 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
2840 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
2841 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2842 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2843 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2846 if (ouv.version != 2) {
2847 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2852 * the new uptodateness vector will at least
2853 * contain 1 entry, one for the source_dsa
2855 * plus optional values from our old vector and the one from the source_dsa
2857 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
2858 if (ruv) nuv.ctr.ctr2.count += ruv->count;
2859 nuv.ctr.ctr2.cursors = talloc_array(ar,
2860 struct drsuapi_DsReplicaCursor2,
2861 nuv.ctr.ctr2.count);
2862 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2864 /* first copy the old vector */
2865 for (i=0; i < ouv.ctr.ctr2.count; i++) {
2866 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
2870 /* get our invocation_id if we have one already attached to the ldb */
2871 our_invocation_id = samdb_ntds_invocation_id(ldb);
2873 /* merge in the source_dsa vector is available */
2874 for (i=0; (ruv && i < ruv->count); i++) {
2877 if (our_invocation_id &&
2878 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
2879 our_invocation_id)) {
2883 for (j=0; j < ni; j++) {
2884 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
2885 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
2892 * we update only the highest_usn and not the latest_sync_success time,
2893 * because the last success stands for direct replication
2895 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
2896 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
2901 if (found) continue;
2903 /* if it's not there yet, add it */
2904 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
2909 * merge in the current highwatermark for the source_dsa
2912 for (j=0; j < ni; j++) {
2913 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
2914 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
2921 * here we update the highest_usn and last_sync_success time
2922 * because we're directly replicating from the source_dsa
2924 * and use the tmp_highest_usn because this is what we have just applied
2927 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
2928 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
2933 * here we update the highest_usn and last_sync_success time
2934 * because we're directly replicating from the source_dsa
2936 * and use the tmp_highest_usn because this is what we have just applied
2939 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
2940 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
2941 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
2946 * finally correct the size of the cursors array
2948 nuv.ctr.ctr2.count = ni;
2953 qsort(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count,
2954 sizeof(struct drsuapi_DsReplicaCursor2),
2955 (comparison_fn_t)drsuapi_DsReplicaCursor2_compare);
2958 * create the change ldb_message
2960 msg = ldb_msg_new(ar);
2961 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2962 msg->dn = ar->search_msg->dn;
2964 ndr_err = ndr_push_struct_blob(&nuv_value, msg,
2965 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2967 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
2968 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2969 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2970 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2972 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
2973 if (ret != LDB_SUCCESS) {
2974 return replmd_replicated_request_error(ar, ret);
2976 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
2979 * now create the new repsFrom value from the given repsFromTo1 structure
2983 nrf.ctr.ctr1 = *ar->objs->source_dsa;
2984 /* and fix some values... */
2985 nrf.ctr.ctr1.consecutive_sync_failures = 0;
2986 nrf.ctr.ctr1.last_success = now;
2987 nrf.ctr.ctr1.last_attempt = now;
2988 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
2989 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
2992 * first see if we already have a repsFrom value for the current source dsa
2993 * if so we'll later replace this value
2995 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
2997 for (i=0; i < orf_el->num_values; i++) {
2998 struct repsFromToBlob *trf;
3000 trf = talloc(ar, struct repsFromToBlob);
3001 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3003 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
3004 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3005 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3006 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3007 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3010 if (trf->version != 1) {
3011 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3015 * we compare the source dsa objectGUID not the invocation_id
3016 * because we want only one repsFrom value per source dsa
3017 * and when the invocation_id of the source dsa has changed we don't need
3018 * the old repsFrom with the old invocation_id
3020 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
3021 &ar->objs->source_dsa->source_dsa_obj_guid)) {
3027 nrf_value = &orf_el->values[i];
3032 * copy over all old values to the new ldb_message
3034 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
3035 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3040 * if we haven't found an old repsFrom value for the current source dsa
3041 * we'll add a new value
3044 struct ldb_val zero_value;
3045 ZERO_STRUCT(zero_value);
3046 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
3047 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3049 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
3052 /* we now fill the value which is already attached to ldb_message */
3053 ndr_err = ndr_push_struct_blob(nrf_value, msg,
3054 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3056 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3057 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3058 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3059 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3063 * the ldb_message_element for the attribute, has all the old values and the new one
3064 * so we'll replace the whole attribute with all values
3066 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
3069 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3070 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
3074 /* prepare the ldb_modify() request */
3075 ret = ldb_build_mod_req(&change_req,
3081 replmd_replicated_uptodate_modify_callback,
3083 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3085 return ldb_next_request(ar->module, change_req);
3088 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
3089 struct ldb_reply *ares)
3091 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3092 struct replmd_replicated_request);
3096 return ldb_module_done(ar->req, NULL, NULL,
3097 LDB_ERR_OPERATIONS_ERROR);
3099 if (ares->error != LDB_SUCCESS &&
3100 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3101 return ldb_module_done(ar->req, ares->controls,
3102 ares->response, ares->error);
3105 switch (ares->type) {
3106 case LDB_REPLY_ENTRY:
3107 ar->search_msg = talloc_steal(ar, ares->message);
3110 case LDB_REPLY_REFERRAL:
3111 /* we ignore referrals */
3114 case LDB_REPLY_DONE:
3115 if (ar->search_msg == NULL) {
3116 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3118 ret = replmd_replicated_uptodate_modify(ar);
3120 if (ret != LDB_SUCCESS) {
3121 return ldb_module_done(ar->req, NULL, NULL, ret);
3130 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
3132 struct ldb_context *ldb;
3134 static const char *attrs[] = {
3135 "replUpToDateVector",
3139 struct ldb_request *search_req;
3141 ldb = ldb_module_get_ctx(ar->module);
3142 ar->search_msg = NULL;
3144 ret = ldb_build_search_req(&search_req,
3147 ar->objs->partition_dn,
3153 replmd_replicated_uptodate_search_callback,
3155 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3157 return ldb_next_request(ar->module, search_req);
3162 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
3164 struct ldb_context *ldb;
3165 struct dsdb_extended_replicated_objects *objs;
3166 struct replmd_replicated_request *ar;
3167 struct ldb_control **ctrls;
3169 struct replmd_private *replmd_private =
3170 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3172 ldb = ldb_module_get_ctx(module);
3174 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
3176 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
3178 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
3179 return LDB_ERR_PROTOCOL_ERROR;
3182 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
3183 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
3184 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
3185 return LDB_ERR_PROTOCOL_ERROR;
3188 ar = replmd_ctx_init(module, req);
3190 return LDB_ERR_OPERATIONS_ERROR;
3192 /* Set the flags to have the replmd_op_callback run over the full set of objects */
3193 ar->apply_mode = true;
3195 ar->schema = dsdb_get_schema(ldb);
3197 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
3199 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3200 return LDB_ERR_CONSTRAINT_VIOLATION;
3203 ctrls = req->controls;
3205 if (req->controls) {
3206 req->controls = talloc_memdup(ar, req->controls,
3207 talloc_get_size(req->controls));
3208 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3211 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
3212 if (ret != LDB_SUCCESS) {
3216 ar->controls = req->controls;
3217 req->controls = ctrls;
3219 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
3221 /* save away the linked attributes for the end of the
3223 for (i=0; i<ar->objs->linked_attributes_count; i++) {
3224 struct la_entry *la_entry;
3226 if (replmd_private->la_ctx == NULL) {
3227 replmd_private->la_ctx = talloc_new(replmd_private);
3229 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
3230 if (la_entry == NULL) {
3232 return LDB_ERR_OPERATIONS_ERROR;
3234 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
3235 if (la_entry->la == NULL) {
3236 talloc_free(la_entry);
3238 return LDB_ERR_OPERATIONS_ERROR;
3240 *la_entry->la = ar->objs->linked_attributes[i];
3242 /* we need to steal the non-scalars so they stay
3243 around until the end of the transaction */
3244 talloc_steal(la_entry->la, la_entry->la->identifier);
3245 talloc_steal(la_entry->la, la_entry->la->value.blob);
3247 DLIST_ADD(replmd_private->la_list, la_entry);
3250 return replmd_replicated_apply_next(ar);
3254 process one linked attribute structure
3256 static int replmd_process_linked_attribute(struct ldb_module *module,
3257 struct la_entry *la_entry)
3259 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
3260 struct ldb_context *ldb = ldb_module_get_ctx(module);
3261 struct dsdb_schema *schema = dsdb_get_schema(ldb);
3262 struct ldb_message *msg;
3263 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
3265 const struct dsdb_attribute *attr;
3266 struct dsdb_dn *dsdb_dn;
3267 uint64_t seq_num = 0;
3268 struct drsuapi_DsReplicaAttribute drs;
3269 struct drsuapi_DsAttributeValue val;
3270 struct ldb_message_element new_el, *old_el;
3272 time_t t = time(NULL);
3273 struct ldb_result *res;
3274 const char *attrs[2];
3275 struct parsed_dn *pdn_list, *pdn;
3278 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
3280 drs.value_ctr.num_values = 1;
3281 drs.value_ctr.values = &val;
3282 val.blob = la->value.blob;
3285 linked_attributes[0]:
3286 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
3288 identifier: struct drsuapi_DsReplicaObjectIdentifier
3289 __ndr_size : 0x0000003a (58)
3290 __ndr_size_sid : 0x00000000 (0)
3291 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
3293 __ndr_size_dn : 0x00000000 (0)
3295 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
3296 value: struct drsuapi_DsAttributeValue
3297 __ndr_size : 0x0000007e (126)
3299 blob : DATA_BLOB length=126
3300 flags : 0x00000001 (1)
3301 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
3302 originating_add_time : Wed Sep 2 22:20:01 2009 EST
3303 meta_data: struct drsuapi_DsReplicaMetaData
3304 version : 0x00000015 (21)
3305 originating_change_time : Wed Sep 2 23:39:07 2009 EST
3306 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
3307 originating_usn : 0x000000000001e19c (123292)
3309 (for cases where the link is to a normal DN)
3310 &target: struct drsuapi_DsReplicaObjectIdentifier3
3311 __ndr_size : 0x0000007e (126)
3312 __ndr_size_sid : 0x0000001c (28)
3313 guid : 7639e594-db75-4086-b0d4-67890ae46031
3314 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
3315 __ndr_size_dn : 0x00000022 (34)
3316 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
3319 /* find the attribute being modified */
3320 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
3322 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
3323 talloc_free(tmp_ctx);
3324 return LDB_ERR_OPERATIONS_ERROR;
3327 attrs[0] = attr->lDAPDisplayName;
3330 /* get the existing message from the db for the object with
3331 this GUID, returning attribute being modified. We will then
3332 use this msg as the basis for a modify call */
3333 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3334 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3335 DSDB_SEARCH_SHOW_DELETED |
3336 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3337 DSDB_SEARCH_REVEAL_INTERNALS,
3338 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
3339 if (ret != LDB_SUCCESS) {
3340 talloc_free(tmp_ctx);
3343 if (res->count != 1) {
3344 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
3345 GUID_string(tmp_ctx, &la->identifier->guid));
3346 talloc_free(tmp_ctx);
3347 return LDB_ERR_NO_SUCH_OBJECT;
3351 if (msg->num_elements == 0) {
3352 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
3353 if (ret != LDB_SUCCESS) {
3354 ldb_module_oom(module);
3355 talloc_free(tmp_ctx);
3356 return LDB_ERR_OPERATIONS_ERROR;
3359 old_el = &msg->elements[0];
3360 old_el->flags = LDB_FLAG_MOD_REPLACE;
3363 /* parse the existing links */
3364 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid);
3365 if (ret != LDB_SUCCESS) {
3366 talloc_free(tmp_ctx);
3370 status = attr->syntax->drsuapi_to_ldb(ldb, schema, attr, &drs, tmp_ctx, &new_el);
3371 if (!W_ERROR_IS_OK(status)) {
3372 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s\n",
3373 old_el->name, ldb_dn_get_linearized(msg->dn));
3374 return LDB_ERR_OPERATIONS_ERROR;
3377 if (new_el.num_values != 1) {
3378 ldb_asprintf_errstring(ldb, "Failed to find value in linked attribute blob for %s on %s\n",
3379 old_el->name, ldb_dn_get_linearized(msg->dn));
3380 return LDB_ERR_OPERATIONS_ERROR;
3383 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &new_el.values[0], attr->syntax->ldap_oid);
3385 ldb_asprintf_errstring(ldb, "Failed to parse DN in linked attribute blob for %s on %s\n",
3386 old_el->name, ldb_dn_get_linearized(msg->dn));
3387 return LDB_ERR_OPERATIONS_ERROR;
3390 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
3391 if (!NT_STATUS_IS_OK(ntstatus)) {
3392 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s\n",
3393 old_el->name, ldb_dn_get_linearized(msg->dn));
3394 return LDB_ERR_OPERATIONS_ERROR;
3397 /* see if this link already exists */
3398 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid);
3400 /* see if this update is newer than what we have already */
3401 struct GUID invocation_id = GUID_zero();
3402 uint32_t version = 0;
3403 NTTIME change_time = 0;
3404 bool was_active = ldb_dn_get_extended_component(pdn->dsdb_dn->dn, "DELETED") == NULL;
3406 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
3407 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
3408 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
3410 if (!replmd_update_is_newer(&invocation_id,
3411 &la->meta_data.originating_invocation_id,
3413 la->meta_data.version,
3415 la->meta_data.originating_change_time)) {
3416 DEBUG(1,("Discarding older DRS linked attribute update to %s on %s from %s\n",
3417 old_el->name, ldb_dn_get_linearized(msg->dn),
3418 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
3419 talloc_free(tmp_ctx);
3423 /* get a seq_num for this change */
3424 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3425 if (ret != LDB_SUCCESS) {
3426 talloc_free(tmp_ctx);
3431 /* remove the existing backlink */
3432 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
3433 if (ret != LDB_SUCCESS) {
3434 talloc_free(tmp_ctx);
3439 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
3440 &la->meta_data.originating_invocation_id,
3441 la->meta_data.originating_usn, seq_num,
3442 la->meta_data.originating_change_time,
3444 if (ret != LDB_SUCCESS) {
3445 talloc_free(tmp_ctx);
3450 /* add the new backlink */
3451 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
3452 if (ret != LDB_SUCCESS) {
3453 talloc_free(tmp_ctx);
3458 /* get a seq_num for this change */
3459 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3460 if (ret != LDB_SUCCESS) {
3461 talloc_free(tmp_ctx);
3465 old_el->values = talloc_realloc(msg->elements, old_el->values,
3466 struct ldb_val, old_el->num_values+1);
3467 if (!old_el->values) {
3468 ldb_module_oom(module);
3469 return LDB_ERR_OPERATIONS_ERROR;
3471 old_el->num_values++;
3473 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
3474 &la->meta_data.originating_invocation_id,
3475 la->meta_data.originating_usn, seq_num,
3476 la->meta_data.originating_change_time,
3477 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
3478 if (ret != LDB_SUCCESS) {
3479 talloc_free(tmp_ctx);
3484 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
3486 if (ret != LDB_SUCCESS) {
3487 talloc_free(tmp_ctx);
3493 /* we only change whenChanged and uSNChanged if the seq_num
3495 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
3496 talloc_free(tmp_ctx);
3497 return LDB_ERR_OPERATIONS_ERROR;
3500 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
3501 talloc_free(tmp_ctx);
3502 return LDB_ERR_OPERATIONS_ERROR;
3505 ret = dsdb_module_modify(module, msg, 0);
3506 if (ret != LDB_SUCCESS) {
3507 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n",
3509 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
3510 talloc_free(tmp_ctx);
3514 talloc_free(tmp_ctx);
3519 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
3521 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
3522 return replmd_extended_replicated_objects(module, req);
3525 return ldb_next_request(module, req);
3530 we hook into the transaction operations to allow us to
3531 perform the linked attribute updates at the end of the whole
3532 transaction. This allows a forward linked attribute to be created
3533 before the object is created. During a vampire, w2k8 sends us linked
3534 attributes before the objects they are part of.
3536 static int replmd_start_transaction(struct ldb_module *module)
3538 /* create our private structure for this transaction */
3539 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
3540 struct replmd_private);
3541 replmd_txn_cleanup(replmd_private);
3543 /* free any leftover mod_usn records from cancelled
3545 while (replmd_private->ncs) {
3546 struct nc_entry *e = replmd_private->ncs;
3547 DLIST_REMOVE(replmd_private->ncs, e);
3551 return ldb_next_start_trans(module);
3555 on prepare commit we loop over our queued la_context structures and
3558 static int replmd_prepare_commit(struct ldb_module *module)
3560 struct replmd_private *replmd_private =
3561 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3562 struct la_entry *la, *prev;
3563 struct la_backlink *bl;
3566 /* walk the list backwards, to do the first entry first, as we
3567 * added the entries with DLIST_ADD() which puts them at the
3568 * start of the list */
3569 for (la = replmd_private->la_list; la && la->next; la=la->next) ;
3571 for (; la; la=prev) {
3573 DLIST_REMOVE(replmd_private->la_list, la);
3574 ret = replmd_process_linked_attribute(module, la);
3575 if (ret != LDB_SUCCESS) {
3576 replmd_txn_cleanup(replmd_private);
3581 /* process our backlink list, creating and deleting backlinks
3583 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
3584 ret = replmd_process_backlink(module, bl);
3585 if (ret != LDB_SUCCESS) {
3586 replmd_txn_cleanup(replmd_private);
3591 replmd_txn_cleanup(replmd_private);
3593 /* possibly change @REPLCHANGED */
3594 ret = replmd_notify_store(module);
3595 if (ret != LDB_SUCCESS) {
3599 return ldb_next_prepare_commit(module);
3602 static int replmd_del_transaction(struct ldb_module *module)
3604 struct replmd_private *replmd_private =
3605 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3606 replmd_txn_cleanup(replmd_private);
3608 return ldb_next_del_trans(module);
3612 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
3613 .name = "repl_meta_data",
3614 .init_context = replmd_init,
3616 .modify = replmd_modify,
3617 .rename = replmd_rename,
3618 .del = replmd_delete,
3619 .extended = replmd_extended,
3620 .start_transaction = replmd_start_transaction,
3621 .prepare_commit = replmd_prepare_commit,
3622 .del_transaction = replmd_del_transaction,