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"
50 #include "libcli/security/security.h"
52 #define W2K3_LINKED_ATTRIBUTES 1
54 struct replmd_private {
56 struct la_entry *la_list;
58 struct la_backlink *la_backlinks;
60 struct nc_entry *prev, *next;
67 struct la_entry *next, *prev;
68 struct drsuapi_DsReplicaLinkedAttribute *la;
71 struct replmd_replicated_request {
72 struct ldb_module *module;
73 struct ldb_request *req;
75 const struct dsdb_schema *schema;
77 /* the controls we pass down */
78 struct ldb_control **controls;
80 /* details for the mode where we apply a bunch of inbound replication meessages */
82 uint32_t index_current;
83 struct dsdb_extended_replicated_objects *objs;
85 struct ldb_message *search_msg;
91 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
96 allocate the private structure and build the list
97 of partition DNs for use by replmd_notify()
99 static int replmd_init(struct ldb_module *module)
101 struct replmd_private *replmd_private;
102 struct ldb_context *ldb = ldb_module_get_ctx(module);
104 replmd_private = talloc_zero(module, struct replmd_private);
105 if (replmd_private == NULL) {
107 return LDB_ERR_OPERATIONS_ERROR;
109 ldb_module_set_private(module, replmd_private);
111 return ldb_next_init(module);
115 cleanup our per-transaction contexts
117 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
119 talloc_free(replmd_private->la_ctx);
120 replmd_private->la_list = NULL;
121 replmd_private->la_ctx = NULL;
123 talloc_free(replmd_private->bl_ctx);
124 replmd_private->la_backlinks = NULL;
125 replmd_private->bl_ctx = NULL;
130 struct la_backlink *next, *prev;
131 const char *attr_name;
132 struct GUID forward_guid, target_guid;
137 process a backlinks we accumulated during a transaction, adding and
138 deleting the backlinks from the target objects
140 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl)
142 struct ldb_dn *target_dn, *source_dn;
144 struct ldb_context *ldb = ldb_module_get_ctx(module);
145 struct ldb_message *msg;
146 TALLOC_CTX *tmp_ctx = talloc_new(bl);
152 - construct ldb_message
153 - either an add or a delete
155 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn);
156 if (ret != LDB_SUCCESS) {
157 ldb_asprintf_errstring(ldb, "Failed to find target DN for linked attribute with GUID %s\n",
158 GUID_string(bl, &bl->target_guid));
159 talloc_free(tmp_ctx);
163 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn);
164 if (ret != LDB_SUCCESS) {
165 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
166 GUID_string(bl, &bl->forward_guid));
167 talloc_free(tmp_ctx);
171 msg = ldb_msg_new(tmp_ctx);
173 ldb_module_oom(module);
174 talloc_free(tmp_ctx);
175 return LDB_ERR_OPERATIONS_ERROR;
178 /* construct a ldb_message for adding/deleting the backlink */
180 dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
182 ldb_module_oom(module);
183 talloc_free(tmp_ctx);
184 return LDB_ERR_OPERATIONS_ERROR;
186 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
187 if (ret != LDB_SUCCESS) {
188 talloc_free(tmp_ctx);
191 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
193 ret = dsdb_module_modify(module, msg, 0);
194 if (ret != LDB_SUCCESS) {
195 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
196 bl->active?"add":"remove",
197 ldb_dn_get_linearized(source_dn),
198 ldb_dn_get_linearized(target_dn),
200 talloc_free(tmp_ctx);
203 talloc_free(tmp_ctx);
208 add a backlink to the list of backlinks to add/delete in the prepare
211 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
212 struct GUID *forward_guid, struct GUID *target_guid,
213 bool active, const struct dsdb_attribute *schema_attr, bool immediate)
215 const struct dsdb_attribute *target_attr;
216 struct la_backlink *bl;
217 struct replmd_private *replmd_private =
218 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
220 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
223 * windows 2003 has a broken schema where the
224 * definition of msDS-IsDomainFor is missing (which is
225 * supposed to be the backlink of the
226 * msDS-HasDomainNCs attribute
231 /* see if its already in the list */
232 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
233 if (GUID_equal(forward_guid, &bl->forward_guid) &&
234 GUID_equal(target_guid, &bl->target_guid) &&
235 (target_attr->lDAPDisplayName == bl->attr_name ||
236 strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
242 /* we found an existing one */
243 if (bl->active == active) {
246 DLIST_REMOVE(replmd_private->la_backlinks, bl);
251 if (replmd_private->bl_ctx == NULL) {
252 replmd_private->bl_ctx = talloc_new(replmd_private);
253 if (replmd_private->bl_ctx == NULL) {
254 ldb_module_oom(module);
255 return LDB_ERR_OPERATIONS_ERROR;
260 bl = talloc(replmd_private->bl_ctx, struct la_backlink);
262 ldb_module_oom(module);
263 return LDB_ERR_OPERATIONS_ERROR;
266 bl->attr_name = target_attr->lDAPDisplayName;
267 bl->forward_guid = *forward_guid;
268 bl->target_guid = *target_guid;
271 /* the caller may ask for this backlink to be processed
274 int ret = replmd_process_backlink(module, bl);
279 DLIST_ADD(replmd_private->la_backlinks, bl);
286 * Callback for most write operations in this module:
288 * notify the repl task that a object has changed. The notifies are
289 * gathered up in the replmd_private structure then written to the
290 * @REPLCHANGED object in each partition during the prepare_commit
292 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
295 struct replmd_replicated_request *ac =
296 talloc_get_type_abort(req->context, struct replmd_replicated_request);
297 struct replmd_private *replmd_private =
298 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
299 struct nc_entry *modified_partition;
300 struct ldb_control *partition_ctrl;
301 const struct dsdb_control_current_partition *partition;
303 struct ldb_control **controls;
305 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
307 /* Remove the 'partition' control from what we pass up the chain */
308 controls = controls_except_specified(ares->controls, ares, partition_ctrl);
310 if (ares->error != LDB_SUCCESS) {
311 return ldb_module_done(ac->req, controls,
312 ares->response, ares->error);
315 if (ares->type != LDB_REPLY_DONE) {
316 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
317 return ldb_module_done(ac->req, NULL,
318 NULL, LDB_ERR_OPERATIONS_ERROR);
321 if (!partition_ctrl) {
322 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
323 return ldb_module_done(ac->req, NULL,
324 NULL, LDB_ERR_OPERATIONS_ERROR);
327 partition = talloc_get_type_abort(partition_ctrl->data,
328 struct dsdb_control_current_partition);
330 if (ac->seq_num > 0) {
331 for (modified_partition = replmd_private->ncs; modified_partition;
332 modified_partition = modified_partition->next) {
333 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
338 if (modified_partition == NULL) {
339 modified_partition = talloc_zero(replmd_private, struct nc_entry);
340 if (!modified_partition) {
341 ldb_oom(ldb_module_get_ctx(ac->module));
342 return ldb_module_done(ac->req, NULL,
343 NULL, LDB_ERR_OPERATIONS_ERROR);
345 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
346 if (!modified_partition->dn) {
347 ldb_oom(ldb_module_get_ctx(ac->module));
348 return ldb_module_done(ac->req, NULL,
349 NULL, LDB_ERR_OPERATIONS_ERROR);
351 DLIST_ADD(replmd_private->ncs, modified_partition);
354 if (ac->seq_num > modified_partition->mod_usn) {
355 modified_partition->mod_usn = ac->seq_num;
359 if (ac->apply_mode) {
363 ret = replmd_replicated_apply_next(ac);
364 if (ret != LDB_SUCCESS) {
365 return ldb_module_done(ac->req, NULL, NULL, ret);
369 /* free the partition control container here, for the
370 * common path. Other cases will have it cleaned up
371 * eventually with the ares */
372 talloc_free(partition_ctrl);
373 return ldb_module_done(ac->req,
374 controls_except_specified(controls, ares, partition_ctrl),
375 ares->response, LDB_SUCCESS);
381 * update a @REPLCHANGED record in each partition if there have been
382 * any writes of replicated data in the partition
384 static int replmd_notify_store(struct ldb_module *module)
386 struct replmd_private *replmd_private =
387 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
388 struct ldb_context *ldb = ldb_module_get_ctx(module);
390 while (replmd_private->ncs) {
392 struct nc_entry *modified_partition = replmd_private->ncs;
394 ret = dsdb_save_partition_usn(ldb, modified_partition->dn, modified_partition->mod_usn);
395 if (ret != LDB_SUCCESS) {
396 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
397 ldb_dn_get_linearized(modified_partition->dn)));
400 DLIST_REMOVE(replmd_private->ncs, modified_partition);
401 talloc_free(modified_partition);
409 created a replmd_replicated_request context
411 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
412 struct ldb_request *req)
414 struct ldb_context *ldb;
415 struct replmd_replicated_request *ac;
417 ldb = ldb_module_get_ctx(module);
419 ac = talloc_zero(req, struct replmd_replicated_request);
428 ac->schema = dsdb_get_schema(ldb);
430 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
431 "replmd_modify: no dsdb_schema loaded");
432 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
440 add a time element to a record
442 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
444 struct ldb_message_element *el;
447 if (ldb_msg_find_element(msg, attr) != NULL) {
451 s = ldb_timestring(msg, t);
453 return LDB_ERR_OPERATIONS_ERROR;
456 if (ldb_msg_add_string(msg, attr, s) != LDB_SUCCESS) {
457 return LDB_ERR_OPERATIONS_ERROR;
460 el = ldb_msg_find_element(msg, attr);
461 /* always set as replace. This works because on add ops, the flag
463 el->flags = LDB_FLAG_MOD_REPLACE;
469 add a uint64_t element to a record
471 static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_t v)
473 struct ldb_message_element *el;
475 if (ldb_msg_find_element(msg, attr) != NULL) {
479 if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != LDB_SUCCESS) {
480 return LDB_ERR_OPERATIONS_ERROR;
483 el = ldb_msg_find_element(msg, attr);
484 /* always set as replace. This works because on add ops, the flag
486 el->flags = LDB_FLAG_MOD_REPLACE;
491 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
492 const struct replPropertyMetaData1 *m2,
493 const uint32_t *rdn_attid)
495 if (m1->attid == m2->attid) {
500 * the rdn attribute should be at the end!
501 * so we need to return a value greater than zero
502 * which means m1 is greater than m2
504 if (m1->attid == *rdn_attid) {
509 * the rdn attribute should be at the end!
510 * so we need to return a value less than zero
511 * which means m2 is greater than m1
513 if (m2->attid == *rdn_attid) {
517 return m1->attid > m2->attid ? 1 : -1;
520 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
521 const struct dsdb_schema *schema,
524 const char *rdn_name;
525 const struct dsdb_attribute *rdn_sa;
527 rdn_name = ldb_dn_get_rdn_name(dn);
529 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
530 return LDB_ERR_OPERATIONS_ERROR;
533 rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
534 if (rdn_sa == NULL) {
535 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
536 return LDB_ERR_OPERATIONS_ERROR;
539 DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
540 rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
542 ldb_qsort(ctr1->array, ctr1->count, sizeof(struct replPropertyMetaData1),
543 discard_const_p(void, &rdn_sa->attributeID_id),
544 (ldb_qsort_cmp_fn_t)replmd_replPropertyMetaData1_attid_sort);
549 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
550 const struct ldb_message_element *e2,
551 const struct dsdb_schema *schema)
553 const struct dsdb_attribute *a1;
554 const struct dsdb_attribute *a2;
557 * TODO: make this faster by caching the dsdb_attribute pointer
558 * on the ldb_messag_element
561 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
562 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
565 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
569 return strcasecmp(e1->name, e2->name);
571 if (a1->attributeID_id == a2->attributeID_id) {
574 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
577 static void replmd_ldb_message_sort(struct ldb_message *msg,
578 const struct dsdb_schema *schema)
580 ldb_qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
581 discard_const_p(void, schema), (ldb_qsort_cmp_fn_t)replmd_ldb_message_element_attid_sort);
584 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
585 const struct GUID *invocation_id, uint64_t seq_num,
586 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
590 fix up linked attributes in replmd_add.
591 This involves setting up the right meta-data in extended DN
592 components, and creating backlinks to the object
594 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
595 uint64_t seq_num, const struct GUID *invocationId, time_t t,
596 struct GUID *guid, const struct dsdb_attribute *sa)
599 TALLOC_CTX *tmp_ctx = talloc_new(el->values);
600 struct ldb_context *ldb = ldb_module_get_ctx(module);
601 struct dsdb_schema *schema = dsdb_get_schema(ldb);
604 unix_to_nt_time(&now, t);
606 for (i=0; i<el->num_values; i++) {
607 struct ldb_val *v = &el->values[i];
608 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
609 struct GUID target_guid;
613 /* note that the DN already has the extended
614 components from the extended_dn_store module */
615 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
616 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
617 ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid);
618 if (ret != LDB_SUCCESS) {
619 talloc_free(tmp_ctx);
622 ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
623 if (ret != LDB_SUCCESS) {
624 talloc_free(tmp_ctx);
629 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
630 seq_num, seq_num, now, 0, false);
631 if (ret != LDB_SUCCESS) {
632 talloc_free(tmp_ctx);
636 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
637 if (ret != LDB_SUCCESS) {
638 talloc_free(tmp_ctx);
643 talloc_free(tmp_ctx);
649 intercept add requests
651 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
653 struct ldb_context *ldb;
654 struct ldb_control *control;
655 struct replmd_replicated_request *ac;
656 enum ndr_err_code ndr_err;
657 struct ldb_request *down_req;
658 struct ldb_message *msg;
659 const DATA_BLOB *guid_blob;
661 struct replPropertyMetaDataBlob nmd;
662 struct ldb_val nmd_value;
663 const struct GUID *our_invocation_id;
664 time_t t = time(NULL);
669 bool allow_add_guid = false;
670 bool remove_current_guid = false;
672 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
673 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
678 /* do not manipulate our control entries */
679 if (ldb_dn_is_special(req->op.add.message->dn)) {
680 return ldb_next_request(module, req);
683 ldb = ldb_module_get_ctx(module);
685 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
687 ac = replmd_ctx_init(module, req);
689 return LDB_ERR_OPERATIONS_ERROR;
692 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
693 if ( guid_blob != NULL ) {
694 if( !allow_add_guid ) {
695 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
696 "replmd_add: it's not allowed to add an object with objectGUID\n");
698 return LDB_ERR_UNWILLING_TO_PERFORM;
700 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
701 if ( !NT_STATUS_IS_OK(status)) {
702 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
703 "replmd_add: Unable to parse as a GUID the attribute objectGUID\n");
705 return LDB_ERR_UNWILLING_TO_PERFORM;
707 /* we remove this attribute as it can be a string and will not be treated
708 correctly and then we will readd it latter on in the good format*/
709 remove_current_guid = true;
713 guid = GUID_random();
716 /* Get a sequence number from the backend */
717 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
718 if (ret != LDB_SUCCESS) {
723 /* get our invocationId */
724 our_invocation_id = samdb_ntds_invocation_id(ldb);
725 if (!our_invocation_id) {
726 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
727 "replmd_add: unable to find invocationId\n");
729 return LDB_ERR_OPERATIONS_ERROR;
732 /* we have to copy the message as the caller might have it as a const */
733 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
737 return LDB_ERR_OPERATIONS_ERROR;
740 /* generated times */
741 unix_to_nt_time(&now, t);
742 time_str = ldb_timestring(msg, t);
746 return LDB_ERR_OPERATIONS_ERROR;
748 if (remove_current_guid) {
749 ldb_msg_remove_attr(msg,"objectGUID");
753 * remove autogenerated attributes
755 ldb_msg_remove_attr(msg, "whenCreated");
756 ldb_msg_remove_attr(msg, "whenChanged");
757 ldb_msg_remove_attr(msg, "uSNCreated");
758 ldb_msg_remove_attr(msg, "uSNChanged");
759 ldb_msg_remove_attr(msg, "replPropertyMetaData");
762 * readd replicated attributes
764 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
765 if (ret != LDB_SUCCESS) {
771 /* build the replication meta_data */
774 nmd.ctr.ctr1.count = msg->num_elements;
775 nmd.ctr.ctr1.array = talloc_array(msg,
776 struct replPropertyMetaData1,
778 if (!nmd.ctr.ctr1.array) {
781 return LDB_ERR_OPERATIONS_ERROR;
784 for (i=0; i < msg->num_elements; i++) {
785 struct ldb_message_element *e = &msg->elements[i];
786 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
787 const struct dsdb_attribute *sa;
789 if (e->name[0] == '@') continue;
791 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
793 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
794 "replmd_add: attribute '%s' not defined in schema\n",
797 return LDB_ERR_NO_SUCH_ATTRIBUTE;
800 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
801 /* if the attribute is not replicated (0x00000001)
802 * or constructed (0x00000004) it has no metadata
807 #if W2K3_LINKED_ATTRIBUTES
808 if (sa->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
809 ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa);
810 if (ret != LDB_SUCCESS) {
814 /* linked attributes are not stored in
815 replPropertyMetaData in FL above w2k */
820 m->attid = sa->attributeID_id;
822 m->originating_change_time = now;
823 m->originating_invocation_id = *our_invocation_id;
824 m->originating_usn = ac->seq_num;
825 m->local_usn = ac->seq_num;
829 /* fix meta data count */
830 nmd.ctr.ctr1.count = ni;
833 * sort meta data array, and move the rdn attribute entry to the end
835 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
836 if (ret != LDB_SUCCESS) {
841 /* generated NDR encoded values */
842 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
843 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
845 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
846 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
849 return LDB_ERR_OPERATIONS_ERROR;
853 * add the autogenerated values
855 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
856 if (ret != LDB_SUCCESS) {
861 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
862 if (ret != LDB_SUCCESS) {
867 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
868 if (ret != LDB_SUCCESS) {
873 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
874 if (ret != LDB_SUCCESS) {
879 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
880 if (ret != LDB_SUCCESS) {
887 * sort the attributes by attid before storing the object
889 replmd_ldb_message_sort(msg, ac->schema);
891 ret = ldb_build_add_req(&down_req, ldb, ac,
894 ac, replmd_op_callback,
896 if (ret != LDB_SUCCESS) {
901 /* mark the control done */
903 control->critical = 0;
906 /* go on with the call chain */
907 return ldb_next_request(module, down_req);
912 * update the replPropertyMetaData for one element
914 static int replmd_update_rpmd_element(struct ldb_context *ldb,
915 struct ldb_message *msg,
916 struct ldb_message_element *el,
917 struct replPropertyMetaDataBlob *omd,
918 const struct dsdb_schema *schema,
920 const struct GUID *our_invocation_id,
924 const struct dsdb_attribute *a;
925 struct replPropertyMetaData1 *md1;
927 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
929 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
931 return LDB_ERR_OPERATIONS_ERROR;
934 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
938 for (i=0; i<omd->ctr.ctr1.count; i++) {
939 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
942 #if W2K3_LINKED_ATTRIBUTES
943 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
944 /* linked attributes are not stored in
945 replPropertyMetaData in FL above w2k, but we do
946 raise the seqnum for the object */
948 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
949 return LDB_ERR_OPERATIONS_ERROR;
955 if (i == omd->ctr.ctr1.count) {
956 /* we need to add a new one */
957 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
958 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
959 if (omd->ctr.ctr1.array == NULL) {
961 return LDB_ERR_OPERATIONS_ERROR;
963 omd->ctr.ctr1.count++;
964 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
967 /* Get a new sequence number from the backend. We only do this
968 * if we have a change that requires a new
969 * replPropertyMetaData element
972 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
973 if (ret != LDB_SUCCESS) {
974 return LDB_ERR_OPERATIONS_ERROR;
978 md1 = &omd->ctr.ctr1.array[i];
980 md1->attid = a->attributeID_id;
981 md1->originating_change_time = now;
982 md1->originating_invocation_id = *our_invocation_id;
983 md1->originating_usn = *seq_num;
984 md1->local_usn = *seq_num;
990 * update the replPropertyMetaData object each time we modify an
991 * object. This is needed for DRS replication, as the merge on the
992 * client is based on this object
994 static int replmd_update_rpmd(struct ldb_module *module,
995 const struct dsdb_schema *schema,
996 struct ldb_message *msg, uint64_t *seq_num,
999 const struct ldb_val *omd_value;
1000 enum ndr_err_code ndr_err;
1001 struct replPropertyMetaDataBlob omd;
1004 const struct GUID *our_invocation_id;
1006 const char *attrs[] = { "replPropertyMetaData" , NULL };
1007 struct ldb_result *res;
1008 struct ldb_context *ldb;
1010 ldb = ldb_module_get_ctx(module);
1012 our_invocation_id = samdb_ntds_invocation_id(ldb);
1013 if (!our_invocation_id) {
1014 /* this happens during an initial vampire while
1015 updating the schema */
1016 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1020 unix_to_nt_time(&now, t);
1022 /* search for the existing replPropertyMetaDataBlob */
1023 ret = dsdb_search_dn_with_deleted(ldb, msg, &res, msg->dn, attrs);
1024 if (ret != LDB_SUCCESS || res->count != 1) {
1025 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1026 ldb_dn_get_linearized(msg->dn)));
1027 return LDB_ERR_OPERATIONS_ERROR;
1031 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1033 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1034 ldb_dn_get_linearized(msg->dn)));
1035 return LDB_ERR_OPERATIONS_ERROR;
1038 ndr_err = ndr_pull_struct_blob(omd_value, msg,
1039 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
1040 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1041 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1042 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1043 ldb_dn_get_linearized(msg->dn)));
1044 return LDB_ERR_OPERATIONS_ERROR;
1047 if (omd.version != 1) {
1048 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1049 omd.version, ldb_dn_get_linearized(msg->dn)));
1050 return LDB_ERR_OPERATIONS_ERROR;
1053 for (i=0; i<msg->num_elements; i++) {
1054 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], &omd, schema, seq_num,
1055 our_invocation_id, now);
1056 if (ret != LDB_SUCCESS) {
1062 * replmd_update_rpmd_element has done an update if the
1065 if (*seq_num != 0) {
1066 struct ldb_val *md_value;
1067 struct ldb_message_element *el;
1069 md_value = talloc(msg, struct ldb_val);
1070 if (md_value == NULL) {
1072 return LDB_ERR_OPERATIONS_ERROR;
1075 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1076 if (ret != LDB_SUCCESS) {
1080 ndr_err = ndr_push_struct_blob(md_value, msg,
1081 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1083 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1084 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1085 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1086 ldb_dn_get_linearized(msg->dn)));
1087 return LDB_ERR_OPERATIONS_ERROR;
1090 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1091 if (ret != LDB_SUCCESS) {
1092 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1093 ldb_dn_get_linearized(msg->dn)));
1098 el->values = md_value;
1106 struct dsdb_dn *dsdb_dn;
1111 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1113 return GUID_compare(pdn1->guid, pdn2->guid);
1116 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid, struct ldb_dn *dn)
1118 struct parsed_dn *ret;
1119 if (dn && GUID_all_zero(guid)) {
1120 /* when updating a link using DRS, we sometimes get a
1121 NULL GUID. We then need to try and match by DN */
1123 for (i=0; i<count; i++) {
1124 if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1125 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1131 BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1136 get a series of message element values as an array of DNs and GUIDs
1137 the result is sorted by GUID
1139 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1140 struct ldb_message_element *el, struct parsed_dn **pdn,
1141 const char *ldap_oid)
1144 struct ldb_context *ldb = ldb_module_get_ctx(module);
1151 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1153 ldb_module_oom(module);
1154 return LDB_ERR_OPERATIONS_ERROR;
1157 for (i=0; i<el->num_values; i++) {
1158 struct ldb_val *v = &el->values[i];
1161 struct parsed_dn *p;
1165 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1166 if (p->dsdb_dn == NULL) {
1167 return LDB_ERR_INVALID_DN_SYNTAX;
1170 dn = p->dsdb_dn->dn;
1172 p->guid = talloc(*pdn, struct GUID);
1173 if (p->guid == NULL) {
1174 ldb_module_oom(module);
1175 return LDB_ERR_OPERATIONS_ERROR;
1178 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1179 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1180 /* we got a DN without a GUID - go find the GUID */
1181 int ret = dsdb_module_guid_by_dn(module, dn, p->guid);
1182 if (ret != LDB_SUCCESS) {
1183 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1184 ldb_dn_get_linearized(dn));
1187 ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1188 if (ret != LDB_SUCCESS) {
1191 } else if (!NT_STATUS_IS_OK(status)) {
1192 return LDB_ERR_OPERATIONS_ERROR;
1195 /* keep a pointer to the original ldb_val */
1199 qsort(*pdn, el->num_values, sizeof((*pdn)[0]), (comparison_fn_t)parsed_dn_compare);
1205 build a new extended DN, including all meta data fields
1207 DELETED = 1 or missing
1208 RMD_ADDTIME = originating_add_time
1209 RMD_INVOCID = originating_invocation_id
1210 RMD_CHANGETIME = originating_change_time
1211 RMD_ORIGINATING_USN = originating_usn
1212 RMD_LOCAL_USN = local_usn
1213 RMD_VERSION = version
1215 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1216 const struct GUID *invocation_id, uint64_t seq_num,
1217 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1219 struct ldb_dn *dn = dsdb_dn->dn;
1220 const char *tstring, *usn_string;
1221 struct ldb_val tval;
1223 struct ldb_val usnv, local_usnv;
1224 struct ldb_val vers;
1227 const char *dnstring;
1230 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1232 return LDB_ERR_OPERATIONS_ERROR;
1234 tval = data_blob_string_const(tstring);
1236 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1238 return LDB_ERR_OPERATIONS_ERROR;
1240 usnv = data_blob_string_const(usn_string);
1242 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1244 return LDB_ERR_OPERATIONS_ERROR;
1246 local_usnv = data_blob_string_const(usn_string);
1248 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1249 vers = data_blob_string_const(vstring);
1251 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1252 if (!NT_STATUS_IS_OK(status)) {
1253 return LDB_ERR_OPERATIONS_ERROR;
1258 dv = data_blob_string_const("1");
1259 ret = ldb_dn_set_extended_component(dn, "DELETED", &dv);
1261 ret = ldb_dn_set_extended_component(dn, "DELETED", NULL);
1263 if (ret != LDB_SUCCESS) return ret;
1264 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1265 if (ret != LDB_SUCCESS) return ret;
1266 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1267 if (ret != LDB_SUCCESS) return ret;
1268 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1269 if (ret != LDB_SUCCESS) return ret;
1270 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1271 if (ret != LDB_SUCCESS) return ret;
1272 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1273 if (ret != LDB_SUCCESS) return ret;
1274 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1275 if (ret != LDB_SUCCESS) return ret;
1277 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1278 if (dnstring == NULL) {
1279 return LDB_ERR_OPERATIONS_ERROR;
1281 *v = data_blob_string_const(dnstring);
1286 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1287 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1288 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1289 uint32_t version, bool deleted);
1292 check if any links need upgrading from w2k format
1294 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, const struct GUID *invocation_id)
1297 for (i=0; i<count; i++) {
1302 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1303 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1307 /* it's an old one that needs upgrading */
1308 ret = replmd_update_la_val(dns, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1310 if (ret != LDB_SUCCESS) {
1318 update an extended DN, including all meta data fields
1320 see replmd_build_la_val for value names
1322 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1323 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1324 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1325 uint32_t version, bool deleted)
1327 struct ldb_dn *dn = dsdb_dn->dn;
1328 const char *tstring, *usn_string;
1329 struct ldb_val tval;
1331 struct ldb_val usnv, local_usnv;
1332 struct ldb_val vers;
1333 const struct ldb_val *old_addtime;
1334 uint32_t old_version;
1337 const char *dnstring;
1340 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1342 return LDB_ERR_OPERATIONS_ERROR;
1344 tval = data_blob_string_const(tstring);
1346 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1348 return LDB_ERR_OPERATIONS_ERROR;
1350 usnv = data_blob_string_const(usn_string);
1352 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1354 return LDB_ERR_OPERATIONS_ERROR;
1356 local_usnv = data_blob_string_const(usn_string);
1358 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1359 if (!NT_STATUS_IS_OK(status)) {
1360 return LDB_ERR_OPERATIONS_ERROR;
1365 dv = data_blob_string_const("1");
1366 ret = ldb_dn_set_extended_component(dn, "DELETED", &dv);
1368 ret = ldb_dn_set_extended_component(dn, "DELETED", NULL);
1370 if (ret != LDB_SUCCESS) return ret;
1372 /* get the ADDTIME from the original */
1373 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1374 if (old_addtime == NULL) {
1375 old_addtime = &tval;
1377 if (dsdb_dn != old_dsdb_dn) {
1378 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1379 if (ret != LDB_SUCCESS) return ret;
1382 /* use our invocation id */
1383 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1384 if (ret != LDB_SUCCESS) return ret;
1386 /* changetime is the current time */
1387 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1388 if (ret != LDB_SUCCESS) return ret;
1390 /* update the USN */
1391 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1392 if (ret != LDB_SUCCESS) return ret;
1394 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1395 if (ret != LDB_SUCCESS) return ret;
1397 /* increase the version by 1 */
1398 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1399 if (NT_STATUS_IS_OK(status) && old_version >= version) {
1400 version = old_version+1;
1402 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1403 vers = data_blob_string_const(vstring);
1404 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1405 if (ret != LDB_SUCCESS) return ret;
1407 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1408 if (dnstring == NULL) {
1409 return LDB_ERR_OPERATIONS_ERROR;
1411 *v = data_blob_string_const(dnstring);
1417 handle adding a linked attribute
1419 static int replmd_modify_la_add(struct ldb_module *module,
1420 struct dsdb_schema *schema,
1421 struct ldb_message *msg,
1422 struct ldb_message_element *el,
1423 struct ldb_message_element *old_el,
1424 const struct dsdb_attribute *schema_attr,
1427 struct GUID *msg_guid)
1430 struct parsed_dn *dns, *old_dns;
1431 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1433 struct ldb_val *new_values = NULL;
1434 unsigned int num_new_values = 0;
1435 unsigned old_num_values = old_el?old_el->num_values:0;
1436 const struct GUID *invocation_id;
1437 struct ldb_context *ldb = ldb_module_get_ctx(module);
1440 unix_to_nt_time(&now, t);
1442 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1443 if (ret != LDB_SUCCESS) {
1444 talloc_free(tmp_ctx);
1448 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1449 if (ret != LDB_SUCCESS) {
1450 talloc_free(tmp_ctx);
1454 invocation_id = samdb_ntds_invocation_id(ldb);
1455 if (!invocation_id) {
1456 talloc_free(tmp_ctx);
1457 return LDB_ERR_OPERATIONS_ERROR;
1460 ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
1461 if (ret != LDB_SUCCESS) {
1462 talloc_free(tmp_ctx);
1466 /* for each new value, see if it exists already with the same GUID */
1467 for (i=0; i<el->num_values; i++) {
1468 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1470 /* this is a new linked attribute value */
1471 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1472 if (new_values == NULL) {
1473 ldb_module_oom(module);
1474 talloc_free(tmp_ctx);
1475 return LDB_ERR_OPERATIONS_ERROR;
1477 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1478 invocation_id, seq_num, seq_num, now, 0, false);
1479 if (ret != LDB_SUCCESS) {
1480 talloc_free(tmp_ctx);
1485 /* this is only allowed if the GUID was
1486 previously deleted. */
1487 const struct ldb_val *v;
1488 v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED");
1490 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1491 el->name, GUID_string(tmp_ctx, p->guid));
1492 talloc_free(tmp_ctx);
1493 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1495 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1496 invocation_id, seq_num, seq_num, now, 0, false);
1497 if (ret != LDB_SUCCESS) {
1498 talloc_free(tmp_ctx);
1503 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1504 if (ret != LDB_SUCCESS) {
1505 talloc_free(tmp_ctx);
1510 /* add the new ones on to the end of the old values, constructing a new el->values */
1511 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1513 old_num_values+num_new_values);
1514 if (el->values == NULL) {
1515 ldb_module_oom(module);
1516 return LDB_ERR_OPERATIONS_ERROR;
1519 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1520 el->num_values = old_num_values + num_new_values;
1522 talloc_steal(msg->elements, el->values);
1523 talloc_steal(el->values, new_values);
1525 talloc_free(tmp_ctx);
1527 /* we now tell the backend to replace all existing values
1528 with the one we have constructed */
1529 el->flags = LDB_FLAG_MOD_REPLACE;
1536 handle deleting all active linked attributes
1538 static int replmd_modify_la_delete(struct ldb_module *module,
1539 struct dsdb_schema *schema,
1540 struct ldb_message *msg,
1541 struct ldb_message_element *el,
1542 struct ldb_message_element *old_el,
1543 const struct dsdb_attribute *schema_attr,
1546 struct GUID *msg_guid)
1549 struct parsed_dn *dns, *old_dns;
1550 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1552 const struct GUID *invocation_id;
1553 struct ldb_context *ldb = ldb_module_get_ctx(module);
1556 unix_to_nt_time(&now, t);
1558 /* check if there is nothing to delete */
1559 if ((!old_el || old_el->num_values == 0) &&
1560 el->num_values == 0) {
1564 if (!old_el || old_el->num_values == 0) {
1565 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1568 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1569 if (ret != LDB_SUCCESS) {
1570 talloc_free(tmp_ctx);
1574 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1575 if (ret != LDB_SUCCESS) {
1576 talloc_free(tmp_ctx);
1580 invocation_id = samdb_ntds_invocation_id(ldb);
1581 if (!invocation_id) {
1582 return LDB_ERR_OPERATIONS_ERROR;
1585 ret = replmd_check_upgrade_links(old_dns, old_el->num_values, invocation_id);
1586 if (ret != LDB_SUCCESS) {
1587 talloc_free(tmp_ctx);
1593 /* see if we are being asked to delete any links that
1594 don't exist or are already deleted */
1595 for (i=0; i<el->num_values; i++) {
1596 struct parsed_dn *p = &dns[i];
1597 struct parsed_dn *p2;
1598 const struct ldb_val *v;
1600 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
1602 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1603 el->name, GUID_string(tmp_ctx, p->guid));
1604 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1606 v = ldb_dn_get_extended_component(p2->dsdb_dn->dn, "DELETED");
1608 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1609 el->name, GUID_string(tmp_ctx, p->guid));
1610 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1614 /* for each new value, see if it exists already with the same GUID
1615 if it is not already deleted and matches the delete list then delete it
1617 for (i=0; i<old_el->num_values; i++) {
1618 struct parsed_dn *p = &old_dns[i];
1619 const struct ldb_val *v;
1621 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
1625 v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED");
1626 if (v != NULL) continue;
1628 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1629 invocation_id, seq_num, seq_num, now, 0, true);
1630 if (ret != LDB_SUCCESS) {
1631 talloc_free(tmp_ctx);
1635 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1636 if (ret != LDB_SUCCESS) {
1637 talloc_free(tmp_ctx);
1642 el->values = talloc_steal(msg->elements, old_el->values);
1643 el->num_values = old_el->num_values;
1645 talloc_free(tmp_ctx);
1647 /* we now tell the backend to replace all existing values
1648 with the one we have constructed */
1649 el->flags = LDB_FLAG_MOD_REPLACE;
1655 handle replacing a linked attribute
1657 static int replmd_modify_la_replace(struct ldb_module *module,
1658 struct dsdb_schema *schema,
1659 struct ldb_message *msg,
1660 struct ldb_message_element *el,
1661 struct ldb_message_element *old_el,
1662 const struct dsdb_attribute *schema_attr,
1665 struct GUID *msg_guid)
1668 struct parsed_dn *dns, *old_dns;
1669 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1671 const struct GUID *invocation_id;
1672 struct ldb_context *ldb = ldb_module_get_ctx(module);
1673 struct ldb_val *new_values = NULL;
1674 uint32_t num_new_values = 0;
1675 unsigned old_num_values = old_el?old_el->num_values:0;
1678 unix_to_nt_time(&now, t);
1680 /* check if there is nothing to replace */
1681 if ((!old_el || old_el->num_values == 0) &&
1682 el->num_values == 0) {
1686 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1687 if (ret != LDB_SUCCESS) {
1688 talloc_free(tmp_ctx);
1692 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1693 if (ret != LDB_SUCCESS) {
1694 talloc_free(tmp_ctx);
1698 invocation_id = samdb_ntds_invocation_id(ldb);
1699 if (!invocation_id) {
1700 return LDB_ERR_OPERATIONS_ERROR;
1703 ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
1704 if (ret != LDB_SUCCESS) {
1705 talloc_free(tmp_ctx);
1709 /* mark all the old ones as deleted */
1710 for (i=0; i<old_num_values; i++) {
1711 struct parsed_dn *old_p = &old_dns[i];
1712 struct parsed_dn *p;
1713 const struct ldb_val *v;
1715 v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED");
1718 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1719 if (ret != LDB_SUCCESS) {
1720 talloc_free(tmp_ctx);
1724 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
1726 /* we don't delete it if we are re-adding it */
1730 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
1731 invocation_id, seq_num, seq_num, now, 0, true);
1732 if (ret != LDB_SUCCESS) {
1733 talloc_free(tmp_ctx);
1738 /* for each new value, either update its meta-data, or add it
1741 for (i=0; i<el->num_values; i++) {
1742 struct parsed_dn *p = &dns[i], *old_p;
1745 (old_p = parsed_dn_find(old_dns,
1746 old_num_values, p->guid, NULL)) != NULL) {
1747 /* update in place */
1748 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
1749 old_p->dsdb_dn, invocation_id,
1750 seq_num, seq_num, now, 0, false);
1751 if (ret != LDB_SUCCESS) {
1752 talloc_free(tmp_ctx);
1757 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
1759 if (new_values == NULL) {
1760 ldb_module_oom(module);
1761 talloc_free(tmp_ctx);
1762 return LDB_ERR_OPERATIONS_ERROR;
1764 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1765 invocation_id, seq_num, seq_num, now, 0, false);
1766 if (ret != LDB_SUCCESS) {
1767 talloc_free(tmp_ctx);
1773 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
1774 if (ret != LDB_SUCCESS) {
1775 talloc_free(tmp_ctx);
1780 /* add the new values to the end of old_el */
1781 if (num_new_values != 0) {
1782 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1783 struct ldb_val, old_num_values+num_new_values);
1784 if (el->values == NULL) {
1785 ldb_module_oom(module);
1786 return LDB_ERR_OPERATIONS_ERROR;
1788 memcpy(&el->values[old_num_values], &new_values[0],
1789 sizeof(struct ldb_val)*num_new_values);
1790 el->num_values = old_num_values + num_new_values;
1791 talloc_steal(msg->elements, new_values);
1793 el->values = old_el->values;
1794 el->num_values = old_el->num_values;
1795 talloc_steal(msg->elements, el->values);
1798 talloc_free(tmp_ctx);
1800 /* we now tell the backend to replace all existing values
1801 with the one we have constructed */
1802 el->flags = LDB_FLAG_MOD_REPLACE;
1809 handle linked attributes in modify requests
1811 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
1812 struct ldb_message *msg,
1813 uint64_t seq_num, time_t t)
1815 struct ldb_result *res;
1817 struct ldb_context *ldb = ldb_module_get_ctx(module);
1818 struct ldb_message *old_msg;
1819 struct dsdb_schema *schema = dsdb_get_schema(ldb);
1820 struct GUID old_guid;
1823 /* there the replmd_update_rpmd code has already
1824 * checked and saw that there are no linked
1829 #if !W2K3_LINKED_ATTRIBUTES
1833 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
1834 /* don't do anything special for linked attributes */
1838 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
1839 DSDB_SEARCH_SHOW_DELETED |
1840 DSDB_SEARCH_REVEAL_INTERNALS |
1841 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
1842 if (ret != LDB_SUCCESS) {
1845 old_msg = res->msgs[0];
1847 old_guid = samdb_result_guid(old_msg, "objectGUID");
1849 for (i=0; i<msg->num_elements; i++) {
1850 struct ldb_message_element *el = &msg->elements[i];
1851 struct ldb_message_element *old_el, *new_el;
1852 const struct dsdb_attribute *schema_attr
1853 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1855 ldb_asprintf_errstring(ldb,
1856 "attribute %s is not a valid attribute in schema", el->name);
1857 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1859 if (schema_attr->linkID == 0) {
1862 if ((schema_attr->linkID & 1) == 1) {
1863 /* Odd is for the target. Illegal to modify */
1864 ldb_asprintf_errstring(ldb,
1865 "attribute %s must not be modified directly, it is a linked attribute", el->name);
1866 return LDB_ERR_UNWILLING_TO_PERFORM;
1868 old_el = ldb_msg_find_element(old_msg, el->name);
1869 switch (el->flags & LDB_FLAG_MOD_MASK) {
1870 case LDB_FLAG_MOD_REPLACE:
1871 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1873 case LDB_FLAG_MOD_DELETE:
1874 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1876 case LDB_FLAG_MOD_ADD:
1877 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1880 ldb_asprintf_errstring(ldb,
1881 "invalid flags 0x%x for %s linked attribute",
1882 el->flags, el->name);
1883 return LDB_ERR_UNWILLING_TO_PERFORM;
1885 if (ret != LDB_SUCCESS) {
1889 ldb_msg_remove_attr(old_msg, el->name);
1891 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
1892 new_el->num_values = el->num_values;
1893 new_el->values = talloc_steal(msg->elements, el->values);
1895 /* TODO: this relises a bit too heavily on the exact
1896 behaviour of ldb_msg_find_element and
1897 ldb_msg_remove_element */
1898 old_el = ldb_msg_find_element(msg, el->name);
1900 ldb_msg_remove_element(msg, old_el);
1911 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
1913 struct ldb_context *ldb;
1914 struct replmd_replicated_request *ac;
1915 struct ldb_request *down_req;
1916 struct ldb_message *msg;
1917 time_t t = time(NULL);
1920 /* do not manipulate our control entries */
1921 if (ldb_dn_is_special(req->op.mod.message->dn)) {
1922 return ldb_next_request(module, req);
1925 ldb = ldb_module_get_ctx(module);
1927 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
1929 ac = replmd_ctx_init(module, req);
1931 return LDB_ERR_OPERATIONS_ERROR;
1934 /* we have to copy the message as the caller might have it as a const */
1935 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
1939 return LDB_ERR_OPERATIONS_ERROR;
1942 ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num, t);
1943 if (ret != LDB_SUCCESS) {
1948 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t);
1949 if (ret != LDB_SUCCESS) {
1955 * - replace the old object with the newly constructed one
1958 ret = ldb_build_mod_req(&down_req, ldb, ac,
1961 ac, replmd_op_callback,
1963 if (ret != LDB_SUCCESS) {
1967 talloc_steal(down_req, msg);
1969 /* we only change whenChanged and uSNChanged if the seq_num
1971 if (ac->seq_num != 0) {
1972 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
1977 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
1983 /* go on with the call chain */
1984 return ldb_next_request(module, down_req);
1987 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
1990 handle a rename request
1992 On a rename we need to do an extra ldb_modify which sets the
1993 whenChanged and uSNChanged attributes. We do this in a callback after the success.
1995 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
1997 struct ldb_context *ldb;
1998 struct replmd_replicated_request *ac;
2000 struct ldb_request *down_req;
2002 /* do not manipulate our control entries */
2003 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2004 return ldb_next_request(module, req);
2007 ldb = ldb_module_get_ctx(module);
2009 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2011 ac = replmd_ctx_init(module, req);
2013 return LDB_ERR_OPERATIONS_ERROR;
2015 ret = ldb_build_rename_req(&down_req, ldb, ac,
2016 ac->req->op.rename.olddn,
2017 ac->req->op.rename.newdn,
2019 ac, replmd_rename_callback,
2022 if (ret != LDB_SUCCESS) {
2027 /* go on with the call chain */
2028 return ldb_next_request(module, down_req);
2031 /* After the rename is compleated, update the whenchanged etc */
2032 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2034 struct ldb_context *ldb;
2035 struct replmd_replicated_request *ac;
2036 struct ldb_request *down_req;
2037 struct ldb_message *msg;
2038 time_t t = time(NULL);
2041 ac = talloc_get_type(req->context, struct replmd_replicated_request);
2042 ldb = ldb_module_get_ctx(ac->module);
2044 if (ares->error != LDB_SUCCESS) {
2045 return ldb_module_done(ac->req, ares->controls,
2046 ares->response, ares->error);
2049 if (ares->type != LDB_REPLY_DONE) {
2050 ldb_set_errstring(ldb,
2051 "invalid ldb_reply_type in callback");
2053 return ldb_module_done(ac->req, NULL, NULL,
2054 LDB_ERR_OPERATIONS_ERROR);
2057 /* Get a sequence number from the backend */
2058 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
2059 if (ret != LDB_SUCCESS) {
2064 * - replace the old object with the newly constructed one
2067 msg = ldb_msg_new(ac);
2070 return LDB_ERR_OPERATIONS_ERROR;
2073 msg->dn = ac->req->op.rename.newdn;
2075 ret = ldb_build_mod_req(&down_req, ldb, ac,
2078 ac, replmd_op_callback,
2081 if (ret != LDB_SUCCESS) {
2085 talloc_steal(down_req, msg);
2087 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2092 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
2097 /* go on with the call chain - do the modify after the rename */
2098 return ldb_next_request(ac->module, down_req);
2102 remove links from objects that point at this object when an object
2105 static int replmd_delete_remove_link(struct ldb_module *module,
2106 struct dsdb_schema *schema,
2108 struct ldb_message_element *el,
2109 const struct dsdb_attribute *sa)
2112 TALLOC_CTX *tmp_ctx = talloc_new(module);
2113 struct ldb_context *ldb = ldb_module_get_ctx(module);
2115 for (i=0; i<el->num_values; i++) {
2116 struct dsdb_dn *dsdb_dn;
2120 struct ldb_message *msg;
2121 const struct dsdb_attribute *target_attr;
2122 struct ldb_message_element *el2;
2123 struct ldb_val dn_val;
2125 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2129 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2131 talloc_free(tmp_ctx);
2132 return LDB_ERR_OPERATIONS_ERROR;
2135 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2136 if (!NT_STATUS_IS_OK(status)) {
2137 talloc_free(tmp_ctx);
2138 return LDB_ERR_OPERATIONS_ERROR;
2141 /* remove the link */
2142 msg = ldb_msg_new(tmp_ctx);
2144 ldb_module_oom(module);
2145 talloc_free(tmp_ctx);
2146 return LDB_ERR_OPERATIONS_ERROR;
2150 msg->dn = dsdb_dn->dn;
2152 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2153 if (target_attr == NULL) {
2157 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2158 if (ret != LDB_SUCCESS) {
2159 ldb_module_oom(module);
2160 talloc_free(tmp_ctx);
2161 return LDB_ERR_OPERATIONS_ERROR;
2163 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2164 el2->values = &dn_val;
2165 el2->num_values = 1;
2167 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE);
2168 if (ret != LDB_SUCCESS) {
2169 talloc_free(tmp_ctx);
2173 talloc_free(tmp_ctx);
2179 handle update of replication meta data for deletion of objects
2181 This also handles the mapping of delete to a rename operation
2182 to allow deletes to be replicated.
2184 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2186 int ret = LDB_ERR_OTHER;
2188 struct ldb_dn *old_dn, *new_dn;
2189 const char *rdn_name;
2190 const struct ldb_val *rdn_value, *new_rdn_value;
2192 struct ldb_context *ldb = ldb_module_get_ctx(module);
2193 struct dsdb_schema *schema = dsdb_get_schema(ldb);
2194 struct ldb_message *msg, *old_msg;
2195 struct ldb_message_element *el;
2196 TALLOC_CTX *tmp_ctx;
2197 struct ldb_result *res, *parent_res;
2198 const char *preserved_attrs[] = {
2199 /* yes, this really is a hard coded list. See MS-ADTS
2200 section 3.1.1.5.5.1.1 */
2201 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2202 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2203 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2204 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2205 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2206 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2207 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2209 uint32_t el_count = 0;
2212 if (ldb_dn_is_special(req->op.del.dn)) {
2213 return ldb_next_request(module, req);
2216 tmp_ctx = talloc_new(ldb);
2218 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2220 /* we need the complete msg off disk, so we can work out which
2221 attributes need to be removed */
2222 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2223 DSDB_SEARCH_SHOW_DELETED |
2224 DSDB_SEARCH_REVEAL_INTERNALS |
2225 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
2226 if (ret != LDB_SUCCESS) {
2227 talloc_free(tmp_ctx);
2230 old_msg = res->msgs[0];
2232 if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2233 struct auth_session_info *session_info =
2234 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2235 if (security_session_user_level(session_info) != SECURITY_SYSTEM) {
2236 ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2237 ldb_dn_get_linearized(old_msg->dn));
2238 return LDB_ERR_UNWILLING_TO_PERFORM;
2241 /* it is already deleted - really remove it this time */
2242 talloc_free(tmp_ctx);
2243 return ldb_next_request(module, req);
2246 /* work out where we will be renaming this object to */
2247 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn, &new_dn);
2248 if (ret != LDB_SUCCESS) {
2249 /* this is probably an attempted delete on a partition
2250 * that doesn't allow delete operations, such as the
2251 * schema partition */
2252 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2253 ldb_dn_get_linearized(old_dn));
2254 talloc_free(tmp_ctx);
2255 return LDB_ERR_UNWILLING_TO_PERFORM;
2258 rdn_name = ldb_dn_get_rdn_name(old_dn);
2259 rdn_value = ldb_dn_get_rdn_val(old_dn);
2261 /* get the objects GUID from the search we just did */
2262 guid = samdb_result_guid(old_msg, "objectGUID");
2264 /* Add a formatted child */
2265 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2268 GUID_string(tmp_ctx, &guid));
2270 DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2271 ldb_dn_get_linearized(new_dn)));
2272 talloc_free(tmp_ctx);
2273 return LDB_ERR_OPERATIONS_ERROR;
2277 now we need to modify the object in the following ways:
2279 - add isDeleted=TRUE
2280 - update rDN and name, with new rDN
2281 - remove linked attributes
2282 - remove objectCategory and sAMAccountType
2283 - remove attribs not on the preserved list
2284 - preserved if in above list, or is rDN
2285 - remove all linked attribs from this object
2286 - remove all links from other objects to this object
2287 - add lastKnownParent
2288 - update replPropertyMetaData?
2290 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2293 msg = ldb_msg_new(tmp_ctx);
2295 ldb_module_oom(module);
2296 talloc_free(tmp_ctx);
2297 return LDB_ERR_OPERATIONS_ERROR;
2302 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2303 if (ret != LDB_SUCCESS) {
2304 DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2305 ldb_module_oom(module);
2306 talloc_free(tmp_ctx);
2309 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2311 /* we also mark it as recycled, meaning this object can't be
2312 recovered (we are stripping its attributes) */
2313 if (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008_R2) {
2314 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
2315 if (ret != LDB_SUCCESS) {
2316 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
2317 ldb_module_oom(module);
2318 talloc_free(tmp_ctx);
2321 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2324 /* we need the storage form of the parent GUID */
2325 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2326 ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2327 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2328 DSDB_SEARCH_REVEAL_INTERNALS);
2329 if (ret != LDB_SUCCESS) {
2330 talloc_free(tmp_ctx);
2334 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2335 ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2336 if (ret != LDB_SUCCESS) {
2337 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2338 ldb_module_oom(module);
2339 talloc_free(tmp_ctx);
2342 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2344 /* work out which of the old attributes we will be removing */
2345 for (i=0; i<old_msg->num_elements; i++) {
2346 const struct dsdb_attribute *sa;
2347 el = &old_msg->elements[i];
2348 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2350 talloc_free(tmp_ctx);
2351 return LDB_ERR_OPERATIONS_ERROR;
2353 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2354 /* don't remove the rDN */
2358 if (sa->linkID && sa->linkID & 1) {
2359 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa);
2360 if (ret != LDB_SUCCESS) {
2361 talloc_free(tmp_ctx);
2362 return LDB_ERR_OPERATIONS_ERROR;
2367 if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2371 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2372 if (ret != LDB_SUCCESS) {
2373 talloc_free(tmp_ctx);
2374 ldb_module_oom(module);
2379 /* work out what the new rdn value is, for updating the
2380 rDN and name fields */
2381 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2382 ret = ldb_msg_add_value(msg, rdn_name, new_rdn_value, &el);
2383 if (ret != LDB_SUCCESS) {
2384 talloc_free(tmp_ctx);
2387 el->flags = LDB_FLAG_MOD_REPLACE;
2389 el = ldb_msg_find_element(old_msg, "name");
2391 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2392 if (ret != LDB_SUCCESS) {
2393 talloc_free(tmp_ctx);
2396 el->flags = LDB_FLAG_MOD_REPLACE;
2399 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE);
2400 if (ret != LDB_SUCCESS) {
2401 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
2402 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
2403 talloc_free(tmp_ctx);
2407 /* now rename onto the new DN */
2408 ret = dsdb_module_rename(module, old_dn, new_dn, 0);
2409 if (ret != LDB_SUCCESS){
2410 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
2411 ldb_dn_get_linearized(old_dn),
2412 ldb_dn_get_linearized(new_dn),
2413 ldb_errstring(ldb)));
2414 talloc_free(tmp_ctx);
2418 talloc_free(tmp_ctx);
2420 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
2425 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
2430 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
2432 int ret = LDB_ERR_OTHER;
2433 /* TODO: do some error mapping */
2437 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
2439 struct ldb_context *ldb;
2440 struct ldb_request *change_req;
2441 enum ndr_err_code ndr_err;
2442 struct ldb_message *msg;
2443 struct replPropertyMetaDataBlob *md;
2444 struct ldb_val md_value;
2449 * TODO: check if the parent object exist
2453 * TODO: handle the conflict case where an object with the
2457 ldb = ldb_module_get_ctx(ar->module);
2458 msg = ar->objs->objects[ar->index_current].msg;
2459 md = ar->objs->objects[ar->index_current].meta_data;
2461 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2462 if (ret != LDB_SUCCESS) {
2463 return replmd_replicated_request_error(ar, ret);
2466 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
2467 if (ret != LDB_SUCCESS) {
2468 return replmd_replicated_request_error(ar, ret);
2471 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2472 if (ret != LDB_SUCCESS) {
2473 return replmd_replicated_request_error(ar, ret);
2476 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
2477 if (ret != LDB_SUCCESS) {
2478 return replmd_replicated_request_error(ar, ret);
2481 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2482 if (ret != LDB_SUCCESS) {
2483 return replmd_replicated_request_error(ar, ret);
2486 /* remove any message elements that have zero values */
2487 for (i=0; i<msg->num_elements; i++) {
2488 struct ldb_message_element *el = &msg->elements[i];
2490 if (el->num_values == 0) {
2491 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
2493 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
2494 msg->num_elements--;
2501 * the meta data array is already sorted by the caller
2503 for (i=0; i < md->ctr.ctr1.count; i++) {
2504 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
2506 ndr_err = ndr_push_struct_blob(&md_value, msg,
2507 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2509 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2510 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2511 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2512 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2514 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
2515 if (ret != LDB_SUCCESS) {
2516 return replmd_replicated_request_error(ar, ret);
2519 replmd_ldb_message_sort(msg, ar->schema);
2522 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
2523 DEBUG(4, ("DRS replication add message:\n%s\n", s));
2527 ret = ldb_build_add_req(&change_req,
2535 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2537 return ldb_next_request(ar->module, change_req);
2541 return true if an update is newer than an existing entry
2542 see section 5.11 of MS-ADTS
2544 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
2545 const struct GUID *update_invocation_id,
2546 uint32_t current_version,
2547 uint32_t update_version,
2548 NTTIME current_change_time,
2549 NTTIME update_change_time)
2551 if (update_version != current_version) {
2552 return update_version > current_version;
2554 if (update_change_time > current_change_time) {
2557 if (update_change_time == current_change_time) {
2558 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
2563 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
2564 struct replPropertyMetaData1 *new_m)
2566 return replmd_update_is_newer(&cur_m->originating_invocation_id,
2567 &new_m->originating_invocation_id,
2570 cur_m->originating_change_time,
2571 new_m->originating_change_time);
2574 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
2576 struct ldb_context *ldb;
2577 struct ldb_request *change_req;
2578 enum ndr_err_code ndr_err;
2579 struct ldb_message *msg;
2580 struct replPropertyMetaDataBlob *rmd;
2581 struct replPropertyMetaDataBlob omd;
2582 const struct ldb_val *omd_value;
2583 struct replPropertyMetaDataBlob nmd;
2584 struct ldb_val nmd_value;
2586 uint32_t removed_attrs = 0;
2589 ldb = ldb_module_get_ctx(ar->module);
2590 msg = ar->objs->objects[ar->index_current].msg;
2591 rmd = ar->objs->objects[ar->index_current].meta_data;
2596 * TODO: check repl data is correct after a rename
2598 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
2599 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
2600 ldb_dn_get_linearized(ar->search_msg->dn),
2601 ldb_dn_get_linearized(msg->dn));
2602 if (dsdb_module_rename(ar->module,
2603 ar->search_msg->dn, msg->dn,
2604 DSDB_FLAG_OWN_MODULE) != LDB_SUCCESS) {
2605 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
2606 ldb_dn_get_linearized(ar->search_msg->dn),
2607 ldb_dn_get_linearized(msg->dn),
2608 ldb_errstring(ldb));
2609 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
2613 /* find existing meta data */
2614 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
2616 ndr_err = ndr_pull_struct_blob(omd_value, ar,
2617 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
2618 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
2619 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2620 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2621 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2624 if (omd.version != 1) {
2625 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2631 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
2632 nmd.ctr.ctr1.array = talloc_array(ar,
2633 struct replPropertyMetaData1,
2634 nmd.ctr.ctr1.count);
2635 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2637 /* first copy the old meta data */
2638 for (i=0; i < omd.ctr.ctr1.count; i++) {
2639 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
2643 /* now merge in the new meta data */
2644 for (i=0; i < rmd->ctr.ctr1.count; i++) {
2647 for (j=0; j < ni; j++) {
2650 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
2654 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
2655 &rmd->ctr.ctr1.array[i]);
2657 /* replace the entry */
2658 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
2663 DEBUG(1,("Discarding older DRS attribute update to %s on %s from %s\n",
2664 msg->elements[i-removed_attrs].name,
2665 ldb_dn_get_linearized(msg->dn),
2666 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
2668 /* we don't want to apply this change so remove the attribute */
2669 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
2676 if (found) continue;
2678 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
2683 * finally correct the size of the meta_data array
2685 nmd.ctr.ctr1.count = ni;
2688 * the rdn attribute (the alias for the name attribute),
2689 * 'cn' for most objects is the last entry in the meta data array
2692 * sort the new meta data array
2694 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
2695 if (ret != LDB_SUCCESS) {
2700 * check if some replicated attributes left, otherwise skip the ldb_modify() call
2702 if (msg->num_elements == 0) {
2703 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
2706 ar->index_current++;
2707 return replmd_replicated_apply_next(ar);
2710 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
2711 ar->index_current, msg->num_elements);
2713 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2714 if (ret != LDB_SUCCESS) {
2715 return replmd_replicated_request_error(ar, ret);
2718 for (i=0; i<ni; i++) {
2719 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
2722 /* create the meta data value */
2723 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
2724 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2726 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2727 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2728 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2729 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2733 * when we know that we'll modify the record, add the whenChanged, uSNChanged
2734 * and replPopertyMetaData attributes
2736 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2737 if (ret != LDB_SUCCESS) {
2738 return replmd_replicated_request_error(ar, ret);
2740 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2741 if (ret != LDB_SUCCESS) {
2742 return replmd_replicated_request_error(ar, ret);
2744 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
2745 if (ret != LDB_SUCCESS) {
2746 return replmd_replicated_request_error(ar, ret);
2749 replmd_ldb_message_sort(msg, ar->schema);
2751 /* we want to replace the old values */
2752 for (i=0; i < msg->num_elements; i++) {
2753 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2757 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
2758 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
2762 ret = ldb_build_mod_req(&change_req,
2770 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2772 return ldb_next_request(ar->module, change_req);
2775 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
2776 struct ldb_reply *ares)
2778 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2779 struct replmd_replicated_request);
2783 return ldb_module_done(ar->req, NULL, NULL,
2784 LDB_ERR_OPERATIONS_ERROR);
2786 if (ares->error != LDB_SUCCESS &&
2787 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
2788 return ldb_module_done(ar->req, ares->controls,
2789 ares->response, ares->error);
2792 switch (ares->type) {
2793 case LDB_REPLY_ENTRY:
2794 ar->search_msg = talloc_steal(ar, ares->message);
2797 case LDB_REPLY_REFERRAL:
2798 /* we ignore referrals */
2801 case LDB_REPLY_DONE:
2802 if (ar->search_msg != NULL) {
2803 ret = replmd_replicated_apply_merge(ar);
2805 ret = replmd_replicated_apply_add(ar);
2807 if (ret != LDB_SUCCESS) {
2808 return ldb_module_done(ar->req, NULL, NULL, ret);
2816 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
2818 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
2820 struct ldb_context *ldb;
2824 struct ldb_request *search_req;
2825 struct ldb_search_options_control *options;
2827 if (ar->index_current >= ar->objs->num_objects) {
2828 /* done with it, go to next stage */
2829 return replmd_replicated_uptodate_vector(ar);
2832 ldb = ldb_module_get_ctx(ar->module);
2833 ar->search_msg = NULL;
2835 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
2836 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2838 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
2839 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2840 talloc_free(tmp_str);
2842 ret = ldb_build_search_req(&search_req,
2851 replmd_replicated_apply_search_callback,
2854 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2855 if (ret != LDB_SUCCESS) {
2859 /* we need to cope with cross-partition links, so search for
2860 the GUID over all partitions */
2861 options = talloc(search_req, struct ldb_search_options_control);
2862 if (options == NULL) {
2863 DEBUG(0, (__location__ ": out of memory\n"));
2864 return LDB_ERR_OPERATIONS_ERROR;
2866 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2868 ret = ldb_request_add_control(search_req,
2869 LDB_CONTROL_SEARCH_OPTIONS_OID,
2871 if (ret != LDB_SUCCESS) {
2875 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2877 return ldb_next_request(ar->module, search_req);
2880 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
2881 struct ldb_reply *ares)
2883 struct ldb_context *ldb;
2884 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2885 struct replmd_replicated_request);
2886 ldb = ldb_module_get_ctx(ar->module);
2889 return ldb_module_done(ar->req, NULL, NULL,
2890 LDB_ERR_OPERATIONS_ERROR);
2892 if (ares->error != LDB_SUCCESS) {
2893 return ldb_module_done(ar->req, ares->controls,
2894 ares->response, ares->error);
2897 if (ares->type != LDB_REPLY_DONE) {
2898 ldb_set_errstring(ldb, "Invalid reply type\n!");
2899 return ldb_module_done(ar->req, NULL, NULL,
2900 LDB_ERR_OPERATIONS_ERROR);
2905 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
2908 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
2910 struct ldb_context *ldb;
2911 struct ldb_request *change_req;
2912 enum ndr_err_code ndr_err;
2913 struct ldb_message *msg;
2914 struct replUpToDateVectorBlob ouv;
2915 const struct ldb_val *ouv_value;
2916 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
2917 struct replUpToDateVectorBlob nuv;
2918 struct ldb_val nuv_value;
2919 struct ldb_message_element *nuv_el = NULL;
2920 const struct GUID *our_invocation_id;
2921 struct ldb_message_element *orf_el = NULL;
2922 struct repsFromToBlob nrf;
2923 struct ldb_val *nrf_value = NULL;
2924 struct ldb_message_element *nrf_el = NULL;
2927 time_t t = time(NULL);
2931 ldb = ldb_module_get_ctx(ar->module);
2932 ruv = ar->objs->uptodateness_vector;
2938 unix_to_nt_time(&now, t);
2941 * first create the new replUpToDateVector
2943 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
2945 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
2946 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
2947 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
2948 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2949 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2950 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2953 if (ouv.version != 2) {
2954 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2959 * the new uptodateness vector will at least
2960 * contain 1 entry, one for the source_dsa
2962 * plus optional values from our old vector and the one from the source_dsa
2964 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
2965 if (ruv) nuv.ctr.ctr2.count += ruv->count;
2966 nuv.ctr.ctr2.cursors = talloc_array(ar,
2967 struct drsuapi_DsReplicaCursor2,
2968 nuv.ctr.ctr2.count);
2969 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2971 /* first copy the old vector */
2972 for (i=0; i < ouv.ctr.ctr2.count; i++) {
2973 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
2977 /* get our invocation_id if we have one already attached to the ldb */
2978 our_invocation_id = samdb_ntds_invocation_id(ldb);
2980 /* merge in the source_dsa vector is available */
2981 for (i=0; (ruv && i < ruv->count); i++) {
2984 if (our_invocation_id &&
2985 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
2986 our_invocation_id)) {
2990 for (j=0; j < ni; j++) {
2991 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
2992 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
2999 * we update only the highest_usn and not the latest_sync_success time,
3000 * because the last success stands for direct replication
3002 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
3003 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
3008 if (found) continue;
3010 /* if it's not there yet, add it */
3011 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
3016 * merge in the current highwatermark for the source_dsa
3019 for (j=0; j < ni; j++) {
3020 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
3021 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3028 * here we update the highest_usn and last_sync_success time
3029 * because we're directly replicating from the source_dsa
3031 * and use the tmp_highest_usn because this is what we have just applied
3034 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3035 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
3040 * here we update the highest_usn and last_sync_success time
3041 * because we're directly replicating from the source_dsa
3043 * and use the tmp_highest_usn because this is what we have just applied
3046 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
3047 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3048 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
3053 * finally correct the size of the cursors array
3055 nuv.ctr.ctr2.count = ni;
3060 qsort(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count,
3061 sizeof(struct drsuapi_DsReplicaCursor2),
3062 (comparison_fn_t)drsuapi_DsReplicaCursor2_compare);
3065 * create the change ldb_message
3067 msg = ldb_msg_new(ar);
3068 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3069 msg->dn = ar->search_msg->dn;
3071 ndr_err = ndr_push_struct_blob(&nuv_value, msg,
3072 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3074 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
3075 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3076 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3077 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3079 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
3080 if (ret != LDB_SUCCESS) {
3081 return replmd_replicated_request_error(ar, ret);
3083 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
3086 * now create the new repsFrom value from the given repsFromTo1 structure
3090 nrf.ctr.ctr1 = *ar->objs->source_dsa;
3091 /* and fix some values... */
3092 nrf.ctr.ctr1.consecutive_sync_failures = 0;
3093 nrf.ctr.ctr1.last_success = now;
3094 nrf.ctr.ctr1.last_attempt = now;
3095 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
3096 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
3099 * first see if we already have a repsFrom value for the current source dsa
3100 * if so we'll later replace this value
3102 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
3104 for (i=0; i < orf_el->num_values; i++) {
3105 struct repsFromToBlob *trf;
3107 trf = talloc(ar, struct repsFromToBlob);
3108 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3110 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
3111 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3112 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3113 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3114 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3117 if (trf->version != 1) {
3118 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3122 * we compare the source dsa objectGUID not the invocation_id
3123 * because we want only one repsFrom value per source dsa
3124 * and when the invocation_id of the source dsa has changed we don't need
3125 * the old repsFrom with the old invocation_id
3127 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
3128 &ar->objs->source_dsa->source_dsa_obj_guid)) {
3134 nrf_value = &orf_el->values[i];
3139 * copy over all old values to the new ldb_message
3141 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
3142 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3147 * if we haven't found an old repsFrom value for the current source dsa
3148 * we'll add a new value
3151 struct ldb_val zero_value;
3152 ZERO_STRUCT(zero_value);
3153 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
3154 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3156 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
3159 /* we now fill the value which is already attached to ldb_message */
3160 ndr_err = ndr_push_struct_blob(nrf_value, msg,
3161 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3163 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3164 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3165 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3166 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3170 * the ldb_message_element for the attribute, has all the old values and the new one
3171 * so we'll replace the whole attribute with all values
3173 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
3176 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3177 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
3181 /* prepare the ldb_modify() request */
3182 ret = ldb_build_mod_req(&change_req,
3188 replmd_replicated_uptodate_modify_callback,
3190 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3192 return ldb_next_request(ar->module, change_req);
3195 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
3196 struct ldb_reply *ares)
3198 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3199 struct replmd_replicated_request);
3203 return ldb_module_done(ar->req, NULL, NULL,
3204 LDB_ERR_OPERATIONS_ERROR);
3206 if (ares->error != LDB_SUCCESS &&
3207 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3208 return ldb_module_done(ar->req, ares->controls,
3209 ares->response, ares->error);
3212 switch (ares->type) {
3213 case LDB_REPLY_ENTRY:
3214 ar->search_msg = talloc_steal(ar, ares->message);
3217 case LDB_REPLY_REFERRAL:
3218 /* we ignore referrals */
3221 case LDB_REPLY_DONE:
3222 if (ar->search_msg == NULL) {
3223 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3225 ret = replmd_replicated_uptodate_modify(ar);
3227 if (ret != LDB_SUCCESS) {
3228 return ldb_module_done(ar->req, NULL, NULL, ret);
3237 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
3239 struct ldb_context *ldb;
3241 static const char *attrs[] = {
3242 "replUpToDateVector",
3246 struct ldb_request *search_req;
3248 ldb = ldb_module_get_ctx(ar->module);
3249 ar->search_msg = NULL;
3251 ret = ldb_build_search_req(&search_req,
3254 ar->objs->partition_dn,
3260 replmd_replicated_uptodate_search_callback,
3262 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3264 return ldb_next_request(ar->module, search_req);
3269 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
3271 struct ldb_context *ldb;
3272 struct dsdb_extended_replicated_objects *objs;
3273 struct replmd_replicated_request *ar;
3274 struct ldb_control **ctrls;
3276 struct replmd_private *replmd_private =
3277 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3279 ldb = ldb_module_get_ctx(module);
3281 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
3283 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
3285 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
3286 return LDB_ERR_PROTOCOL_ERROR;
3289 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
3290 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
3291 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
3292 return LDB_ERR_PROTOCOL_ERROR;
3295 ar = replmd_ctx_init(module, req);
3297 return LDB_ERR_OPERATIONS_ERROR;
3299 /* Set the flags to have the replmd_op_callback run over the full set of objects */
3300 ar->apply_mode = true;
3302 ar->schema = dsdb_get_schema(ldb);
3304 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
3306 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3307 return LDB_ERR_CONSTRAINT_VIOLATION;
3310 ctrls = req->controls;
3312 if (req->controls) {
3313 req->controls = talloc_memdup(ar, req->controls,
3314 talloc_get_size(req->controls));
3315 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3318 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
3319 if (ret != LDB_SUCCESS) {
3323 ar->controls = req->controls;
3324 req->controls = ctrls;
3326 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
3328 /* save away the linked attributes for the end of the
3330 for (i=0; i<ar->objs->linked_attributes_count; i++) {
3331 struct la_entry *la_entry;
3333 if (replmd_private->la_ctx == NULL) {
3334 replmd_private->la_ctx = talloc_new(replmd_private);
3336 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
3337 if (la_entry == NULL) {
3339 return LDB_ERR_OPERATIONS_ERROR;
3341 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
3342 if (la_entry->la == NULL) {
3343 talloc_free(la_entry);
3345 return LDB_ERR_OPERATIONS_ERROR;
3347 *la_entry->la = ar->objs->linked_attributes[i];
3349 /* we need to steal the non-scalars so they stay
3350 around until the end of the transaction */
3351 talloc_steal(la_entry->la, la_entry->la->identifier);
3352 talloc_steal(la_entry->la, la_entry->la->value.blob);
3354 DLIST_ADD(replmd_private->la_list, la_entry);
3357 return replmd_replicated_apply_next(ar);
3361 process one linked attribute structure
3363 static int replmd_process_linked_attribute(struct ldb_module *module,
3364 struct la_entry *la_entry)
3366 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
3367 struct ldb_context *ldb = ldb_module_get_ctx(module);
3368 struct dsdb_schema *schema = dsdb_get_schema(ldb);
3369 struct ldb_message *msg;
3370 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
3372 const struct dsdb_attribute *attr;
3373 struct dsdb_dn *dsdb_dn;
3374 uint64_t seq_num = 0;
3375 struct ldb_message_element *old_el;
3377 time_t t = time(NULL);
3378 struct ldb_result *res;
3379 const char *attrs[2];
3380 struct parsed_dn *pdn_list, *pdn;
3381 struct GUID guid = GUID_zero();
3383 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
3384 const struct GUID *our_invocation_id;
3387 linked_attributes[0]:
3388 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
3390 identifier: struct drsuapi_DsReplicaObjectIdentifier
3391 __ndr_size : 0x0000003a (58)
3392 __ndr_size_sid : 0x00000000 (0)
3393 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
3395 __ndr_size_dn : 0x00000000 (0)
3397 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
3398 value: struct drsuapi_DsAttributeValue
3399 __ndr_size : 0x0000007e (126)
3401 blob : DATA_BLOB length=126
3402 flags : 0x00000001 (1)
3403 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
3404 originating_add_time : Wed Sep 2 22:20:01 2009 EST
3405 meta_data: struct drsuapi_DsReplicaMetaData
3406 version : 0x00000015 (21)
3407 originating_change_time : Wed Sep 2 23:39:07 2009 EST
3408 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
3409 originating_usn : 0x000000000001e19c (123292)
3411 (for cases where the link is to a normal DN)
3412 &target: struct drsuapi_DsReplicaObjectIdentifier3
3413 __ndr_size : 0x0000007e (126)
3414 __ndr_size_sid : 0x0000001c (28)
3415 guid : 7639e594-db75-4086-b0d4-67890ae46031
3416 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
3417 __ndr_size_dn : 0x00000022 (34)
3418 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
3421 /* find the attribute being modified */
3422 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
3424 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
3425 talloc_free(tmp_ctx);
3426 return LDB_ERR_OPERATIONS_ERROR;
3429 attrs[0] = attr->lDAPDisplayName;
3432 /* get the existing message from the db for the object with
3433 this GUID, returning attribute being modified. We will then
3434 use this msg as the basis for a modify call */
3435 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3436 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3437 DSDB_SEARCH_SHOW_DELETED |
3438 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3439 DSDB_SEARCH_REVEAL_INTERNALS,
3440 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
3441 if (ret != LDB_SUCCESS) {
3442 talloc_free(tmp_ctx);
3445 if (res->count != 1) {
3446 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
3447 GUID_string(tmp_ctx, &la->identifier->guid));
3448 talloc_free(tmp_ctx);
3449 return LDB_ERR_NO_SUCH_OBJECT;
3453 if (msg->num_elements == 0) {
3454 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
3455 if (ret != LDB_SUCCESS) {
3456 ldb_module_oom(module);
3457 talloc_free(tmp_ctx);
3458 return LDB_ERR_OPERATIONS_ERROR;
3461 old_el = &msg->elements[0];
3462 old_el->flags = LDB_FLAG_MOD_REPLACE;
3465 /* parse the existing links */
3466 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid);
3467 if (ret != LDB_SUCCESS) {
3468 talloc_free(tmp_ctx);
3472 /* get our invocationId */
3473 our_invocation_id = samdb_ntds_invocation_id(ldb);
3474 if (!our_invocation_id) {
3475 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
3476 talloc_free(tmp_ctx);
3477 return LDB_ERR_OPERATIONS_ERROR;
3480 ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, our_invocation_id);
3481 if (ret != LDB_SUCCESS) {
3482 talloc_free(tmp_ctx);
3486 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
3487 if (!W_ERROR_IS_OK(status)) {
3488 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
3489 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
3490 return LDB_ERR_OPERATIONS_ERROR;
3493 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
3494 if (!NT_STATUS_IS_OK(ntstatus) && active) {
3495 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
3497 ldb_dn_get_linearized(dsdb_dn->dn),
3498 ldb_dn_get_linearized(msg->dn));
3499 return LDB_ERR_OPERATIONS_ERROR;
3502 /* re-resolve the DN by GUID, as the DRS server may give us an
3504 ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn);
3505 if (ret != LDB_SUCCESS) {
3506 ldb_asprintf_errstring(ldb, __location__ ": Failed to re-resolve GUID %s",
3507 GUID_string(tmp_ctx, &guid));
3508 talloc_free(tmp_ctx);
3512 /* see if this link already exists */
3513 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
3515 /* see if this update is newer than what we have already */
3516 struct GUID invocation_id = GUID_zero();
3517 uint32_t version = 0;
3518 NTTIME change_time = 0;
3519 bool was_active = ldb_dn_get_extended_component(pdn->dsdb_dn->dn, "DELETED") == NULL;
3521 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
3522 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
3523 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
3525 if (!replmd_update_is_newer(&invocation_id,
3526 &la->meta_data.originating_invocation_id,
3528 la->meta_data.version,
3530 la->meta_data.originating_change_time)) {
3531 DEBUG(1,("Discarding older DRS linked attribute update to %s on %s from %s\n",
3532 old_el->name, ldb_dn_get_linearized(msg->dn),
3533 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
3534 talloc_free(tmp_ctx);
3538 /* get a seq_num for this change */
3539 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3540 if (ret != LDB_SUCCESS) {
3541 talloc_free(tmp_ctx);
3546 /* remove the existing backlink */
3547 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
3548 if (ret != LDB_SUCCESS) {
3549 talloc_free(tmp_ctx);
3554 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
3555 &la->meta_data.originating_invocation_id,
3556 la->meta_data.originating_usn, seq_num,
3557 la->meta_data.originating_change_time,
3558 la->meta_data.version,
3560 if (ret != LDB_SUCCESS) {
3561 talloc_free(tmp_ctx);
3566 /* add the new backlink */
3567 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
3568 if (ret != LDB_SUCCESS) {
3569 talloc_free(tmp_ctx);
3574 /* get a seq_num for this change */
3575 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3576 if (ret != LDB_SUCCESS) {
3577 talloc_free(tmp_ctx);
3581 old_el->values = talloc_realloc(msg->elements, old_el->values,
3582 struct ldb_val, old_el->num_values+1);
3583 if (!old_el->values) {
3584 ldb_module_oom(module);
3585 return LDB_ERR_OPERATIONS_ERROR;
3587 old_el->num_values++;
3589 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
3590 &la->meta_data.originating_invocation_id,
3591 la->meta_data.originating_usn, seq_num,
3592 la->meta_data.originating_change_time,
3593 la->meta_data.version,
3594 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
3595 if (ret != LDB_SUCCESS) {
3596 talloc_free(tmp_ctx);
3601 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
3603 if (ret != LDB_SUCCESS) {
3604 talloc_free(tmp_ctx);
3610 /* we only change whenChanged and uSNChanged if the seq_num
3612 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
3613 talloc_free(tmp_ctx);
3614 return LDB_ERR_OPERATIONS_ERROR;
3617 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
3618 talloc_free(tmp_ctx);
3619 return LDB_ERR_OPERATIONS_ERROR;
3622 ret = dsdb_check_single_valued_link(attr, old_el);
3623 if (ret != LDB_SUCCESS) {
3624 talloc_free(tmp_ctx);
3628 ret = dsdb_module_modify(module, msg, DSDB_MODIFY_RELAX);
3629 if (ret != LDB_SUCCESS) {
3630 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
3632 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
3633 talloc_free(tmp_ctx);
3637 talloc_free(tmp_ctx);
3642 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
3644 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
3645 return replmd_extended_replicated_objects(module, req);
3648 return ldb_next_request(module, req);
3653 we hook into the transaction operations to allow us to
3654 perform the linked attribute updates at the end of the whole
3655 transaction. This allows a forward linked attribute to be created
3656 before the object is created. During a vampire, w2k8 sends us linked
3657 attributes before the objects they are part of.
3659 static int replmd_start_transaction(struct ldb_module *module)
3661 /* create our private structure for this transaction */
3662 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
3663 struct replmd_private);
3664 replmd_txn_cleanup(replmd_private);
3666 /* free any leftover mod_usn records from cancelled
3668 while (replmd_private->ncs) {
3669 struct nc_entry *e = replmd_private->ncs;
3670 DLIST_REMOVE(replmd_private->ncs, e);
3674 return ldb_next_start_trans(module);
3678 on prepare commit we loop over our queued la_context structures and
3681 static int replmd_prepare_commit(struct ldb_module *module)
3683 struct replmd_private *replmd_private =
3684 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3685 struct la_entry *la, *prev;
3686 struct la_backlink *bl;
3689 /* walk the list backwards, to do the first entry first, as we
3690 * added the entries with DLIST_ADD() which puts them at the
3691 * start of the list */
3692 for (la = replmd_private->la_list; la && la->next; la=la->next) ;
3694 for (; la; la=prev) {
3696 DLIST_REMOVE(replmd_private->la_list, la);
3697 ret = replmd_process_linked_attribute(module, la);
3698 if (ret != LDB_SUCCESS) {
3699 replmd_txn_cleanup(replmd_private);
3704 /* process our backlink list, creating and deleting backlinks
3706 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
3707 ret = replmd_process_backlink(module, bl);
3708 if (ret != LDB_SUCCESS) {
3709 replmd_txn_cleanup(replmd_private);
3714 replmd_txn_cleanup(replmd_private);
3716 /* possibly change @REPLCHANGED */
3717 ret = replmd_notify_store(module);
3718 if (ret != LDB_SUCCESS) {
3722 return ldb_next_prepare_commit(module);
3725 static int replmd_del_transaction(struct ldb_module *module)
3727 struct replmd_private *replmd_private =
3728 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3729 replmd_txn_cleanup(replmd_private);
3731 return ldb_next_del_trans(module);
3735 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
3736 .name = "repl_meta_data",
3737 .init_context = replmd_init,
3739 .modify = replmd_modify,
3740 .rename = replmd_rename,
3741 .del = replmd_delete,
3742 .extended = replmd_extended,
3743 .start_transaction = replmd_start_transaction,
3744 .prepare_commit = replmd_prepare_commit,
3745 .del_transaction = replmd_del_transaction,