s4-repl: fixed a memory error handling linked attributes
[Samba/aatanasov.git] / source4 / dsdb / samdb / ldb_modules / repl_meta_data.c
blobb9323b912ba52353a49ffe52bc7e00f74569ce19
1 /*
2 ldb database library
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/>.
24 * Name: ldb
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
33 * Author: Simo Sorce
34 * Author: Stefan Metzmacher
37 #include "includes.h"
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"
49 struct replmd_private {
50 TALLOC_CTX *la_ctx;
51 struct la_entry *la_list;
52 uint32_t num_ncs;
53 struct nc_entry {
54 struct ldb_dn *dn;
55 struct GUID guid;
56 uint64_t mod_usn;
57 } *ncs;
60 struct la_entry {
61 struct la_entry *next, *prev;
62 struct drsuapi_DsReplicaLinkedAttribute *la;
65 struct replmd_replicated_request {
66 struct ldb_module *module;
67 struct ldb_request *req;
69 const struct dsdb_schema *schema;
71 struct dsdb_extended_replicated_objects *objs;
73 /* the controls we pass down */
74 struct ldb_control **controls;
76 uint32_t index_current;
78 struct ldb_message *search_msg;
83 initialise the module
84 allocate the private structure and build the list
85 of partition DNs for use by replmd_notify()
87 static int replmd_init(struct ldb_module *module)
89 struct replmd_private *replmd_private;
90 struct ldb_context *ldb = ldb_module_get_ctx(module);
92 replmd_private = talloc_zero(module, struct replmd_private);
93 if (replmd_private == NULL) {
94 ldb_oom(ldb);
95 return LDB_ERR_OPERATIONS_ERROR;
97 ldb_module_set_private(module, replmd_private);
99 return ldb_next_init(module);
103 static int nc_compare(struct nc_entry *n1, struct nc_entry *n2)
105 return ldb_dn_compare(n1->dn, n2->dn);
109 build the list of partition DNs for use by replmd_notify()
111 static int replmd_load_NCs(struct ldb_module *module)
113 const char *attrs[] = { "namingContexts", NULL };
114 struct ldb_result *res = NULL;
115 int i, ret;
116 TALLOC_CTX *tmp_ctx;
117 struct ldb_context *ldb;
118 struct ldb_message_element *el;
119 struct replmd_private *replmd_private =
120 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
122 if (replmd_private->ncs != NULL) {
123 return LDB_SUCCESS;
126 ldb = ldb_module_get_ctx(module);
127 tmp_ctx = talloc_new(module);
129 /* load the list of naming contexts */
130 ret = ldb_search(ldb, tmp_ctx, &res, ldb_dn_new(tmp_ctx, ldb, ""),
131 LDB_SCOPE_BASE, attrs, NULL);
132 if (ret != LDB_SUCCESS ||
133 res->count != 1) {
134 DEBUG(0,(__location__ ": Failed to load rootDSE\n"));
135 return LDB_ERR_OPERATIONS_ERROR;
138 el = ldb_msg_find_element(res->msgs[0], "namingContexts");
139 if (el == NULL) {
140 DEBUG(0,(__location__ ": Failed to load namingContexts\n"));
141 return LDB_ERR_OPERATIONS_ERROR;
144 replmd_private->num_ncs = el->num_values;
145 replmd_private->ncs = talloc_array(replmd_private, struct nc_entry,
146 replmd_private->num_ncs);
147 if (replmd_private->ncs == NULL) {
148 ldb_oom(ldb);
149 return LDB_ERR_OPERATIONS_ERROR;
152 for (i=0; i<replmd_private->num_ncs; i++) {
153 replmd_private->ncs[i].dn =
154 ldb_dn_from_ldb_val(replmd_private->ncs,
155 ldb, &el->values[i]);
156 replmd_private->ncs[i].mod_usn = 0;
159 talloc_free(res);
161 /* now find the GUIDs of each of those DNs */
162 for (i=0; i<replmd_private->num_ncs; i++) {
163 const char *attrs2[] = { "objectGUID", NULL };
164 ret = ldb_search(ldb, tmp_ctx, &res, replmd_private->ncs[i].dn,
165 LDB_SCOPE_BASE, attrs2, NULL);
166 if (ret != LDB_SUCCESS ||
167 res->count != 1) {
168 /* this happens when the schema is first being
169 setup */
170 talloc_free(replmd_private->ncs);
171 replmd_private->ncs = NULL;
172 replmd_private->num_ncs = 0;
173 talloc_free(tmp_ctx);
174 return LDB_SUCCESS;
176 replmd_private->ncs[i].guid =
177 samdb_result_guid(res->msgs[0], "objectGUID");
178 talloc_free(res);
181 /* sort the NCs into order, most to least specific */
182 qsort(replmd_private->ncs, replmd_private->num_ncs,
183 sizeof(replmd_private->ncs[0]), QSORT_CAST nc_compare);
186 talloc_free(tmp_ctx);
188 return LDB_SUCCESS;
193 * notify the repl task that a object has changed. The notifies are
194 * gathered up in the replmd_private structure then written to the
195 * @REPLCHANGED object in each partition during the prepare_commit
197 static int replmd_notify(struct ldb_module *module, struct ldb_dn *dn, uint64_t uSN)
199 int ret, i;
200 struct replmd_private *replmd_private =
201 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
203 ret = replmd_load_NCs(module);
204 if (ret != LDB_SUCCESS) {
205 return ret;
207 if (replmd_private->num_ncs == 0) {
208 return LDB_SUCCESS;
211 for (i=0; i<replmd_private->num_ncs; i++) {
212 if (ldb_dn_compare_base(replmd_private->ncs[i].dn, dn) == 0) {
213 break;
216 if (i == replmd_private->num_ncs) {
217 DEBUG(0,(__location__ ": DN not within known NCs '%s'\n",
218 ldb_dn_get_linearized(dn)));
219 return LDB_ERR_OPERATIONS_ERROR;
222 if (uSN > replmd_private->ncs[i].mod_usn) {
223 replmd_private->ncs[i].mod_usn = uSN;
226 return LDB_SUCCESS;
231 * update a @REPLCHANGED record in each partition if there have been
232 * any writes of replicated data in the partition
234 static int replmd_notify_store(struct ldb_module *module)
236 int i;
237 struct replmd_private *replmd_private =
238 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
239 struct ldb_context *ldb = ldb_module_get_ctx(module);
241 for (i=0; i<replmd_private->num_ncs; i++) {
242 int ret;
244 if (replmd_private->ncs[i].mod_usn == 0) {
245 /* this partition has not changed in this
246 transaction */
247 continue;
250 ret = dsdb_save_partition_usn(ldb, replmd_private->ncs[i].dn,
251 replmd_private->ncs[i].mod_usn);
252 if (ret != LDB_SUCCESS) {
253 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
254 ldb_dn_get_linearized(replmd_private->ncs[i].dn)));
255 return ret;
259 return LDB_SUCCESS;
264 created a replmd_replicated_request context
266 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
267 struct ldb_request *req)
269 struct ldb_context *ldb;
270 struct replmd_replicated_request *ac;
272 ldb = ldb_module_get_ctx(module);
274 ac = talloc_zero(req, struct replmd_replicated_request);
275 if (ac == NULL) {
276 ldb_oom(ldb);
277 return NULL;
280 ac->module = module;
281 ac->req = req;
282 return ac;
286 add a time element to a record
288 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
290 struct ldb_message_element *el;
291 char *s;
293 if (ldb_msg_find_element(msg, attr) != NULL) {
294 return LDB_SUCCESS;
297 s = ldb_timestring(msg, t);
298 if (s == NULL) {
299 return LDB_ERR_OPERATIONS_ERROR;
302 if (ldb_msg_add_string(msg, attr, s) != LDB_SUCCESS) {
303 return LDB_ERR_OPERATIONS_ERROR;
306 el = ldb_msg_find_element(msg, attr);
307 /* always set as replace. This works because on add ops, the flag
308 is ignored */
309 el->flags = LDB_FLAG_MOD_REPLACE;
311 return LDB_SUCCESS;
315 add a uint64_t element to a record
317 static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_t v)
319 struct ldb_message_element *el;
321 if (ldb_msg_find_element(msg, attr) != NULL) {
322 return LDB_SUCCESS;
325 if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != LDB_SUCCESS) {
326 return LDB_ERR_OPERATIONS_ERROR;
329 el = ldb_msg_find_element(msg, attr);
330 /* always set as replace. This works because on add ops, the flag
331 is ignored */
332 el->flags = LDB_FLAG_MOD_REPLACE;
334 return LDB_SUCCESS;
337 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
338 const struct replPropertyMetaData1 *m2,
339 const uint32_t *rdn_attid)
341 if (m1->attid == m2->attid) {
342 return 0;
346 * the rdn attribute should be at the end!
347 * so we need to return a value greater than zero
348 * which means m1 is greater than m2
350 if (m1->attid == *rdn_attid) {
351 return 1;
355 * the rdn attribute should be at the end!
356 * so we need to return a value less than zero
357 * which means m2 is greater than m1
359 if (m2->attid == *rdn_attid) {
360 return -1;
363 return m1->attid - m2->attid;
366 static void replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
367 const uint32_t *rdn_attid)
369 ldb_qsort(ctr1->array, ctr1->count, sizeof(struct replPropertyMetaData1),
370 discard_const_p(void, rdn_attid), (ldb_qsort_cmp_fn_t)replmd_replPropertyMetaData1_attid_sort);
373 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
374 const struct ldb_message_element *e2,
375 const struct dsdb_schema *schema)
377 const struct dsdb_attribute *a1;
378 const struct dsdb_attribute *a2;
381 * TODO: make this faster by caching the dsdb_attribute pointer
382 * on the ldb_messag_element
385 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
386 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
389 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
390 * in the schema
392 if (!a1 || !a2) {
393 return strcasecmp(e1->name, e2->name);
396 return a1->attributeID_id - a2->attributeID_id;
399 static void replmd_ldb_message_sort(struct ldb_message *msg,
400 const struct dsdb_schema *schema)
402 ldb_qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
403 discard_const_p(void, schema), (ldb_qsort_cmp_fn_t)replmd_ldb_message_element_attid_sort);
406 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
408 struct ldb_context *ldb;
409 struct replmd_replicated_request *ac;
411 ac = talloc_get_type(req->context, struct replmd_replicated_request);
412 ldb = ldb_module_get_ctx(ac->module);
414 if (!ares) {
415 return ldb_module_done(ac->req, NULL, NULL,
416 LDB_ERR_OPERATIONS_ERROR);
418 if (ares->error != LDB_SUCCESS) {
419 return ldb_module_done(ac->req, ares->controls,
420 ares->response, ares->error);
423 if (ares->type != LDB_REPLY_DONE) {
424 ldb_set_errstring(ldb,
425 "invalid ldb_reply_type in callback");
426 talloc_free(ares);
427 return ldb_module_done(ac->req, NULL, NULL,
428 LDB_ERR_OPERATIONS_ERROR);
431 return ldb_module_done(ac->req, ares->controls,
432 ares->response, LDB_SUCCESS);
435 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
437 struct ldb_context *ldb;
438 struct replmd_replicated_request *ac;
439 const struct dsdb_schema *schema;
440 enum ndr_err_code ndr_err;
441 struct ldb_request *down_req;
442 struct ldb_message *msg;
443 const struct dsdb_attribute *rdn_attr = NULL;
444 struct GUID guid;
445 struct ldb_val guid_value;
446 struct replPropertyMetaDataBlob nmd;
447 struct ldb_val nmd_value;
448 uint64_t seq_num;
449 const struct GUID *our_invocation_id;
450 time_t t = time(NULL);
451 NTTIME now;
452 char *time_str;
453 int ret;
454 uint32_t i, ni=0;
456 /* do not manipulate our control entries */
457 if (ldb_dn_is_special(req->op.add.message->dn)) {
458 return ldb_next_request(module, req);
461 ldb = ldb_module_get_ctx(module);
463 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
465 schema = dsdb_get_schema(ldb);
466 if (!schema) {
467 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
468 "replmd_add: no dsdb_schema loaded");
469 return LDB_ERR_CONSTRAINT_VIOLATION;
472 ac = replmd_ctx_init(module, req);
473 if (!ac) {
474 return LDB_ERR_OPERATIONS_ERROR;
477 ac->schema = schema;
479 if (ldb_msg_find_element(req->op.add.message, "objectGUID") != NULL) {
480 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
481 "replmd_add: it's not allowed to add an object with objectGUID\n");
482 return LDB_ERR_UNWILLING_TO_PERFORM;
485 /* Get a sequence number from the backend */
486 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
487 if (ret != LDB_SUCCESS) {
488 return ret;
491 /* a new GUID */
492 guid = GUID_random();
494 /* get our invocationId */
495 our_invocation_id = samdb_ntds_invocation_id(ldb);
496 if (!our_invocation_id) {
497 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
498 "replmd_add: unable to find invocationId\n");
499 return LDB_ERR_OPERATIONS_ERROR;
502 /* we have to copy the message as the caller might have it as a const */
503 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
504 if (msg == NULL) {
505 ldb_oom(ldb);
506 return LDB_ERR_OPERATIONS_ERROR;
509 /* generated times */
510 unix_to_nt_time(&now, t);
511 time_str = ldb_timestring(msg, t);
512 if (!time_str) {
513 return LDB_ERR_OPERATIONS_ERROR;
517 * remove autogenerated attributes
519 ldb_msg_remove_attr(msg, "whenCreated");
520 ldb_msg_remove_attr(msg, "whenChanged");
521 ldb_msg_remove_attr(msg, "uSNCreated");
522 ldb_msg_remove_attr(msg, "uSNChanged");
523 ldb_msg_remove_attr(msg, "replPropertyMetaData");
526 * readd replicated attributes
528 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
529 if (ret != LDB_SUCCESS) {
530 ldb_oom(ldb);
531 return LDB_ERR_OPERATIONS_ERROR;
534 /* build the replication meta_data */
535 ZERO_STRUCT(nmd);
536 nmd.version = 1;
537 nmd.ctr.ctr1.count = msg->num_elements;
538 nmd.ctr.ctr1.array = talloc_array(msg,
539 struct replPropertyMetaData1,
540 nmd.ctr.ctr1.count);
541 if (!nmd.ctr.ctr1.array) {
542 ldb_oom(ldb);
543 return LDB_ERR_OPERATIONS_ERROR;
546 for (i=0; i < msg->num_elements; i++) {
547 struct ldb_message_element *e = &msg->elements[i];
548 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
549 const struct dsdb_attribute *sa;
551 if (e->name[0] == '@') continue;
553 sa = dsdb_attribute_by_lDAPDisplayName(schema, e->name);
554 if (!sa) {
555 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
556 "replmd_add: attribute '%s' not defined in schema\n",
557 e->name);
558 return LDB_ERR_NO_SUCH_ATTRIBUTE;
561 if ((sa->systemFlags & 0x00000001) || (sa->systemFlags & 0x00000004)) {
562 /* if the attribute is not replicated (0x00000001)
563 * or constructed (0x00000004) it has no metadata
565 continue;
568 m->attid = sa->attributeID_id;
569 m->version = 1;
570 m->originating_change_time = now;
571 m->originating_invocation_id = *our_invocation_id;
572 m->originating_usn = seq_num;
573 m->local_usn = seq_num;
574 ni++;
576 if (ldb_attr_cmp(e->name, ldb_dn_get_rdn_name(msg->dn))) {
577 rdn_attr = sa;
581 /* fix meta data count */
582 nmd.ctr.ctr1.count = ni;
585 * sort meta data array, and move the rdn attribute entry to the end
587 replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, &rdn_attr->attributeID_id);
589 /* generated NDR encoded values */
590 ndr_err = ndr_push_struct_blob(&guid_value, msg,
591 NULL,
592 &guid,
593 (ndr_push_flags_fn_t)ndr_push_GUID);
594 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
595 ldb_oom(ldb);
596 return LDB_ERR_OPERATIONS_ERROR;
598 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
599 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
600 &nmd,
601 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
602 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
603 ldb_oom(ldb);
604 return LDB_ERR_OPERATIONS_ERROR;
608 * add the autogenerated values
610 ret = ldb_msg_add_value(msg, "objectGUID", &guid_value, NULL);
611 if (ret != LDB_SUCCESS) {
612 ldb_oom(ldb);
613 return LDB_ERR_OPERATIONS_ERROR;
615 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
616 if (ret != LDB_SUCCESS) {
617 ldb_oom(ldb);
618 return LDB_ERR_OPERATIONS_ERROR;
620 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", seq_num);
621 if (ret != LDB_SUCCESS) {
622 ldb_oom(ldb);
623 return LDB_ERR_OPERATIONS_ERROR;
625 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", seq_num);
626 if (ret != LDB_SUCCESS) {
627 ldb_oom(ldb);
628 return LDB_ERR_OPERATIONS_ERROR;
630 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
631 if (ret != LDB_SUCCESS) {
632 ldb_oom(ldb);
633 return LDB_ERR_OPERATIONS_ERROR;
637 * sort the attributes by attid before storing the object
639 replmd_ldb_message_sort(msg, schema);
641 ret = ldb_build_add_req(&down_req, ldb, ac,
642 msg,
643 req->controls,
644 ac, replmd_op_callback,
645 req);
646 if (ret != LDB_SUCCESS) {
647 return ret;
650 ret = replmd_notify(module, msg->dn, seq_num);
651 if (ret != LDB_SUCCESS) {
652 return ret;
655 /* go on with the call chain */
656 return ldb_next_request(module, down_req);
661 * update the replPropertyMetaData for one element
663 static int replmd_update_rpmd_element(struct ldb_context *ldb,
664 struct ldb_message *msg,
665 struct ldb_message_element *el,
666 struct replPropertyMetaDataBlob *omd,
667 struct dsdb_schema *schema,
668 uint64_t *seq_num,
669 const struct GUID *our_invocation_id,
670 NTTIME now)
672 int i;
673 const struct dsdb_attribute *a;
674 struct replPropertyMetaData1 *md1;
676 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
677 if (a == NULL) {
678 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
679 el->name));
680 return LDB_ERR_OPERATIONS_ERROR;
683 if ((a->systemFlags & 0x00000001) || (a->systemFlags & 0x00000004)) {
684 /* if the attribute is not replicated (0x00000001)
685 * or constructed (0x00000004) it has no metadata
687 return LDB_SUCCESS;
690 for (i=0; i<omd->ctr.ctr1.count; i++) {
691 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
693 if (i == omd->ctr.ctr1.count) {
694 /* we need to add a new one */
695 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
696 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
697 if (omd->ctr.ctr1.array == NULL) {
698 ldb_oom(ldb);
699 return LDB_ERR_OPERATIONS_ERROR;
701 omd->ctr.ctr1.count++;
702 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
705 /* Get a new sequence number from the backend. We only do this
706 * if we have a change that requires a new
707 * replPropertyMetaData element
709 if (*seq_num == 0) {
710 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
711 if (ret != LDB_SUCCESS) {
712 return LDB_ERR_OPERATIONS_ERROR;
716 md1 = &omd->ctr.ctr1.array[i];
717 md1->version++;
718 md1->attid = a->attributeID_id;
719 md1->originating_change_time = now;
720 md1->originating_invocation_id = *our_invocation_id;
721 md1->originating_usn = *seq_num;
722 md1->local_usn = *seq_num;
724 return LDB_SUCCESS;
728 * update the replPropertyMetaData object each time we modify an
729 * object. This is needed for DRS replication, as the merge on the
730 * client is based on this object
732 static int replmd_update_rpmd(struct ldb_module *module,
733 struct ldb_message *msg, uint64_t *seq_num)
735 const struct ldb_val *omd_value;
736 enum ndr_err_code ndr_err;
737 struct replPropertyMetaDataBlob omd;
738 int i;
739 struct dsdb_schema *schema;
740 time_t t = time(NULL);
741 NTTIME now;
742 const struct GUID *our_invocation_id;
743 int ret;
744 const char *attrs[] = { "replPropertyMetaData" , NULL };
745 struct ldb_result *res;
746 struct ldb_context *ldb;
748 ldb = ldb_module_get_ctx(module);
750 our_invocation_id = samdb_ntds_invocation_id(ldb);
751 if (!our_invocation_id) {
752 /* this happens during an initial vampire while
753 updating the schema */
754 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
755 return LDB_SUCCESS;
758 unix_to_nt_time(&now, t);
760 /* search for the existing replPropertyMetaDataBlob */
761 ret = ldb_search(ldb, msg, &res, msg->dn, LDB_SCOPE_BASE, attrs, NULL);
762 if (ret != LDB_SUCCESS || res->count < 1) {
763 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
764 ldb_dn_get_linearized(msg->dn)));
765 return LDB_ERR_OPERATIONS_ERROR;
769 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
770 if (!omd_value) {
771 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
772 ldb_dn_get_linearized(msg->dn)));
773 return LDB_ERR_OPERATIONS_ERROR;
776 ndr_err = ndr_pull_struct_blob(omd_value, msg,
777 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
778 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
779 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
780 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
781 ldb_dn_get_linearized(msg->dn)));
782 return LDB_ERR_OPERATIONS_ERROR;
785 if (omd.version != 1) {
786 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
787 omd.version, ldb_dn_get_linearized(msg->dn)));
788 return LDB_ERR_OPERATIONS_ERROR;
791 schema = dsdb_get_schema(ldb);
793 for (i=0; i<msg->num_elements; i++) {
794 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], &omd, schema, seq_num,
795 our_invocation_id, now);
796 if (ret != LDB_SUCCESS) {
797 return ret;
802 * replmd_update_rpmd_element has done an update if the
803 * seq_num is set
805 if (*seq_num != 0) {
806 struct ldb_val *md_value;
807 struct ldb_message_element *el;
809 md_value = talloc(msg, struct ldb_val);
810 if (md_value == NULL) {
811 ldb_oom(ldb);
812 return LDB_ERR_OPERATIONS_ERROR;
815 ndr_err = ndr_push_struct_blob(md_value, msg,
816 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
817 &omd,
818 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
819 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
820 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
821 ldb_dn_get_linearized(msg->dn)));
822 return LDB_ERR_OPERATIONS_ERROR;
825 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
826 if (ret != LDB_SUCCESS) {
827 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
828 ldb_dn_get_linearized(msg->dn)));
829 return ret;
832 ret = replmd_notify(module, msg->dn, *seq_num);
833 if (ret != LDB_SUCCESS) {
834 return ret;
837 el->num_values = 1;
838 el->values = md_value;
841 return LDB_SUCCESS;
845 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
847 struct ldb_context *ldb;
848 struct replmd_replicated_request *ac;
849 const struct dsdb_schema *schema;
850 struct ldb_request *down_req;
851 struct ldb_message *msg;
852 int ret;
853 time_t t = time(NULL);
854 uint64_t seq_num = 0;
856 /* do not manipulate our control entries */
857 if (ldb_dn_is_special(req->op.mod.message->dn)) {
858 return ldb_next_request(module, req);
861 ldb = ldb_module_get_ctx(module);
863 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
865 schema = dsdb_get_schema(ldb);
866 if (!schema) {
867 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
868 "replmd_modify: no dsdb_schema loaded");
869 return LDB_ERR_CONSTRAINT_VIOLATION;
872 ac = replmd_ctx_init(module, req);
873 if (!ac) {
874 return LDB_ERR_OPERATIONS_ERROR;
877 ac->schema = schema;
879 /* we have to copy the message as the caller might have it as a const */
880 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
881 if (msg == NULL) {
882 talloc_free(ac);
883 return LDB_ERR_OPERATIONS_ERROR;
886 /* TODO:
887 * - get the whole old object
888 * - if the old object doesn't exist report an error
889 * - give an error when a readonly attribute should
890 * be modified
891 * - merge the changed into the old object
892 * if the caller set values to the same value
893 * ignore the attribute, return success when no
894 * attribute was changed
897 ret = replmd_update_rpmd(module, msg, &seq_num);
898 if (ret != LDB_SUCCESS) {
899 return ret;
902 /* TODO:
903 * - sort the attributes by attid with replmd_ldb_message_sort()
904 * - replace the old object with the newly constructed one
907 ret = ldb_build_mod_req(&down_req, ldb, ac,
908 msg,
909 req->controls,
910 ac, replmd_op_callback,
911 req);
912 if (ret != LDB_SUCCESS) {
913 return ret;
915 talloc_steal(down_req, msg);
917 /* we only change whenChanged and uSNChanged if the seq_num
918 has changed */
919 if (seq_num != 0) {
920 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
921 talloc_free(ac);
922 return LDB_ERR_OPERATIONS_ERROR;
925 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
926 talloc_free(ac);
927 return LDB_ERR_OPERATIONS_ERROR;
931 /* go on with the call chain */
932 return ldb_next_request(module, down_req);
935 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
937 return ret;
940 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
942 int ret = LDB_ERR_OTHER;
943 /* TODO: do some error mapping */
944 return ret;
947 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
949 static int replmd_replicated_apply_add_callback(struct ldb_request *req,
950 struct ldb_reply *ares)
952 struct ldb_context *ldb;
953 struct replmd_replicated_request *ar = talloc_get_type(req->context,
954 struct replmd_replicated_request);
955 int ret;
957 ldb = ldb_module_get_ctx(ar->module);
959 if (!ares) {
960 return ldb_module_done(ar->req, NULL, NULL,
961 LDB_ERR_OPERATIONS_ERROR);
963 if (ares->error != LDB_SUCCESS) {
964 return ldb_module_done(ar->req, ares->controls,
965 ares->response, ares->error);
968 if (ares->type != LDB_REPLY_DONE) {
969 ldb_set_errstring(ldb, "Invalid reply type\n!");
970 return ldb_module_done(ar->req, NULL, NULL,
971 LDB_ERR_OPERATIONS_ERROR);
974 talloc_free(ares);
975 ar->index_current++;
977 ret = replmd_replicated_apply_next(ar);
978 if (ret != LDB_SUCCESS) {
979 return ldb_module_done(ar->req, NULL, NULL, ret);
982 return LDB_SUCCESS;
985 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
987 struct ldb_context *ldb;
988 struct ldb_request *change_req;
989 enum ndr_err_code ndr_err;
990 struct ldb_message *msg;
991 struct replPropertyMetaDataBlob *md;
992 struct ldb_val md_value;
993 uint32_t i;
994 uint64_t seq_num;
995 int ret;
998 * TODO: check if the parent object exist
1002 * TODO: handle the conflict case where an object with the
1003 * same name exist
1006 ldb = ldb_module_get_ctx(ar->module);
1007 msg = ar->objs->objects[ar->index_current].msg;
1008 md = ar->objs->objects[ar->index_current].meta_data;
1010 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
1011 if (ret != LDB_SUCCESS) {
1012 return replmd_replicated_request_error(ar, ret);
1015 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
1016 if (ret != LDB_SUCCESS) {
1017 return replmd_replicated_request_error(ar, ret);
1020 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
1021 if (ret != LDB_SUCCESS) {
1022 return replmd_replicated_request_error(ar, ret);
1025 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", seq_num);
1026 if (ret != LDB_SUCCESS) {
1027 return replmd_replicated_request_error(ar, ret);
1030 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", seq_num);
1031 if (ret != LDB_SUCCESS) {
1032 return replmd_replicated_request_error(ar, ret);
1035 ret = replmd_notify(ar->module, msg->dn, seq_num);
1036 if (ret != LDB_SUCCESS) {
1037 return replmd_replicated_request_error(ar, ret);
1041 * the meta data array is already sorted by the caller
1043 for (i=0; i < md->ctr.ctr1.count; i++) {
1044 md->ctr.ctr1.array[i].local_usn = seq_num;
1046 ndr_err = ndr_push_struct_blob(&md_value, msg,
1047 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1049 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1050 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1051 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1052 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1054 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
1055 if (ret != LDB_SUCCESS) {
1056 return replmd_replicated_request_error(ar, ret);
1059 replmd_ldb_message_sort(msg, ar->schema);
1061 if (DEBUGLVL(4)) {
1062 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
1063 DEBUG(4, ("DRS replication add message:\n%s\n", s));
1064 talloc_free(s);
1067 ret = ldb_build_add_req(&change_req,
1068 ldb,
1070 msg,
1071 ar->controls,
1073 replmd_replicated_apply_add_callback,
1074 ar->req);
1075 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1077 return ldb_next_request(ar->module, change_req);
1080 static int replmd_replPropertyMetaData1_conflict_compare(struct replPropertyMetaData1 *m1,
1081 struct replPropertyMetaData1 *m2)
1083 int ret;
1085 if (m1->version != m2->version) {
1086 return m1->version - m2->version;
1089 if (m1->originating_change_time != m2->originating_change_time) {
1090 return m1->originating_change_time - m2->originating_change_time;
1093 ret = GUID_compare(&m1->originating_invocation_id, &m2->originating_invocation_id);
1094 if (ret != 0) {
1095 return ret;
1098 return m1->originating_usn - m2->originating_usn;
1101 static int replmd_replicated_apply_merge_callback(struct ldb_request *req,
1102 struct ldb_reply *ares)
1104 struct ldb_context *ldb;
1105 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1106 struct replmd_replicated_request);
1107 int ret;
1109 ldb = ldb_module_get_ctx(ar->module);
1111 if (!ares) {
1112 return ldb_module_done(ar->req, NULL, NULL,
1113 LDB_ERR_OPERATIONS_ERROR);
1115 if (ares->error != LDB_SUCCESS) {
1116 return ldb_module_done(ar->req, ares->controls,
1117 ares->response, ares->error);
1120 if (ares->type != LDB_REPLY_DONE) {
1121 ldb_set_errstring(ldb, "Invalid reply type\n!");
1122 return ldb_module_done(ar->req, NULL, NULL,
1123 LDB_ERR_OPERATIONS_ERROR);
1126 talloc_free(ares);
1127 ar->index_current++;
1129 ret = replmd_replicated_apply_next(ar);
1130 if (ret != LDB_SUCCESS) {
1131 return ldb_module_done(ar->req, NULL, NULL, ret);
1134 return LDB_SUCCESS;
1137 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
1139 struct ldb_context *ldb;
1140 struct ldb_request *change_req;
1141 enum ndr_err_code ndr_err;
1142 struct ldb_message *msg;
1143 struct replPropertyMetaDataBlob *rmd;
1144 struct replPropertyMetaDataBlob omd;
1145 const struct ldb_val *omd_value;
1146 struct replPropertyMetaDataBlob nmd;
1147 struct ldb_val nmd_value;
1148 uint32_t i,j,ni=0;
1149 uint32_t removed_attrs = 0;
1150 uint64_t seq_num;
1151 int ret;
1153 ldb = ldb_module_get_ctx(ar->module);
1154 msg = ar->objs->objects[ar->index_current].msg;
1155 rmd = ar->objs->objects[ar->index_current].meta_data;
1156 ZERO_STRUCT(omd);
1157 omd.version = 1;
1160 * TODO: check repl data is correct after a rename
1162 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
1163 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
1164 ldb_dn_get_linearized(ar->search_msg->dn),
1165 ldb_dn_get_linearized(msg->dn));
1166 if (ldb_rename(ldb, ar->search_msg->dn, msg->dn) != LDB_SUCCESS) {
1167 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
1168 ldb_dn_get_linearized(ar->search_msg->dn),
1169 ldb_dn_get_linearized(msg->dn),
1170 ldb_errstring(ldb));
1171 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
1175 /* find existing meta data */
1176 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
1177 if (omd_value) {
1178 ndr_err = ndr_pull_struct_blob(omd_value, ar,
1179 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
1180 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1181 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1182 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1183 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1186 if (omd.version != 1) {
1187 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1191 ZERO_STRUCT(nmd);
1192 nmd.version = 1;
1193 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
1194 nmd.ctr.ctr1.array = talloc_array(ar,
1195 struct replPropertyMetaData1,
1196 nmd.ctr.ctr1.count);
1197 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1199 /* first copy the old meta data */
1200 for (i=0; i < omd.ctr.ctr1.count; i++) {
1201 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
1202 ni++;
1205 /* now merge in the new meta data */
1206 for (i=0; i < rmd->ctr.ctr1.count; i++) {
1207 bool found = false;
1209 for (j=0; j < ni; j++) {
1210 int cmp;
1212 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
1213 continue;
1216 cmp = replmd_replPropertyMetaData1_conflict_compare(&rmd->ctr.ctr1.array[i],
1217 &nmd.ctr.ctr1.array[j]);
1218 if (cmp > 0) {
1219 /* replace the entry */
1220 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
1221 found = true;
1222 break;
1225 /* we don't want to apply this change so remove the attribute */
1226 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
1227 removed_attrs++;
1229 found = true;
1230 break;
1233 if (found) continue;
1235 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
1236 ni++;
1240 * finally correct the size of the meta_data array
1242 nmd.ctr.ctr1.count = ni;
1245 * the rdn attribute (the alias for the name attribute),
1246 * 'cn' for most objects is the last entry in the meta data array
1247 * we have stored
1249 * sort the new meta data array
1252 struct replPropertyMetaData1 *rdn_p;
1253 uint32_t rdn_idx = omd.ctr.ctr1.count - 1;
1255 rdn_p = &nmd.ctr.ctr1.array[rdn_idx];
1256 replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, &rdn_p->attid);
1259 /* create the meta data value */
1260 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1261 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1262 &nmd,
1263 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1264 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1265 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1266 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1270 * check if some replicated attributes left, otherwise skip the ldb_modify() call
1272 if (msg->num_elements == 0) {
1273 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
1274 ar->index_current);
1276 ar->index_current++;
1277 return replmd_replicated_apply_next(ar);
1280 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
1281 ar->index_current, msg->num_elements);
1283 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
1284 if (ret != LDB_SUCCESS) {
1285 return replmd_replicated_request_error(ar, ret);
1288 for (i=0; i<ni; i++) {
1289 nmd.ctr.ctr1.array[i].local_usn = seq_num;
1293 * when we know that we'll modify the record, add the whenChanged, uSNChanged
1294 * and replPopertyMetaData attributes
1296 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
1297 if (ret != LDB_SUCCESS) {
1298 return replmd_replicated_request_error(ar, ret);
1300 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", seq_num);
1301 if (ret != LDB_SUCCESS) {
1302 return replmd_replicated_request_error(ar, ret);
1304 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1305 if (ret != LDB_SUCCESS) {
1306 return replmd_replicated_request_error(ar, ret);
1309 replmd_ldb_message_sort(msg, ar->schema);
1311 /* we want to replace the old values */
1312 for (i=0; i < msg->num_elements; i++) {
1313 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1316 ret = replmd_notify(ar->module, msg->dn, seq_num);
1317 if (ret != LDB_SUCCESS) {
1318 return replmd_replicated_request_error(ar, ret);
1321 if (DEBUGLVL(4)) {
1322 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
1323 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
1324 talloc_free(s);
1327 ret = ldb_build_mod_req(&change_req,
1328 ldb,
1330 msg,
1331 ar->controls,
1333 replmd_replicated_apply_merge_callback,
1334 ar->req);
1335 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1337 return ldb_next_request(ar->module, change_req);
1340 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
1341 struct ldb_reply *ares)
1343 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1344 struct replmd_replicated_request);
1345 int ret;
1347 if (!ares) {
1348 return ldb_module_done(ar->req, NULL, NULL,
1349 LDB_ERR_OPERATIONS_ERROR);
1351 if (ares->error != LDB_SUCCESS &&
1352 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
1353 return ldb_module_done(ar->req, ares->controls,
1354 ares->response, ares->error);
1357 switch (ares->type) {
1358 case LDB_REPLY_ENTRY:
1359 ar->search_msg = talloc_steal(ar, ares->message);
1360 break;
1362 case LDB_REPLY_REFERRAL:
1363 /* we ignore referrals */
1364 break;
1366 case LDB_REPLY_DONE:
1367 if (ar->search_msg != NULL) {
1368 ret = replmd_replicated_apply_merge(ar);
1369 } else {
1370 ret = replmd_replicated_apply_add(ar);
1372 if (ret != LDB_SUCCESS) {
1373 return ldb_module_done(ar->req, NULL, NULL, ret);
1377 talloc_free(ares);
1378 return LDB_SUCCESS;
1381 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
1383 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
1385 struct ldb_context *ldb;
1386 int ret;
1387 char *tmp_str;
1388 char *filter;
1389 struct ldb_request *search_req;
1391 if (ar->index_current >= ar->objs->num_objects) {
1392 /* done with it, go to next stage */
1393 return replmd_replicated_uptodate_vector(ar);
1396 ldb = ldb_module_get_ctx(ar->module);
1397 ar->search_msg = NULL;
1399 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
1400 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1402 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
1403 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1404 talloc_free(tmp_str);
1406 ret = ldb_build_search_req(&search_req,
1407 ldb,
1409 ar->objs->partition_dn,
1410 LDB_SCOPE_SUBTREE,
1411 filter,
1412 NULL,
1413 NULL,
1415 replmd_replicated_apply_search_callback,
1416 ar->req);
1417 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1419 return ldb_next_request(ar->module, search_req);
1422 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
1423 struct ldb_reply *ares)
1425 struct ldb_context *ldb;
1426 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1427 struct replmd_replicated_request);
1428 ldb = ldb_module_get_ctx(ar->module);
1430 if (!ares) {
1431 return ldb_module_done(ar->req, NULL, NULL,
1432 LDB_ERR_OPERATIONS_ERROR);
1434 if (ares->error != LDB_SUCCESS) {
1435 return ldb_module_done(ar->req, ares->controls,
1436 ares->response, ares->error);
1439 if (ares->type != LDB_REPLY_DONE) {
1440 ldb_set_errstring(ldb, "Invalid reply type\n!");
1441 return ldb_module_done(ar->req, NULL, NULL,
1442 LDB_ERR_OPERATIONS_ERROR);
1445 talloc_free(ares);
1447 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
1450 static int replmd_drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
1451 const struct drsuapi_DsReplicaCursor2 *c2)
1453 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
1456 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
1458 struct ldb_context *ldb;
1459 struct ldb_request *change_req;
1460 enum ndr_err_code ndr_err;
1461 struct ldb_message *msg;
1462 struct replUpToDateVectorBlob ouv;
1463 const struct ldb_val *ouv_value;
1464 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
1465 struct replUpToDateVectorBlob nuv;
1466 struct ldb_val nuv_value;
1467 struct ldb_message_element *nuv_el = NULL;
1468 const struct GUID *our_invocation_id;
1469 struct ldb_message_element *orf_el = NULL;
1470 struct repsFromToBlob nrf;
1471 struct ldb_val *nrf_value = NULL;
1472 struct ldb_message_element *nrf_el = NULL;
1473 uint32_t i,j,ni=0;
1474 bool found = false;
1475 time_t t = time(NULL);
1476 NTTIME now;
1477 int ret;
1479 ldb = ldb_module_get_ctx(ar->module);
1480 ruv = ar->objs->uptodateness_vector;
1481 ZERO_STRUCT(ouv);
1482 ouv.version = 2;
1483 ZERO_STRUCT(nuv);
1484 nuv.version = 2;
1486 unix_to_nt_time(&now, t);
1489 * first create the new replUpToDateVector
1491 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
1492 if (ouv_value) {
1493 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
1494 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
1495 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
1496 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1497 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1498 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1501 if (ouv.version != 2) {
1502 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1507 * the new uptodateness vector will at least
1508 * contain 1 entry, one for the source_dsa
1510 * plus optional values from our old vector and the one from the source_dsa
1512 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
1513 if (ruv) nuv.ctr.ctr2.count += ruv->count;
1514 nuv.ctr.ctr2.cursors = talloc_array(ar,
1515 struct drsuapi_DsReplicaCursor2,
1516 nuv.ctr.ctr2.count);
1517 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1519 /* first copy the old vector */
1520 for (i=0; i < ouv.ctr.ctr2.count; i++) {
1521 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
1522 ni++;
1525 /* get our invocation_id if we have one already attached to the ldb */
1526 our_invocation_id = samdb_ntds_invocation_id(ldb);
1528 /* merge in the source_dsa vector is available */
1529 for (i=0; (ruv && i < ruv->count); i++) {
1530 found = false;
1532 if (our_invocation_id &&
1533 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
1534 our_invocation_id)) {
1535 continue;
1538 for (j=0; j < ni; j++) {
1539 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
1540 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
1541 continue;
1544 found = true;
1547 * we update only the highest_usn and not the latest_sync_success time,
1548 * because the last success stands for direct replication
1550 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
1551 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
1553 break;
1556 if (found) continue;
1558 /* if it's not there yet, add it */
1559 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
1560 ni++;
1564 * merge in the current highwatermark for the source_dsa
1566 found = false;
1567 for (j=0; j < ni; j++) {
1568 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
1569 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
1570 continue;
1573 found = true;
1576 * here we update the highest_usn and last_sync_success time
1577 * because we're directly replicating from the source_dsa
1579 * and use the tmp_highest_usn because this is what we have just applied
1580 * to our ldb
1582 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
1583 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
1584 break;
1586 if (!found) {
1588 * here we update the highest_usn and last_sync_success time
1589 * because we're directly replicating from the source_dsa
1591 * and use the tmp_highest_usn because this is what we have just applied
1592 * to our ldb
1594 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
1595 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
1596 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
1597 ni++;
1601 * finally correct the size of the cursors array
1603 nuv.ctr.ctr2.count = ni;
1606 * sort the cursors
1608 qsort(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count,
1609 sizeof(struct drsuapi_DsReplicaCursor2),
1610 (comparison_fn_t)replmd_drsuapi_DsReplicaCursor2_compare);
1613 * create the change ldb_message
1615 msg = ldb_msg_new(ar);
1616 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1617 msg->dn = ar->search_msg->dn;
1619 ndr_err = ndr_push_struct_blob(&nuv_value, msg,
1620 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1621 &nuv,
1622 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
1623 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1624 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1625 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1627 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
1628 if (ret != LDB_SUCCESS) {
1629 return replmd_replicated_request_error(ar, ret);
1631 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
1634 * now create the new repsFrom value from the given repsFromTo1 structure
1636 ZERO_STRUCT(nrf);
1637 nrf.version = 1;
1638 nrf.ctr.ctr1 = *ar->objs->source_dsa;
1639 /* and fix some values... */
1640 nrf.ctr.ctr1.consecutive_sync_failures = 0;
1641 nrf.ctr.ctr1.last_success = now;
1642 nrf.ctr.ctr1.last_attempt = now;
1643 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
1644 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
1647 * first see if we already have a repsFrom value for the current source dsa
1648 * if so we'll later replace this value
1650 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
1651 if (orf_el) {
1652 for (i=0; i < orf_el->num_values; i++) {
1653 struct repsFromToBlob *trf;
1655 trf = talloc(ar, struct repsFromToBlob);
1656 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1658 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
1659 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
1660 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1661 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1662 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1665 if (trf->version != 1) {
1666 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1670 * we compare the source dsa objectGUID not the invocation_id
1671 * because we want only one repsFrom value per source dsa
1672 * and when the invocation_id of the source dsa has changed we don't need
1673 * the old repsFrom with the old invocation_id
1675 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
1676 &ar->objs->source_dsa->source_dsa_obj_guid)) {
1677 talloc_free(trf);
1678 continue;
1681 talloc_free(trf);
1682 nrf_value = &orf_el->values[i];
1683 break;
1687 * copy over all old values to the new ldb_message
1689 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
1690 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1691 *nrf_el = *orf_el;
1695 * if we haven't found an old repsFrom value for the current source dsa
1696 * we'll add a new value
1698 if (!nrf_value) {
1699 struct ldb_val zero_value;
1700 ZERO_STRUCT(zero_value);
1701 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
1702 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1704 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
1707 /* we now fill the value which is already attached to ldb_message */
1708 ndr_err = ndr_push_struct_blob(nrf_value, msg,
1709 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1710 &nrf,
1711 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
1712 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1713 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1714 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1718 * the ldb_message_element for the attribute, has all the old values and the new one
1719 * so we'll replace the whole attribute with all values
1721 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
1723 if (DEBUGLVL(4)) {
1724 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
1725 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
1726 talloc_free(s);
1729 /* prepare the ldb_modify() request */
1730 ret = ldb_build_mod_req(&change_req,
1731 ldb,
1733 msg,
1734 ar->controls,
1736 replmd_replicated_uptodate_modify_callback,
1737 ar->req);
1738 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1740 return ldb_next_request(ar->module, change_req);
1743 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
1744 struct ldb_reply *ares)
1746 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1747 struct replmd_replicated_request);
1748 int ret;
1750 if (!ares) {
1751 return ldb_module_done(ar->req, NULL, NULL,
1752 LDB_ERR_OPERATIONS_ERROR);
1754 if (ares->error != LDB_SUCCESS &&
1755 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
1756 return ldb_module_done(ar->req, ares->controls,
1757 ares->response, ares->error);
1760 switch (ares->type) {
1761 case LDB_REPLY_ENTRY:
1762 ar->search_msg = talloc_steal(ar, ares->message);
1763 break;
1765 case LDB_REPLY_REFERRAL:
1766 /* we ignore referrals */
1767 break;
1769 case LDB_REPLY_DONE:
1770 if (ar->search_msg == NULL) {
1771 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1772 } else {
1773 ret = replmd_replicated_uptodate_modify(ar);
1775 if (ret != LDB_SUCCESS) {
1776 return ldb_module_done(ar->req, NULL, NULL, ret);
1780 talloc_free(ares);
1781 return LDB_SUCCESS;
1785 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
1787 struct ldb_context *ldb;
1788 int ret;
1789 static const char *attrs[] = {
1790 "replUpToDateVector",
1791 "repsFrom",
1792 NULL
1794 struct ldb_request *search_req;
1796 ldb = ldb_module_get_ctx(ar->module);
1797 ar->search_msg = NULL;
1799 ret = ldb_build_search_req(&search_req,
1800 ldb,
1802 ar->objs->partition_dn,
1803 LDB_SCOPE_BASE,
1804 "(objectClass=*)",
1805 attrs,
1806 NULL,
1808 replmd_replicated_uptodate_search_callback,
1809 ar->req);
1810 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1812 return ldb_next_request(ar->module, search_req);
1817 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
1819 struct ldb_context *ldb;
1820 struct dsdb_extended_replicated_objects *objs;
1821 struct replmd_replicated_request *ar;
1822 struct ldb_control **ctrls;
1823 int ret, i;
1824 struct dsdb_control_current_partition *partition_ctrl;
1825 struct replmd_private *replmd_private =
1826 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
1828 ldb = ldb_module_get_ctx(module);
1830 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
1832 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
1833 if (!objs) {
1834 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
1835 return LDB_ERR_PROTOCOL_ERROR;
1838 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
1839 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
1840 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
1841 return LDB_ERR_PROTOCOL_ERROR;
1844 ar = replmd_ctx_init(module, req);
1845 if (!ar)
1846 return LDB_ERR_OPERATIONS_ERROR;
1848 ar->objs = objs;
1849 ar->schema = dsdb_get_schema(ldb);
1850 if (!ar->schema) {
1851 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
1852 talloc_free(ar);
1853 return LDB_ERR_CONSTRAINT_VIOLATION;
1856 ctrls = req->controls;
1858 if (req->controls) {
1859 req->controls = talloc_memdup(ar, req->controls,
1860 talloc_get_size(req->controls));
1861 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1864 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
1865 if (ret != LDB_SUCCESS) {
1866 return ret;
1870 add the DSDB_CONTROL_CURRENT_PARTITION_OID control. This
1871 tells the partition module which partition this request is
1872 directed at. That is important as the partition roots appear
1873 twice in the directory, once as mount points in the top
1874 level store, and once as the roots of each partition. The
1875 replication code wants to operate on the root of the
1876 partitions, not the top level mount points
1878 partition_ctrl = talloc(req, struct dsdb_control_current_partition);
1879 if (partition_ctrl == NULL) {
1880 if (!partition_ctrl) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1882 partition_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
1883 partition_ctrl->dn = objs->partition_dn;
1885 ret = ldb_request_add_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID, false, partition_ctrl);
1886 if (ret != LDB_SUCCESS) {
1887 return ret;
1890 ar->controls = req->controls;
1891 req->controls = ctrls;
1893 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
1895 /* save away the linked attributes for the end of the
1896 transaction */
1897 for (i=0; i<ar->objs->linked_attributes_count; i++) {
1898 struct la_entry *la_entry;
1900 if (replmd_private->la_ctx == NULL) {
1901 replmd_private->la_ctx = talloc_new(replmd_private);
1903 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
1904 if (la_entry == NULL) {
1905 ldb_oom(ldb);
1906 return LDB_ERR_OPERATIONS_ERROR;
1908 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
1909 if (la_entry->la == NULL) {
1910 talloc_free(la_entry);
1911 ldb_oom(ldb);
1912 return LDB_ERR_OPERATIONS_ERROR;
1914 *la_entry->la = ar->objs->linked_attributes[i];
1916 /* we need to steal the non-scalars so they stay
1917 around until the end of the transaction */
1918 talloc_steal(la_entry->la, la_entry->la->identifier);
1919 talloc_steal(la_entry->la, la_entry->la->value.blob);
1921 DLIST_ADD(replmd_private->la_list, la_entry);
1924 return replmd_replicated_apply_next(ar);
1928 process one linked attribute structure
1930 static int replmd_process_linked_attribute(struct ldb_module *module,
1931 struct la_entry *la_entry)
1933 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
1934 struct ldb_context *ldb = ldb_module_get_ctx(module);
1935 struct drsuapi_DsReplicaObjectIdentifier3 target;
1936 struct ldb_message *msg;
1937 struct ldb_message_element *ret_el;
1938 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
1939 enum ndr_err_code ndr_err;
1940 char *target_dn;
1941 struct ldb_request *mod_req;
1942 int ret;
1943 const struct dsdb_attribute *attr;
1946 linked_attributes[0]:
1947 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
1948 identifier : *
1949 identifier: struct drsuapi_DsReplicaObjectIdentifier
1950 __ndr_size : 0x0000003a (58)
1951 __ndr_size_sid : 0x00000000 (0)
1952 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
1953 sid : S-0-0
1954 __ndr_size_dn : 0x00000000 (0)
1955 dn : ''
1956 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
1957 value: struct drsuapi_DsAttributeValue
1958 __ndr_size : 0x0000007e (126)
1959 blob : *
1960 blob : DATA_BLOB length=126
1961 flags : 0x00000001 (1)
1962 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
1963 originating_add_time : Wed Sep 2 22:20:01 2009 EST
1964 meta_data: struct drsuapi_DsReplicaMetaData
1965 version : 0x00000015 (21)
1966 originating_change_time : Wed Sep 2 23:39:07 2009 EST
1967 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
1968 originating_usn : 0x000000000001e19c (123292)
1969 &target: struct drsuapi_DsReplicaObjectIdentifier3
1970 __ndr_size : 0x0000007e (126)
1971 __ndr_size_sid : 0x0000001c (28)
1972 guid : 7639e594-db75-4086-b0d4-67890ae46031
1973 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
1974 __ndr_size_dn : 0x00000022 (34)
1975 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
1977 if (DEBUGLVL(4)) {
1978 NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, la);
1981 /* decode the target of the link */
1982 ndr_err = ndr_pull_struct_blob(la->value.blob,
1983 tmp_ctx, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1984 &target,
1985 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
1986 if (ndr_err != NDR_ERR_SUCCESS) {
1987 DEBUG(0,("Unable to decode linked_attribute target\n"));
1988 dump_data(4, la->value.blob->data, la->value.blob->length);
1989 talloc_free(tmp_ctx);
1990 return LDB_ERR_OPERATIONS_ERROR;
1992 if (DEBUGLVL(4)) {
1993 NDR_PRINT_DEBUG(drsuapi_DsReplicaObjectIdentifier3, &target);
1996 /* construct a modify request for this attribute change */
1997 msg = ldb_msg_new(tmp_ctx);
1998 if (!msg) {
1999 ldb_oom(ldb);
2000 talloc_free(tmp_ctx);
2001 return LDB_ERR_OPERATIONS_ERROR;
2004 ret = dsdb_find_dn_by_guid(ldb, tmp_ctx,
2005 GUID_string(tmp_ctx, &la->identifier->guid), &msg->dn);
2006 if (ret != LDB_SUCCESS) {
2007 talloc_free(tmp_ctx);
2008 return ret;
2011 /* find the attribute being modified */
2012 attr = dsdb_attribute_by_attributeID_id(dsdb_get_schema(ldb), la->attid);
2013 if (attr == NULL) {
2014 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
2015 talloc_free(tmp_ctx);
2016 return LDB_ERR_OPERATIONS_ERROR;
2019 if (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) {
2020 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName,
2021 LDB_FLAG_MOD_ADD, &ret_el);
2022 } else {
2023 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName,
2024 LDB_FLAG_MOD_DELETE, &ret_el);
2026 if (ret != LDB_SUCCESS) {
2027 talloc_free(tmp_ctx);
2028 return ret;
2030 ret_el->values = talloc_array(msg, struct ldb_val, 1);
2031 if (!ret_el->values) {
2032 ldb_oom(ldb);
2033 talloc_free(tmp_ctx);
2034 return LDB_ERR_OPERATIONS_ERROR;
2036 ret_el->num_values = 1;
2038 target_dn = talloc_asprintf(tmp_ctx, "<GUID=%s>;<SID=%s>;%s",
2039 GUID_string(tmp_ctx, &target.guid),
2040 dom_sid_string(tmp_ctx, &target.sid),
2041 target.dn);
2042 if (target_dn == NULL) {
2043 ldb_oom(ldb);
2044 talloc_free(tmp_ctx);
2045 return LDB_ERR_OPERATIONS_ERROR;
2047 ret_el->values[0] = data_blob_string_const(target_dn);
2049 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
2050 msg,
2051 NULL,
2052 NULL,
2053 ldb_op_default_callback,
2054 NULL);
2055 if (ret != LDB_SUCCESS) {
2056 talloc_free(tmp_ctx);
2057 return ret;
2059 talloc_steal(mod_req, msg);
2061 if (DEBUGLVL(4)) {
2062 DEBUG(4,("Applying DRS linked attribute change:\n%s\n",
2063 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg)));
2066 /* Run the new request */
2067 ret = ldb_next_request(module, mod_req);
2069 /* we need to wait for this to finish, as we are being called
2070 from the synchronous end_transaction hook of this module */
2071 if (ret == LDB_SUCCESS) {
2072 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
2075 if (ret != LDB_SUCCESS) {
2076 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n",
2077 ldb_errstring(ldb),
2078 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
2081 talloc_free(tmp_ctx);
2083 return ret;
2086 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
2088 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
2089 return replmd_extended_replicated_objects(module, req);
2092 return ldb_next_request(module, req);
2097 we hook into the transaction operations to allow us to
2098 perform the linked attribute updates at the end of the whole
2099 transaction. This allows a forward linked attribute to be created
2100 before the object is created. During a vampire, w2k8 sends us linked
2101 attributes before the objects they are part of.
2103 static int replmd_start_transaction(struct ldb_module *module)
2105 /* create our private structure for this transaction */
2106 int i;
2107 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
2108 struct replmd_private);
2109 talloc_free(replmd_private->la_ctx);
2110 replmd_private->la_list = NULL;
2111 replmd_private->la_ctx = NULL;
2113 for (i=0; i<replmd_private->num_ncs; i++) {
2114 replmd_private->ncs[i].mod_usn = 0;
2117 return ldb_next_start_trans(module);
2121 on prepare commit we loop over our queued la_context structures and
2122 apply each of them
2124 static int replmd_prepare_commit(struct ldb_module *module)
2126 struct replmd_private *replmd_private =
2127 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2128 struct la_entry *la, *prev;
2129 int ret;
2131 /* walk the list backwards, to do the first entry first, as we
2132 * added the entries with DLIST_ADD() which puts them at the
2133 * start of the list */
2134 for (la = replmd_private->la_list; la && la->next; la=la->next) ;
2136 for (; la; la=prev) {
2137 prev = la->prev;
2138 DLIST_REMOVE(replmd_private->la_list, la);
2139 ret = replmd_process_linked_attribute(module, la);
2140 if (ret != LDB_SUCCESS) {
2141 return ret;
2145 talloc_free(replmd_private->la_ctx);
2146 replmd_private->la_list = NULL;
2147 replmd_private->la_ctx = NULL;
2149 /* possibly change @REPLCHANGED */
2150 ret = replmd_notify_store(module);
2151 if (ret != LDB_SUCCESS) {
2152 return ret;
2155 return ldb_next_prepare_commit(module);
2158 static int replmd_del_transaction(struct ldb_module *module)
2160 struct replmd_private *replmd_private =
2161 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2162 talloc_free(replmd_private->la_ctx);
2163 replmd_private->la_list = NULL;
2164 replmd_private->la_ctx = NULL;
2165 return ldb_next_del_trans(module);
2169 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
2170 .name = "repl_meta_data",
2171 .init_context = replmd_init,
2172 .add = replmd_add,
2173 .modify = replmd_modify,
2174 .extended = replmd_extended,
2175 .start_transaction = replmd_start_transaction,
2176 .prepare_commit = replmd_prepare_commit,
2177 .del_transaction = replmd_del_transaction,