4 Copyright (C) Simo Sorce 2004-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 * Component: ldb repl_meta_data module
28 * Description: - add a unique objectGUID onto every new record,
29 * - handle whenCreated, whenChanged timestamps
30 * - handle uSNCreated, uSNChanged numbers
31 * - handle replPropertyMetaData attribute
34 * Author: Stefan Metzmacher
38 #include "ldb_module.h"
39 #include "dsdb/samdb/samdb.h"
40 #include "dsdb/common/proto.h"
41 #include "../libds/common/flags.h"
42 #include "librpc/gen_ndr/ndr_misc.h"
43 #include "librpc/gen_ndr/ndr_drsuapi.h"
44 #include "librpc/gen_ndr/ndr_drsblobs.h"
45 #include "param/param.h"
46 #include "libcli/security/dom_sid.h"
47 #include "lib/util/dlinklist.h"
48 #include "dsdb/samdb/ldb_modules/util.h"
49 #include "lib/util/binsearch.h"
51 #define W2K3_LINKED_ATTRIBUTES 1
53 struct replmd_private {
55 struct la_entry *la_list;
57 struct la_backlink *la_backlinks;
59 struct nc_entry *prev, *next;
66 struct la_entry *next, *prev;
67 struct drsuapi_DsReplicaLinkedAttribute *la;
70 struct replmd_replicated_request {
71 struct ldb_module *module;
72 struct ldb_request *req;
74 const struct dsdb_schema *schema;
76 /* the controls we pass down */
77 struct ldb_control **controls;
79 /* details for the mode where we apply a bunch of inbound replication meessages */
81 uint32_t index_current;
82 struct dsdb_extended_replicated_objects *objs;
84 struct ldb_message *search_msg;
90 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
95 allocate the private structure and build the list
96 of partition DNs for use by replmd_notify()
98 static int replmd_init(struct ldb_module *module)
100 struct replmd_private *replmd_private;
101 struct ldb_context *ldb = ldb_module_get_ctx(module);
103 replmd_private = talloc_zero(module, struct replmd_private);
104 if (replmd_private == NULL) {
106 return LDB_ERR_OPERATIONS_ERROR;
108 ldb_module_set_private(module, replmd_private);
110 return ldb_next_init(module);
114 cleanup our per-transaction contexts
116 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
118 talloc_free(replmd_private->la_ctx);
119 replmd_private->la_list = NULL;
120 replmd_private->la_ctx = NULL;
122 talloc_free(replmd_private->bl_ctx);
123 replmd_private->la_backlinks = NULL;
124 replmd_private->bl_ctx = NULL;
129 struct la_backlink *next, *prev;
130 const char *attr_name;
131 struct GUID forward_guid, target_guid;
136 process a backlinks we accumulated during a transaction, adding and
137 deleting the backlinks from the target objects
139 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl)
141 struct ldb_dn *target_dn, *source_dn;
143 struct ldb_context *ldb = ldb_module_get_ctx(module);
144 struct ldb_message *msg;
145 TALLOC_CTX *tmp_ctx = talloc_new(bl);
151 - construct ldb_message
152 - either an add or a delete
154 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn);
155 if (ret != LDB_SUCCESS) {
156 ldb_asprintf_errstring(ldb, "Failed to find target DN for linked attribute with GUID %s\n",
157 GUID_string(bl, &bl->target_guid));
158 talloc_free(tmp_ctx);
162 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn);
163 if (ret != LDB_SUCCESS) {
164 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
165 GUID_string(bl, &bl->forward_guid));
166 talloc_free(tmp_ctx);
170 msg = ldb_msg_new(tmp_ctx);
172 ldb_module_oom(module);
173 talloc_free(tmp_ctx);
174 return LDB_ERR_OPERATIONS_ERROR;
177 /* construct a ldb_message for adding/deleting the backlink */
179 dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
181 ldb_module_oom(module);
182 talloc_free(tmp_ctx);
183 return LDB_ERR_OPERATIONS_ERROR;
185 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
186 if (ret != LDB_SUCCESS) {
187 talloc_free(tmp_ctx);
190 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
192 ret = dsdb_module_modify(module, msg, 0);
193 if (ret != LDB_SUCCESS) {
194 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
195 bl->active?"add":"remove",
196 ldb_dn_get_linearized(source_dn),
197 ldb_dn_get_linearized(target_dn),
199 talloc_free(tmp_ctx);
202 talloc_free(tmp_ctx);
207 add a backlink to the list of backlinks to add/delete in the prepare
210 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
211 struct GUID *forward_guid, struct GUID *target_guid,
212 bool active, const struct dsdb_attribute *schema_attr, bool immediate)
214 const struct dsdb_attribute *target_attr;
215 struct la_backlink *bl;
216 struct replmd_private *replmd_private =
217 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
219 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID + 1);
222 * windows 2003 has a broken schema where the
223 * definition of msDS-IsDomainFor is missing (which is
224 * supposed to be the backlink of the
225 * msDS-HasDomainNCs attribute
230 /* see if its already in the list */
231 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
232 if (GUID_equal(forward_guid, &bl->forward_guid) &&
233 GUID_equal(target_guid, &bl->target_guid) &&
234 (target_attr->lDAPDisplayName == bl->attr_name ||
235 strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
241 /* we found an existing one */
242 if (bl->active == active) {
245 DLIST_REMOVE(replmd_private->la_backlinks, bl);
250 if (replmd_private->bl_ctx == NULL) {
251 replmd_private->bl_ctx = talloc_new(replmd_private);
252 if (replmd_private->bl_ctx == NULL) {
253 ldb_module_oom(module);
254 return LDB_ERR_OPERATIONS_ERROR;
259 bl = talloc(replmd_private->bl_ctx, struct la_backlink);
261 ldb_module_oom(module);
262 return LDB_ERR_OPERATIONS_ERROR;
265 bl->attr_name = target_attr->lDAPDisplayName;
266 bl->forward_guid = *forward_guid;
267 bl->target_guid = *target_guid;
270 /* the caller may ask for this backlink to be processed
273 int ret = replmd_process_backlink(module, bl);
278 DLIST_ADD(replmd_private->la_backlinks, bl);
285 * Callback for most write operations in this module:
287 * notify the repl task that a object has changed. The notifies are
288 * gathered up in the replmd_private structure then written to the
289 * @REPLCHANGED object in each partition during the prepare_commit
291 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
294 struct replmd_replicated_request *ac =
295 talloc_get_type_abort(req->context, struct replmd_replicated_request);
296 struct replmd_private *replmd_private =
297 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
298 struct nc_entry *modified_partition;
299 struct ldb_control *partition_ctrl;
300 const struct dsdb_control_current_partition *partition;
302 struct ldb_control **controls;
304 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
306 /* Remove the 'partition' control from what we pass up the chain */
307 controls = controls_except_specified(ares->controls, ares, partition_ctrl);
309 if (ares->error != LDB_SUCCESS) {
310 return ldb_module_done(ac->req, controls,
311 ares->response, ares->error);
314 if (ares->type != LDB_REPLY_DONE) {
315 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
316 return ldb_module_done(ac->req, NULL,
317 NULL, LDB_ERR_OPERATIONS_ERROR);
320 if (!partition_ctrl) {
321 return ldb_module_done(ac->req, NULL,
322 NULL, LDB_ERR_OPERATIONS_ERROR);
325 partition = talloc_get_type_abort(partition_ctrl->data,
326 struct dsdb_control_current_partition);
328 if (ac->seq_num > 0) {
329 for (modified_partition = replmd_private->ncs; modified_partition;
330 modified_partition = modified_partition->next) {
331 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
336 if (modified_partition == NULL) {
337 modified_partition = talloc_zero(replmd_private, struct nc_entry);
338 if (!modified_partition) {
339 ldb_oom(ldb_module_get_ctx(ac->module));
340 return ldb_module_done(ac->req, NULL,
341 NULL, LDB_ERR_OPERATIONS_ERROR);
343 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
344 if (!modified_partition->dn) {
345 ldb_oom(ldb_module_get_ctx(ac->module));
346 return ldb_module_done(ac->req, NULL,
347 NULL, LDB_ERR_OPERATIONS_ERROR);
349 DLIST_ADD(replmd_private->ncs, modified_partition);
352 if (ac->seq_num > modified_partition->mod_usn) {
353 modified_partition->mod_usn = ac->seq_num;
357 if (ac->apply_mode) {
361 ret = replmd_replicated_apply_next(ac);
362 if (ret != LDB_SUCCESS) {
363 return ldb_module_done(ac->req, NULL, NULL, ret);
367 /* free the partition control container here, for the
368 * common path. Other cases will have it cleaned up
369 * eventually with the ares */
370 talloc_free(partition_ctrl);
371 return ldb_module_done(ac->req,
372 controls_except_specified(controls, ares, partition_ctrl),
373 ares->response, LDB_SUCCESS);
379 * update a @REPLCHANGED record in each partition if there have been
380 * any writes of replicated data in the partition
382 static int replmd_notify_store(struct ldb_module *module)
384 struct replmd_private *replmd_private =
385 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
386 struct ldb_context *ldb = ldb_module_get_ctx(module);
388 while (replmd_private->ncs) {
390 struct nc_entry *modified_partition = replmd_private->ncs;
392 ret = dsdb_save_partition_usn(ldb, modified_partition->dn, modified_partition->mod_usn);
393 if (ret != LDB_SUCCESS) {
394 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
395 ldb_dn_get_linearized(modified_partition->dn)));
398 DLIST_REMOVE(replmd_private->ncs, modified_partition);
399 talloc_free(modified_partition);
407 created a replmd_replicated_request context
409 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
410 struct ldb_request *req)
412 struct ldb_context *ldb;
413 struct replmd_replicated_request *ac;
415 ldb = ldb_module_get_ctx(module);
417 ac = talloc_zero(req, struct replmd_replicated_request);
426 ac->schema = dsdb_get_schema(ldb);
428 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
429 "replmd_modify: no dsdb_schema loaded");
430 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
438 add a time element to a record
440 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
442 struct ldb_message_element *el;
445 if (ldb_msg_find_element(msg, attr) != NULL) {
449 s = ldb_timestring(msg, t);
451 return LDB_ERR_OPERATIONS_ERROR;
454 if (ldb_msg_add_string(msg, attr, s) != LDB_SUCCESS) {
455 return LDB_ERR_OPERATIONS_ERROR;
458 el = ldb_msg_find_element(msg, attr);
459 /* always set as replace. This works because on add ops, the flag
461 el->flags = LDB_FLAG_MOD_REPLACE;
467 add a uint64_t element to a record
469 static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_t v)
471 struct ldb_message_element *el;
473 if (ldb_msg_find_element(msg, attr) != NULL) {
477 if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != LDB_SUCCESS) {
478 return LDB_ERR_OPERATIONS_ERROR;
481 el = ldb_msg_find_element(msg, attr);
482 /* always set as replace. This works because on add ops, the flag
484 el->flags = LDB_FLAG_MOD_REPLACE;
489 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
490 const struct replPropertyMetaData1 *m2,
491 const uint32_t *rdn_attid)
493 if (m1->attid == m2->attid) {
498 * the rdn attribute should be at the end!
499 * so we need to return a value greater than zero
500 * which means m1 is greater than m2
502 if (m1->attid == *rdn_attid) {
507 * the rdn attribute should be at the end!
508 * so we need to return a value less than zero
509 * which means m2 is greater than m1
511 if (m2->attid == *rdn_attid) {
515 return m1->attid > m2->attid ? 1 : -1;
518 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
519 const struct dsdb_schema *schema,
522 const char *rdn_name;
523 const struct dsdb_attribute *rdn_sa;
525 rdn_name = ldb_dn_get_rdn_name(dn);
527 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
528 return LDB_ERR_OPERATIONS_ERROR;
531 rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
532 if (rdn_sa == NULL) {
533 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
534 return LDB_ERR_OPERATIONS_ERROR;
537 DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
538 rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
540 ldb_qsort(ctr1->array, ctr1->count, sizeof(struct replPropertyMetaData1),
541 discard_const_p(void, &rdn_sa->attributeID_id),
542 (ldb_qsort_cmp_fn_t)replmd_replPropertyMetaData1_attid_sort);
547 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
548 const struct ldb_message_element *e2,
549 const struct dsdb_schema *schema)
551 const struct dsdb_attribute *a1;
552 const struct dsdb_attribute *a2;
555 * TODO: make this faster by caching the dsdb_attribute pointer
556 * on the ldb_messag_element
559 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
560 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
563 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
567 return strcasecmp(e1->name, e2->name);
569 if (a1->attributeID_id == a2->attributeID_id) {
572 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
575 static void replmd_ldb_message_sort(struct ldb_message *msg,
576 const struct dsdb_schema *schema)
578 ldb_qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
579 discard_const_p(void, schema), (ldb_qsort_cmp_fn_t)replmd_ldb_message_element_attid_sort);
582 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
583 const struct GUID *invocation_id, uint64_t seq_num,
584 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
588 fix up linked attributes in replmd_add.
589 This involves setting up the right meta-data in extended DN
590 components, and creating backlinks to the object
592 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
593 uint64_t seq_num, const struct GUID *invocationId, time_t t,
594 struct GUID *guid, const struct dsdb_attribute *sa)
597 TALLOC_CTX *tmp_ctx = talloc_new(el->values);
598 struct ldb_context *ldb = ldb_module_get_ctx(module);
599 struct dsdb_schema *schema = dsdb_get_schema(ldb);
602 unix_to_nt_time(&now, t);
604 for (i=0; i<el->num_values; i++) {
605 struct ldb_val *v = &el->values[i];
606 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
607 struct GUID target_guid;
611 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
612 seq_num, seq_num, now, 0, false);
613 if (ret != LDB_SUCCESS) {
614 talloc_free(tmp_ctx);
618 /* note that the DN already has the extended
619 components from the extended_dn_store module */
620 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
621 if (!NT_STATUS_IS_OK(status)) {
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, uint32_t version, 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;
1204 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1206 return LDB_ERR_OPERATIONS_ERROR;
1208 tval = data_blob_string_const(tstring);
1210 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1212 return LDB_ERR_OPERATIONS_ERROR;
1214 usnv = data_blob_string_const(usn_string);
1216 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1218 return LDB_ERR_OPERATIONS_ERROR;
1220 local_usnv = data_blob_string_const(usn_string);
1222 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1223 vers = data_blob_string_const(vstring);
1225 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1226 if (!NT_STATUS_IS_OK(status)) {
1227 return LDB_ERR_OPERATIONS_ERROR;
1232 dv = data_blob_string_const("1");
1233 ret = ldb_dn_set_extended_component(dn, "DELETED", &dv);
1235 ret = ldb_dn_set_extended_component(dn, "DELETED", NULL);
1237 if (ret != LDB_SUCCESS) return ret;
1238 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1239 if (ret != LDB_SUCCESS) return ret;
1240 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1241 if (ret != LDB_SUCCESS) return ret;
1242 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1243 if (ret != LDB_SUCCESS) return ret;
1244 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1245 if (ret != LDB_SUCCESS) return ret;
1246 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1247 if (ret != LDB_SUCCESS) return ret;
1248 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1249 if (ret != LDB_SUCCESS) return ret;
1251 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1252 if (dnstring == NULL) {
1253 return LDB_ERR_OPERATIONS_ERROR;
1255 *v = data_blob_string_const(dnstring);
1260 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1261 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1262 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1263 uint32_t version, bool deleted);
1266 check if any links need upgrading from w2k format
1268 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, const struct GUID *invocation_id)
1271 for (i=0; i<count; i++) {
1276 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1277 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1281 /* it's an old one that needs upgrading */
1282 ret = replmd_update_la_val(dns, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1284 if (ret != LDB_SUCCESS) {
1292 update an extended DN, including all meta data fields
1294 see replmd_build_la_val for value names
1296 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1297 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1298 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1299 uint32_t version, bool deleted)
1301 struct ldb_dn *dn = dsdb_dn->dn;
1302 const char *tstring, *usn_string;
1303 struct ldb_val tval;
1305 struct ldb_val usnv, local_usnv;
1306 struct ldb_val vers;
1307 const struct ldb_val *old_addtime;
1308 uint32_t old_version;
1311 const char *dnstring;
1314 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1316 return LDB_ERR_OPERATIONS_ERROR;
1318 tval = data_blob_string_const(tstring);
1320 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1322 return LDB_ERR_OPERATIONS_ERROR;
1324 usnv = data_blob_string_const(usn_string);
1326 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1328 return LDB_ERR_OPERATIONS_ERROR;
1330 local_usnv = data_blob_string_const(usn_string);
1332 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1333 if (!NT_STATUS_IS_OK(status)) {
1334 return LDB_ERR_OPERATIONS_ERROR;
1339 dv = data_blob_string_const("1");
1340 ret = ldb_dn_set_extended_component(dn, "DELETED", &dv);
1342 ret = ldb_dn_set_extended_component(dn, "DELETED", NULL);
1344 if (ret != LDB_SUCCESS) return ret;
1346 /* get the ADDTIME from the original */
1347 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1348 if (old_addtime == NULL) {
1349 old_addtime = &tval;
1351 if (dsdb_dn != old_dsdb_dn) {
1352 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1353 if (ret != LDB_SUCCESS) return ret;
1356 /* use our invocation id */
1357 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1358 if (ret != LDB_SUCCESS) return ret;
1360 /* changetime is the current time */
1361 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1362 if (ret != LDB_SUCCESS) return ret;
1364 /* update the USN */
1365 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1366 if (ret != LDB_SUCCESS) return ret;
1368 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1369 if (ret != LDB_SUCCESS) return ret;
1371 /* increase the version by 1 */
1372 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1373 if (NT_STATUS_IS_OK(status) && old_version >= version) {
1374 version = old_version+1;
1376 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1377 vers = data_blob_string_const(vstring);
1378 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1379 if (ret != LDB_SUCCESS) return ret;
1381 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1382 if (dnstring == NULL) {
1383 return LDB_ERR_OPERATIONS_ERROR;
1385 *v = data_blob_string_const(dnstring);
1391 handle adding a linked attribute
1393 static int replmd_modify_la_add(struct ldb_module *module,
1394 struct dsdb_schema *schema,
1395 struct ldb_message *msg,
1396 struct ldb_message_element *el,
1397 struct ldb_message_element *old_el,
1398 const struct dsdb_attribute *schema_attr,
1401 struct GUID *msg_guid)
1404 struct parsed_dn *dns, *old_dns;
1405 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1407 struct ldb_val *new_values = NULL;
1408 unsigned int num_new_values = 0;
1409 unsigned old_num_values = old_el?old_el->num_values:0;
1410 const struct GUID *invocation_id;
1411 struct ldb_context *ldb = ldb_module_get_ctx(module);
1414 unix_to_nt_time(&now, t);
1416 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1417 if (ret != LDB_SUCCESS) {
1418 talloc_free(tmp_ctx);
1422 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1423 if (ret != LDB_SUCCESS) {
1424 talloc_free(tmp_ctx);
1428 invocation_id = samdb_ntds_invocation_id(ldb);
1429 if (!invocation_id) {
1430 talloc_free(tmp_ctx);
1431 return LDB_ERR_OPERATIONS_ERROR;
1434 ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
1435 if (ret != LDB_SUCCESS) {
1436 talloc_free(tmp_ctx);
1440 /* for each new value, see if it exists already with the same GUID */
1441 for (i=0; i<el->num_values; i++) {
1442 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid);
1444 /* this is a new linked attribute value */
1445 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1446 if (new_values == NULL) {
1447 ldb_module_oom(module);
1448 talloc_free(tmp_ctx);
1449 return LDB_ERR_OPERATIONS_ERROR;
1451 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1452 invocation_id, seq_num, seq_num, now, 0, false);
1453 if (ret != LDB_SUCCESS) {
1454 talloc_free(tmp_ctx);
1459 /* this is only allowed if the GUID was
1460 previously deleted. */
1461 const struct ldb_val *v;
1462 v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED");
1464 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1465 el->name, GUID_string(tmp_ctx, p->guid));
1466 talloc_free(tmp_ctx);
1467 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1469 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1470 invocation_id, seq_num, seq_num, now, 0, false);
1471 if (ret != LDB_SUCCESS) {
1472 talloc_free(tmp_ctx);
1477 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1478 if (ret != LDB_SUCCESS) {
1479 talloc_free(tmp_ctx);
1484 /* add the new ones on to the end of the old values, constructing a new el->values */
1485 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1487 old_num_values+num_new_values);
1488 if (el->values == NULL) {
1489 ldb_module_oom(module);
1490 return LDB_ERR_OPERATIONS_ERROR;
1493 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1494 el->num_values = old_num_values + num_new_values;
1496 talloc_steal(msg->elements, el->values);
1497 talloc_steal(el->values, new_values);
1499 talloc_free(tmp_ctx);
1501 /* we now tell the backend to replace all existing values
1502 with the one we have constructed */
1503 el->flags = LDB_FLAG_MOD_REPLACE;
1510 handle deleting all active linked attributes
1512 static int replmd_modify_la_delete(struct ldb_module *module,
1513 struct dsdb_schema *schema,
1514 struct ldb_message *msg,
1515 struct ldb_message_element *el,
1516 struct ldb_message_element *old_el,
1517 const struct dsdb_attribute *schema_attr,
1520 struct GUID *msg_guid)
1523 struct parsed_dn *dns, *old_dns;
1524 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1526 const struct GUID *invocation_id;
1527 struct ldb_context *ldb = ldb_module_get_ctx(module);
1530 unix_to_nt_time(&now, t);
1532 /* check if there is nothing to delete */
1533 if ((!old_el || old_el->num_values == 0) &&
1534 el->num_values == 0) {
1538 if (!old_el || old_el->num_values == 0) {
1539 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1542 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1543 if (ret != LDB_SUCCESS) {
1544 talloc_free(tmp_ctx);
1548 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1549 if (ret != LDB_SUCCESS) {
1550 talloc_free(tmp_ctx);
1554 invocation_id = samdb_ntds_invocation_id(ldb);
1555 if (!invocation_id) {
1556 return LDB_ERR_OPERATIONS_ERROR;
1559 ret = replmd_check_upgrade_links(old_dns, old_el->num_values, invocation_id);
1560 if (ret != LDB_SUCCESS) {
1561 talloc_free(tmp_ctx);
1567 /* see if we are being asked to delete any links that
1568 don't exist or are already deleted */
1569 for (i=0; i<el->num_values; i++) {
1570 struct parsed_dn *p = &dns[i];
1571 struct parsed_dn *p2;
1572 const struct ldb_val *v;
1574 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid);
1576 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1577 el->name, GUID_string(tmp_ctx, p->guid));
1578 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1580 v = ldb_dn_get_extended_component(p2->dsdb_dn->dn, "DELETED");
1582 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1583 el->name, GUID_string(tmp_ctx, p->guid));
1584 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1588 /* for each new value, see if it exists already with the same GUID
1589 if it is not already deleted and matches the delete list then delete it
1591 for (i=0; i<old_el->num_values; i++) {
1592 struct parsed_dn *p = &old_dns[i];
1593 const struct ldb_val *v;
1595 if (dns && parsed_dn_find(dns, el->num_values, p->guid) == NULL) {
1599 v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED");
1600 if (v != NULL) continue;
1602 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1603 invocation_id, seq_num, seq_num, now, 0, true);
1604 if (ret != LDB_SUCCESS) {
1605 talloc_free(tmp_ctx);
1609 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1610 if (ret != LDB_SUCCESS) {
1611 talloc_free(tmp_ctx);
1616 el->values = talloc_steal(msg->elements, old_el->values);
1617 el->num_values = old_el->num_values;
1619 talloc_free(tmp_ctx);
1621 /* we now tell the backend to replace all existing values
1622 with the one we have constructed */
1623 el->flags = LDB_FLAG_MOD_REPLACE;
1629 handle replacing a linked attribute
1631 static int replmd_modify_la_replace(struct ldb_module *module,
1632 struct dsdb_schema *schema,
1633 struct ldb_message *msg,
1634 struct ldb_message_element *el,
1635 struct ldb_message_element *old_el,
1636 const struct dsdb_attribute *schema_attr,
1639 struct GUID *msg_guid)
1642 struct parsed_dn *dns, *old_dns;
1643 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1645 const struct GUID *invocation_id;
1646 struct ldb_context *ldb = ldb_module_get_ctx(module);
1647 struct ldb_val *new_values = NULL;
1648 uint32_t num_new_values = 0;
1649 unsigned old_num_values = old_el?old_el->num_values:0;
1652 unix_to_nt_time(&now, t);
1654 /* check if there is nothing to replace */
1655 if ((!old_el || old_el->num_values == 0) &&
1656 el->num_values == 0) {
1660 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1661 if (ret != LDB_SUCCESS) {
1662 talloc_free(tmp_ctx);
1666 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1667 if (ret != LDB_SUCCESS) {
1668 talloc_free(tmp_ctx);
1672 invocation_id = samdb_ntds_invocation_id(ldb);
1673 if (!invocation_id) {
1674 return LDB_ERR_OPERATIONS_ERROR;
1677 ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
1678 if (ret != LDB_SUCCESS) {
1679 talloc_free(tmp_ctx);
1683 /* mark all the old ones as deleted */
1684 for (i=0; i<old_num_values; i++) {
1685 struct parsed_dn *old_p = &old_dns[i];
1686 struct parsed_dn *p;
1687 const struct ldb_val *v;
1689 v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED");
1692 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1693 if (ret != LDB_SUCCESS) {
1694 talloc_free(tmp_ctx);
1698 p = parsed_dn_find(dns, el->num_values, old_p->guid);
1700 /* we don't delete it if we are re-adding it */
1704 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
1705 invocation_id, seq_num, seq_num, now, 0, true);
1706 if (ret != LDB_SUCCESS) {
1707 talloc_free(tmp_ctx);
1712 /* for each new value, either update its meta-data, or add it
1715 for (i=0; i<el->num_values; i++) {
1716 struct parsed_dn *p = &dns[i], *old_p;
1719 (old_p = parsed_dn_find(old_dns,
1720 old_num_values, p->guid)) != NULL) {
1721 /* update in place */
1722 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
1723 old_p->dsdb_dn, invocation_id,
1724 seq_num, seq_num, now, 0, false);
1725 if (ret != LDB_SUCCESS) {
1726 talloc_free(tmp_ctx);
1731 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
1733 if (new_values == NULL) {
1734 ldb_module_oom(module);
1735 talloc_free(tmp_ctx);
1736 return LDB_ERR_OPERATIONS_ERROR;
1738 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1739 invocation_id, seq_num, seq_num, now, 0, false);
1740 if (ret != LDB_SUCCESS) {
1741 talloc_free(tmp_ctx);
1747 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
1748 if (ret != LDB_SUCCESS) {
1749 talloc_free(tmp_ctx);
1754 /* add the new values to the end of old_el */
1755 if (num_new_values != 0) {
1756 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1757 struct ldb_val, old_num_values+num_new_values);
1758 if (el->values == NULL) {
1759 ldb_module_oom(module);
1760 return LDB_ERR_OPERATIONS_ERROR;
1762 memcpy(&el->values[old_num_values], &new_values[0],
1763 sizeof(struct ldb_val)*num_new_values);
1764 el->num_values = old_num_values + num_new_values;
1765 talloc_steal(msg->elements, new_values);
1767 el->values = old_el->values;
1768 el->num_values = old_el->num_values;
1769 talloc_steal(msg->elements, el->values);
1772 talloc_free(tmp_ctx);
1774 /* we now tell the backend to replace all existing values
1775 with the one we have constructed */
1776 el->flags = LDB_FLAG_MOD_REPLACE;
1783 handle linked attributes in modify requests
1785 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
1786 struct ldb_message *msg,
1787 uint64_t seq_num, time_t t)
1789 struct ldb_result *res;
1791 struct ldb_context *ldb = ldb_module_get_ctx(module);
1792 struct ldb_message *old_msg;
1793 struct dsdb_schema *schema = dsdb_get_schema(ldb);
1794 struct GUID old_guid;
1797 /* there the replmd_update_rpmd code has already
1798 * checked and saw that there are no linked
1803 #if !W2K3_LINKED_ATTRIBUTES
1807 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
1808 /* don't do anything special for linked attributes */
1812 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
1813 DSDB_SEARCH_SHOW_DELETED |
1814 DSDB_SEARCH_REVEAL_INTERNALS |
1815 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
1816 if (ret != LDB_SUCCESS) {
1819 old_msg = res->msgs[0];
1821 old_guid = samdb_result_guid(old_msg, "objectGUID");
1823 for (i=0; i<msg->num_elements; i++) {
1824 struct ldb_message_element *el = &msg->elements[i];
1825 struct ldb_message_element *old_el, *new_el;
1826 const struct dsdb_attribute *schema_attr
1827 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1829 ldb_asprintf_errstring(ldb,
1830 "attribute %s is not a valid attribute in schema", el->name);
1831 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1833 if (schema_attr->linkID == 0) {
1836 if ((schema_attr->linkID & 1) == 1) {
1837 /* Odd is for the target. Illegal to modify */
1838 ldb_asprintf_errstring(ldb,
1839 "attribute %s must not be modified directly, it is a linked attribute", el->name);
1840 return LDB_ERR_UNWILLING_TO_PERFORM;
1842 old_el = ldb_msg_find_element(old_msg, el->name);
1843 switch (el->flags & LDB_FLAG_MOD_MASK) {
1844 case LDB_FLAG_MOD_REPLACE:
1845 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1847 case LDB_FLAG_MOD_DELETE:
1848 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1850 case LDB_FLAG_MOD_ADD:
1851 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1854 ldb_asprintf_errstring(ldb,
1855 "invalid flags 0x%x for %s linked attribute",
1856 el->flags, el->name);
1857 return LDB_ERR_UNWILLING_TO_PERFORM;
1859 if (ret != LDB_SUCCESS) {
1863 ldb_msg_remove_attr(old_msg, el->name);
1865 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
1866 new_el->num_values = el->num_values;
1867 new_el->values = el->values;
1869 /* TODO: this relises a bit too heavily on the exact
1870 behaviour of ldb_msg_find_element and
1871 ldb_msg_remove_element */
1872 old_el = ldb_msg_find_element(msg, el->name);
1874 ldb_msg_remove_element(msg, old_el);
1885 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
1887 struct ldb_context *ldb;
1888 struct replmd_replicated_request *ac;
1889 struct ldb_request *down_req;
1890 struct ldb_message *msg;
1891 time_t t = time(NULL);
1894 /* do not manipulate our control entries */
1895 if (ldb_dn_is_special(req->op.mod.message->dn)) {
1896 return ldb_next_request(module, req);
1899 ldb = ldb_module_get_ctx(module);
1901 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
1903 ac = replmd_ctx_init(module, req);
1905 return LDB_ERR_OPERATIONS_ERROR;
1908 /* we have to copy the message as the caller might have it as a const */
1909 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
1913 return LDB_ERR_OPERATIONS_ERROR;
1916 ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num, t);
1917 if (ret != LDB_SUCCESS) {
1922 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t);
1923 if (ret != LDB_SUCCESS) {
1929 * - replace the old object with the newly constructed one
1932 ret = ldb_build_mod_req(&down_req, ldb, ac,
1935 ac, replmd_op_callback,
1937 if (ret != LDB_SUCCESS) {
1941 talloc_steal(down_req, msg);
1943 /* we only change whenChanged and uSNChanged if the seq_num
1945 if (ac->seq_num != 0) {
1946 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
1951 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
1957 /* go on with the call chain */
1958 return ldb_next_request(module, down_req);
1961 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
1964 handle a rename request
1966 On a rename we need to do an extra ldb_modify which sets the
1967 whenChanged and uSNChanged attributes. We do this in a callback after the success.
1969 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
1971 struct ldb_context *ldb;
1972 struct replmd_replicated_request *ac;
1974 struct ldb_request *down_req;
1976 /* do not manipulate our control entries */
1977 if (ldb_dn_is_special(req->op.mod.message->dn)) {
1978 return ldb_next_request(module, req);
1981 ldb = ldb_module_get_ctx(module);
1983 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
1985 ac = replmd_ctx_init(module, req);
1987 return LDB_ERR_OPERATIONS_ERROR;
1989 ret = ldb_build_rename_req(&down_req, ldb, ac,
1990 ac->req->op.rename.olddn,
1991 ac->req->op.rename.newdn,
1993 ac, replmd_rename_callback,
1996 if (ret != LDB_SUCCESS) {
2001 /* go on with the call chain */
2002 return ldb_next_request(module, down_req);
2005 /* After the rename is compleated, update the whenchanged etc */
2006 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2008 struct ldb_context *ldb;
2009 struct replmd_replicated_request *ac;
2010 struct ldb_request *down_req;
2011 struct ldb_message *msg;
2012 time_t t = time(NULL);
2015 ac = talloc_get_type(req->context, struct replmd_replicated_request);
2016 ldb = ldb_module_get_ctx(ac->module);
2018 if (ares->error != LDB_SUCCESS) {
2019 return ldb_module_done(ac->req, ares->controls,
2020 ares->response, ares->error);
2023 if (ares->type != LDB_REPLY_DONE) {
2024 ldb_set_errstring(ldb,
2025 "invalid ldb_reply_type in callback");
2027 return ldb_module_done(ac->req, NULL, NULL,
2028 LDB_ERR_OPERATIONS_ERROR);
2031 /* Get a sequence number from the backend */
2032 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
2033 if (ret != LDB_SUCCESS) {
2038 * - replace the old object with the newly constructed one
2041 msg = ldb_msg_new(ac);
2044 return LDB_ERR_OPERATIONS_ERROR;
2047 msg->dn = ac->req->op.rename.newdn;
2049 ret = ldb_build_mod_req(&down_req, ldb, ac,
2052 ac, replmd_op_callback,
2055 if (ret != LDB_SUCCESS) {
2059 talloc_steal(down_req, msg);
2061 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2066 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
2071 /* go on with the call chain - do the modify after the rename */
2072 return ldb_next_request(ac->module, down_req);
2075 /* remove forwards and backlinks as needed when an object
2077 static int replmd_delete_remove_link(struct ldb_module *module,
2078 struct dsdb_schema *schema,
2080 struct ldb_message_element *el,
2081 const struct dsdb_attribute *sa)
2084 TALLOC_CTX *tmp_ctx = talloc_new(module);
2085 struct ldb_context *ldb = ldb_module_get_ctx(module);
2087 for (i=0; i<el->num_values; i++) {
2088 struct dsdb_dn *dsdb_dn;
2092 struct ldb_message *msg;
2093 const struct dsdb_attribute *target_attr;
2094 struct ldb_message_element *el2;
2095 struct ldb_val dn_val;
2097 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2101 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2103 talloc_free(tmp_ctx);
2104 return LDB_ERR_OPERATIONS_ERROR;
2107 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2108 if (!NT_STATUS_IS_OK(status)) {
2109 talloc_free(tmp_ctx);
2110 return LDB_ERR_OPERATIONS_ERROR;
2113 /* remove the link */
2114 msg = ldb_msg_new(tmp_ctx);
2116 ldb_module_oom(module);
2117 talloc_free(tmp_ctx);
2118 return LDB_ERR_OPERATIONS_ERROR;
2122 msg->dn = dsdb_dn->dn;
2124 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2125 if (target_attr == NULL) {
2129 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2130 if (ret != LDB_SUCCESS) {
2131 ldb_module_oom(module);
2132 talloc_free(tmp_ctx);
2133 return LDB_ERR_OPERATIONS_ERROR;
2135 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2136 el2->values = &dn_val;
2137 el2->num_values = 1;
2139 ret = dsdb_module_modify(module, msg, 0);
2140 if (ret != LDB_SUCCESS) {
2141 talloc_free(tmp_ctx);
2145 talloc_free(tmp_ctx);
2151 handle update of replication meta data for deletion of objects
2153 This also handles the mapping of delete to a rename operation
2154 to allow deletes to be replicated.
2156 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2158 int ret = LDB_ERR_OTHER;
2160 struct ldb_dn *old_dn, *new_dn;
2161 const char *rdn_name;
2162 const struct ldb_val *rdn_value, *new_rdn_value;
2164 struct ldb_context *ldb = ldb_module_get_ctx(module);
2165 struct dsdb_schema *schema = dsdb_get_schema(ldb);
2166 struct ldb_message *msg, *old_msg;
2167 struct ldb_message_element *el;
2168 TALLOC_CTX *tmp_ctx;
2169 struct ldb_result *res, *parent_res;
2170 const char *preserved_attrs[] = {
2171 /* yes, this really is a hard coded list. See MS-ADTS
2172 section 3.1.1.5.5.1.1 */
2173 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2174 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2175 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2176 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2177 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2178 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2179 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreate",
2181 uint32_t el_count = 0;
2184 tmp_ctx = talloc_new(ldb);
2186 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2188 /* we need the complete msg off disk, so we can work out which
2189 attributes need to be removed */
2190 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2191 DSDB_SEARCH_SHOW_DELETED |
2192 DSDB_SEARCH_REVEAL_INTERNALS |
2193 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
2194 if (ret != LDB_SUCCESS) {
2195 talloc_free(tmp_ctx);
2198 old_msg = res->msgs[0];
2200 /* work out where we will be renaming this object to */
2201 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn, &new_dn);
2202 if (ret != LDB_SUCCESS) {
2203 /* this is probably an attempted delete on a partition
2204 * that doesn't allow delete operations, such as the
2205 * schema partition */
2206 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2207 ldb_dn_get_linearized(old_dn));
2208 talloc_free(tmp_ctx);
2209 return LDB_ERR_UNWILLING_TO_PERFORM;
2212 rdn_name = ldb_dn_get_rdn_name(old_dn);
2213 rdn_value = ldb_dn_get_rdn_val(old_dn);
2215 /* get the objects GUID from the search we just did */
2216 guid = samdb_result_guid(old_msg, "objectGUID");
2218 /* Add a formatted child */
2219 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2222 GUID_string(tmp_ctx, &guid));
2224 DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2225 ldb_dn_get_linearized(new_dn)));
2226 talloc_free(tmp_ctx);
2227 return LDB_ERR_OPERATIONS_ERROR;
2231 now we need to modify the object in the following ways:
2233 - add isDeleted=TRUE
2234 - update rDN and name, with new rDN
2235 - remove linked attributes
2236 - remove objectCategory and sAMAccountType
2237 - remove attribs not on the preserved list
2238 - preserved if in above list, or is rDN
2239 - remove all linked attribs from this object
2240 - remove all links from other objects to this object
2241 - add lastKnownParent
2242 - update replPropertyMetaData?
2244 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2247 msg = ldb_msg_new(tmp_ctx);
2249 ldb_module_oom(module);
2250 talloc_free(tmp_ctx);
2251 return LDB_ERR_OPERATIONS_ERROR;
2256 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2257 if (ret != LDB_SUCCESS) {
2258 DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2259 ldb_module_oom(module);
2260 talloc_free(tmp_ctx);
2263 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2265 /* we need the storage form of the parent GUID */
2266 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2267 ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2268 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2269 DSDB_SEARCH_REVEAL_INTERNALS);
2270 if (ret != LDB_SUCCESS) {
2271 talloc_free(tmp_ctx);
2275 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2276 ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2277 if (ret != LDB_SUCCESS) {
2278 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2279 ldb_module_oom(module);
2280 talloc_free(tmp_ctx);
2283 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2285 /* work out which of the old attributes we will be removing */
2286 for (i=0; i<old_msg->num_elements; i++) {
2287 const struct dsdb_attribute *sa;
2288 el = &old_msg->elements[i];
2289 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2291 talloc_free(tmp_ctx);
2292 return LDB_ERR_OPERATIONS_ERROR;
2294 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2295 /* don't remove the rDN */
2300 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa);
2301 if (ret != LDB_SUCCESS) {
2302 talloc_free(tmp_ctx);
2303 return LDB_ERR_OPERATIONS_ERROR;
2307 if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2311 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2312 if (ret != LDB_SUCCESS) {
2313 talloc_free(tmp_ctx);
2314 ldb_module_oom(module);
2319 /* work out what the new rdn value is, for updating the
2320 rDN and name fields */
2321 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2322 ret = ldb_msg_add_value(msg, rdn_name, new_rdn_value, &el);
2323 if (ret != LDB_SUCCESS) {
2324 talloc_free(tmp_ctx);
2327 el->flags = LDB_FLAG_MOD_REPLACE;
2329 el = ldb_msg_find_element(old_msg, "name");
2331 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2332 if (ret != LDB_SUCCESS) {
2333 talloc_free(tmp_ctx);
2336 el->flags = LDB_FLAG_MOD_REPLACE;
2339 ret = dsdb_module_modify(module, msg, 0);
2340 if (ret != LDB_SUCCESS){
2341 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
2342 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
2343 talloc_free(tmp_ctx);
2347 /* now rename onto the new DN */
2348 ret = dsdb_module_rename(module, old_dn, new_dn, 0);
2349 if (ret != LDB_SUCCESS){
2350 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
2351 ldb_dn_get_linearized(old_dn),
2352 ldb_dn_get_linearized(new_dn),
2353 ldb_errstring(ldb)));
2354 talloc_free(tmp_ctx);
2358 talloc_free(tmp_ctx);
2360 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
2365 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
2370 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
2372 int ret = LDB_ERR_OTHER;
2373 /* TODO: do some error mapping */
2377 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
2379 struct ldb_context *ldb;
2380 struct ldb_request *change_req;
2381 enum ndr_err_code ndr_err;
2382 struct ldb_message *msg;
2383 struct replPropertyMetaDataBlob *md;
2384 struct ldb_val md_value;
2389 * TODO: check if the parent object exist
2393 * TODO: handle the conflict case where an object with the
2397 ldb = ldb_module_get_ctx(ar->module);
2398 msg = ar->objs->objects[ar->index_current].msg;
2399 md = ar->objs->objects[ar->index_current].meta_data;
2401 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2402 if (ret != LDB_SUCCESS) {
2403 return replmd_replicated_request_error(ar, ret);
2406 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
2407 if (ret != LDB_SUCCESS) {
2408 return replmd_replicated_request_error(ar, ret);
2411 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2412 if (ret != LDB_SUCCESS) {
2413 return replmd_replicated_request_error(ar, ret);
2416 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
2417 if (ret != LDB_SUCCESS) {
2418 return replmd_replicated_request_error(ar, ret);
2421 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2422 if (ret != LDB_SUCCESS) {
2423 return replmd_replicated_request_error(ar, ret);
2426 /* remove any message elements that have zero values */
2427 for (i=0; i<msg->num_elements; i++) {
2428 struct ldb_message_element *el = &msg->elements[i];
2430 if (el->num_values == 0) {
2431 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
2433 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
2434 msg->num_elements--;
2441 * the meta data array is already sorted by the caller
2443 for (i=0; i < md->ctr.ctr1.count; i++) {
2444 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
2446 ndr_err = ndr_push_struct_blob(&md_value, msg,
2447 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2449 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2450 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2451 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2452 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2454 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
2455 if (ret != LDB_SUCCESS) {
2456 return replmd_replicated_request_error(ar, ret);
2459 replmd_ldb_message_sort(msg, ar->schema);
2462 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
2463 DEBUG(4, ("DRS replication add message:\n%s\n", s));
2467 ret = ldb_build_add_req(&change_req,
2475 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2477 return ldb_next_request(ar->module, change_req);
2481 return true if an update is newer than an existing entry
2482 see section 5.11 of MS-ADTS
2484 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
2485 const struct GUID *update_invocation_id,
2486 uint32_t current_version,
2487 uint32_t update_version,
2488 NTTIME current_change_time,
2489 NTTIME update_change_time)
2491 if (update_version != current_version) {
2492 return update_version > current_version;
2494 if (update_change_time > current_change_time) {
2497 if (update_change_time == current_change_time) {
2498 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
2503 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
2504 struct replPropertyMetaData1 *new_m)
2506 return replmd_update_is_newer(&cur_m->originating_invocation_id,
2507 &new_m->originating_invocation_id,
2510 cur_m->originating_change_time,
2511 new_m->originating_change_time);
2514 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
2516 struct ldb_context *ldb;
2517 struct ldb_request *change_req;
2518 enum ndr_err_code ndr_err;
2519 struct ldb_message *msg;
2520 struct replPropertyMetaDataBlob *rmd;
2521 struct replPropertyMetaDataBlob omd;
2522 const struct ldb_val *omd_value;
2523 struct replPropertyMetaDataBlob nmd;
2524 struct ldb_val nmd_value;
2526 uint32_t removed_attrs = 0;
2529 ldb = ldb_module_get_ctx(ar->module);
2530 msg = ar->objs->objects[ar->index_current].msg;
2531 rmd = ar->objs->objects[ar->index_current].meta_data;
2536 * TODO: check repl data is correct after a rename
2538 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
2539 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
2540 ldb_dn_get_linearized(ar->search_msg->dn),
2541 ldb_dn_get_linearized(msg->dn));
2542 /* we can't use dsdb_module_rename() here as we need
2543 the rename call to be intercepted by this module, to
2544 allow it to process linked attribute changes */
2545 if (ldb_rename(ldb, ar->search_msg->dn, msg->dn) != LDB_SUCCESS) {
2546 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
2547 ldb_dn_get_linearized(ar->search_msg->dn),
2548 ldb_dn_get_linearized(msg->dn),
2549 ldb_errstring(ldb));
2550 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
2554 /* find existing meta data */
2555 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
2557 ndr_err = ndr_pull_struct_blob(omd_value, ar,
2558 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
2559 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
2560 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2561 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2562 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2565 if (omd.version != 1) {
2566 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2572 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
2573 nmd.ctr.ctr1.array = talloc_array(ar,
2574 struct replPropertyMetaData1,
2575 nmd.ctr.ctr1.count);
2576 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2578 /* first copy the old meta data */
2579 for (i=0; i < omd.ctr.ctr1.count; i++) {
2580 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
2584 /* now merge in the new meta data */
2585 for (i=0; i < rmd->ctr.ctr1.count; i++) {
2588 for (j=0; j < ni; j++) {
2591 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
2595 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
2596 &rmd->ctr.ctr1.array[i]);
2598 /* replace the entry */
2599 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
2604 DEBUG(1,("Discarding older DRS attribute update to %s on %s from %s\n",
2605 msg->elements[i-removed_attrs].name,
2606 ldb_dn_get_linearized(msg->dn),
2607 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
2609 /* we don't want to apply this change so remove the attribute */
2610 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
2617 if (found) continue;
2619 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
2624 * finally correct the size of the meta_data array
2626 nmd.ctr.ctr1.count = ni;
2629 * the rdn attribute (the alias for the name attribute),
2630 * 'cn' for most objects is the last entry in the meta data array
2633 * sort the new meta data array
2635 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
2636 if (ret != LDB_SUCCESS) {
2641 * check if some replicated attributes left, otherwise skip the ldb_modify() call
2643 if (msg->num_elements == 0) {
2644 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
2647 ar->index_current++;
2648 return replmd_replicated_apply_next(ar);
2651 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
2652 ar->index_current, msg->num_elements);
2654 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2655 if (ret != LDB_SUCCESS) {
2656 return replmd_replicated_request_error(ar, ret);
2659 for (i=0; i<ni; i++) {
2660 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
2663 /* create the meta data value */
2664 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
2665 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2667 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2668 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2669 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2670 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2674 * when we know that we'll modify the record, add the whenChanged, uSNChanged
2675 * and replPopertyMetaData attributes
2677 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2678 if (ret != LDB_SUCCESS) {
2679 return replmd_replicated_request_error(ar, ret);
2681 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2682 if (ret != LDB_SUCCESS) {
2683 return replmd_replicated_request_error(ar, ret);
2685 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
2686 if (ret != LDB_SUCCESS) {
2687 return replmd_replicated_request_error(ar, ret);
2690 replmd_ldb_message_sort(msg, ar->schema);
2692 /* we want to replace the old values */
2693 for (i=0; i < msg->num_elements; i++) {
2694 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2698 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
2699 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
2703 ret = ldb_build_mod_req(&change_req,
2711 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2713 return ldb_next_request(ar->module, change_req);
2716 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
2717 struct ldb_reply *ares)
2719 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2720 struct replmd_replicated_request);
2724 return ldb_module_done(ar->req, NULL, NULL,
2725 LDB_ERR_OPERATIONS_ERROR);
2727 if (ares->error != LDB_SUCCESS &&
2728 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
2729 return ldb_module_done(ar->req, ares->controls,
2730 ares->response, ares->error);
2733 switch (ares->type) {
2734 case LDB_REPLY_ENTRY:
2735 ar->search_msg = talloc_steal(ar, ares->message);
2738 case LDB_REPLY_REFERRAL:
2739 /* we ignore referrals */
2742 case LDB_REPLY_DONE:
2743 if (ar->search_msg != NULL) {
2744 ret = replmd_replicated_apply_merge(ar);
2746 ret = replmd_replicated_apply_add(ar);
2748 if (ret != LDB_SUCCESS) {
2749 return ldb_module_done(ar->req, NULL, NULL, ret);
2757 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
2759 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
2761 struct ldb_context *ldb;
2765 struct ldb_request *search_req;
2766 struct ldb_search_options_control *options;
2768 if (ar->index_current >= ar->objs->num_objects) {
2769 /* done with it, go to next stage */
2770 return replmd_replicated_uptodate_vector(ar);
2773 ldb = ldb_module_get_ctx(ar->module);
2774 ar->search_msg = NULL;
2776 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
2777 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2779 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
2780 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2781 talloc_free(tmp_str);
2783 ret = ldb_build_search_req(&search_req,
2792 replmd_replicated_apply_search_callback,
2795 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2796 if (ret != LDB_SUCCESS) {
2800 /* we need to cope with cross-partition links, so search for
2801 the GUID over all partitions */
2802 options = talloc(search_req, struct ldb_search_options_control);
2803 if (options == NULL) {
2804 DEBUG(0, (__location__ ": out of memory\n"));
2805 return LDB_ERR_OPERATIONS_ERROR;
2807 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2809 ret = ldb_request_add_control(search_req,
2810 LDB_CONTROL_SEARCH_OPTIONS_OID,
2812 if (ret != LDB_SUCCESS) {
2816 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2818 return ldb_next_request(ar->module, search_req);
2821 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
2822 struct ldb_reply *ares)
2824 struct ldb_context *ldb;
2825 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2826 struct replmd_replicated_request);
2827 ldb = ldb_module_get_ctx(ar->module);
2830 return ldb_module_done(ar->req, NULL, NULL,
2831 LDB_ERR_OPERATIONS_ERROR);
2833 if (ares->error != LDB_SUCCESS) {
2834 return ldb_module_done(ar->req, ares->controls,
2835 ares->response, ares->error);
2838 if (ares->type != LDB_REPLY_DONE) {
2839 ldb_set_errstring(ldb, "Invalid reply type\n!");
2840 return ldb_module_done(ar->req, NULL, NULL,
2841 LDB_ERR_OPERATIONS_ERROR);
2846 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
2849 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
2851 struct ldb_context *ldb;
2852 struct ldb_request *change_req;
2853 enum ndr_err_code ndr_err;
2854 struct ldb_message *msg;
2855 struct replUpToDateVectorBlob ouv;
2856 const struct ldb_val *ouv_value;
2857 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
2858 struct replUpToDateVectorBlob nuv;
2859 struct ldb_val nuv_value;
2860 struct ldb_message_element *nuv_el = NULL;
2861 const struct GUID *our_invocation_id;
2862 struct ldb_message_element *orf_el = NULL;
2863 struct repsFromToBlob nrf;
2864 struct ldb_val *nrf_value = NULL;
2865 struct ldb_message_element *nrf_el = NULL;
2868 time_t t = time(NULL);
2872 ldb = ldb_module_get_ctx(ar->module);
2873 ruv = ar->objs->uptodateness_vector;
2879 unix_to_nt_time(&now, t);
2882 * first create the new replUpToDateVector
2884 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
2886 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
2887 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
2888 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
2889 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2890 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2891 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2894 if (ouv.version != 2) {
2895 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2900 * the new uptodateness vector will at least
2901 * contain 1 entry, one for the source_dsa
2903 * plus optional values from our old vector and the one from the source_dsa
2905 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
2906 if (ruv) nuv.ctr.ctr2.count += ruv->count;
2907 nuv.ctr.ctr2.cursors = talloc_array(ar,
2908 struct drsuapi_DsReplicaCursor2,
2909 nuv.ctr.ctr2.count);
2910 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2912 /* first copy the old vector */
2913 for (i=0; i < ouv.ctr.ctr2.count; i++) {
2914 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
2918 /* get our invocation_id if we have one already attached to the ldb */
2919 our_invocation_id = samdb_ntds_invocation_id(ldb);
2921 /* merge in the source_dsa vector is available */
2922 for (i=0; (ruv && i < ruv->count); i++) {
2925 if (our_invocation_id &&
2926 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
2927 our_invocation_id)) {
2931 for (j=0; j < ni; j++) {
2932 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
2933 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
2940 * we update only the highest_usn and not the latest_sync_success time,
2941 * because the last success stands for direct replication
2943 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
2944 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
2949 if (found) continue;
2951 /* if it's not there yet, add it */
2952 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
2957 * merge in the current highwatermark for the source_dsa
2960 for (j=0; j < ni; j++) {
2961 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
2962 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
2969 * here we update the highest_usn and last_sync_success time
2970 * because we're directly replicating from the source_dsa
2972 * and use the tmp_highest_usn because this is what we have just applied
2975 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
2976 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
2981 * here we update the highest_usn and last_sync_success time
2982 * because we're directly replicating from the source_dsa
2984 * and use the tmp_highest_usn because this is what we have just applied
2987 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
2988 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
2989 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
2994 * finally correct the size of the cursors array
2996 nuv.ctr.ctr2.count = ni;
3001 qsort(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count,
3002 sizeof(struct drsuapi_DsReplicaCursor2),
3003 (comparison_fn_t)drsuapi_DsReplicaCursor2_compare);
3006 * create the change ldb_message
3008 msg = ldb_msg_new(ar);
3009 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3010 msg->dn = ar->search_msg->dn;
3012 ndr_err = ndr_push_struct_blob(&nuv_value, msg,
3013 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3015 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
3016 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3017 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3018 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3020 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
3021 if (ret != LDB_SUCCESS) {
3022 return replmd_replicated_request_error(ar, ret);
3024 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
3027 * now create the new repsFrom value from the given repsFromTo1 structure
3031 nrf.ctr.ctr1 = *ar->objs->source_dsa;
3032 /* and fix some values... */
3033 nrf.ctr.ctr1.consecutive_sync_failures = 0;
3034 nrf.ctr.ctr1.last_success = now;
3035 nrf.ctr.ctr1.last_attempt = now;
3036 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
3037 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
3040 * first see if we already have a repsFrom value for the current source dsa
3041 * if so we'll later replace this value
3043 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
3045 for (i=0; i < orf_el->num_values; i++) {
3046 struct repsFromToBlob *trf;
3048 trf = talloc(ar, struct repsFromToBlob);
3049 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3051 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
3052 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3053 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3054 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3055 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3058 if (trf->version != 1) {
3059 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3063 * we compare the source dsa objectGUID not the invocation_id
3064 * because we want only one repsFrom value per source dsa
3065 * and when the invocation_id of the source dsa has changed we don't need
3066 * the old repsFrom with the old invocation_id
3068 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
3069 &ar->objs->source_dsa->source_dsa_obj_guid)) {
3075 nrf_value = &orf_el->values[i];
3080 * copy over all old values to the new ldb_message
3082 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
3083 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3088 * if we haven't found an old repsFrom value for the current source dsa
3089 * we'll add a new value
3092 struct ldb_val zero_value;
3093 ZERO_STRUCT(zero_value);
3094 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
3095 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3097 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
3100 /* we now fill the value which is already attached to ldb_message */
3101 ndr_err = ndr_push_struct_blob(nrf_value, msg,
3102 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3104 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3105 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3106 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3107 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3111 * the ldb_message_element for the attribute, has all the old values and the new one
3112 * so we'll replace the whole attribute with all values
3114 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
3117 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3118 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
3122 /* prepare the ldb_modify() request */
3123 ret = ldb_build_mod_req(&change_req,
3129 replmd_replicated_uptodate_modify_callback,
3131 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3133 return ldb_next_request(ar->module, change_req);
3136 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
3137 struct ldb_reply *ares)
3139 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3140 struct replmd_replicated_request);
3144 return ldb_module_done(ar->req, NULL, NULL,
3145 LDB_ERR_OPERATIONS_ERROR);
3147 if (ares->error != LDB_SUCCESS &&
3148 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3149 return ldb_module_done(ar->req, ares->controls,
3150 ares->response, ares->error);
3153 switch (ares->type) {
3154 case LDB_REPLY_ENTRY:
3155 ar->search_msg = talloc_steal(ar, ares->message);
3158 case LDB_REPLY_REFERRAL:
3159 /* we ignore referrals */
3162 case LDB_REPLY_DONE:
3163 if (ar->search_msg == NULL) {
3164 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3166 ret = replmd_replicated_uptodate_modify(ar);
3168 if (ret != LDB_SUCCESS) {
3169 return ldb_module_done(ar->req, NULL, NULL, ret);
3178 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
3180 struct ldb_context *ldb;
3182 static const char *attrs[] = {
3183 "replUpToDateVector",
3187 struct ldb_request *search_req;
3189 ldb = ldb_module_get_ctx(ar->module);
3190 ar->search_msg = NULL;
3192 ret = ldb_build_search_req(&search_req,
3195 ar->objs->partition_dn,
3201 replmd_replicated_uptodate_search_callback,
3203 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3205 return ldb_next_request(ar->module, search_req);
3210 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
3212 struct ldb_context *ldb;
3213 struct dsdb_extended_replicated_objects *objs;
3214 struct replmd_replicated_request *ar;
3215 struct ldb_control **ctrls;
3217 struct replmd_private *replmd_private =
3218 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3220 ldb = ldb_module_get_ctx(module);
3222 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
3224 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
3226 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
3227 return LDB_ERR_PROTOCOL_ERROR;
3230 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
3231 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
3232 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
3233 return LDB_ERR_PROTOCOL_ERROR;
3236 ar = replmd_ctx_init(module, req);
3238 return LDB_ERR_OPERATIONS_ERROR;
3240 /* Set the flags to have the replmd_op_callback run over the full set of objects */
3241 ar->apply_mode = true;
3243 ar->schema = dsdb_get_schema(ldb);
3245 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
3247 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3248 return LDB_ERR_CONSTRAINT_VIOLATION;
3251 ctrls = req->controls;
3253 if (req->controls) {
3254 req->controls = talloc_memdup(ar, req->controls,
3255 talloc_get_size(req->controls));
3256 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3259 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
3260 if (ret != LDB_SUCCESS) {
3264 ar->controls = req->controls;
3265 req->controls = ctrls;
3267 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
3269 /* save away the linked attributes for the end of the
3271 for (i=0; i<ar->objs->linked_attributes_count; i++) {
3272 struct la_entry *la_entry;
3274 if (replmd_private->la_ctx == NULL) {
3275 replmd_private->la_ctx = talloc_new(replmd_private);
3277 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
3278 if (la_entry == NULL) {
3280 return LDB_ERR_OPERATIONS_ERROR;
3282 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
3283 if (la_entry->la == NULL) {
3284 talloc_free(la_entry);
3286 return LDB_ERR_OPERATIONS_ERROR;
3288 *la_entry->la = ar->objs->linked_attributes[i];
3290 /* we need to steal the non-scalars so they stay
3291 around until the end of the transaction */
3292 talloc_steal(la_entry->la, la_entry->la->identifier);
3293 talloc_steal(la_entry->la, la_entry->la->value.blob);
3295 DLIST_ADD(replmd_private->la_list, la_entry);
3298 return replmd_replicated_apply_next(ar);
3302 process one linked attribute structure
3304 static int replmd_process_linked_attribute(struct ldb_module *module,
3305 struct la_entry *la_entry)
3307 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
3308 struct ldb_context *ldb = ldb_module_get_ctx(module);
3309 struct dsdb_schema *schema = dsdb_get_schema(ldb);
3310 struct ldb_message *msg;
3311 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
3313 const struct dsdb_attribute *attr;
3314 struct dsdb_dn *dsdb_dn;
3315 uint64_t seq_num = 0;
3316 struct drsuapi_DsReplicaAttribute drs;
3317 struct drsuapi_DsAttributeValue val;
3318 struct ldb_message_element new_el, *old_el;
3320 time_t t = time(NULL);
3321 struct ldb_result *res;
3322 const char *attrs[2];
3323 struct parsed_dn *pdn_list, *pdn;
3326 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
3327 const struct GUID *our_invocation_id;
3329 drs.value_ctr.num_values = 1;
3330 drs.value_ctr.values = &val;
3331 val.blob = la->value.blob;
3334 linked_attributes[0]:
3335 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
3337 identifier: struct drsuapi_DsReplicaObjectIdentifier
3338 __ndr_size : 0x0000003a (58)
3339 __ndr_size_sid : 0x00000000 (0)
3340 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
3342 __ndr_size_dn : 0x00000000 (0)
3344 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
3345 value: struct drsuapi_DsAttributeValue
3346 __ndr_size : 0x0000007e (126)
3348 blob : DATA_BLOB length=126
3349 flags : 0x00000001 (1)
3350 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
3351 originating_add_time : Wed Sep 2 22:20:01 2009 EST
3352 meta_data: struct drsuapi_DsReplicaMetaData
3353 version : 0x00000015 (21)
3354 originating_change_time : Wed Sep 2 23:39:07 2009 EST
3355 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
3356 originating_usn : 0x000000000001e19c (123292)
3358 (for cases where the link is to a normal DN)
3359 &target: struct drsuapi_DsReplicaObjectIdentifier3
3360 __ndr_size : 0x0000007e (126)
3361 __ndr_size_sid : 0x0000001c (28)
3362 guid : 7639e594-db75-4086-b0d4-67890ae46031
3363 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
3364 __ndr_size_dn : 0x00000022 (34)
3365 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
3368 /* find the attribute being modified */
3369 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
3371 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
3372 talloc_free(tmp_ctx);
3373 return LDB_ERR_OPERATIONS_ERROR;
3376 attrs[0] = attr->lDAPDisplayName;
3379 /* get the existing message from the db for the object with
3380 this GUID, returning attribute being modified. We will then
3381 use this msg as the basis for a modify call */
3382 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3383 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3384 DSDB_SEARCH_SHOW_DELETED |
3385 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3386 DSDB_SEARCH_REVEAL_INTERNALS,
3387 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
3388 if (ret != LDB_SUCCESS) {
3389 talloc_free(tmp_ctx);
3392 if (res->count != 1) {
3393 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
3394 GUID_string(tmp_ctx, &la->identifier->guid));
3395 talloc_free(tmp_ctx);
3396 return LDB_ERR_NO_SUCH_OBJECT;
3400 if (msg->num_elements == 0) {
3401 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
3402 if (ret != LDB_SUCCESS) {
3403 ldb_module_oom(module);
3404 talloc_free(tmp_ctx);
3405 return LDB_ERR_OPERATIONS_ERROR;
3408 old_el = &msg->elements[0];
3409 old_el->flags = LDB_FLAG_MOD_REPLACE;
3412 /* parse the existing links */
3413 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid);
3414 if (ret != LDB_SUCCESS) {
3415 talloc_free(tmp_ctx);
3419 /* get our invocationId */
3420 our_invocation_id = samdb_ntds_invocation_id(ldb);
3421 if (!our_invocation_id) {
3422 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
3423 talloc_free(tmp_ctx);
3424 return LDB_ERR_OPERATIONS_ERROR;
3427 ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, our_invocation_id);
3428 if (ret != LDB_SUCCESS) {
3429 talloc_free(tmp_ctx);
3433 status = attr->syntax->drsuapi_to_ldb(ldb, schema, attr, &drs, tmp_ctx, &new_el);
3434 if (!W_ERROR_IS_OK(status)) {
3435 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s\n",
3436 old_el->name, ldb_dn_get_linearized(msg->dn));
3437 return LDB_ERR_OPERATIONS_ERROR;
3440 if (new_el.num_values != 1) {
3441 ldb_asprintf_errstring(ldb, "Failed to find value in linked attribute blob for %s on %s\n",
3442 old_el->name, ldb_dn_get_linearized(msg->dn));
3443 return LDB_ERR_OPERATIONS_ERROR;
3446 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &new_el.values[0], attr->syntax->ldap_oid);
3448 ldb_asprintf_errstring(ldb, "Failed to parse DN in linked attribute blob for %s on %s\n",
3449 old_el->name, ldb_dn_get_linearized(msg->dn));
3450 return LDB_ERR_OPERATIONS_ERROR;
3453 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
3454 if (!NT_STATUS_IS_OK(ntstatus)) {
3455 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s\n",
3456 old_el->name, ldb_dn_get_linearized(msg->dn));
3457 return LDB_ERR_OPERATIONS_ERROR;
3460 /* see if this link already exists */
3461 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid);
3463 /* see if this update is newer than what we have already */
3464 struct GUID invocation_id = GUID_zero();
3465 uint32_t version = 0;
3466 NTTIME change_time = 0;
3467 bool was_active = ldb_dn_get_extended_component(pdn->dsdb_dn->dn, "DELETED") == NULL;
3469 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
3470 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
3471 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
3473 if (!replmd_update_is_newer(&invocation_id,
3474 &la->meta_data.originating_invocation_id,
3476 la->meta_data.version,
3478 la->meta_data.originating_change_time)) {
3479 DEBUG(1,("Discarding older DRS linked attribute update to %s on %s from %s\n",
3480 old_el->name, ldb_dn_get_linearized(msg->dn),
3481 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
3482 talloc_free(tmp_ctx);
3486 /* get a seq_num for this change */
3487 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3488 if (ret != LDB_SUCCESS) {
3489 talloc_free(tmp_ctx);
3494 /* remove the existing backlink */
3495 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
3496 if (ret != LDB_SUCCESS) {
3497 talloc_free(tmp_ctx);
3502 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
3503 &la->meta_data.originating_invocation_id,
3504 la->meta_data.originating_usn, seq_num,
3505 la->meta_data.originating_change_time,
3506 la->meta_data.version,
3508 if (ret != LDB_SUCCESS) {
3509 talloc_free(tmp_ctx);
3514 /* add the new backlink */
3515 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
3516 if (ret != LDB_SUCCESS) {
3517 talloc_free(tmp_ctx);
3522 /* get a seq_num for this change */
3523 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3524 if (ret != LDB_SUCCESS) {
3525 talloc_free(tmp_ctx);
3529 old_el->values = talloc_realloc(msg->elements, old_el->values,
3530 struct ldb_val, old_el->num_values+1);
3531 if (!old_el->values) {
3532 ldb_module_oom(module);
3533 return LDB_ERR_OPERATIONS_ERROR;
3535 old_el->num_values++;
3537 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
3538 &la->meta_data.originating_invocation_id,
3539 la->meta_data.originating_usn, seq_num,
3540 la->meta_data.originating_change_time,
3541 la->meta_data.version,
3542 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
3543 if (ret != LDB_SUCCESS) {
3544 talloc_free(tmp_ctx);
3549 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
3551 if (ret != LDB_SUCCESS) {
3552 talloc_free(tmp_ctx);
3558 /* we only change whenChanged and uSNChanged if the seq_num
3560 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
3561 talloc_free(tmp_ctx);
3562 return LDB_ERR_OPERATIONS_ERROR;
3565 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
3566 talloc_free(tmp_ctx);
3567 return LDB_ERR_OPERATIONS_ERROR;
3570 ret = dsdb_check_single_valued_link(attr, old_el);
3571 if (ret != LDB_SUCCESS) {
3572 talloc_free(tmp_ctx);
3576 ret = dsdb_module_modify(module, msg, DSDB_MODIFY_RELAX);
3577 if (ret != LDB_SUCCESS) {
3578 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
3580 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
3581 talloc_free(tmp_ctx);
3585 talloc_free(tmp_ctx);
3590 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
3592 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
3593 return replmd_extended_replicated_objects(module, req);
3596 return ldb_next_request(module, req);
3601 we hook into the transaction operations to allow us to
3602 perform the linked attribute updates at the end of the whole
3603 transaction. This allows a forward linked attribute to be created
3604 before the object is created. During a vampire, w2k8 sends us linked
3605 attributes before the objects they are part of.
3607 static int replmd_start_transaction(struct ldb_module *module)
3609 /* create our private structure for this transaction */
3610 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
3611 struct replmd_private);
3612 replmd_txn_cleanup(replmd_private);
3614 /* free any leftover mod_usn records from cancelled
3616 while (replmd_private->ncs) {
3617 struct nc_entry *e = replmd_private->ncs;
3618 DLIST_REMOVE(replmd_private->ncs, e);
3622 return ldb_next_start_trans(module);
3626 on prepare commit we loop over our queued la_context structures and
3629 static int replmd_prepare_commit(struct ldb_module *module)
3631 struct replmd_private *replmd_private =
3632 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3633 struct la_entry *la, *prev;
3634 struct la_backlink *bl;
3637 /* walk the list backwards, to do the first entry first, as we
3638 * added the entries with DLIST_ADD() which puts them at the
3639 * start of the list */
3640 for (la = replmd_private->la_list; la && la->next; la=la->next) ;
3642 for (; la; la=prev) {
3644 DLIST_REMOVE(replmd_private->la_list, la);
3645 ret = replmd_process_linked_attribute(module, la);
3646 if (ret != LDB_SUCCESS) {
3647 replmd_txn_cleanup(replmd_private);
3652 /* process our backlink list, creating and deleting backlinks
3654 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
3655 ret = replmd_process_backlink(module, bl);
3656 if (ret != LDB_SUCCESS) {
3657 replmd_txn_cleanup(replmd_private);
3662 replmd_txn_cleanup(replmd_private);
3664 /* possibly change @REPLCHANGED */
3665 ret = replmd_notify_store(module);
3666 if (ret != LDB_SUCCESS) {
3670 return ldb_next_prepare_commit(module);
3673 static int replmd_del_transaction(struct ldb_module *module)
3675 struct replmd_private *replmd_private =
3676 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3677 replmd_txn_cleanup(replmd_private);
3679 return ldb_next_del_trans(module);
3683 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
3684 .name = "repl_meta_data",
3685 .init_context = replmd_init,
3687 .modify = replmd_modify,
3688 .rename = replmd_rename,
3689 .del = replmd_delete,
3690 .extended = replmd_extended,
3691 .start_transaction = replmd_start_transaction,
3692 .prepare_commit = replmd_prepare_commit,
3693 .del_transaction = replmd_del_transaction,