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);
675 allow_add_guid = true;
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 RMD_FLAGS = DSDB_RMD_FLAG_* bits
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, *flags_string;
1221 struct ldb_val tval;
1223 struct ldb_val usnv, local_usnv;
1224 struct ldb_val vers, flagsv;
1227 const char *dnstring;
1229 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1231 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1233 return LDB_ERR_OPERATIONS_ERROR;
1235 tval = data_blob_string_const(tstring);
1237 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1239 return LDB_ERR_OPERATIONS_ERROR;
1241 usnv = data_blob_string_const(usn_string);
1243 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1245 return LDB_ERR_OPERATIONS_ERROR;
1247 local_usnv = data_blob_string_const(usn_string);
1249 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1251 return LDB_ERR_OPERATIONS_ERROR;
1253 vers = data_blob_string_const(vstring);
1255 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1256 if (!NT_STATUS_IS_OK(status)) {
1257 return LDB_ERR_OPERATIONS_ERROR;
1260 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1261 if (!flags_string) {
1262 return LDB_ERR_OPERATIONS_ERROR;
1264 flagsv = data_blob_string_const(flags_string);
1266 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1267 if (ret != LDB_SUCCESS) return ret;
1268 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1269 if (ret != LDB_SUCCESS) return ret;
1270 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1271 if (ret != LDB_SUCCESS) return ret;
1272 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1273 if (ret != LDB_SUCCESS) return ret;
1274 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1275 if (ret != LDB_SUCCESS) return ret;
1276 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1277 if (ret != LDB_SUCCESS) return ret;
1278 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1279 if (ret != LDB_SUCCESS) return ret;
1281 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1282 if (dnstring == NULL) {
1283 return LDB_ERR_OPERATIONS_ERROR;
1285 *v = data_blob_string_const(dnstring);
1290 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1291 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1292 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1293 uint32_t version, bool deleted);
1296 check if any links need upgrading from w2k format
1298 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, const struct GUID *invocation_id)
1301 for (i=0; i<count; i++) {
1306 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1307 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1311 /* it's an old one that needs upgrading */
1312 ret = replmd_update_la_val(dns, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1314 if (ret != LDB_SUCCESS) {
1322 update an extended DN, including all meta data fields
1324 see replmd_build_la_val for value names
1326 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1327 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1328 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1329 uint32_t version, bool deleted)
1331 struct ldb_dn *dn = dsdb_dn->dn;
1332 const char *tstring, *usn_string, *flags_string;
1333 struct ldb_val tval;
1335 struct ldb_val usnv, local_usnv;
1336 struct ldb_val vers, flagsv;
1337 const struct ldb_val *old_addtime;
1338 uint32_t old_version;
1341 const char *dnstring;
1343 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1345 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1347 return LDB_ERR_OPERATIONS_ERROR;
1349 tval = data_blob_string_const(tstring);
1351 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1353 return LDB_ERR_OPERATIONS_ERROR;
1355 usnv = data_blob_string_const(usn_string);
1357 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1359 return LDB_ERR_OPERATIONS_ERROR;
1361 local_usnv = data_blob_string_const(usn_string);
1363 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1364 if (!NT_STATUS_IS_OK(status)) {
1365 return LDB_ERR_OPERATIONS_ERROR;
1368 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1369 if (!flags_string) {
1370 return LDB_ERR_OPERATIONS_ERROR;
1372 flagsv = data_blob_string_const(flags_string);
1374 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1375 if (ret != LDB_SUCCESS) return ret;
1377 /* get the ADDTIME from the original */
1378 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1379 if (old_addtime == NULL) {
1380 old_addtime = &tval;
1382 if (dsdb_dn != old_dsdb_dn) {
1383 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1384 if (ret != LDB_SUCCESS) return ret;
1387 /* use our invocation id */
1388 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1389 if (ret != LDB_SUCCESS) return ret;
1391 /* changetime is the current time */
1392 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1393 if (ret != LDB_SUCCESS) return ret;
1395 /* update the USN */
1396 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1397 if (ret != LDB_SUCCESS) return ret;
1399 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1400 if (ret != LDB_SUCCESS) return ret;
1402 /* increase the version by 1 */
1403 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1404 if (NT_STATUS_IS_OK(status) && old_version >= version) {
1405 version = old_version+1;
1407 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1408 vers = data_blob_string_const(vstring);
1409 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1410 if (ret != LDB_SUCCESS) return ret;
1412 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1413 if (dnstring == NULL) {
1414 return LDB_ERR_OPERATIONS_ERROR;
1416 *v = data_blob_string_const(dnstring);
1422 handle adding a linked attribute
1424 static int replmd_modify_la_add(struct ldb_module *module,
1425 struct dsdb_schema *schema,
1426 struct ldb_message *msg,
1427 struct ldb_message_element *el,
1428 struct ldb_message_element *old_el,
1429 const struct dsdb_attribute *schema_attr,
1432 struct GUID *msg_guid)
1435 struct parsed_dn *dns, *old_dns;
1436 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1438 struct ldb_val *new_values = NULL;
1439 unsigned int num_new_values = 0;
1440 unsigned old_num_values = old_el?old_el->num_values:0;
1441 const struct GUID *invocation_id;
1442 struct ldb_context *ldb = ldb_module_get_ctx(module);
1445 unix_to_nt_time(&now, t);
1447 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1448 if (ret != LDB_SUCCESS) {
1449 talloc_free(tmp_ctx);
1453 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1454 if (ret != LDB_SUCCESS) {
1455 talloc_free(tmp_ctx);
1459 invocation_id = samdb_ntds_invocation_id(ldb);
1460 if (!invocation_id) {
1461 talloc_free(tmp_ctx);
1462 return LDB_ERR_OPERATIONS_ERROR;
1465 ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
1466 if (ret != LDB_SUCCESS) {
1467 talloc_free(tmp_ctx);
1471 /* for each new value, see if it exists already with the same GUID */
1472 for (i=0; i<el->num_values; i++) {
1473 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1475 /* this is a new linked attribute value */
1476 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1477 if (new_values == NULL) {
1478 ldb_module_oom(module);
1479 talloc_free(tmp_ctx);
1480 return LDB_ERR_OPERATIONS_ERROR;
1482 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1483 invocation_id, seq_num, seq_num, now, 0, false);
1484 if (ret != LDB_SUCCESS) {
1485 talloc_free(tmp_ctx);
1490 /* this is only allowed if the GUID was
1491 previously deleted. */
1492 uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1494 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
1495 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1496 el->name, GUID_string(tmp_ctx, p->guid));
1497 talloc_free(tmp_ctx);
1498 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1500 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1501 invocation_id, seq_num, seq_num, now, 0, false);
1502 if (ret != LDB_SUCCESS) {
1503 talloc_free(tmp_ctx);
1508 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1509 if (ret != LDB_SUCCESS) {
1510 talloc_free(tmp_ctx);
1515 /* add the new ones on to the end of the old values, constructing a new el->values */
1516 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1518 old_num_values+num_new_values);
1519 if (el->values == NULL) {
1520 ldb_module_oom(module);
1521 return LDB_ERR_OPERATIONS_ERROR;
1524 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1525 el->num_values = old_num_values + num_new_values;
1527 talloc_steal(msg->elements, el->values);
1528 talloc_steal(el->values, new_values);
1530 talloc_free(tmp_ctx);
1532 /* we now tell the backend to replace all existing values
1533 with the one we have constructed */
1534 el->flags = LDB_FLAG_MOD_REPLACE;
1541 handle deleting all active linked attributes
1543 static int replmd_modify_la_delete(struct ldb_module *module,
1544 struct dsdb_schema *schema,
1545 struct ldb_message *msg,
1546 struct ldb_message_element *el,
1547 struct ldb_message_element *old_el,
1548 const struct dsdb_attribute *schema_attr,
1551 struct GUID *msg_guid)
1554 struct parsed_dn *dns, *old_dns;
1555 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1557 const struct GUID *invocation_id;
1558 struct ldb_context *ldb = ldb_module_get_ctx(module);
1561 unix_to_nt_time(&now, t);
1563 /* check if there is nothing to delete */
1564 if ((!old_el || old_el->num_values == 0) &&
1565 el->num_values == 0) {
1569 if (!old_el || old_el->num_values == 0) {
1570 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1573 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1574 if (ret != LDB_SUCCESS) {
1575 talloc_free(tmp_ctx);
1579 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1580 if (ret != LDB_SUCCESS) {
1581 talloc_free(tmp_ctx);
1585 invocation_id = samdb_ntds_invocation_id(ldb);
1586 if (!invocation_id) {
1587 return LDB_ERR_OPERATIONS_ERROR;
1590 ret = replmd_check_upgrade_links(old_dns, old_el->num_values, invocation_id);
1591 if (ret != LDB_SUCCESS) {
1592 talloc_free(tmp_ctx);
1598 /* see if we are being asked to delete any links that
1599 don't exist or are already deleted */
1600 for (i=0; i<el->num_values; i++) {
1601 struct parsed_dn *p = &dns[i];
1602 struct parsed_dn *p2;
1605 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
1607 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1608 el->name, GUID_string(tmp_ctx, p->guid));
1609 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1611 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
1612 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
1613 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1614 el->name, GUID_string(tmp_ctx, p->guid));
1615 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1619 /* for each new value, see if it exists already with the same GUID
1620 if it is not already deleted and matches the delete list then delete it
1622 for (i=0; i<old_el->num_values; i++) {
1623 struct parsed_dn *p = &old_dns[i];
1626 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
1630 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1631 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1633 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1634 invocation_id, seq_num, seq_num, now, 0, true);
1635 if (ret != LDB_SUCCESS) {
1636 talloc_free(tmp_ctx);
1640 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1641 if (ret != LDB_SUCCESS) {
1642 talloc_free(tmp_ctx);
1647 el->values = talloc_steal(msg->elements, old_el->values);
1648 el->num_values = old_el->num_values;
1650 talloc_free(tmp_ctx);
1652 /* we now tell the backend to replace all existing values
1653 with the one we have constructed */
1654 el->flags = LDB_FLAG_MOD_REPLACE;
1660 handle replacing a linked attribute
1662 static int replmd_modify_la_replace(struct ldb_module *module,
1663 struct dsdb_schema *schema,
1664 struct ldb_message *msg,
1665 struct ldb_message_element *el,
1666 struct ldb_message_element *old_el,
1667 const struct dsdb_attribute *schema_attr,
1670 struct GUID *msg_guid)
1673 struct parsed_dn *dns, *old_dns;
1674 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1676 const struct GUID *invocation_id;
1677 struct ldb_context *ldb = ldb_module_get_ctx(module);
1678 struct ldb_val *new_values = NULL;
1679 uint32_t num_new_values = 0;
1680 unsigned old_num_values = old_el?old_el->num_values:0;
1683 unix_to_nt_time(&now, t);
1685 /* check if there is nothing to replace */
1686 if ((!old_el || old_el->num_values == 0) &&
1687 el->num_values == 0) {
1691 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1692 if (ret != LDB_SUCCESS) {
1693 talloc_free(tmp_ctx);
1697 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1698 if (ret != LDB_SUCCESS) {
1699 talloc_free(tmp_ctx);
1703 invocation_id = samdb_ntds_invocation_id(ldb);
1704 if (!invocation_id) {
1705 return LDB_ERR_OPERATIONS_ERROR;
1708 ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
1709 if (ret != LDB_SUCCESS) {
1710 talloc_free(tmp_ctx);
1714 /* mark all the old ones as deleted */
1715 for (i=0; i<old_num_values; i++) {
1716 struct parsed_dn *old_p = &old_dns[i];
1717 struct parsed_dn *p;
1718 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
1720 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1722 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1723 if (ret != LDB_SUCCESS) {
1724 talloc_free(tmp_ctx);
1728 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
1730 /* we don't delete it if we are re-adding it */
1734 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
1735 invocation_id, seq_num, seq_num, now, 0, true);
1736 if (ret != LDB_SUCCESS) {
1737 talloc_free(tmp_ctx);
1742 /* for each new value, either update its meta-data, or add it
1745 for (i=0; i<el->num_values; i++) {
1746 struct parsed_dn *p = &dns[i], *old_p;
1749 (old_p = parsed_dn_find(old_dns,
1750 old_num_values, p->guid, NULL)) != NULL) {
1751 /* update in place */
1752 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
1753 old_p->dsdb_dn, invocation_id,
1754 seq_num, seq_num, now, 0, false);
1755 if (ret != LDB_SUCCESS) {
1756 talloc_free(tmp_ctx);
1761 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
1763 if (new_values == NULL) {
1764 ldb_module_oom(module);
1765 talloc_free(tmp_ctx);
1766 return LDB_ERR_OPERATIONS_ERROR;
1768 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1769 invocation_id, seq_num, seq_num, now, 0, false);
1770 if (ret != LDB_SUCCESS) {
1771 talloc_free(tmp_ctx);
1777 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
1778 if (ret != LDB_SUCCESS) {
1779 talloc_free(tmp_ctx);
1784 /* add the new values to the end of old_el */
1785 if (num_new_values != 0) {
1786 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1787 struct ldb_val, old_num_values+num_new_values);
1788 if (el->values == NULL) {
1789 ldb_module_oom(module);
1790 return LDB_ERR_OPERATIONS_ERROR;
1792 memcpy(&el->values[old_num_values], &new_values[0],
1793 sizeof(struct ldb_val)*num_new_values);
1794 el->num_values = old_num_values + num_new_values;
1795 talloc_steal(msg->elements, new_values);
1797 el->values = old_el->values;
1798 el->num_values = old_el->num_values;
1799 talloc_steal(msg->elements, el->values);
1802 talloc_free(tmp_ctx);
1804 /* we now tell the backend to replace all existing values
1805 with the one we have constructed */
1806 el->flags = LDB_FLAG_MOD_REPLACE;
1813 handle linked attributes in modify requests
1815 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
1816 struct ldb_message *msg,
1817 uint64_t seq_num, time_t t)
1819 struct ldb_result *res;
1821 struct ldb_context *ldb = ldb_module_get_ctx(module);
1822 struct ldb_message *old_msg;
1823 struct dsdb_schema *schema = dsdb_get_schema(ldb);
1824 struct GUID old_guid;
1827 /* there the replmd_update_rpmd code has already
1828 * checked and saw that there are no linked
1833 #if !W2K3_LINKED_ATTRIBUTES
1837 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
1838 /* don't do anything special for linked attributes */
1842 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
1843 DSDB_SEARCH_SHOW_DELETED |
1844 DSDB_SEARCH_REVEAL_INTERNALS |
1845 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
1846 if (ret != LDB_SUCCESS) {
1849 old_msg = res->msgs[0];
1851 old_guid = samdb_result_guid(old_msg, "objectGUID");
1853 for (i=0; i<msg->num_elements; i++) {
1854 struct ldb_message_element *el = &msg->elements[i];
1855 struct ldb_message_element *old_el, *new_el;
1856 const struct dsdb_attribute *schema_attr
1857 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1859 ldb_asprintf_errstring(ldb,
1860 "attribute %s is not a valid attribute in schema", el->name);
1861 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1863 if (schema_attr->linkID == 0) {
1866 if ((schema_attr->linkID & 1) == 1) {
1867 /* Odd is for the target. Illegal to modify */
1868 ldb_asprintf_errstring(ldb,
1869 "attribute %s must not be modified directly, it is a linked attribute", el->name);
1870 return LDB_ERR_UNWILLING_TO_PERFORM;
1872 old_el = ldb_msg_find_element(old_msg, el->name);
1873 switch (el->flags & LDB_FLAG_MOD_MASK) {
1874 case LDB_FLAG_MOD_REPLACE:
1875 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1877 case LDB_FLAG_MOD_DELETE:
1878 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1880 case LDB_FLAG_MOD_ADD:
1881 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1884 ldb_asprintf_errstring(ldb,
1885 "invalid flags 0x%x for %s linked attribute",
1886 el->flags, el->name);
1887 return LDB_ERR_UNWILLING_TO_PERFORM;
1889 if (ret != LDB_SUCCESS) {
1893 ldb_msg_remove_attr(old_msg, el->name);
1895 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
1896 new_el->num_values = el->num_values;
1897 new_el->values = talloc_steal(msg->elements, el->values);
1899 /* TODO: this relises a bit too heavily on the exact
1900 behaviour of ldb_msg_find_element and
1901 ldb_msg_remove_element */
1902 old_el = ldb_msg_find_element(msg, el->name);
1904 ldb_msg_remove_element(msg, old_el);
1915 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
1917 struct ldb_context *ldb;
1918 struct replmd_replicated_request *ac;
1919 struct ldb_request *down_req;
1920 struct ldb_message *msg;
1921 time_t t = time(NULL);
1924 /* do not manipulate our control entries */
1925 if (ldb_dn_is_special(req->op.mod.message->dn)) {
1926 return ldb_next_request(module, req);
1929 ldb = ldb_module_get_ctx(module);
1931 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
1933 ac = replmd_ctx_init(module, req);
1935 return LDB_ERR_OPERATIONS_ERROR;
1938 /* we have to copy the message as the caller might have it as a const */
1939 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
1943 return LDB_ERR_OPERATIONS_ERROR;
1946 ldb_msg_remove_attr(msg, "whenChanged");
1947 ldb_msg_remove_attr(msg, "uSNChanged");
1949 ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num, t);
1950 if (ret != LDB_SUCCESS) {
1955 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t);
1956 if (ret != LDB_SUCCESS) {
1962 * - replace the old object with the newly constructed one
1965 ret = ldb_build_mod_req(&down_req, ldb, ac,
1968 ac, replmd_op_callback,
1970 if (ret != LDB_SUCCESS) {
1974 talloc_steal(down_req, msg);
1976 /* we only change whenChanged and uSNChanged if the seq_num
1978 if (ac->seq_num != 0) {
1979 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
1984 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
1990 /* go on with the call chain */
1991 return ldb_next_request(module, down_req);
1994 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
1997 handle a rename request
1999 On a rename we need to do an extra ldb_modify which sets the
2000 whenChanged and uSNChanged attributes. We do this in a callback after the success.
2002 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2004 struct ldb_context *ldb;
2005 struct replmd_replicated_request *ac;
2007 struct ldb_request *down_req;
2009 /* do not manipulate our control entries */
2010 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2011 return ldb_next_request(module, req);
2014 ldb = ldb_module_get_ctx(module);
2016 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2018 ac = replmd_ctx_init(module, req);
2020 return LDB_ERR_OPERATIONS_ERROR;
2022 ret = ldb_build_rename_req(&down_req, ldb, ac,
2023 ac->req->op.rename.olddn,
2024 ac->req->op.rename.newdn,
2026 ac, replmd_rename_callback,
2029 if (ret != LDB_SUCCESS) {
2034 /* go on with the call chain */
2035 return ldb_next_request(module, down_req);
2038 /* After the rename is compleated, update the whenchanged etc */
2039 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2041 struct ldb_context *ldb;
2042 struct replmd_replicated_request *ac;
2043 struct ldb_request *down_req;
2044 struct ldb_message *msg;
2045 time_t t = time(NULL);
2048 ac = talloc_get_type(req->context, struct replmd_replicated_request);
2049 ldb = ldb_module_get_ctx(ac->module);
2051 if (ares->error != LDB_SUCCESS) {
2052 return ldb_module_done(ac->req, ares->controls,
2053 ares->response, ares->error);
2056 if (ares->type != LDB_REPLY_DONE) {
2057 ldb_set_errstring(ldb,
2058 "invalid ldb_reply_type in callback");
2060 return ldb_module_done(ac->req, NULL, NULL,
2061 LDB_ERR_OPERATIONS_ERROR);
2064 /* Get a sequence number from the backend */
2065 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
2066 if (ret != LDB_SUCCESS) {
2071 * - replace the old object with the newly constructed one
2074 msg = ldb_msg_new(ac);
2077 return LDB_ERR_OPERATIONS_ERROR;
2080 msg->dn = ac->req->op.rename.newdn;
2082 ret = ldb_build_mod_req(&down_req, ldb, ac,
2085 ac, replmd_op_callback,
2088 if (ret != LDB_SUCCESS) {
2092 talloc_steal(down_req, msg);
2094 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2099 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
2104 /* go on with the call chain - do the modify after the rename */
2105 return ldb_next_request(ac->module, down_req);
2109 remove links from objects that point at this object when an object
2112 static int replmd_delete_remove_link(struct ldb_module *module,
2113 struct dsdb_schema *schema,
2115 struct ldb_message_element *el,
2116 const struct dsdb_attribute *sa)
2119 TALLOC_CTX *tmp_ctx = talloc_new(module);
2120 struct ldb_context *ldb = ldb_module_get_ctx(module);
2122 for (i=0; i<el->num_values; i++) {
2123 struct dsdb_dn *dsdb_dn;
2127 struct ldb_message *msg;
2128 const struct dsdb_attribute *target_attr;
2129 struct ldb_message_element *el2;
2130 struct ldb_val dn_val;
2132 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2136 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2138 talloc_free(tmp_ctx);
2139 return LDB_ERR_OPERATIONS_ERROR;
2142 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2143 if (!NT_STATUS_IS_OK(status)) {
2144 talloc_free(tmp_ctx);
2145 return LDB_ERR_OPERATIONS_ERROR;
2148 /* remove the link */
2149 msg = ldb_msg_new(tmp_ctx);
2151 ldb_module_oom(module);
2152 talloc_free(tmp_ctx);
2153 return LDB_ERR_OPERATIONS_ERROR;
2157 msg->dn = dsdb_dn->dn;
2159 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2160 if (target_attr == NULL) {
2164 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2165 if (ret != LDB_SUCCESS) {
2166 ldb_module_oom(module);
2167 talloc_free(tmp_ctx);
2168 return LDB_ERR_OPERATIONS_ERROR;
2170 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2171 el2->values = &dn_val;
2172 el2->num_values = 1;
2174 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE);
2175 if (ret != LDB_SUCCESS) {
2176 talloc_free(tmp_ctx);
2180 talloc_free(tmp_ctx);
2186 handle update of replication meta data for deletion of objects
2188 This also handles the mapping of delete to a rename operation
2189 to allow deletes to be replicated.
2191 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2193 int ret = LDB_ERR_OTHER;
2195 struct ldb_dn *old_dn, *new_dn;
2196 const char *rdn_name;
2197 const struct ldb_val *rdn_value, *new_rdn_value;
2199 struct ldb_context *ldb = ldb_module_get_ctx(module);
2200 struct dsdb_schema *schema = dsdb_get_schema(ldb);
2201 struct ldb_message *msg, *old_msg;
2202 struct ldb_message_element *el;
2203 TALLOC_CTX *tmp_ctx;
2204 struct ldb_result *res, *parent_res;
2205 const char *preserved_attrs[] = {
2206 /* yes, this really is a hard coded list. See MS-ADTS
2207 section 3.1.1.5.5.1.1 */
2208 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2209 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2210 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2211 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2212 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2213 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2214 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2215 "whenChanged", NULL};
2216 uint32_t el_count = 0;
2219 if (ldb_dn_is_special(req->op.del.dn)) {
2220 return ldb_next_request(module, req);
2223 tmp_ctx = talloc_new(ldb);
2225 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2227 /* we need the complete msg off disk, so we can work out which
2228 attributes need to be removed */
2229 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2230 DSDB_SEARCH_SHOW_DELETED |
2231 DSDB_SEARCH_REVEAL_INTERNALS |
2232 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
2233 if (ret != LDB_SUCCESS) {
2234 talloc_free(tmp_ctx);
2237 old_msg = res->msgs[0];
2239 if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2240 struct auth_session_info *session_info =
2241 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2242 if (security_session_user_level(session_info) != SECURITY_SYSTEM) {
2243 ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2244 ldb_dn_get_linearized(old_msg->dn));
2245 return LDB_ERR_UNWILLING_TO_PERFORM;
2248 /* it is already deleted - really remove it this time */
2249 talloc_free(tmp_ctx);
2250 return ldb_next_request(module, req);
2253 /* work out where we will be renaming this object to */
2254 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn, &new_dn);
2255 if (ret != LDB_SUCCESS) {
2256 /* this is probably an attempted delete on a partition
2257 * that doesn't allow delete operations, such as the
2258 * schema partition */
2259 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2260 ldb_dn_get_linearized(old_dn));
2261 talloc_free(tmp_ctx);
2262 return LDB_ERR_UNWILLING_TO_PERFORM;
2265 rdn_name = ldb_dn_get_rdn_name(old_dn);
2266 rdn_value = ldb_dn_get_rdn_val(old_dn);
2268 /* get the objects GUID from the search we just did */
2269 guid = samdb_result_guid(old_msg, "objectGUID");
2271 /* Add a formatted child */
2272 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2275 GUID_string(tmp_ctx, &guid));
2277 DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2278 ldb_dn_get_linearized(new_dn)));
2279 talloc_free(tmp_ctx);
2280 return LDB_ERR_OPERATIONS_ERROR;
2284 now we need to modify the object in the following ways:
2286 - add isDeleted=TRUE
2287 - update rDN and name, with new rDN
2288 - remove linked attributes
2289 - remove objectCategory and sAMAccountType
2290 - remove attribs not on the preserved list
2291 - preserved if in above list, or is rDN
2292 - remove all linked attribs from this object
2293 - remove all links from other objects to this object
2294 - add lastKnownParent
2295 - update replPropertyMetaData?
2297 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2300 msg = ldb_msg_new(tmp_ctx);
2302 ldb_module_oom(module);
2303 talloc_free(tmp_ctx);
2304 return LDB_ERR_OPERATIONS_ERROR;
2309 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2310 if (ret != LDB_SUCCESS) {
2311 DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2312 ldb_module_oom(module);
2313 talloc_free(tmp_ctx);
2316 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2318 /* we also mark it as recycled, meaning this object can't be
2319 recovered (we are stripping its attributes) */
2320 if (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008_R2) {
2321 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
2322 if (ret != LDB_SUCCESS) {
2323 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
2324 ldb_module_oom(module);
2325 talloc_free(tmp_ctx);
2328 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2331 /* we need the storage form of the parent GUID */
2332 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2333 ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2334 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2335 DSDB_SEARCH_REVEAL_INTERNALS);
2336 if (ret != LDB_SUCCESS) {
2337 talloc_free(tmp_ctx);
2341 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2342 ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2343 if (ret != LDB_SUCCESS) {
2344 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2345 ldb_module_oom(module);
2346 talloc_free(tmp_ctx);
2349 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2351 /* work out which of the old attributes we will be removing */
2352 for (i=0; i<old_msg->num_elements; i++) {
2353 const struct dsdb_attribute *sa;
2354 el = &old_msg->elements[i];
2355 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2357 talloc_free(tmp_ctx);
2358 return LDB_ERR_OPERATIONS_ERROR;
2360 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2361 /* don't remove the rDN */
2365 if (sa->linkID && sa->linkID & 1) {
2366 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa);
2367 if (ret != LDB_SUCCESS) {
2368 talloc_free(tmp_ctx);
2369 return LDB_ERR_OPERATIONS_ERROR;
2374 if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2378 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2379 if (ret != LDB_SUCCESS) {
2380 talloc_free(tmp_ctx);
2381 ldb_module_oom(module);
2386 /* work out what the new rdn value is, for updating the
2387 rDN and name fields */
2388 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2389 ret = ldb_msg_add_value(msg, rdn_name, new_rdn_value, &el);
2390 if (ret != LDB_SUCCESS) {
2391 talloc_free(tmp_ctx);
2394 el->flags = LDB_FLAG_MOD_REPLACE;
2396 el = ldb_msg_find_element(old_msg, "name");
2398 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2399 if (ret != LDB_SUCCESS) {
2400 talloc_free(tmp_ctx);
2403 el->flags = LDB_FLAG_MOD_REPLACE;
2406 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE);
2407 if (ret != LDB_SUCCESS) {
2408 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
2409 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
2410 talloc_free(tmp_ctx);
2414 /* now rename onto the new DN */
2415 ret = dsdb_module_rename(module, old_dn, new_dn, 0);
2416 if (ret != LDB_SUCCESS){
2417 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
2418 ldb_dn_get_linearized(old_dn),
2419 ldb_dn_get_linearized(new_dn),
2420 ldb_errstring(ldb)));
2421 talloc_free(tmp_ctx);
2425 talloc_free(tmp_ctx);
2427 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
2432 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
2437 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
2439 int ret = LDB_ERR_OTHER;
2440 /* TODO: do some error mapping */
2444 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
2446 struct ldb_context *ldb;
2447 struct ldb_request *change_req;
2448 enum ndr_err_code ndr_err;
2449 struct ldb_message *msg;
2450 struct replPropertyMetaDataBlob *md;
2451 struct ldb_val md_value;
2456 * TODO: check if the parent object exist
2460 * TODO: handle the conflict case where an object with the
2464 ldb = ldb_module_get_ctx(ar->module);
2465 msg = ar->objs->objects[ar->index_current].msg;
2466 md = ar->objs->objects[ar->index_current].meta_data;
2468 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2469 if (ret != LDB_SUCCESS) {
2470 return replmd_replicated_request_error(ar, ret);
2473 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
2474 if (ret != LDB_SUCCESS) {
2475 return replmd_replicated_request_error(ar, ret);
2478 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2479 if (ret != LDB_SUCCESS) {
2480 return replmd_replicated_request_error(ar, ret);
2483 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
2484 if (ret != LDB_SUCCESS) {
2485 return replmd_replicated_request_error(ar, ret);
2488 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2489 if (ret != LDB_SUCCESS) {
2490 return replmd_replicated_request_error(ar, ret);
2493 /* remove any message elements that have zero values */
2494 for (i=0; i<msg->num_elements; i++) {
2495 struct ldb_message_element *el = &msg->elements[i];
2497 if (el->num_values == 0) {
2498 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
2500 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
2501 msg->num_elements--;
2508 * the meta data array is already sorted by the caller
2510 for (i=0; i < md->ctr.ctr1.count; i++) {
2511 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
2513 ndr_err = ndr_push_struct_blob(&md_value, msg,
2514 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2516 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2517 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2518 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2519 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2521 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
2522 if (ret != LDB_SUCCESS) {
2523 return replmd_replicated_request_error(ar, ret);
2526 replmd_ldb_message_sort(msg, ar->schema);
2529 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
2530 DEBUG(4, ("DRS replication add message:\n%s\n", s));
2534 ret = ldb_build_add_req(&change_req,
2542 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2544 return ldb_next_request(ar->module, change_req);
2548 return true if an update is newer than an existing entry
2549 see section 5.11 of MS-ADTS
2551 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
2552 const struct GUID *update_invocation_id,
2553 uint32_t current_version,
2554 uint32_t update_version,
2555 NTTIME current_change_time,
2556 NTTIME update_change_time)
2558 if (update_version != current_version) {
2559 return update_version > current_version;
2561 if (update_change_time > current_change_time) {
2564 if (update_change_time == current_change_time) {
2565 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
2570 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
2571 struct replPropertyMetaData1 *new_m)
2573 return replmd_update_is_newer(&cur_m->originating_invocation_id,
2574 &new_m->originating_invocation_id,
2577 cur_m->originating_change_time,
2578 new_m->originating_change_time);
2581 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
2583 struct ldb_context *ldb;
2584 struct ldb_request *change_req;
2585 enum ndr_err_code ndr_err;
2586 struct ldb_message *msg;
2587 struct replPropertyMetaDataBlob *rmd;
2588 struct replPropertyMetaDataBlob omd;
2589 const struct ldb_val *omd_value;
2590 struct replPropertyMetaDataBlob nmd;
2591 struct ldb_val nmd_value;
2593 uint32_t removed_attrs = 0;
2596 ldb = ldb_module_get_ctx(ar->module);
2597 msg = ar->objs->objects[ar->index_current].msg;
2598 rmd = ar->objs->objects[ar->index_current].meta_data;
2603 * TODO: check repl data is correct after a rename
2605 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
2606 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
2607 ldb_dn_get_linearized(ar->search_msg->dn),
2608 ldb_dn_get_linearized(msg->dn));
2609 if (dsdb_module_rename(ar->module,
2610 ar->search_msg->dn, msg->dn,
2611 DSDB_FLAG_OWN_MODULE) != LDB_SUCCESS) {
2612 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
2613 ldb_dn_get_linearized(ar->search_msg->dn),
2614 ldb_dn_get_linearized(msg->dn),
2615 ldb_errstring(ldb));
2616 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
2620 /* find existing meta data */
2621 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
2623 ndr_err = ndr_pull_struct_blob(omd_value, ar,
2624 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
2625 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
2626 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2627 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2628 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2631 if (omd.version != 1) {
2632 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2638 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
2639 nmd.ctr.ctr1.array = talloc_array(ar,
2640 struct replPropertyMetaData1,
2641 nmd.ctr.ctr1.count);
2642 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2644 /* first copy the old meta data */
2645 for (i=0; i < omd.ctr.ctr1.count; i++) {
2646 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
2650 /* now merge in the new meta data */
2651 for (i=0; i < rmd->ctr.ctr1.count; i++) {
2654 for (j=0; j < ni; j++) {
2657 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
2661 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
2662 &rmd->ctr.ctr1.array[i]);
2664 /* replace the entry */
2665 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
2670 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTRIBUTE_instanceType) {
2671 DEBUG(1,("Discarding older DRS attribute update to %s on %s from %s\n",
2672 msg->elements[i-removed_attrs].name,
2673 ldb_dn_get_linearized(msg->dn),
2674 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
2677 /* we don't want to apply this change so remove the attribute */
2678 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
2685 if (found) continue;
2687 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
2692 * finally correct the size of the meta_data array
2694 nmd.ctr.ctr1.count = ni;
2697 * the rdn attribute (the alias for the name attribute),
2698 * 'cn' for most objects is the last entry in the meta data array
2701 * sort the new meta data array
2703 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
2704 if (ret != LDB_SUCCESS) {
2709 * check if some replicated attributes left, otherwise skip the ldb_modify() call
2711 if (msg->num_elements == 0) {
2712 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
2715 ar->index_current++;
2716 return replmd_replicated_apply_next(ar);
2719 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
2720 ar->index_current, msg->num_elements);
2722 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2723 if (ret != LDB_SUCCESS) {
2724 return replmd_replicated_request_error(ar, ret);
2727 for (i=0; i<ni; i++) {
2728 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
2731 /* create the meta data value */
2732 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
2733 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2735 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2736 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2737 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2738 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2742 * when we know that we'll modify the record, add the whenChanged, uSNChanged
2743 * and replPopertyMetaData attributes
2745 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2746 if (ret != LDB_SUCCESS) {
2747 return replmd_replicated_request_error(ar, ret);
2749 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2750 if (ret != LDB_SUCCESS) {
2751 return replmd_replicated_request_error(ar, ret);
2753 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
2754 if (ret != LDB_SUCCESS) {
2755 return replmd_replicated_request_error(ar, ret);
2758 replmd_ldb_message_sort(msg, ar->schema);
2760 /* we want to replace the old values */
2761 for (i=0; i < msg->num_elements; i++) {
2762 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2766 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
2767 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
2771 ret = ldb_build_mod_req(&change_req,
2779 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2781 return ldb_next_request(ar->module, change_req);
2784 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
2785 struct ldb_reply *ares)
2787 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2788 struct replmd_replicated_request);
2792 return ldb_module_done(ar->req, NULL, NULL,
2793 LDB_ERR_OPERATIONS_ERROR);
2795 if (ares->error != LDB_SUCCESS &&
2796 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
2797 return ldb_module_done(ar->req, ares->controls,
2798 ares->response, ares->error);
2801 switch (ares->type) {
2802 case LDB_REPLY_ENTRY:
2803 ar->search_msg = talloc_steal(ar, ares->message);
2806 case LDB_REPLY_REFERRAL:
2807 /* we ignore referrals */
2810 case LDB_REPLY_DONE:
2811 if (ar->search_msg != NULL) {
2812 ret = replmd_replicated_apply_merge(ar);
2814 ret = replmd_replicated_apply_add(ar);
2816 if (ret != LDB_SUCCESS) {
2817 return ldb_module_done(ar->req, NULL, NULL, ret);
2825 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
2827 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
2829 struct ldb_context *ldb;
2833 struct ldb_request *search_req;
2834 struct ldb_search_options_control *options;
2836 if (ar->index_current >= ar->objs->num_objects) {
2837 /* done with it, go to next stage */
2838 return replmd_replicated_uptodate_vector(ar);
2841 ldb = ldb_module_get_ctx(ar->module);
2842 ar->search_msg = NULL;
2844 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
2845 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2847 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
2848 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2849 talloc_free(tmp_str);
2851 ret = ldb_build_search_req(&search_req,
2860 replmd_replicated_apply_search_callback,
2863 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2864 if (ret != LDB_SUCCESS) {
2868 /* we need to cope with cross-partition links, so search for
2869 the GUID over all partitions */
2870 options = talloc(search_req, struct ldb_search_options_control);
2871 if (options == NULL) {
2872 DEBUG(0, (__location__ ": out of memory\n"));
2873 return LDB_ERR_OPERATIONS_ERROR;
2875 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2877 ret = ldb_request_add_control(search_req,
2878 LDB_CONTROL_SEARCH_OPTIONS_OID,
2880 if (ret != LDB_SUCCESS) {
2884 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2886 return ldb_next_request(ar->module, search_req);
2889 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
2890 struct ldb_reply *ares)
2892 struct ldb_context *ldb;
2893 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2894 struct replmd_replicated_request);
2895 ldb = ldb_module_get_ctx(ar->module);
2898 return ldb_module_done(ar->req, NULL, NULL,
2899 LDB_ERR_OPERATIONS_ERROR);
2901 if (ares->error != LDB_SUCCESS) {
2902 return ldb_module_done(ar->req, ares->controls,
2903 ares->response, ares->error);
2906 if (ares->type != LDB_REPLY_DONE) {
2907 ldb_set_errstring(ldb, "Invalid reply type\n!");
2908 return ldb_module_done(ar->req, NULL, NULL,
2909 LDB_ERR_OPERATIONS_ERROR);
2914 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
2917 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
2919 struct ldb_context *ldb;
2920 struct ldb_request *change_req;
2921 enum ndr_err_code ndr_err;
2922 struct ldb_message *msg;
2923 struct replUpToDateVectorBlob ouv;
2924 const struct ldb_val *ouv_value;
2925 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
2926 struct replUpToDateVectorBlob nuv;
2927 struct ldb_val nuv_value;
2928 struct ldb_message_element *nuv_el = NULL;
2929 const struct GUID *our_invocation_id;
2930 struct ldb_message_element *orf_el = NULL;
2931 struct repsFromToBlob nrf;
2932 struct ldb_val *nrf_value = NULL;
2933 struct ldb_message_element *nrf_el = NULL;
2936 time_t t = time(NULL);
2940 ldb = ldb_module_get_ctx(ar->module);
2941 ruv = ar->objs->uptodateness_vector;
2947 unix_to_nt_time(&now, t);
2950 * first create the new replUpToDateVector
2952 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
2954 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
2955 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
2956 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
2957 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2958 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2959 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2962 if (ouv.version != 2) {
2963 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2968 * the new uptodateness vector will at least
2969 * contain 1 entry, one for the source_dsa
2971 * plus optional values from our old vector and the one from the source_dsa
2973 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
2974 if (ruv) nuv.ctr.ctr2.count += ruv->count;
2975 nuv.ctr.ctr2.cursors = talloc_array(ar,
2976 struct drsuapi_DsReplicaCursor2,
2977 nuv.ctr.ctr2.count);
2978 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2980 /* first copy the old vector */
2981 for (i=0; i < ouv.ctr.ctr2.count; i++) {
2982 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
2986 /* get our invocation_id if we have one already attached to the ldb */
2987 our_invocation_id = samdb_ntds_invocation_id(ldb);
2989 /* merge in the source_dsa vector is available */
2990 for (i=0; (ruv && i < ruv->count); i++) {
2993 if (our_invocation_id &&
2994 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
2995 our_invocation_id)) {
2999 for (j=0; j < ni; j++) {
3000 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3001 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3008 * we update only the highest_usn and not the latest_sync_success time,
3009 * because the last success stands for direct replication
3011 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
3012 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
3017 if (found) continue;
3019 /* if it's not there yet, add it */
3020 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
3025 * merge in the current highwatermark for the source_dsa
3028 for (j=0; j < ni; j++) {
3029 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
3030 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3037 * here we update the highest_usn and last_sync_success time
3038 * because we're directly replicating from the source_dsa
3040 * and use the tmp_highest_usn because this is what we have just applied
3043 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3044 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
3049 * here we update the highest_usn and last_sync_success time
3050 * because we're directly replicating from the source_dsa
3052 * and use the tmp_highest_usn because this is what we have just applied
3055 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
3056 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3057 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
3062 * finally correct the size of the cursors array
3064 nuv.ctr.ctr2.count = ni;
3069 qsort(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count,
3070 sizeof(struct drsuapi_DsReplicaCursor2),
3071 (comparison_fn_t)drsuapi_DsReplicaCursor2_compare);
3074 * create the change ldb_message
3076 msg = ldb_msg_new(ar);
3077 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3078 msg->dn = ar->search_msg->dn;
3080 ndr_err = ndr_push_struct_blob(&nuv_value, msg,
3081 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3083 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
3084 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3085 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3086 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3088 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
3089 if (ret != LDB_SUCCESS) {
3090 return replmd_replicated_request_error(ar, ret);
3092 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
3095 * now create the new repsFrom value from the given repsFromTo1 structure
3099 nrf.ctr.ctr1 = *ar->objs->source_dsa;
3100 /* and fix some values... */
3101 nrf.ctr.ctr1.consecutive_sync_failures = 0;
3102 nrf.ctr.ctr1.last_success = now;
3103 nrf.ctr.ctr1.last_attempt = now;
3104 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
3105 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
3108 * first see if we already have a repsFrom value for the current source dsa
3109 * if so we'll later replace this value
3111 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
3113 for (i=0; i < orf_el->num_values; i++) {
3114 struct repsFromToBlob *trf;
3116 trf = talloc(ar, struct repsFromToBlob);
3117 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3119 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
3120 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3121 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3122 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3123 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3126 if (trf->version != 1) {
3127 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3131 * we compare the source dsa objectGUID not the invocation_id
3132 * because we want only one repsFrom value per source dsa
3133 * and when the invocation_id of the source dsa has changed we don't need
3134 * the old repsFrom with the old invocation_id
3136 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
3137 &ar->objs->source_dsa->source_dsa_obj_guid)) {
3143 nrf_value = &orf_el->values[i];
3148 * copy over all old values to the new ldb_message
3150 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
3151 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3156 * if we haven't found an old repsFrom value for the current source dsa
3157 * we'll add a new value
3160 struct ldb_val zero_value;
3161 ZERO_STRUCT(zero_value);
3162 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
3163 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3165 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
3168 /* we now fill the value which is already attached to ldb_message */
3169 ndr_err = ndr_push_struct_blob(nrf_value, msg,
3170 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3172 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3173 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3174 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3175 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3179 * the ldb_message_element for the attribute, has all the old values and the new one
3180 * so we'll replace the whole attribute with all values
3182 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
3185 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3186 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
3190 /* prepare the ldb_modify() request */
3191 ret = ldb_build_mod_req(&change_req,
3197 replmd_replicated_uptodate_modify_callback,
3199 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3201 return ldb_next_request(ar->module, change_req);
3204 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
3205 struct ldb_reply *ares)
3207 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3208 struct replmd_replicated_request);
3212 return ldb_module_done(ar->req, NULL, NULL,
3213 LDB_ERR_OPERATIONS_ERROR);
3215 if (ares->error != LDB_SUCCESS &&
3216 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3217 return ldb_module_done(ar->req, ares->controls,
3218 ares->response, ares->error);
3221 switch (ares->type) {
3222 case LDB_REPLY_ENTRY:
3223 ar->search_msg = talloc_steal(ar, ares->message);
3226 case LDB_REPLY_REFERRAL:
3227 /* we ignore referrals */
3230 case LDB_REPLY_DONE:
3231 if (ar->search_msg == NULL) {
3232 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3234 ret = replmd_replicated_uptodate_modify(ar);
3236 if (ret != LDB_SUCCESS) {
3237 return ldb_module_done(ar->req, NULL, NULL, ret);
3246 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
3248 struct ldb_context *ldb;
3250 static const char *attrs[] = {
3251 "replUpToDateVector",
3255 struct ldb_request *search_req;
3257 ldb = ldb_module_get_ctx(ar->module);
3258 ar->search_msg = NULL;
3260 ret = ldb_build_search_req(&search_req,
3263 ar->objs->partition_dn,
3269 replmd_replicated_uptodate_search_callback,
3271 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3273 return ldb_next_request(ar->module, search_req);
3278 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
3280 struct ldb_context *ldb;
3281 struct dsdb_extended_replicated_objects *objs;
3282 struct replmd_replicated_request *ar;
3283 struct ldb_control **ctrls;
3285 struct replmd_private *replmd_private =
3286 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3288 ldb = ldb_module_get_ctx(module);
3290 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
3292 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
3294 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
3295 return LDB_ERR_PROTOCOL_ERROR;
3298 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
3299 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
3300 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
3301 return LDB_ERR_PROTOCOL_ERROR;
3304 ar = replmd_ctx_init(module, req);
3306 return LDB_ERR_OPERATIONS_ERROR;
3308 /* Set the flags to have the replmd_op_callback run over the full set of objects */
3309 ar->apply_mode = true;
3311 ar->schema = dsdb_get_schema(ldb);
3313 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
3315 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3316 return LDB_ERR_CONSTRAINT_VIOLATION;
3319 ctrls = req->controls;
3321 if (req->controls) {
3322 req->controls = talloc_memdup(ar, req->controls,
3323 talloc_get_size(req->controls));
3324 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3327 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
3328 if (ret != LDB_SUCCESS) {
3332 ar->controls = req->controls;
3333 req->controls = ctrls;
3335 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
3337 /* save away the linked attributes for the end of the
3339 for (i=0; i<ar->objs->linked_attributes_count; i++) {
3340 struct la_entry *la_entry;
3342 if (replmd_private->la_ctx == NULL) {
3343 replmd_private->la_ctx = talloc_new(replmd_private);
3345 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
3346 if (la_entry == NULL) {
3348 return LDB_ERR_OPERATIONS_ERROR;
3350 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
3351 if (la_entry->la == NULL) {
3352 talloc_free(la_entry);
3354 return LDB_ERR_OPERATIONS_ERROR;
3356 *la_entry->la = ar->objs->linked_attributes[i];
3358 /* we need to steal the non-scalars so they stay
3359 around until the end of the transaction */
3360 talloc_steal(la_entry->la, la_entry->la->identifier);
3361 talloc_steal(la_entry->la, la_entry->la->value.blob);
3363 DLIST_ADD(replmd_private->la_list, la_entry);
3366 return replmd_replicated_apply_next(ar);
3370 process one linked attribute structure
3372 static int replmd_process_linked_attribute(struct ldb_module *module,
3373 struct la_entry *la_entry)
3375 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
3376 struct ldb_context *ldb = ldb_module_get_ctx(module);
3377 struct dsdb_schema *schema = dsdb_get_schema(ldb);
3378 struct ldb_message *msg;
3379 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
3381 const struct dsdb_attribute *attr;
3382 struct dsdb_dn *dsdb_dn;
3383 uint64_t seq_num = 0;
3384 struct ldb_message_element *old_el;
3386 time_t t = time(NULL);
3387 struct ldb_result *res;
3388 const char *attrs[2];
3389 struct parsed_dn *pdn_list, *pdn;
3390 struct GUID guid = GUID_zero();
3392 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
3393 const struct GUID *our_invocation_id;
3396 linked_attributes[0]:
3397 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
3399 identifier: struct drsuapi_DsReplicaObjectIdentifier
3400 __ndr_size : 0x0000003a (58)
3401 __ndr_size_sid : 0x00000000 (0)
3402 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
3404 __ndr_size_dn : 0x00000000 (0)
3406 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
3407 value: struct drsuapi_DsAttributeValue
3408 __ndr_size : 0x0000007e (126)
3410 blob : DATA_BLOB length=126
3411 flags : 0x00000001 (1)
3412 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
3413 originating_add_time : Wed Sep 2 22:20:01 2009 EST
3414 meta_data: struct drsuapi_DsReplicaMetaData
3415 version : 0x00000015 (21)
3416 originating_change_time : Wed Sep 2 23:39:07 2009 EST
3417 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
3418 originating_usn : 0x000000000001e19c (123292)
3420 (for cases where the link is to a normal DN)
3421 &target: struct drsuapi_DsReplicaObjectIdentifier3
3422 __ndr_size : 0x0000007e (126)
3423 __ndr_size_sid : 0x0000001c (28)
3424 guid : 7639e594-db75-4086-b0d4-67890ae46031
3425 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
3426 __ndr_size_dn : 0x00000022 (34)
3427 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
3430 /* find the attribute being modified */
3431 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
3433 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
3434 talloc_free(tmp_ctx);
3435 return LDB_ERR_OPERATIONS_ERROR;
3438 attrs[0] = attr->lDAPDisplayName;
3441 /* get the existing message from the db for the object with
3442 this GUID, returning attribute being modified. We will then
3443 use this msg as the basis for a modify call */
3444 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3445 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3446 DSDB_SEARCH_SHOW_DELETED |
3447 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3448 DSDB_SEARCH_REVEAL_INTERNALS,
3449 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
3450 if (ret != LDB_SUCCESS) {
3451 talloc_free(tmp_ctx);
3454 if (res->count != 1) {
3455 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
3456 GUID_string(tmp_ctx, &la->identifier->guid));
3457 talloc_free(tmp_ctx);
3458 return LDB_ERR_NO_SUCH_OBJECT;
3462 if (msg->num_elements == 0) {
3463 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
3464 if (ret != LDB_SUCCESS) {
3465 ldb_module_oom(module);
3466 talloc_free(tmp_ctx);
3467 return LDB_ERR_OPERATIONS_ERROR;
3470 old_el = &msg->elements[0];
3471 old_el->flags = LDB_FLAG_MOD_REPLACE;
3474 /* parse the existing links */
3475 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid);
3476 if (ret != LDB_SUCCESS) {
3477 talloc_free(tmp_ctx);
3481 /* get our invocationId */
3482 our_invocation_id = samdb_ntds_invocation_id(ldb);
3483 if (!our_invocation_id) {
3484 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
3485 talloc_free(tmp_ctx);
3486 return LDB_ERR_OPERATIONS_ERROR;
3489 ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, our_invocation_id);
3490 if (ret != LDB_SUCCESS) {
3491 talloc_free(tmp_ctx);
3495 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
3496 if (!W_ERROR_IS_OK(status)) {
3497 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
3498 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
3499 return LDB_ERR_OPERATIONS_ERROR;
3502 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
3503 if (!NT_STATUS_IS_OK(ntstatus) && active) {
3504 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
3506 ldb_dn_get_linearized(dsdb_dn->dn),
3507 ldb_dn_get_linearized(msg->dn));
3508 return LDB_ERR_OPERATIONS_ERROR;
3511 /* re-resolve the DN by GUID, as the DRS server may give us an
3513 ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn);
3514 if (ret != LDB_SUCCESS) {
3515 ldb_asprintf_errstring(ldb, __location__ ": Failed to re-resolve GUID %s",
3516 GUID_string(tmp_ctx, &guid));
3517 talloc_free(tmp_ctx);
3521 /* see if this link already exists */
3522 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
3524 /* see if this update is newer than what we have already */
3525 struct GUID invocation_id = GUID_zero();
3526 uint32_t version = 0;
3527 NTTIME change_time = 0;
3528 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
3530 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
3531 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
3532 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
3534 if (!replmd_update_is_newer(&invocation_id,
3535 &la->meta_data.originating_invocation_id,
3537 la->meta_data.version,
3539 la->meta_data.originating_change_time)) {
3540 DEBUG(1,("Discarding older DRS linked attribute update to %s on %s from %s\n",
3541 old_el->name, ldb_dn_get_linearized(msg->dn),
3542 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
3543 talloc_free(tmp_ctx);
3547 /* get a seq_num for this change */
3548 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3549 if (ret != LDB_SUCCESS) {
3550 talloc_free(tmp_ctx);
3554 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
3555 /* remove the existing backlink */
3556 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
3557 if (ret != LDB_SUCCESS) {
3558 talloc_free(tmp_ctx);
3563 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
3564 &la->meta_data.originating_invocation_id,
3565 la->meta_data.originating_usn, seq_num,
3566 la->meta_data.originating_change_time,
3567 la->meta_data.version,
3569 if (ret != LDB_SUCCESS) {
3570 talloc_free(tmp_ctx);
3575 /* add the new backlink */
3576 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
3577 if (ret != LDB_SUCCESS) {
3578 talloc_free(tmp_ctx);
3583 /* get a seq_num for this change */
3584 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3585 if (ret != LDB_SUCCESS) {
3586 talloc_free(tmp_ctx);
3590 old_el->values = talloc_realloc(msg->elements, old_el->values,
3591 struct ldb_val, old_el->num_values+1);
3592 if (!old_el->values) {
3593 ldb_module_oom(module);
3594 return LDB_ERR_OPERATIONS_ERROR;
3596 old_el->num_values++;
3598 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
3599 &la->meta_data.originating_invocation_id,
3600 la->meta_data.originating_usn, seq_num,
3601 la->meta_data.originating_change_time,
3602 la->meta_data.version,
3603 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
3604 if (ret != LDB_SUCCESS) {
3605 talloc_free(tmp_ctx);
3610 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
3612 if (ret != LDB_SUCCESS) {
3613 talloc_free(tmp_ctx);
3619 /* we only change whenChanged and uSNChanged if the seq_num
3621 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
3622 talloc_free(tmp_ctx);
3623 return LDB_ERR_OPERATIONS_ERROR;
3626 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
3627 talloc_free(tmp_ctx);
3628 return LDB_ERR_OPERATIONS_ERROR;
3631 ret = dsdb_check_single_valued_link(attr, old_el);
3632 if (ret != LDB_SUCCESS) {
3633 talloc_free(tmp_ctx);
3637 ret = dsdb_module_modify(module, msg, DSDB_MODIFY_RELAX);
3638 if (ret != LDB_SUCCESS) {
3639 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
3641 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
3642 talloc_free(tmp_ctx);
3646 talloc_free(tmp_ctx);
3651 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
3653 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
3654 return replmd_extended_replicated_objects(module, req);
3657 return ldb_next_request(module, req);
3662 we hook into the transaction operations to allow us to
3663 perform the linked attribute updates at the end of the whole
3664 transaction. This allows a forward linked attribute to be created
3665 before the object is created. During a vampire, w2k8 sends us linked
3666 attributes before the objects they are part of.
3668 static int replmd_start_transaction(struct ldb_module *module)
3670 /* create our private structure for this transaction */
3671 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
3672 struct replmd_private);
3673 replmd_txn_cleanup(replmd_private);
3675 /* free any leftover mod_usn records from cancelled
3677 while (replmd_private->ncs) {
3678 struct nc_entry *e = replmd_private->ncs;
3679 DLIST_REMOVE(replmd_private->ncs, e);
3683 return ldb_next_start_trans(module);
3687 on prepare commit we loop over our queued la_context structures and
3690 static int replmd_prepare_commit(struct ldb_module *module)
3692 struct replmd_private *replmd_private =
3693 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3694 struct la_entry *la, *prev;
3695 struct la_backlink *bl;
3698 /* walk the list backwards, to do the first entry first, as we
3699 * added the entries with DLIST_ADD() which puts them at the
3700 * start of the list */
3701 for (la = replmd_private->la_list; la && la->next; la=la->next) ;
3703 for (; la; la=prev) {
3705 DLIST_REMOVE(replmd_private->la_list, la);
3706 ret = replmd_process_linked_attribute(module, la);
3707 if (ret != LDB_SUCCESS) {
3708 replmd_txn_cleanup(replmd_private);
3713 /* process our backlink list, creating and deleting backlinks
3715 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
3716 ret = replmd_process_backlink(module, bl);
3717 if (ret != LDB_SUCCESS) {
3718 replmd_txn_cleanup(replmd_private);
3723 replmd_txn_cleanup(replmd_private);
3725 /* possibly change @REPLCHANGED */
3726 ret = replmd_notify_store(module);
3727 if (ret != LDB_SUCCESS) {
3731 return ldb_next_prepare_commit(module);
3734 static int replmd_del_transaction(struct ldb_module *module)
3736 struct replmd_private *replmd_private =
3737 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3738 replmd_txn_cleanup(replmd_private);
3740 return ldb_next_del_trans(module);
3744 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
3745 .name = "repl_meta_data",
3746 .init_context = replmd_init,
3748 .modify = replmd_modify,
3749 .rename = replmd_rename,
3750 .del = replmd_delete,
3751 .extended = replmd_extended,
3752 .start_transaction = replmd_start_transaction,
3753 .prepare_commit = replmd_prepare_commit,
3754 .del_transaction = replmd_del_transaction,