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, time_t t);
586 fix up linked attributes in replmd_add.
587 This involves setting up the right meta-data in extended DN
588 components, and creating backlinks to the object
590 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
591 uint64_t seq_num, const struct GUID *invocationId, time_t t,
592 struct GUID *guid, const struct dsdb_attribute *sa)
595 TALLOC_CTX *tmp_ctx = talloc_new(el->values);
596 struct ldb_context *ldb = ldb_module_get_ctx(module);
597 struct dsdb_schema *schema = dsdb_get_schema(ldb);
599 for (i=0; i<el->num_values; i++) {
600 struct ldb_val *v = &el->values[i];
601 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
602 struct GUID target_guid;
606 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId, seq_num, t);
607 if (ret != LDB_SUCCESS) {
608 talloc_free(tmp_ctx);
612 /* note that the DN already has the extended
613 components from the extended_dn_store module */
614 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid);
615 if (!NT_STATUS_IS_OK(status)) {
616 talloc_free(tmp_ctx);
617 return LDB_ERR_OPERATIONS_ERROR;
620 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
621 if (ret != LDB_SUCCESS) {
622 talloc_free(tmp_ctx);
627 talloc_free(tmp_ctx);
633 intercept add requests
635 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
637 struct ldb_context *ldb;
638 struct ldb_control *control;
639 struct replmd_replicated_request *ac;
640 enum ndr_err_code ndr_err;
641 struct ldb_request *down_req;
642 struct ldb_message *msg;
643 const DATA_BLOB *guid_blob;
645 struct replPropertyMetaDataBlob nmd;
646 struct ldb_val nmd_value;
647 const struct GUID *our_invocation_id;
648 time_t t = time(NULL);
653 bool allow_add_guid = false;
654 bool remove_current_guid = false;
656 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
657 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
662 /* do not manipulate our control entries */
663 if (ldb_dn_is_special(req->op.add.message->dn)) {
664 return ldb_next_request(module, req);
667 ldb = ldb_module_get_ctx(module);
669 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
671 ac = replmd_ctx_init(module, req);
673 return LDB_ERR_OPERATIONS_ERROR;
676 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
677 if ( guid_blob != NULL ) {
678 if( !allow_add_guid ) {
679 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
680 "replmd_add: it's not allowed to add an object with objectGUID\n");
682 return LDB_ERR_UNWILLING_TO_PERFORM;
684 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
685 if ( !NT_STATUS_IS_OK(status)) {
686 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
687 "replmd_add: Unable to parse as a GUID the attribute objectGUID\n");
689 return LDB_ERR_UNWILLING_TO_PERFORM;
691 /* we remove this attribute as it can be a string and will not be treated
692 correctly and then we will readd it latter on in the good format*/
693 remove_current_guid = true;
697 guid = GUID_random();
700 /* Get a sequence number from the backend */
701 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
702 if (ret != LDB_SUCCESS) {
707 /* get our invocationId */
708 our_invocation_id = samdb_ntds_invocation_id(ldb);
709 if (!our_invocation_id) {
710 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
711 "replmd_add: unable to find invocationId\n");
713 return LDB_ERR_OPERATIONS_ERROR;
716 /* we have to copy the message as the caller might have it as a const */
717 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
721 return LDB_ERR_OPERATIONS_ERROR;
724 /* generated times */
725 unix_to_nt_time(&now, t);
726 time_str = ldb_timestring(msg, t);
730 return LDB_ERR_OPERATIONS_ERROR;
732 if (remove_current_guid) {
733 ldb_msg_remove_attr(msg,"objectGUID");
737 * remove autogenerated attributes
739 ldb_msg_remove_attr(msg, "whenCreated");
740 ldb_msg_remove_attr(msg, "whenChanged");
741 ldb_msg_remove_attr(msg, "uSNCreated");
742 ldb_msg_remove_attr(msg, "uSNChanged");
743 ldb_msg_remove_attr(msg, "replPropertyMetaData");
746 * readd replicated attributes
748 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
749 if (ret != LDB_SUCCESS) {
755 /* build the replication meta_data */
758 nmd.ctr.ctr1.count = msg->num_elements;
759 nmd.ctr.ctr1.array = talloc_array(msg,
760 struct replPropertyMetaData1,
762 if (!nmd.ctr.ctr1.array) {
765 return LDB_ERR_OPERATIONS_ERROR;
768 for (i=0; i < msg->num_elements; i++) {
769 struct ldb_message_element *e = &msg->elements[i];
770 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
771 const struct dsdb_attribute *sa;
773 if (e->name[0] == '@') continue;
775 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
777 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
778 "replmd_add: attribute '%s' not defined in schema\n",
781 return LDB_ERR_NO_SUCH_ATTRIBUTE;
784 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
785 /* if the attribute is not replicated (0x00000001)
786 * or constructed (0x00000004) it has no metadata
791 #if W2K3_LINKED_ATTRIBUTES
792 if (sa->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
793 ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa);
794 if (ret != LDB_SUCCESS) {
798 /* linked attributes are not stored in
799 replPropertyMetaData in FL above w2k */
804 m->attid = sa->attributeID_id;
806 m->originating_change_time = now;
807 m->originating_invocation_id = *our_invocation_id;
808 m->originating_usn = ac->seq_num;
809 m->local_usn = ac->seq_num;
813 /* fix meta data count */
814 nmd.ctr.ctr1.count = ni;
817 * sort meta data array, and move the rdn attribute entry to the end
819 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
820 if (ret != LDB_SUCCESS) {
825 /* generated NDR encoded values */
826 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
827 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
829 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
830 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
833 return LDB_ERR_OPERATIONS_ERROR;
837 * add the autogenerated values
839 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
840 if (ret != LDB_SUCCESS) {
845 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
846 if (ret != LDB_SUCCESS) {
851 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
852 if (ret != LDB_SUCCESS) {
857 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
858 if (ret != LDB_SUCCESS) {
863 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
864 if (ret != LDB_SUCCESS) {
871 * sort the attributes by attid before storing the object
873 replmd_ldb_message_sort(msg, ac->schema);
875 ret = ldb_build_add_req(&down_req, ldb, ac,
878 ac, replmd_op_callback,
880 if (ret != LDB_SUCCESS) {
885 /* mark the control done */
887 control->critical = 0;
890 /* go on with the call chain */
891 return ldb_next_request(module, down_req);
896 * update the replPropertyMetaData for one element
898 static int replmd_update_rpmd_element(struct ldb_context *ldb,
899 struct ldb_message *msg,
900 struct ldb_message_element *el,
901 struct replPropertyMetaDataBlob *omd,
902 const struct dsdb_schema *schema,
904 const struct GUID *our_invocation_id,
908 const struct dsdb_attribute *a;
909 struct replPropertyMetaData1 *md1;
911 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
913 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
915 return LDB_ERR_OPERATIONS_ERROR;
918 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
922 for (i=0; i<omd->ctr.ctr1.count; i++) {
923 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
926 #if W2K3_LINKED_ATTRIBUTES
927 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
928 /* linked attributes are not stored in
929 replPropertyMetaData in FL above w2k, but we do
930 raise the seqnum for the object */
932 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
933 return LDB_ERR_OPERATIONS_ERROR;
939 if (i == omd->ctr.ctr1.count) {
940 /* we need to add a new one */
941 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
942 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
943 if (omd->ctr.ctr1.array == NULL) {
945 return LDB_ERR_OPERATIONS_ERROR;
947 omd->ctr.ctr1.count++;
948 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
951 /* Get a new sequence number from the backend. We only do this
952 * if we have a change that requires a new
953 * replPropertyMetaData element
956 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
957 if (ret != LDB_SUCCESS) {
958 return LDB_ERR_OPERATIONS_ERROR;
962 md1 = &omd->ctr.ctr1.array[i];
964 md1->attid = a->attributeID_id;
965 md1->originating_change_time = now;
966 md1->originating_invocation_id = *our_invocation_id;
967 md1->originating_usn = *seq_num;
968 md1->local_usn = *seq_num;
974 * update the replPropertyMetaData object each time we modify an
975 * object. This is needed for DRS replication, as the merge on the
976 * client is based on this object
978 static int replmd_update_rpmd(struct ldb_module *module,
979 const struct dsdb_schema *schema,
980 struct ldb_message *msg, uint64_t *seq_num,
983 const struct ldb_val *omd_value;
984 enum ndr_err_code ndr_err;
985 struct replPropertyMetaDataBlob omd;
988 const struct GUID *our_invocation_id;
990 const char *attrs[] = { "replPropertyMetaData" , NULL };
991 struct ldb_result *res;
992 struct ldb_context *ldb;
994 ldb = ldb_module_get_ctx(module);
996 our_invocation_id = samdb_ntds_invocation_id(ldb);
997 if (!our_invocation_id) {
998 /* this happens during an initial vampire while
999 updating the schema */
1000 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1004 unix_to_nt_time(&now, t);
1006 /* search for the existing replPropertyMetaDataBlob */
1007 ret = dsdb_search_dn_with_deleted(ldb, msg, &res, msg->dn, attrs);
1008 if (ret != LDB_SUCCESS || res->count != 1) {
1009 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1010 ldb_dn_get_linearized(msg->dn)));
1011 return LDB_ERR_OPERATIONS_ERROR;
1015 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1017 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1018 ldb_dn_get_linearized(msg->dn)));
1019 return LDB_ERR_OPERATIONS_ERROR;
1022 ndr_err = ndr_pull_struct_blob(omd_value, msg,
1023 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
1024 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1025 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1026 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1027 ldb_dn_get_linearized(msg->dn)));
1028 return LDB_ERR_OPERATIONS_ERROR;
1031 if (omd.version != 1) {
1032 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1033 omd.version, ldb_dn_get_linearized(msg->dn)));
1034 return LDB_ERR_OPERATIONS_ERROR;
1037 for (i=0; i<msg->num_elements; i++) {
1038 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], &omd, schema, seq_num,
1039 our_invocation_id, now);
1040 if (ret != LDB_SUCCESS) {
1046 * replmd_update_rpmd_element has done an update if the
1049 if (*seq_num != 0) {
1050 struct ldb_val *md_value;
1051 struct ldb_message_element *el;
1053 md_value = talloc(msg, struct ldb_val);
1054 if (md_value == NULL) {
1056 return LDB_ERR_OPERATIONS_ERROR;
1059 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1060 if (ret != LDB_SUCCESS) {
1064 ndr_err = ndr_push_struct_blob(md_value, msg,
1065 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1067 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1068 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1069 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1070 ldb_dn_get_linearized(msg->dn)));
1071 return LDB_ERR_OPERATIONS_ERROR;
1074 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1075 if (ret != LDB_SUCCESS) {
1076 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1077 ldb_dn_get_linearized(msg->dn)));
1082 el->values = md_value;
1090 struct dsdb_dn *dsdb_dn;
1095 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1097 return GUID_compare(pdn1->guid, pdn2->guid);
1100 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid)
1102 struct parsed_dn *ret;
1103 BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1108 get a series of message element values as an array of DNs and GUIDs
1109 the result is sorted by GUID
1111 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1112 struct ldb_message_element *el, struct parsed_dn **pdn,
1113 const char *ldap_oid)
1116 struct ldb_context *ldb = ldb_module_get_ctx(module);
1123 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1125 ldb_module_oom(module);
1126 return LDB_ERR_OPERATIONS_ERROR;
1129 for (i=0; i<el->num_values; i++) {
1130 struct ldb_val *v = &el->values[i];
1133 struct parsed_dn *p;
1137 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1138 if (p->dsdb_dn == NULL) {
1139 return LDB_ERR_INVALID_DN_SYNTAX;
1142 dn = p->dsdb_dn->dn;
1144 p->guid = talloc(*pdn, struct GUID);
1145 if (p->guid == NULL) {
1146 ldb_module_oom(module);
1147 return LDB_ERR_OPERATIONS_ERROR;
1150 status = dsdb_get_extended_dn_guid(dn, p->guid);
1151 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1152 /* we got a DN without a GUID - go find the GUID */
1153 int ret = dsdb_find_guid_by_dn(ldb, dn, p->guid);
1154 if (ret != LDB_SUCCESS) {
1155 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1156 ldb_dn_get_linearized(dn));
1159 } else if (!NT_STATUS_IS_OK(status)) {
1160 return LDB_ERR_OPERATIONS_ERROR;
1163 /* keep a pointer to the original ldb_val */
1167 qsort(*pdn, el->num_values, sizeof((*pdn)[0]), (comparison_fn_t)parsed_dn_compare);
1173 build a new extended DN, including all meta data fields
1175 DELETED = 1 or missing
1176 RMD_ADDTIME = originating_add_time
1177 RMD_INVOCID = originating_invocation_id
1178 RMD_CHANGETIME = originating_change_time
1179 RMD_USN = originating_usn
1180 RMD_VERSION = version
1182 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1183 const struct GUID *invocation_id, uint64_t seq_num, time_t t)
1185 struct ldb_dn *dn = dsdb_dn->dn;
1187 const char *tstring, *usn_string;
1188 struct ldb_val tval;
1190 struct ldb_val usnv;
1191 struct ldb_val vers;
1194 const char *dnstring;
1196 unix_to_nt_time(&now, t);
1197 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)now);
1199 return LDB_ERR_OPERATIONS_ERROR;
1201 tval = data_blob_string_const(tstring);
1203 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1205 return LDB_ERR_OPERATIONS_ERROR;
1207 usnv = data_blob_string_const(usn_string);
1209 vers = data_blob_string_const("0");
1211 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1212 if (!NT_STATUS_IS_OK(status)) {
1213 return LDB_ERR_OPERATIONS_ERROR;
1216 ret = ldb_dn_set_extended_component(dn, "DELETED", NULL);
1217 if (ret != LDB_SUCCESS) return ret;
1218 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1219 if (ret != LDB_SUCCESS) return ret;
1220 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1221 if (ret != LDB_SUCCESS) return ret;
1222 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1223 if (ret != LDB_SUCCESS) return ret;
1224 ret = ldb_dn_set_extended_component(dn, "RMD_USN", &usnv);
1225 if (ret != LDB_SUCCESS) return ret;
1226 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1227 if (ret != LDB_SUCCESS) return ret;
1229 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1230 if (dnstring == NULL) {
1231 return LDB_ERR_OPERATIONS_ERROR;
1233 *v = data_blob_string_const(dnstring);
1240 update an extended DN, including all meta data fields
1242 see replmd_build_la_val for value names
1244 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1245 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1246 uint64_t seq_num, time_t t, bool deleted)
1248 struct ldb_dn *dn = dsdb_dn->dn;
1250 const char *tstring, *usn_string;
1251 struct ldb_val tval;
1253 struct ldb_val usnv;
1254 struct ldb_val vers;
1255 const struct ldb_val *old_addtime, *old_version;
1258 const char *dnstring;
1260 unix_to_nt_time(&now, t);
1261 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)now);
1263 return LDB_ERR_OPERATIONS_ERROR;
1265 tval = data_blob_string_const(tstring);
1267 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1269 return LDB_ERR_OPERATIONS_ERROR;
1271 usnv = data_blob_string_const(usn_string);
1273 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1274 if (!NT_STATUS_IS_OK(status)) {
1275 return LDB_ERR_OPERATIONS_ERROR;
1280 dv = data_blob_string_const("1");
1281 ret = ldb_dn_set_extended_component(dn, "DELETED", &dv);
1283 ret = ldb_dn_set_extended_component(dn, "DELETED", NULL);
1285 if (ret != LDB_SUCCESS) return ret;
1287 /* get the ADDTIME from the original */
1288 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1289 if (old_addtime == NULL) {
1290 old_addtime = &tval;
1292 if (dsdb_dn != old_dsdb_dn) {
1293 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1294 if (ret != LDB_SUCCESS) return ret;
1297 /* use our invocation id */
1298 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1299 if (ret != LDB_SUCCESS) return ret;
1301 /* changetime is the current time */
1302 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1303 if (ret != LDB_SUCCESS) return ret;
1305 /* update the USN */
1306 ret = ldb_dn_set_extended_component(dn, "RMD_USN", &usnv);
1307 if (ret != LDB_SUCCESS) return ret;
1309 /* increase the version by 1 */
1310 old_version = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_VERSION");
1311 if (old_version == NULL) {
1312 vers = data_blob_string_const("0");
1315 vstring = talloc_strndup(dn, (const char *)old_version->data, old_version->length);
1317 return LDB_ERR_OPERATIONS_ERROR;
1319 vstring = talloc_asprintf(dn, "%lu",
1320 (unsigned long)strtoul(vstring, NULL, 0)+1);
1321 vers = data_blob_string_const(vstring);
1323 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1324 if (ret != LDB_SUCCESS) return ret;
1326 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1327 if (dnstring == NULL) {
1328 return LDB_ERR_OPERATIONS_ERROR;
1330 *v = data_blob_string_const(dnstring);
1336 handle adding a linked attribute
1338 static int replmd_modify_la_add(struct ldb_module *module,
1339 struct dsdb_schema *schema,
1340 struct ldb_message *msg,
1341 struct ldb_message_element *el,
1342 struct ldb_message_element *old_el,
1343 const struct dsdb_attribute *schema_attr,
1346 struct GUID *msg_guid)
1349 struct parsed_dn *dns, *old_dns;
1350 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1352 struct ldb_val *new_values = NULL;
1353 unsigned int num_new_values = 0;
1354 unsigned old_num_values = old_el?old_el->num_values:0;
1355 const struct GUID *invocation_id;
1356 struct ldb_context *ldb = ldb_module_get_ctx(module);
1358 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1359 if (ret != LDB_SUCCESS) {
1360 talloc_free(tmp_ctx);
1364 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1365 if (ret != LDB_SUCCESS) {
1366 talloc_free(tmp_ctx);
1370 invocation_id = samdb_ntds_invocation_id(ldb);
1371 if (!invocation_id) {
1372 return LDB_ERR_OPERATIONS_ERROR;
1375 /* for each new value, see if it exists already with the same GUID */
1376 for (i=0; i<el->num_values; i++) {
1377 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid);
1379 /* this is a new linked attribute value */
1380 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1381 if (new_values == NULL) {
1382 ldb_module_oom(module);
1383 talloc_free(tmp_ctx);
1384 return LDB_ERR_OPERATIONS_ERROR;
1386 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1387 invocation_id, seq_num, t);
1388 if (ret != LDB_SUCCESS) {
1389 talloc_free(tmp_ctx);
1394 /* this is only allowed if the GUID was
1395 previously deleted. */
1396 const struct ldb_val *v;
1397 v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED");
1399 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1400 el->name, GUID_string(tmp_ctx, p->guid));
1401 talloc_free(tmp_ctx);
1402 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1404 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1405 invocation_id, seq_num, t, false);
1406 if (ret != LDB_SUCCESS) {
1407 talloc_free(tmp_ctx);
1412 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1413 if (ret != LDB_SUCCESS) {
1414 talloc_free(tmp_ctx);
1419 /* add the new ones on to the end of the old values, constructing a new el->values */
1420 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1422 old_num_values+num_new_values);
1423 if (el->values == NULL) {
1424 ldb_module_oom(module);
1425 return LDB_ERR_OPERATIONS_ERROR;
1428 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1429 el->num_values = old_num_values + num_new_values;
1431 talloc_steal(msg->elements, el->values);
1432 talloc_steal(el->values, new_values);
1434 talloc_free(tmp_ctx);
1436 /* we now tell the backend to replace all existing values
1437 with the one we have constructed */
1438 el->flags = LDB_FLAG_MOD_REPLACE;
1445 handle deleting all active linked attributes
1447 static int replmd_modify_la_delete(struct ldb_module *module,
1448 struct dsdb_schema *schema,
1449 struct ldb_message *msg,
1450 struct ldb_message_element *el,
1451 struct ldb_message_element *old_el,
1452 const struct dsdb_attribute *schema_attr,
1455 struct GUID *msg_guid)
1458 struct parsed_dn *dns, *old_dns;
1459 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1461 const struct GUID *invocation_id;
1462 struct ldb_context *ldb = ldb_module_get_ctx(module);
1464 /* check if there is nothing to delete */
1465 if ((!old_el || old_el->num_values == 0) &&
1466 el->num_values == 0) {
1470 if (!old_el || old_el->num_values == 0) {
1471 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1474 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1475 if (ret != LDB_SUCCESS) {
1476 talloc_free(tmp_ctx);
1480 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1481 if (ret != LDB_SUCCESS) {
1482 talloc_free(tmp_ctx);
1486 invocation_id = samdb_ntds_invocation_id(ldb);
1487 if (!invocation_id) {
1488 return LDB_ERR_OPERATIONS_ERROR;
1493 /* see if we are being asked to delete any links that
1494 don't exist or are already deleted */
1495 for (i=0; i<el->num_values; i++) {
1496 struct parsed_dn *p = &dns[i];
1497 struct parsed_dn *p2;
1498 const struct ldb_val *v;
1500 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid);
1502 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1503 el->name, GUID_string(tmp_ctx, p->guid));
1504 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1506 v = ldb_dn_get_extended_component(p2->dsdb_dn->dn, "DELETED");
1508 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1509 el->name, GUID_string(tmp_ctx, p->guid));
1510 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1514 /* for each new value, see if it exists already with the same GUID
1515 if it is not already deleted and matches the delete list then delete it
1517 for (i=0; i<old_el->num_values; i++) {
1518 struct parsed_dn *p = &old_dns[i];
1519 const struct ldb_val *v;
1521 if (dns && parsed_dn_find(dns, el->num_values, p->guid) == NULL) {
1525 v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED");
1526 if (v != NULL) continue;
1528 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1529 invocation_id, seq_num, t, true);
1530 if (ret != LDB_SUCCESS) {
1531 talloc_free(tmp_ctx);
1535 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1536 if (ret != LDB_SUCCESS) {
1537 talloc_free(tmp_ctx);
1542 el->values = talloc_steal(msg->elements, old_el->values);
1543 el->num_values = old_el->num_values;
1545 talloc_free(tmp_ctx);
1547 /* we now tell the backend to replace all existing values
1548 with the one we have constructed */
1549 el->flags = LDB_FLAG_MOD_REPLACE;
1555 handle replacing a linked attribute
1557 static int replmd_modify_la_replace(struct ldb_module *module,
1558 struct dsdb_schema *schema,
1559 struct ldb_message *msg,
1560 struct ldb_message_element *el,
1561 struct ldb_message_element *old_el,
1562 const struct dsdb_attribute *schema_attr,
1565 struct GUID *msg_guid)
1568 struct parsed_dn *dns, *old_dns;
1569 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1571 const struct GUID *invocation_id;
1572 struct ldb_context *ldb = ldb_module_get_ctx(module);
1573 struct ldb_val *new_values = NULL;
1574 uint32_t num_new_values = 0;
1575 unsigned old_num_values = old_el?old_el->num_values:0;
1577 /* check if there is nothing to replace */
1578 if ((!old_el || old_el->num_values == 0) &&
1579 el->num_values == 0) {
1583 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1584 if (ret != LDB_SUCCESS) {
1585 talloc_free(tmp_ctx);
1589 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1590 if (ret != LDB_SUCCESS) {
1591 talloc_free(tmp_ctx);
1595 invocation_id = samdb_ntds_invocation_id(ldb);
1596 if (!invocation_id) {
1597 return LDB_ERR_OPERATIONS_ERROR;
1600 /* mark all the old ones as deleted */
1601 for (i=0; i<old_num_values; i++) {
1602 struct parsed_dn *old_p = &old_dns[i];
1603 struct parsed_dn *p;
1604 const struct ldb_val *v;
1606 v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED");
1609 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1610 if (ret != LDB_SUCCESS) {
1611 talloc_free(tmp_ctx);
1615 p = parsed_dn_find(dns, el->num_values, old_p->guid);
1617 /* we don't delete it if we are re-adding it */
1621 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
1622 invocation_id, seq_num, t, true);
1623 if (ret != LDB_SUCCESS) {
1624 talloc_free(tmp_ctx);
1629 /* for each new value, either update its meta-data, or add it
1632 for (i=0; i<el->num_values; i++) {
1633 struct parsed_dn *p = &dns[i], *old_p;
1636 (old_p = parsed_dn_find(old_dns,
1637 old_num_values, p->guid)) != NULL) {
1638 /* update in place */
1639 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
1640 old_p->dsdb_dn, invocation_id,
1642 if (ret != LDB_SUCCESS) {
1643 talloc_free(tmp_ctx);
1648 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
1650 if (new_values == NULL) {
1651 ldb_module_oom(module);
1652 talloc_free(tmp_ctx);
1653 return LDB_ERR_OPERATIONS_ERROR;
1655 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1656 invocation_id, seq_num, t);
1657 if (ret != LDB_SUCCESS) {
1658 talloc_free(tmp_ctx);
1664 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
1665 if (ret != LDB_SUCCESS) {
1666 talloc_free(tmp_ctx);
1671 /* add the new values to the end of old_el */
1672 if (num_new_values != 0) {
1673 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1674 struct ldb_val, old_num_values+num_new_values);
1675 if (el->values == NULL) {
1676 ldb_module_oom(module);
1677 return LDB_ERR_OPERATIONS_ERROR;
1679 memcpy(&el->values[old_num_values], &new_values[0],
1680 sizeof(struct ldb_val)*num_new_values);
1681 el->num_values = old_num_values + num_new_values;
1682 talloc_steal(msg->elements, new_values);
1684 el->values = old_el->values;
1685 el->num_values = old_el->num_values;
1686 talloc_steal(msg->elements, el->values);
1689 talloc_free(tmp_ctx);
1691 /* we now tell the backend to replace all existing values
1692 with the one we have constructed */
1693 el->flags = LDB_FLAG_MOD_REPLACE;
1700 handle linked attributes in modify requests
1702 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
1703 struct ldb_message *msg,
1704 uint64_t seq_num, time_t t)
1706 struct ldb_result *res;
1708 struct ldb_context *ldb = ldb_module_get_ctx(module);
1709 struct ldb_message *old_msg;
1710 struct dsdb_schema *schema = dsdb_get_schema(ldb);
1711 struct GUID old_guid;
1714 /* there the replmd_update_rpmd code has already
1715 * checked and saw that there are no linked
1720 #if !W2K3_LINKED_ATTRIBUTES
1724 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
1725 /* don't do anything special for linked attributes */
1729 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
1730 DSDB_SEARCH_SHOW_DELETED |
1731 DSDB_SEARCH_REVEAL_INTERNALS |
1732 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
1733 if (ret != LDB_SUCCESS) {
1736 old_msg = res->msgs[0];
1738 old_guid = samdb_result_guid(old_msg, "objectGUID");
1740 for (i=0; i<msg->num_elements; i++) {
1741 struct ldb_message_element *el = &msg->elements[i];
1742 struct ldb_message_element *old_el, *new_el;
1743 const struct dsdb_attribute *schema_attr
1744 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1746 ldb_asprintf_errstring(ldb,
1747 "attribute %s is not a valid attribute in schema", el->name);
1748 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1750 if (schema_attr->linkID == 0) {
1753 if ((schema_attr->linkID & 1) == 1) {
1754 /* Odd is for the target. Illegal to modify */
1755 ldb_asprintf_errstring(ldb,
1756 "attribute %s must not be modified directly, it is a linked attribute", el->name);
1757 return LDB_ERR_UNWILLING_TO_PERFORM;
1759 old_el = ldb_msg_find_element(old_msg, el->name);
1760 switch (el->flags & LDB_FLAG_MOD_MASK) {
1761 case LDB_FLAG_MOD_REPLACE:
1762 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1764 case LDB_FLAG_MOD_DELETE:
1765 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1767 case LDB_FLAG_MOD_ADD:
1768 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1771 ldb_asprintf_errstring(ldb,
1772 "invalid flags 0x%x for %s linked attribute",
1773 el->flags, el->name);
1774 return LDB_ERR_UNWILLING_TO_PERFORM;
1776 if (ret != LDB_SUCCESS) {
1780 ldb_msg_remove_attr(old_msg, el->name);
1782 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
1783 new_el->num_values = el->num_values;
1784 new_el->values = el->values;
1786 /* TODO: this relises a bit too heavily on the exact
1787 behaviour of ldb_msg_find_element and
1788 ldb_msg_remove_element */
1789 old_el = ldb_msg_find_element(msg, el->name);
1791 ldb_msg_remove_element(msg, old_el);
1802 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
1804 struct ldb_context *ldb;
1805 struct replmd_replicated_request *ac;
1806 struct ldb_request *down_req;
1807 struct ldb_message *msg;
1808 time_t t = time(NULL);
1811 /* do not manipulate our control entries */
1812 if (ldb_dn_is_special(req->op.mod.message->dn)) {
1813 return ldb_next_request(module, req);
1816 ldb = ldb_module_get_ctx(module);
1818 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
1820 ac = replmd_ctx_init(module, req);
1822 return LDB_ERR_OPERATIONS_ERROR;
1825 /* we have to copy the message as the caller might have it as a const */
1826 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
1830 return LDB_ERR_OPERATIONS_ERROR;
1833 ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num, t);
1834 if (ret != LDB_SUCCESS) {
1839 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t);
1840 if (ret != LDB_SUCCESS) {
1846 * - replace the old object with the newly constructed one
1849 ret = ldb_build_mod_req(&down_req, ldb, ac,
1852 ac, replmd_op_callback,
1854 if (ret != LDB_SUCCESS) {
1858 talloc_steal(down_req, msg);
1860 /* we only change whenChanged and uSNChanged if the seq_num
1862 if (ac->seq_num != 0) {
1863 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
1868 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
1874 /* go on with the call chain */
1875 return ldb_next_request(module, down_req);
1878 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
1881 handle a rename request
1883 On a rename we need to do an extra ldb_modify which sets the
1884 whenChanged and uSNChanged attributes. We do this in a callback after the success.
1886 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
1888 struct ldb_context *ldb;
1889 struct replmd_replicated_request *ac;
1891 struct ldb_request *down_req;
1893 /* do not manipulate our control entries */
1894 if (ldb_dn_is_special(req->op.mod.message->dn)) {
1895 return ldb_next_request(module, req);
1898 ldb = ldb_module_get_ctx(module);
1900 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
1902 ac = replmd_ctx_init(module, req);
1904 return LDB_ERR_OPERATIONS_ERROR;
1906 ret = ldb_build_rename_req(&down_req, ldb, ac,
1907 ac->req->op.rename.olddn,
1908 ac->req->op.rename.newdn,
1910 ac, replmd_rename_callback,
1913 if (ret != LDB_SUCCESS) {
1918 /* go on with the call chain */
1919 return ldb_next_request(module, down_req);
1922 /* After the rename is compleated, update the whenchanged etc */
1923 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
1925 struct ldb_context *ldb;
1926 struct replmd_replicated_request *ac;
1927 struct ldb_request *down_req;
1928 struct ldb_message *msg;
1929 time_t t = time(NULL);
1932 ac = talloc_get_type(req->context, struct replmd_replicated_request);
1933 ldb = ldb_module_get_ctx(ac->module);
1935 if (ares->error != LDB_SUCCESS) {
1936 return ldb_module_done(ac->req, ares->controls,
1937 ares->response, ares->error);
1940 if (ares->type != LDB_REPLY_DONE) {
1941 ldb_set_errstring(ldb,
1942 "invalid ldb_reply_type in callback");
1944 return ldb_module_done(ac->req, NULL, NULL,
1945 LDB_ERR_OPERATIONS_ERROR);
1948 /* Get a sequence number from the backend */
1949 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1950 if (ret != LDB_SUCCESS) {
1955 * - replace the old object with the newly constructed one
1958 msg = ldb_msg_new(ac);
1961 return LDB_ERR_OPERATIONS_ERROR;
1964 msg->dn = ac->req->op.rename.newdn;
1966 ret = ldb_build_mod_req(&down_req, ldb, ac,
1969 ac, replmd_op_callback,
1972 if (ret != LDB_SUCCESS) {
1976 talloc_steal(down_req, msg);
1978 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
1983 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
1988 /* go on with the call chain - do the modify after the rename */
1989 return ldb_next_request(ac->module, down_req);
1992 /* remove forwards and backlinks as needed when an object
1994 static int replmd_delete_remove_link(struct ldb_module *module,
1995 struct dsdb_schema *schema,
1997 struct ldb_message_element *el,
1998 const struct dsdb_attribute *sa)
2001 TALLOC_CTX *tmp_ctx = talloc_new(module);
2002 struct ldb_context *ldb = ldb_module_get_ctx(module);
2004 for (i=0; i<el->num_values; i++) {
2005 struct dsdb_dn *dsdb_dn;
2009 struct ldb_message *msg;
2010 const struct dsdb_attribute *target_attr;
2011 struct ldb_message_element *el2;
2012 struct ldb_val dn_val;
2014 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2018 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2020 talloc_free(tmp_ctx);
2021 return LDB_ERR_OPERATIONS_ERROR;
2024 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2);
2025 if (!NT_STATUS_IS_OK(status)) {
2026 talloc_free(tmp_ctx);
2027 return LDB_ERR_OPERATIONS_ERROR;
2030 /* remove the link */
2031 msg = ldb_msg_new(tmp_ctx);
2033 ldb_module_oom(module);
2034 talloc_free(tmp_ctx);
2035 return LDB_ERR_OPERATIONS_ERROR;
2039 msg->dn = dsdb_dn->dn;
2041 if (sa->linkID & 1) {
2042 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID - 1);
2044 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID + 1);
2047 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2048 if (ret != LDB_SUCCESS) {
2049 ldb_module_oom(module);
2050 talloc_free(tmp_ctx);
2051 return LDB_ERR_OPERATIONS_ERROR;
2053 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2054 el2->values = &dn_val;
2055 el2->num_values = 1;
2057 ret = dsdb_module_modify(module, msg, 0);
2058 if (ret != LDB_SUCCESS) {
2059 talloc_free(tmp_ctx);
2063 talloc_free(tmp_ctx);
2069 handle update of replication meta data for deletion of objects
2071 This also handles the mapping of delete to a rename operation
2072 to allow deletes to be replicated.
2074 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2076 int ret = LDB_ERR_OTHER;
2078 struct ldb_dn *old_dn, *new_dn;
2079 const char *rdn_name;
2080 const struct ldb_val *rdn_value, *new_rdn_value;
2082 struct ldb_context *ldb = ldb_module_get_ctx(module);
2083 struct dsdb_schema *schema = dsdb_get_schema(ldb);
2084 struct ldb_message *msg, *old_msg;
2085 struct ldb_message_element *el;
2086 TALLOC_CTX *tmp_ctx;
2087 struct ldb_result *res, *parent_res;
2088 const char *preserved_attrs[] = {
2089 /* yes, this really is a hard coded list. See MS-ADTS
2090 section 3.1.1.5.5.1.1 */
2091 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2092 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2093 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2094 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2095 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2096 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2097 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreate",
2099 uint32_t el_count = 0;
2102 tmp_ctx = talloc_new(ldb);
2104 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2106 /* we need the complete msg off disk, so we can work out which
2107 attributes need to be removed */
2108 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2109 DSDB_SEARCH_SHOW_DELETED |
2110 DSDB_SEARCH_REVEAL_INTERNALS |
2111 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
2112 if (ret != LDB_SUCCESS) {
2113 talloc_free(tmp_ctx);
2116 old_msg = res->msgs[0];
2118 /* work out where we will be renaming this object to */
2119 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn, &new_dn);
2120 if (ret != LDB_SUCCESS) {
2121 /* this is probably an attempted delete on a partition
2122 * that doesn't allow delete operations, such as the
2123 * schema partition */
2124 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2125 ldb_dn_get_linearized(old_dn));
2126 talloc_free(tmp_ctx);
2127 return LDB_ERR_UNWILLING_TO_PERFORM;
2130 rdn_name = ldb_dn_get_rdn_name(old_dn);
2131 rdn_value = ldb_dn_get_rdn_val(old_dn);
2133 /* get the objects GUID from the search we just did */
2134 guid = samdb_result_guid(old_msg, "objectGUID");
2136 /* Add a formatted child */
2137 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2140 GUID_string(tmp_ctx, &guid));
2142 DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2143 ldb_dn_get_linearized(new_dn)));
2144 talloc_free(tmp_ctx);
2145 return LDB_ERR_OPERATIONS_ERROR;
2149 now we need to modify the object in the following ways:
2151 - add isDeleted=TRUE
2152 - update rDN and name, with new rDN
2153 - remove linked attributes
2154 - remove objectCategory and sAMAccountType
2155 - remove attribs not on the preserved list
2156 - preserved if in above list, or is rDN
2157 - remove all linked attribs from this object
2158 - remove all links from other objects to this object
2159 - add lastKnownParent
2160 - update replPropertyMetaData?
2162 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2165 msg = ldb_msg_new(tmp_ctx);
2167 ldb_module_oom(module);
2168 talloc_free(tmp_ctx);
2169 return LDB_ERR_OPERATIONS_ERROR;
2174 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2175 if (ret != LDB_SUCCESS) {
2176 DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2177 ldb_module_oom(module);
2178 talloc_free(tmp_ctx);
2181 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2183 /* we need the storage form of the parent GUID */
2184 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2185 ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2186 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
2187 if (ret != LDB_SUCCESS) {
2188 talloc_free(tmp_ctx);
2192 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2193 ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2194 if (ret != LDB_SUCCESS) {
2195 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2196 ldb_module_oom(module);
2197 talloc_free(tmp_ctx);
2200 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2202 /* work out which of the old attributes we will be removing */
2203 for (i=0; i<old_msg->num_elements; i++) {
2204 const struct dsdb_attribute *sa;
2205 el = &old_msg->elements[i];
2206 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2208 talloc_free(tmp_ctx);
2209 return LDB_ERR_OPERATIONS_ERROR;
2211 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2212 /* don't remove the rDN */
2217 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa);
2218 if (ret != LDB_SUCCESS) {
2219 talloc_free(tmp_ctx);
2220 return LDB_ERR_OPERATIONS_ERROR;
2224 if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2228 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2229 if (ret != LDB_SUCCESS) {
2230 talloc_free(tmp_ctx);
2231 ldb_module_oom(module);
2236 /* work out what the new rdn value is, for updating the
2237 rDN and name fields */
2238 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2239 ret = ldb_msg_add_value(msg, rdn_name, new_rdn_value, &el);
2240 if (ret != LDB_SUCCESS) {
2241 talloc_free(tmp_ctx);
2244 el->flags = LDB_FLAG_MOD_REPLACE;
2246 el = ldb_msg_find_element(old_msg, "name");
2248 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2249 if (ret != LDB_SUCCESS) {
2250 talloc_free(tmp_ctx);
2253 el->flags = LDB_FLAG_MOD_REPLACE;
2256 ret = dsdb_module_modify(module, msg, 0);
2257 if (ret != LDB_SUCCESS){
2258 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
2259 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
2260 talloc_free(tmp_ctx);
2264 /* now rename onto the new DN */
2265 ret = dsdb_module_rename(module, old_dn, new_dn, 0);
2266 if (ret != LDB_SUCCESS){
2267 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
2268 ldb_dn_get_linearized(old_dn),
2269 ldb_dn_get_linearized(new_dn),
2270 ldb_errstring(ldb)));
2271 talloc_free(tmp_ctx);
2275 talloc_free(tmp_ctx);
2277 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
2282 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
2287 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
2289 int ret = LDB_ERR_OTHER;
2290 /* TODO: do some error mapping */
2294 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
2296 struct ldb_context *ldb;
2297 struct ldb_request *change_req;
2298 enum ndr_err_code ndr_err;
2299 struct ldb_message *msg;
2300 struct replPropertyMetaDataBlob *md;
2301 struct ldb_val md_value;
2306 * TODO: check if the parent object exist
2310 * TODO: handle the conflict case where an object with the
2314 ldb = ldb_module_get_ctx(ar->module);
2315 msg = ar->objs->objects[ar->index_current].msg;
2316 md = ar->objs->objects[ar->index_current].meta_data;
2318 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2319 if (ret != LDB_SUCCESS) {
2320 return replmd_replicated_request_error(ar, ret);
2323 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
2324 if (ret != LDB_SUCCESS) {
2325 return replmd_replicated_request_error(ar, ret);
2328 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2329 if (ret != LDB_SUCCESS) {
2330 return replmd_replicated_request_error(ar, ret);
2333 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
2334 if (ret != LDB_SUCCESS) {
2335 return replmd_replicated_request_error(ar, ret);
2338 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2339 if (ret != LDB_SUCCESS) {
2340 return replmd_replicated_request_error(ar, ret);
2343 /* remove any message elements that have zero values */
2344 for (i=0; i<msg->num_elements; i++) {
2345 if (msg->elements[i].num_values == 0) {
2346 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
2347 msg->elements[i].name));
2348 memmove(&msg->elements[i],
2349 &msg->elements[i+1],
2350 sizeof(msg->elements[i])*(msg->num_elements - (i+1)));
2351 msg->num_elements--;
2357 * the meta data array is already sorted by the caller
2359 for (i=0; i < md->ctr.ctr1.count; i++) {
2360 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
2362 ndr_err = ndr_push_struct_blob(&md_value, msg,
2363 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2365 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2366 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2367 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2368 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2370 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
2371 if (ret != LDB_SUCCESS) {
2372 return replmd_replicated_request_error(ar, ret);
2375 replmd_ldb_message_sort(msg, ar->schema);
2378 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
2379 DEBUG(4, ("DRS replication add message:\n%s\n", s));
2383 ret = ldb_build_add_req(&change_req,
2391 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2393 return ldb_next_request(ar->module, change_req);
2396 static int replmd_replPropertyMetaData1_conflict_compare(struct replPropertyMetaData1 *m1,
2397 struct replPropertyMetaData1 *m2)
2401 if (m1->version != m2->version) {
2402 return m1->version - m2->version;
2405 if (m1->originating_change_time != m2->originating_change_time) {
2406 return m1->originating_change_time - m2->originating_change_time;
2409 ret = GUID_compare(&m1->originating_invocation_id, &m2->originating_invocation_id);
2414 return m1->originating_usn - m2->originating_usn;
2417 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
2419 struct ldb_context *ldb;
2420 struct ldb_request *change_req;
2421 enum ndr_err_code ndr_err;
2422 struct ldb_message *msg;
2423 struct replPropertyMetaDataBlob *rmd;
2424 struct replPropertyMetaDataBlob omd;
2425 const struct ldb_val *omd_value;
2426 struct replPropertyMetaDataBlob nmd;
2427 struct ldb_val nmd_value;
2429 uint32_t removed_attrs = 0;
2432 ldb = ldb_module_get_ctx(ar->module);
2433 msg = ar->objs->objects[ar->index_current].msg;
2434 rmd = ar->objs->objects[ar->index_current].meta_data;
2439 * TODO: check repl data is correct after a rename
2441 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
2442 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
2443 ldb_dn_get_linearized(ar->search_msg->dn),
2444 ldb_dn_get_linearized(msg->dn));
2445 /* we can't use dsdb_module_rename() here as we need
2446 the rename call to be intercepted by this module, to
2447 allow it to process linked attribute changes */
2448 if (ldb_rename(ldb, ar->search_msg->dn, msg->dn) != LDB_SUCCESS) {
2449 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
2450 ldb_dn_get_linearized(ar->search_msg->dn),
2451 ldb_dn_get_linearized(msg->dn),
2452 ldb_errstring(ldb));
2453 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
2457 /* find existing meta data */
2458 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
2460 ndr_err = ndr_pull_struct_blob(omd_value, ar,
2461 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
2462 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
2463 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2464 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2465 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2468 if (omd.version != 1) {
2469 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2475 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
2476 nmd.ctr.ctr1.array = talloc_array(ar,
2477 struct replPropertyMetaData1,
2478 nmd.ctr.ctr1.count);
2479 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2481 /* first copy the old meta data */
2482 for (i=0; i < omd.ctr.ctr1.count; i++) {
2483 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
2487 /* now merge in the new meta data */
2488 for (i=0; i < rmd->ctr.ctr1.count; i++) {
2491 for (j=0; j < ni; j++) {
2494 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
2498 cmp = replmd_replPropertyMetaData1_conflict_compare(&rmd->ctr.ctr1.array[i],
2499 &nmd.ctr.ctr1.array[j]);
2501 /* replace the entry */
2502 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
2507 /* we don't want to apply this change so remove the attribute */
2508 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
2515 if (found) continue;
2517 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
2522 * finally correct the size of the meta_data array
2524 nmd.ctr.ctr1.count = ni;
2527 * the rdn attribute (the alias for the name attribute),
2528 * 'cn' for most objects is the last entry in the meta data array
2531 * sort the new meta data array
2533 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
2534 if (ret != LDB_SUCCESS) {
2539 * check if some replicated attributes left, otherwise skip the ldb_modify() call
2541 if (msg->num_elements == 0) {
2542 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
2545 ar->index_current++;
2546 return replmd_replicated_apply_next(ar);
2549 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
2550 ar->index_current, msg->num_elements);
2552 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2553 if (ret != LDB_SUCCESS) {
2554 return replmd_replicated_request_error(ar, ret);
2557 for (i=0; i<ni; i++) {
2558 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
2561 /* create the meta data value */
2562 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
2563 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2565 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2566 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2567 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2568 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2572 * when we know that we'll modify the record, add the whenChanged, uSNChanged
2573 * and replPopertyMetaData attributes
2575 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2576 if (ret != LDB_SUCCESS) {
2577 return replmd_replicated_request_error(ar, ret);
2579 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2580 if (ret != LDB_SUCCESS) {
2581 return replmd_replicated_request_error(ar, ret);
2583 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
2584 if (ret != LDB_SUCCESS) {
2585 return replmd_replicated_request_error(ar, ret);
2588 replmd_ldb_message_sort(msg, ar->schema);
2590 /* we want to replace the old values */
2591 for (i=0; i < msg->num_elements; i++) {
2592 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2596 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
2597 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
2601 ret = ldb_build_mod_req(&change_req,
2609 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2611 return ldb_next_request(ar->module, change_req);
2614 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
2615 struct ldb_reply *ares)
2617 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2618 struct replmd_replicated_request);
2622 return ldb_module_done(ar->req, NULL, NULL,
2623 LDB_ERR_OPERATIONS_ERROR);
2625 if (ares->error != LDB_SUCCESS &&
2626 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
2627 return ldb_module_done(ar->req, ares->controls,
2628 ares->response, ares->error);
2631 switch (ares->type) {
2632 case LDB_REPLY_ENTRY:
2633 ar->search_msg = talloc_steal(ar, ares->message);
2636 case LDB_REPLY_REFERRAL:
2637 /* we ignore referrals */
2640 case LDB_REPLY_DONE:
2641 if (ar->search_msg != NULL) {
2642 ret = replmd_replicated_apply_merge(ar);
2644 ret = replmd_replicated_apply_add(ar);
2646 if (ret != LDB_SUCCESS) {
2647 return ldb_module_done(ar->req, NULL, NULL, ret);
2655 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
2657 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
2659 struct ldb_context *ldb;
2663 struct ldb_request *search_req;
2664 struct ldb_search_options_control *options;
2666 if (ar->index_current >= ar->objs->num_objects) {
2667 /* done with it, go to next stage */
2668 return replmd_replicated_uptodate_vector(ar);
2671 ldb = ldb_module_get_ctx(ar->module);
2672 ar->search_msg = NULL;
2674 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
2675 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2677 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
2678 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2679 talloc_free(tmp_str);
2681 ret = ldb_build_search_req(&search_req,
2690 replmd_replicated_apply_search_callback,
2693 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2694 if (ret != LDB_SUCCESS) {
2698 /* we need to cope with cross-partition links, so search for
2699 the GUID over all partitions */
2700 options = talloc(search_req, struct ldb_search_options_control);
2701 if (options == NULL) {
2702 DEBUG(0, (__location__ ": out of memory\n"));
2703 return LDB_ERR_OPERATIONS_ERROR;
2705 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2707 ret = ldb_request_add_control(search_req,
2708 LDB_CONTROL_SEARCH_OPTIONS_OID,
2710 if (ret != LDB_SUCCESS) {
2714 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2716 return ldb_next_request(ar->module, search_req);
2719 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
2720 struct ldb_reply *ares)
2722 struct ldb_context *ldb;
2723 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2724 struct replmd_replicated_request);
2725 ldb = ldb_module_get_ctx(ar->module);
2728 return ldb_module_done(ar->req, NULL, NULL,
2729 LDB_ERR_OPERATIONS_ERROR);
2731 if (ares->error != LDB_SUCCESS) {
2732 return ldb_module_done(ar->req, ares->controls,
2733 ares->response, ares->error);
2736 if (ares->type != LDB_REPLY_DONE) {
2737 ldb_set_errstring(ldb, "Invalid reply type\n!");
2738 return ldb_module_done(ar->req, NULL, NULL,
2739 LDB_ERR_OPERATIONS_ERROR);
2744 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
2747 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
2749 struct ldb_context *ldb;
2750 struct ldb_request *change_req;
2751 enum ndr_err_code ndr_err;
2752 struct ldb_message *msg;
2753 struct replUpToDateVectorBlob ouv;
2754 const struct ldb_val *ouv_value;
2755 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
2756 struct replUpToDateVectorBlob nuv;
2757 struct ldb_val nuv_value;
2758 struct ldb_message_element *nuv_el = NULL;
2759 const struct GUID *our_invocation_id;
2760 struct ldb_message_element *orf_el = NULL;
2761 struct repsFromToBlob nrf;
2762 struct ldb_val *nrf_value = NULL;
2763 struct ldb_message_element *nrf_el = NULL;
2766 time_t t = time(NULL);
2770 ldb = ldb_module_get_ctx(ar->module);
2771 ruv = ar->objs->uptodateness_vector;
2777 unix_to_nt_time(&now, t);
2780 * first create the new replUpToDateVector
2782 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
2784 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
2785 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
2786 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
2787 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2788 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2789 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2792 if (ouv.version != 2) {
2793 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2798 * the new uptodateness vector will at least
2799 * contain 1 entry, one for the source_dsa
2801 * plus optional values from our old vector and the one from the source_dsa
2803 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
2804 if (ruv) nuv.ctr.ctr2.count += ruv->count;
2805 nuv.ctr.ctr2.cursors = talloc_array(ar,
2806 struct drsuapi_DsReplicaCursor2,
2807 nuv.ctr.ctr2.count);
2808 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2810 /* first copy the old vector */
2811 for (i=0; i < ouv.ctr.ctr2.count; i++) {
2812 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
2816 /* get our invocation_id if we have one already attached to the ldb */
2817 our_invocation_id = samdb_ntds_invocation_id(ldb);
2819 /* merge in the source_dsa vector is available */
2820 for (i=0; (ruv && i < ruv->count); i++) {
2823 if (our_invocation_id &&
2824 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
2825 our_invocation_id)) {
2829 for (j=0; j < ni; j++) {
2830 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
2831 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
2838 * we update only the highest_usn and not the latest_sync_success time,
2839 * because the last success stands for direct replication
2841 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
2842 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
2847 if (found) continue;
2849 /* if it's not there yet, add it */
2850 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
2855 * merge in the current highwatermark for the source_dsa
2858 for (j=0; j < ni; j++) {
2859 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
2860 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
2867 * here we update the highest_usn and last_sync_success time
2868 * because we're directly replicating from the source_dsa
2870 * and use the tmp_highest_usn because this is what we have just applied
2873 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
2874 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
2879 * here we update the highest_usn and last_sync_success time
2880 * because we're directly replicating from the source_dsa
2882 * and use the tmp_highest_usn because this is what we have just applied
2885 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
2886 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
2887 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
2892 * finally correct the size of the cursors array
2894 nuv.ctr.ctr2.count = ni;
2899 qsort(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count,
2900 sizeof(struct drsuapi_DsReplicaCursor2),
2901 (comparison_fn_t)drsuapi_DsReplicaCursor2_compare);
2904 * create the change ldb_message
2906 msg = ldb_msg_new(ar);
2907 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2908 msg->dn = ar->search_msg->dn;
2910 ndr_err = ndr_push_struct_blob(&nuv_value, msg,
2911 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2913 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
2914 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2915 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2916 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2918 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
2919 if (ret != LDB_SUCCESS) {
2920 return replmd_replicated_request_error(ar, ret);
2922 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
2925 * now create the new repsFrom value from the given repsFromTo1 structure
2929 nrf.ctr.ctr1 = *ar->objs->source_dsa;
2930 /* and fix some values... */
2931 nrf.ctr.ctr1.consecutive_sync_failures = 0;
2932 nrf.ctr.ctr1.last_success = now;
2933 nrf.ctr.ctr1.last_attempt = now;
2934 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
2935 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
2938 * first see if we already have a repsFrom value for the current source dsa
2939 * if so we'll later replace this value
2941 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
2943 for (i=0; i < orf_el->num_values; i++) {
2944 struct repsFromToBlob *trf;
2946 trf = talloc(ar, struct repsFromToBlob);
2947 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2949 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
2950 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2951 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2952 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2953 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2956 if (trf->version != 1) {
2957 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2961 * we compare the source dsa objectGUID not the invocation_id
2962 * because we want only one repsFrom value per source dsa
2963 * and when the invocation_id of the source dsa has changed we don't need
2964 * the old repsFrom with the old invocation_id
2966 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
2967 &ar->objs->source_dsa->source_dsa_obj_guid)) {
2973 nrf_value = &orf_el->values[i];
2978 * copy over all old values to the new ldb_message
2980 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
2981 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2986 * if we haven't found an old repsFrom value for the current source dsa
2987 * we'll add a new value
2990 struct ldb_val zero_value;
2991 ZERO_STRUCT(zero_value);
2992 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
2993 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2995 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
2998 /* we now fill the value which is already attached to ldb_message */
2999 ndr_err = ndr_push_struct_blob(nrf_value, msg,
3000 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3002 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3003 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3004 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3005 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3009 * the ldb_message_element for the attribute, has all the old values and the new one
3010 * so we'll replace the whole attribute with all values
3012 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
3015 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3016 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
3020 /* prepare the ldb_modify() request */
3021 ret = ldb_build_mod_req(&change_req,
3027 replmd_replicated_uptodate_modify_callback,
3029 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3031 return ldb_next_request(ar->module, change_req);
3034 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
3035 struct ldb_reply *ares)
3037 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3038 struct replmd_replicated_request);
3042 return ldb_module_done(ar->req, NULL, NULL,
3043 LDB_ERR_OPERATIONS_ERROR);
3045 if (ares->error != LDB_SUCCESS &&
3046 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3047 return ldb_module_done(ar->req, ares->controls,
3048 ares->response, ares->error);
3051 switch (ares->type) {
3052 case LDB_REPLY_ENTRY:
3053 ar->search_msg = talloc_steal(ar, ares->message);
3056 case LDB_REPLY_REFERRAL:
3057 /* we ignore referrals */
3060 case LDB_REPLY_DONE:
3061 if (ar->search_msg == NULL) {
3062 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3064 ret = replmd_replicated_uptodate_modify(ar);
3066 if (ret != LDB_SUCCESS) {
3067 return ldb_module_done(ar->req, NULL, NULL, ret);
3076 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
3078 struct ldb_context *ldb;
3080 static const char *attrs[] = {
3081 "replUpToDateVector",
3085 struct ldb_request *search_req;
3087 ldb = ldb_module_get_ctx(ar->module);
3088 ar->search_msg = NULL;
3090 ret = ldb_build_search_req(&search_req,
3093 ar->objs->partition_dn,
3099 replmd_replicated_uptodate_search_callback,
3101 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3103 return ldb_next_request(ar->module, search_req);
3108 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
3110 struct ldb_context *ldb;
3111 struct dsdb_extended_replicated_objects *objs;
3112 struct replmd_replicated_request *ar;
3113 struct ldb_control **ctrls;
3115 struct replmd_private *replmd_private =
3116 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3118 ldb = ldb_module_get_ctx(module);
3120 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
3122 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
3124 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
3125 return LDB_ERR_PROTOCOL_ERROR;
3128 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
3129 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
3130 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
3131 return LDB_ERR_PROTOCOL_ERROR;
3134 ar = replmd_ctx_init(module, req);
3136 return LDB_ERR_OPERATIONS_ERROR;
3138 /* Set the flags to have the replmd_op_callback run over the full set of objects */
3139 ar->apply_mode = true;
3141 ar->schema = dsdb_get_schema(ldb);
3143 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
3145 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3146 return LDB_ERR_CONSTRAINT_VIOLATION;
3149 ctrls = req->controls;
3151 if (req->controls) {
3152 req->controls = talloc_memdup(ar, req->controls,
3153 talloc_get_size(req->controls));
3154 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3157 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
3158 if (ret != LDB_SUCCESS) {
3162 ar->controls = req->controls;
3163 req->controls = ctrls;
3165 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
3167 /* save away the linked attributes for the end of the
3169 for (i=0; i<ar->objs->linked_attributes_count; i++) {
3170 struct la_entry *la_entry;
3172 if (replmd_private->la_ctx == NULL) {
3173 replmd_private->la_ctx = talloc_new(replmd_private);
3175 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
3176 if (la_entry == NULL) {
3178 return LDB_ERR_OPERATIONS_ERROR;
3180 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
3181 if (la_entry->la == NULL) {
3182 talloc_free(la_entry);
3184 return LDB_ERR_OPERATIONS_ERROR;
3186 *la_entry->la = ar->objs->linked_attributes[i];
3188 /* we need to steal the non-scalars so they stay
3189 around until the end of the transaction */
3190 talloc_steal(la_entry->la, la_entry->la->identifier);
3191 talloc_steal(la_entry->la, la_entry->la->value.blob);
3193 DLIST_ADD(replmd_private->la_list, la_entry);
3196 return replmd_replicated_apply_next(ar);
3200 process one linked attribute structure
3202 static int replmd_process_linked_attribute(struct ldb_module *module,
3203 struct la_entry *la_entry)
3205 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
3206 struct ldb_context *ldb = ldb_module_get_ctx(module);
3207 struct dsdb_schema *schema = dsdb_get_schema(ldb);
3208 struct drsuapi_DsReplicaObjectIdentifier3 target;
3209 struct ldb_message *msg;
3210 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
3211 struct ldb_request *mod_req;
3213 const struct dsdb_attribute *attr;
3214 struct ldb_dn *target_dn;
3215 struct dsdb_dn *dsdb_dn;
3216 uint64_t seq_num = 0;
3217 struct drsuapi_DsReplicaAttribute drs;
3218 struct drsuapi_DsAttributeValue val;
3219 struct ldb_message_element el;
3220 const struct ldb_val *guid;
3222 time_t t = time(NULL);
3224 drs.value_ctr.num_values = 1;
3225 drs.value_ctr.values = &val;
3226 val.blob = la->value.blob;
3229 linked_attributes[0]:
3230 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
3232 identifier: struct drsuapi_DsReplicaObjectIdentifier
3233 __ndr_size : 0x0000003a (58)
3234 __ndr_size_sid : 0x00000000 (0)
3235 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
3237 __ndr_size_dn : 0x00000000 (0)
3239 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
3240 value: struct drsuapi_DsAttributeValue
3241 __ndr_size : 0x0000007e (126)
3243 blob : DATA_BLOB length=126
3244 flags : 0x00000001 (1)
3245 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
3246 originating_add_time : Wed Sep 2 22:20:01 2009 EST
3247 meta_data: struct drsuapi_DsReplicaMetaData
3248 version : 0x00000015 (21)
3249 originating_change_time : Wed Sep 2 23:39:07 2009 EST
3250 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
3251 originating_usn : 0x000000000001e19c (123292)
3253 (for cases where the link is to a normal DN)
3254 &target: struct drsuapi_DsReplicaObjectIdentifier3
3255 __ndr_size : 0x0000007e (126)
3256 __ndr_size_sid : 0x0000001c (28)
3257 guid : 7639e594-db75-4086-b0d4-67890ae46031
3258 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
3259 __ndr_size_dn : 0x00000022 (34)
3260 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
3263 /* find the attribute being modified */
3264 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
3266 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
3267 talloc_free(tmp_ctx);
3268 return LDB_ERR_OPERATIONS_ERROR;
3271 status = attr->syntax->drsuapi_to_ldb(ldb, schema, attr, &drs, tmp_ctx, &el);
3273 /* construct a modify request for this attribute change */
3274 msg = ldb_msg_new(tmp_ctx);
3277 talloc_free(tmp_ctx);
3278 return LDB_ERR_OPERATIONS_ERROR;
3281 ret = dsdb_find_dn_by_guid(ldb, tmp_ctx,
3282 GUID_string(tmp_ctx, &la->identifier->guid), &msg->dn);
3283 if (ret != LDB_SUCCESS) {
3284 talloc_free(tmp_ctx);
3288 el.name = attr->lDAPDisplayName;
3289 if (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) {
3290 ret = ldb_msg_add(msg, &el, LDB_FLAG_MOD_ADD);
3292 ret = ldb_msg_add(msg, &el, LDB_FLAG_MOD_DELETE);
3294 if (ret != LDB_SUCCESS) {
3295 talloc_free(tmp_ctx);
3299 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el.values[0], attr->syntax->ldap_oid);
3301 DEBUG(0,(__location__ ": Failed to parse just-generated DN\n"));
3302 talloc_free(tmp_ctx);
3303 return LDB_ERR_INVALID_DN_SYNTAX;
3306 guid = ldb_dn_get_extended_component(dsdb_dn->dn, "GUID");
3308 DEBUG(0,(__location__ ": Failed to parse GUID from just-generated DN\n"));
3309 talloc_free(tmp_ctx);
3310 return LDB_ERR_INVALID_DN_SYNTAX;
3313 ret = dsdb_find_dn_by_guid(ldb, tmp_ctx, ldb_binary_encode(tmp_ctx, *guid), &target_dn);
3314 if (ret != LDB_SUCCESS) {
3315 /* If this proves to be a problem in the future, then
3316 * just remove the return - perhaps we can just use
3317 * the details the replication peer supplied */
3319 DEBUG(0,(__location__ ": Failed to map GUID %s to DN\n", GUID_string(tmp_ctx, &target.guid)));
3320 talloc_free(tmp_ctx);
3321 return LDB_ERR_OPERATIONS_ERROR;
3324 /* Now update with full DN we just found in the DB (including extended components) */
3325 dsdb_dn->dn = target_dn;
3326 /* Now make a linearized version, using the original binary components (if any) */
3327 el.values[0] = data_blob_string_const(dsdb_dn_get_extended_linearized(tmp_ctx, dsdb_dn, 1));
3330 ret = replmd_update_rpmd(module, schema, msg, &seq_num, t);
3331 if (ret != LDB_SUCCESS) {
3332 talloc_free(tmp_ctx);
3336 /* we only change whenChanged and uSNChanged if the seq_num
3339 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
3340 talloc_free(tmp_ctx);
3341 return LDB_ERR_OPERATIONS_ERROR;
3344 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
3345 talloc_free(tmp_ctx);
3346 return LDB_ERR_OPERATIONS_ERROR;
3350 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
3354 ldb_op_default_callback,
3356 if (ret != LDB_SUCCESS) {
3357 talloc_free(tmp_ctx);
3360 talloc_steal(mod_req, msg);
3363 DEBUG(4,("Applying DRS linked attribute change:\n%s\n",
3364 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg)));
3367 /* Run the new request */
3368 ret = ldb_next_request(module, mod_req);
3370 /* we need to wait for this to finish, as we are being called
3371 from the synchronous end_transaction hook of this module */
3372 if (ret == LDB_SUCCESS) {
3373 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
3376 if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
3377 /* the link destination exists, we need to update it
3378 * by deleting the old one for the same DN then adding
3380 msg->elements = talloc_realloc(msg, msg->elements,
3381 struct ldb_message_element,
3382 msg->num_elements+1);
3383 if (msg->elements == NULL) {
3385 talloc_free(tmp_ctx);
3386 return LDB_ERR_OPERATIONS_ERROR;
3388 /* this relies on the backend matching the old entry
3389 only by the DN portion of the extended DN */
3390 msg->elements[1] = msg->elements[0];
3391 msg->elements[0].flags = LDB_FLAG_MOD_DELETE;
3392 msg->num_elements++;
3394 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
3398 ldb_op_default_callback,
3400 if (ret != LDB_SUCCESS) {
3401 talloc_free(tmp_ctx);
3405 /* Run the new request */
3406 ret = ldb_next_request(module, mod_req);
3408 if (ret == LDB_SUCCESS) {
3409 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
3413 if (ret != LDB_SUCCESS) {
3414 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n",
3416 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
3420 talloc_free(tmp_ctx);
3425 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
3427 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
3428 return replmd_extended_replicated_objects(module, req);
3431 return ldb_next_request(module, req);
3436 we hook into the transaction operations to allow us to
3437 perform the linked attribute updates at the end of the whole
3438 transaction. This allows a forward linked attribute to be created
3439 before the object is created. During a vampire, w2k8 sends us linked
3440 attributes before the objects they are part of.
3442 static int replmd_start_transaction(struct ldb_module *module)
3444 /* create our private structure for this transaction */
3445 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
3446 struct replmd_private);
3447 replmd_txn_cleanup(replmd_private);
3449 /* free any leftover mod_usn records from cancelled
3451 while (replmd_private->ncs) {
3452 struct nc_entry *e = replmd_private->ncs;
3453 DLIST_REMOVE(replmd_private->ncs, e);
3457 return ldb_next_start_trans(module);
3461 on prepare commit we loop over our queued la_context structures and
3464 static int replmd_prepare_commit(struct ldb_module *module)
3466 struct replmd_private *replmd_private =
3467 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3468 struct la_entry *la, *prev;
3469 struct la_backlink *bl;
3472 /* walk the list backwards, to do the first entry first, as we
3473 * added the entries with DLIST_ADD() which puts them at the
3474 * start of the list */
3475 for (la = replmd_private->la_list; la && la->next; la=la->next) ;
3477 for (; la; la=prev) {
3479 DLIST_REMOVE(replmd_private->la_list, la);
3480 ret = replmd_process_linked_attribute(module, la);
3481 if (ret != LDB_SUCCESS) {
3482 replmd_txn_cleanup(replmd_private);
3487 /* process our backlink list, creating and deleting backlinks
3489 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
3490 ret = replmd_process_backlink(module, bl);
3491 if (ret != LDB_SUCCESS) {
3492 replmd_txn_cleanup(replmd_private);
3497 replmd_txn_cleanup(replmd_private);
3499 /* possibly change @REPLCHANGED */
3500 ret = replmd_notify_store(module);
3501 if (ret != LDB_SUCCESS) {
3505 return ldb_next_prepare_commit(module);
3508 static int replmd_del_transaction(struct ldb_module *module)
3510 struct replmd_private *replmd_private =
3511 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3512 replmd_txn_cleanup(replmd_private);
3514 return ldb_next_del_trans(module);
3518 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
3519 .name = "repl_meta_data",
3520 .init_context = replmd_init,
3522 .modify = replmd_modify,
3523 .rename = replmd_rename,
3524 .del = replmd_delete,
3525 .extended = replmd_extended,
3526 .start_transaction = replmd_start_transaction,
3527 .prepare_commit = replmd_prepare_commit,
3528 .del_transaction = replmd_del_transaction,