2 Unix SMB/CIFS mplementation.
3 Helper functions for applying replicated objects
5 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "dsdb/samdb/samdb.h"
24 #include <ldb_errors.h>
25 #include "../lib/util/dlinklist.h"
26 #include "librpc/gen_ndr/ndr_misc.h"
27 #include "librpc/gen_ndr/ndr_drsuapi.h"
28 #include "librpc/gen_ndr/ndr_drsblobs.h"
29 #include "../lib/crypto/crypto.h"
30 #include "../libcli/drsuapi/drsuapi.h"
31 #include "libcli/auth/libcli_auth.h"
32 #include "param/param.h"
34 static WERROR dsdb_repl_merge_working_schema(struct ldb_context *ldb,
35 struct dsdb_schema *dest_schema,
36 const struct dsdb_schema *ref_schema)
38 const struct dsdb_class *cur_class = NULL;
39 const struct dsdb_attribute *cur_attr = NULL;
42 for (cur_class = ref_schema->classes;
44 cur_class = cur_class->next)
46 const struct dsdb_class *tmp1;
47 struct dsdb_class *tmp2;
49 tmp1 = dsdb_class_by_governsID_id(dest_schema,
50 cur_class->governsID_id);
56 * Do a shallow copy so that original next and prev are
57 * not modified, we don't need to do a deep copy
58 * as the rest won't be modified and this is for
59 * a short lived object.
61 tmp2 = talloc(dest_schema, struct dsdb_class);
66 DLIST_ADD(dest_schema->classes, tmp2);
69 for (cur_attr = ref_schema->attributes;
71 cur_attr = cur_attr->next)
73 const struct dsdb_attribute *tmp1;
74 struct dsdb_attribute *tmp2;
76 tmp1 = dsdb_attribute_by_attributeID_id(dest_schema,
77 cur_attr->attributeID_id);
83 * Do a shallow copy so that original next and prev are
84 * not modified, we don't need to do a deep copy
85 * as the rest won't be modified and this is for
86 * a short lived object.
88 tmp2 = talloc(dest_schema, struct dsdb_attribute);
93 DLIST_ADD(dest_schema->attributes, tmp2);
96 ret = dsdb_setup_sorted_accessors(ldb, dest_schema);
97 if (LDB_SUCCESS != ret) {
98 DEBUG(0,("Failed to add new attribute to reference schema!\n"));
99 return WERR_INTERNAL_ERROR;
105 WERROR dsdb_repl_resolve_working_schema(struct ldb_context *ldb,
107 struct dsdb_schema_prefixmap *pfm_remote,
108 uint32_t cycle_before_switching,
109 struct dsdb_schema *initial_schema,
110 struct dsdb_schema *resulting_schema,
111 uint32_t object_count,
112 const struct drsuapi_DsReplicaObjectListItemEx *first_object)
115 struct schema_list *next, *prev;
116 const struct drsuapi_DsReplicaObjectListItemEx *obj;
118 struct schema_list *schema_list = NULL, *schema_list_item, *schema_list_next_item;
120 struct dsdb_schema *working_schema;
121 const struct drsuapi_DsReplicaObjectListItemEx *cur;
122 DATA_BLOB empty_key = data_blob_null;
124 uint32_t ignore_attids[] = {
125 DRSUAPI_ATTID_auxiliaryClass,
126 DRSUAPI_ATTID_mayContain,
127 DRSUAPI_ATTID_mustContain,
128 DRSUAPI_ATTID_possSuperiors,
129 DRSUAPI_ATTID_systemPossSuperiors,
130 DRSUAPI_ATTID_INVALID
133 /* create a list of objects yet to be converted */
134 for (cur = first_object; cur; cur = cur->next_object) {
135 schema_list_item = talloc(mem_ctx, struct schema_list);
136 if (schema_list_item == NULL) {
140 schema_list_item->obj = cur;
141 DLIST_ADD_END(schema_list, schema_list_item);
144 /* resolve objects until all are resolved and in local schema */
146 working_schema = initial_schema;
148 while (schema_list) {
149 uint32_t converted_obj_count = 0;
150 uint32_t failed_obj_count = 0;
152 if (resulting_schema != working_schema) {
154 * If the selfmade schema is not the schema used to
155 * translate and validate replicated object,
156 * Which means that we are using the bootstrap schema
157 * Then we add attributes and classes that were already
158 * translated to the working schema, the idea is that
159 * we might need to add new attributes and classes
160 * to be able to translate critical replicated objects
161 * and without that we wouldn't be able to translate them
163 werr = dsdb_repl_merge_working_schema(ldb,
166 if (!W_ERROR_IS_OK(werr)) {
171 for (schema_list_item = schema_list;
173 schema_list_item=schema_list_next_item) {
174 struct dsdb_extended_replicated_object object;
176 cur = schema_list_item->obj;
179 * Save the next item, now we have saved out
180 * the current one, so we can DLIST_REMOVE it
183 schema_list_next_item = schema_list_item->next;
186 * Convert the objects into LDB messages using the
187 * schema we have so far. It's ok if we fail to convert
188 * an object. We should convert more objects on next pass.
190 werr = dsdb_convert_object_ex(ldb, working_schema,
196 schema_list_item, &object);
197 if (!W_ERROR_IS_OK(werr)) {
198 DEBUG(4,("debug: Failed to convert schema "
199 "object %s into ldb msg, "
200 "will try during next loop\n",
201 cur->object.identifier->dn));
206 * Convert the schema from ldb_message format
207 * (OIDs as OID strings) into schema, using
208 * the remote prefixMap
210 * It's not likely, but possible to get the
211 * same object twice and we should keep
214 werr = dsdb_schema_set_el_from_ldb_msg_dups(ldb,
218 if (!W_ERROR_IS_OK(werr)) {
219 DEBUG(4,("debug: failed to convert "
220 "object %s into a schema element, "
221 "will try during next loop: %s\n",
222 ldb_dn_get_linearized(object.msg->dn),
226 DEBUG(8,("Converted object %s into a schema element\n",
227 ldb_dn_get_linearized(object.msg->dn)));
228 DLIST_REMOVE(schema_list, schema_list_item);
229 TALLOC_FREE(schema_list_item);
230 converted_obj_count++;
235 DEBUG(4,("Schema load pass %d: converted %d, %d of %d objects left to be converted.\n",
236 pass_no, converted_obj_count, failed_obj_count, object_count));
238 /* check if we converted any objects in this pass */
239 if (converted_obj_count == 0) {
240 DEBUG(0,("Can't continue Schema load: "
241 "didn't manage to convert any objects: "
242 "all %d remaining of %d objects "
243 "failed to convert\n",
244 failed_obj_count, object_count));
245 return WERR_INTERNAL_ERROR;
249 * Don't try to load the schema if there is missing object
250 * _and_ we are on the first pass as some critical objects
253 if (failed_obj_count == 0 || pass_no > cycle_before_switching) {
254 /* prepare for another cycle */
255 working_schema = resulting_schema;
257 ret = dsdb_setup_sorted_accessors(ldb, working_schema);
258 if (LDB_SUCCESS != ret) {
259 DEBUG(0,("Failed to create schema-cache indexes!\n"));
260 return WERR_INTERNAL_ERROR;
270 * Multi-pass working schema creation
272 * - shallow copy initial schema supplied
273 * - create a working schema in multiple passes
274 * until all objects are resolved
275 * Working schema is a schema with Attributes, Classes
276 * and indexes, but w/o subClassOf, possibleSupperiors etc.
277 * It is to be used just us cache for converting attribute values.
279 WERROR dsdb_repl_make_working_schema(struct ldb_context *ldb,
280 const struct dsdb_schema *initial_schema,
281 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr,
282 uint32_t object_count,
283 const struct drsuapi_DsReplicaObjectListItemEx *first_object,
284 const DATA_BLOB *gensec_skey,
286 struct dsdb_schema **_schema_out)
289 struct dsdb_schema_prefixmap *pfm_remote;
290 struct dsdb_schema *working_schema;
292 /* make a copy of the iniatial_scheam so we don't mess with it */
293 working_schema = dsdb_schema_copy_shallow(mem_ctx, ldb, initial_schema);
294 if (!working_schema) {
295 DEBUG(0,(__location__ ": schema copy failed!\n"));
299 /* we are going to need remote prefixMap for decoding */
300 werr = dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr, true,
301 mem_ctx, &pfm_remote, NULL);
302 if (!W_ERROR_IS_OK(werr)) {
303 DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s",
308 werr = dsdb_repl_resolve_working_schema(ldb, mem_ctx,
310 0, /* cycle_before_switching */
315 if (!W_ERROR_IS_OK(werr)) {
316 DEBUG(0, ("%s: dsdb_repl_resolve_working_schema() failed: %s",
317 __location__, win_errstr(werr)));
321 *_schema_out = working_schema;
326 static bool dsdb_attid_in_list(const uint32_t attid_list[], uint32_t attid)
332 for (cur = attid_list; *cur != DRSUAPI_ATTID_INVALID; cur++) {
340 WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
341 const struct dsdb_schema *schema,
342 struct ldb_dn *partition_dn,
343 const struct dsdb_schema_prefixmap *pfm_remote,
344 const struct drsuapi_DsReplicaObjectListItemEx *in,
345 const DATA_BLOB *gensec_skey,
346 const uint32_t *ignore_attids,
347 uint32_t dsdb_repl_flags,
349 struct dsdb_extended_replicated_object *out)
351 WERROR status = WERR_OK;
353 struct ldb_message *msg;
354 struct replPropertyMetaDataBlob *md;
356 struct ldb_message_element *instanceType_e = NULL;
357 NTTIME whenChanged = 0;
358 time_t whenChanged_t;
359 const char *whenChanged_s;
360 struct dom_sid *sid = NULL;
364 if (!in->object.identifier) {
368 if (!in->object.identifier->dn || !in->object.identifier->dn[0]) {
372 if (in->object.attribute_ctr.num_attributes != 0 && !in->meta_data_ctr) {
376 if (in->object.attribute_ctr.num_attributes != in->meta_data_ctr->count) {
380 sid = &in->object.identifier->sid;
381 if (sid->num_auths > 0) {
382 rid = sid->sub_auths[sid->num_auths - 1];
385 msg = ldb_msg_new(mem_ctx);
386 W_ERROR_HAVE_NO_MEMORY(msg);
388 msg->dn = ldb_dn_new(msg, ldb, in->object.identifier->dn);
389 W_ERROR_HAVE_NO_MEMORY(msg->dn);
391 msg->num_elements = in->object.attribute_ctr.num_attributes;
392 msg->elements = talloc_array(msg, struct ldb_message_element,
394 W_ERROR_HAVE_NO_MEMORY(msg->elements);
396 md = talloc(mem_ctx, struct replPropertyMetaDataBlob);
397 W_ERROR_HAVE_NO_MEMORY(md);
401 md->ctr.ctr1.count = in->meta_data_ctr->count;
402 md->ctr.ctr1.reserved = 0;
403 md->ctr.ctr1.array = talloc_array(mem_ctx,
404 struct replPropertyMetaData1,
406 W_ERROR_HAVE_NO_MEMORY(md->ctr.ctr1.array);
408 for (i=0, attr_count=0; i < in->meta_data_ctr->count; i++, attr_count++) {
409 struct drsuapi_DsReplicaAttribute *a;
410 struct drsuapi_DsReplicaMetaData *d;
411 struct replPropertyMetaData1 *m;
412 struct ldb_message_element *e;
415 a = &in->object.attribute_ctr.attributes[i];
416 d = &in->meta_data_ctr->meta_data[i];
417 m = &md->ctr.ctr1.array[attr_count];
418 e = &msg->elements[attr_count];
420 if (dsdb_attid_in_list(ignore_attids, a->attid)) {
425 if (GUID_all_zero(&d->originating_invocation_id)) {
426 status = WERR_DS_SRC_GUID_MISMATCH;
427 DEBUG(0, ("Refusing replication of object containing invalid zero invocationID on attribute %d of %s: %s\n",
429 ldb_dn_get_linearized(msg->dn),
430 win_errstr(status)));
434 if (a->attid == DRSUAPI_ATTID_instanceType) {
435 if (instanceType_e != NULL) {
441 for (j=0; j<a->value_ctr.num_values; j++) {
442 status = drsuapi_decrypt_attribute(a->value_ctr.values[j].blob,
445 if (!W_ERROR_IS_OK(status)) {
449 if (W_ERROR_EQUAL(status, WERR_TOO_MANY_SECRETS)) {
450 WERROR get_name_status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, pfm_remote,
451 a, msg->elements, e, NULL);
452 if (W_ERROR_IS_OK(get_name_status)) {
453 DEBUG(0, ("Unxpectedly got secret value %s on %s from DRS server\n",
454 e->name, ldb_dn_get_linearized(msg->dn)));
456 DEBUG(0, ("Unxpectedly got secret value on %s from DRS server",
457 ldb_dn_get_linearized(msg->dn)));
459 } else if (!W_ERROR_IS_OK(status)) {
464 * This function also fills in the local attid value,
465 * based on comparing the remote and local prefixMap
466 * tables. If we don't convert the value, then we can
467 * have invalid values in the replPropertyMetaData we
468 * store on disk, as the prefixMap is per host, not
469 * per-domain. This may be why Microsoft added the
470 * msDS-IntID feature, however this is not used for
471 * extra attributes in the schema partition itself.
473 status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, pfm_remote,
476 W_ERROR_NOT_OK_RETURN(status);
478 m->version = d->version;
479 m->originating_change_time = d->originating_change_time;
480 m->originating_invocation_id = d->originating_invocation_id;
481 m->originating_usn = d->originating_usn;
484 if (a->attid == DRSUAPI_ATTID_name) {
485 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
486 if (rdn_val == NULL) {
487 DEBUG(0, ("Unxpectedly unable to get RDN from %s for validation",
488 ldb_dn_get_linearized(msg->dn)));
491 if (e->num_values != 1) {
492 DEBUG(0, ("Unxpectedly got wrong number of attribute values (got %u, expected 1) when checking RDN against name of %s",
494 ldb_dn_get_linearized(msg->dn)));
497 if (data_blob_cmp(rdn_val,
498 &e->values[0]) != 0) {
499 DEBUG(0, ("Unxpectedly got mismatching RDN values when checking RDN against name of %s",
500 ldb_dn_get_linearized(msg->dn)));
504 if (d->originating_change_time > whenChanged) {
505 whenChanged = d->originating_change_time;
510 msg->num_elements = attr_count;
511 md->ctr.ctr1.count = attr_count;
513 if (instanceType_e == NULL) {
517 instanceType = ldb_msg_find_attr_as_int(msg, "instanceType", 0);
519 if ((instanceType & INSTANCE_TYPE_IS_NC_HEAD)
520 && partition_dn != NULL) {
521 int partition_dn_cmp = ldb_dn_compare(partition_dn, msg->dn);
522 if (partition_dn_cmp != 0) {
523 DEBUG(4, ("Remote server advised us of a new partition %s while processing %s, ignoring\n",
524 ldb_dn_get_linearized(msg->dn),
525 ldb_dn_get_linearized(partition_dn)));
526 return WERR_DS_ADD_REPLICA_INHIBITED;
530 if (dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
531 /* the instanceType type for partial_replica
532 replication is sent via DRS with TYPE_WRITE set, but
533 must be used on the client with TYPE_WRITE removed
535 if (instanceType & INSTANCE_TYPE_WRITE) {
537 * Make sure we do not change the order
541 * instanceType_e->num_values = 0
543 * ldb_msg_remove_attr(msg, "instanceType");
545 struct ldb_message_element *e;
547 e = ldb_msg_find_element(msg, "instanceType");
548 if (e != instanceType_e) {
549 DEBUG(0,("instanceType_e[%p] changed to e[%p]\n",
554 instanceType_e->num_values = 0;
556 instanceType &= ~INSTANCE_TYPE_WRITE;
557 if (ldb_msg_add_fmt(msg, "instanceType", "%d", instanceType) != LDB_SUCCESS) {
558 return WERR_INTERNAL_ERROR;
562 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
563 DEBUG(0, ("Refusing to replicate %s from a read-only repilca into a read-write replica!\n",
564 ldb_dn_get_linearized(msg->dn)));
565 return WERR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA;
569 whenChanged_t = nt_time_to_unix(whenChanged);
570 whenChanged_s = ldb_timestring(msg, whenChanged_t);
571 W_ERROR_HAVE_NO_MEMORY(whenChanged_s);
573 out->object_guid = in->object.identifier->guid;
575 if (in->parent_object_guid == NULL) {
576 out->parent_guid = NULL;
577 if ((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0) {
578 DEBUG(0, ("Refusing to replicate %s from a server that did not provide a parentGUID!\n",
579 ldb_dn_get_linearized(msg->dn)));
580 return WERR_DS_DRA_INCONSISTENT_DIT;
583 out->parent_guid = talloc(mem_ctx, struct GUID);
584 W_ERROR_HAVE_NO_MEMORY(out->parent_guid);
585 *out->parent_guid = *in->parent_object_guid;
589 out->when_changed = whenChanged_s;
594 WERROR dsdb_replicated_objects_convert(struct ldb_context *ldb,
595 const struct dsdb_schema *schema,
596 struct ldb_dn *partition_dn,
597 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr,
598 uint32_t object_count,
599 const struct drsuapi_DsReplicaObjectListItemEx *first_object,
600 uint32_t linked_attributes_count,
601 const struct drsuapi_DsReplicaLinkedAttribute *linked_attributes,
602 const struct repsFromTo1 *source_dsa,
603 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector,
604 const DATA_BLOB *gensec_skey,
605 uint32_t dsdb_repl_flags,
607 struct dsdb_extended_replicated_objects **objects)
610 struct dsdb_schema_prefixmap *pfm_remote;
611 struct dsdb_extended_replicated_objects *out;
612 const struct drsuapi_DsReplicaObjectListItemEx *cur;
615 out = talloc_zero(mem_ctx, struct dsdb_extended_replicated_objects);
616 W_ERROR_HAVE_NO_MEMORY(out);
617 out->version = DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION;
618 out->dsdb_repl_flags = dsdb_repl_flags;
621 * Ensure schema is kept valid for as long as 'out'
622 * which may contain pointers to it
624 schema = talloc_reference(out, schema);
625 W_ERROR_HAVE_NO_MEMORY(schema);
627 status = dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr, true,
628 out, &pfm_remote, NULL);
629 if (!W_ERROR_IS_OK(status)) {
630 DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s",
631 win_errstr(status)));
636 if (ldb_dn_compare(partition_dn, ldb_get_schema_basedn(ldb)) != 0) {
638 * check for schema changes in case
639 * we are not replicating Schema NC
641 status = dsdb_schema_info_cmp(schema, mapping_ctr);
642 if (!W_ERROR_IS_OK(status)) {
643 DEBUG(4,("Can't replicate %s because remote schema has changed since we last replicated the schema\n",
644 ldb_dn_get_linearized(partition_dn)));
650 out->partition_dn = partition_dn;
652 out->source_dsa = source_dsa;
653 out->uptodateness_vector= uptodateness_vector;
655 out->num_objects = 0;
656 out->objects = talloc_array(out,
657 struct dsdb_extended_replicated_object,
659 W_ERROR_HAVE_NO_MEMORY_AND_FREE(out->objects, out);
661 /* pass the linked attributes down to the repl_meta_data
663 out->linked_attributes_count = linked_attributes_count;
664 out->linked_attributes = linked_attributes;
666 for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
667 if (i == object_count) {
672 status = dsdb_convert_object_ex(ldb, schema, out->partition_dn,
678 &out->objects[out->num_objects]);
681 * Check to see if we have been advised of a
682 * subdomain or new application partition. We don't
683 * want to start on that here, instead the caller
684 * should consider if it would like to replicate it
685 * based on the cross-ref object.
687 if (W_ERROR_EQUAL(status, WERR_DS_ADD_REPLICA_INHIBITED)) {
691 if (!W_ERROR_IS_OK(status)) {
693 DEBUG(0,("Failed to convert object %s: %s\n",
694 cur->object.identifier->dn,
695 win_errstr(status)));
699 /* Assuming we didn't skip or error, increment the number of objects */
702 out->objects = talloc_realloc(out, out->objects,
703 struct dsdb_extended_replicated_object,
705 if (out->num_objects != 0 && out->objects == NULL) {
709 if (i != object_count) {
714 /* free pfm_remote, we won't need it anymore */
715 talloc_free(pfm_remote);
722 * Commits a list of replicated objects.
724 * @param working_schema dsdb_schema to be used for resolving
725 * Classes/Attributes during Schema replication. If not NULL,
726 * it will be set on ldb and used while committing replicated objects
728 WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
729 struct dsdb_schema *working_schema,
730 struct dsdb_extended_replicated_objects *objects,
731 uint64_t *notify_uSN)
734 struct ldb_result *ext_res;
735 struct dsdb_schema *cur_schema = NULL;
736 struct dsdb_schema *new_schema = NULL;
738 uint64_t seq_num1, seq_num2;
739 bool used_global_schema = false;
741 TALLOC_CTX *tmp_ctx = talloc_new(objects);
743 DEBUG(0,("Failed to start talloc\n"));
747 /* TODO: handle linked attributes */
749 /* wrap the extended operation in a transaction
750 See [MS-DRSR] 3.3.2 Transactions
752 ret = ldb_transaction_start(ldb);
753 if (ret != LDB_SUCCESS) {
754 DEBUG(0,(__location__ " Failed to start transaction\n"));
758 ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num1, NULL);
759 if (ret != LDB_SUCCESS) {
760 DEBUG(0,(__location__ " Failed to load partition uSN\n"));
761 ldb_transaction_cancel(ldb);
762 TALLOC_FREE(tmp_ctx);
767 * Set working_schema for ldb in case we are replicating from Schema NC.
768 * Schema won't be reloaded during Replicated Objects commit, as it is
769 * done in a transaction. So we need some way to search for newly
770 * added Classes and Attributes
772 if (working_schema) {
773 /* store current schema so we can fall back in case of failure */
774 cur_schema = dsdb_get_schema(ldb, tmp_ctx);
775 used_global_schema = dsdb_uses_global_schema(ldb);
777 ret = dsdb_reference_schema(ldb, working_schema, false);
778 if (ret != LDB_SUCCESS) {
779 DEBUG(0,(__location__ "Failed to reference working schema - %s\n",
781 /* TODO: Map LDB Error to NTSTATUS? */
782 ldb_transaction_cancel(ldb);
783 TALLOC_FREE(tmp_ctx);
784 return WERR_INTERNAL_ERROR;
788 ret = ldb_extended(ldb, DSDB_EXTENDED_REPLICATED_OBJECTS_OID, objects, &ext_res);
789 if (ret != LDB_SUCCESS) {
790 /* restore previous schema */
791 if (used_global_schema) {
792 dsdb_set_global_schema(ldb);
793 } else if (cur_schema) {
794 dsdb_reference_schema(ldb, cur_schema, false);
797 if (!W_ERROR_EQUAL(objects->error, WERR_DS_DRA_MISSING_PARENT)) {
798 DEBUG(1,("Failed to apply records: %s: %s\n",
799 ldb_errstring(ldb), ldb_strerror(ret)));
801 DEBUG(3,("Missing parent while attempting to apply records: %s\n",
802 ldb_errstring(ldb)));
804 ldb_transaction_cancel(ldb);
805 TALLOC_FREE(tmp_ctx);
807 if (!W_ERROR_IS_OK(objects->error)) {
808 return objects->error;
812 talloc_free(ext_res);
814 /* Save our updated prefixMap */
815 if (working_schema) {
816 werr = dsdb_write_prefixes_from_schema_to_ldb(working_schema,
819 if (!W_ERROR_IS_OK(werr)) {
820 /* restore previous schema */
821 if (used_global_schema) {
822 dsdb_set_global_schema(ldb);
823 } else if (cur_schema ) {
824 dsdb_reference_schema(ldb, cur_schema, false);
826 DEBUG(0,("Failed to save updated prefixMap: %s\n",
828 TALLOC_FREE(tmp_ctx);
833 ret = ldb_transaction_prepare_commit(ldb);
834 if (ret != LDB_SUCCESS) {
835 /* restore previous schema */
836 if (used_global_schema) {
837 dsdb_set_global_schema(ldb);
838 } else if (cur_schema ) {
839 dsdb_reference_schema(ldb, cur_schema, false);
841 DEBUG(0,(__location__ " Failed to prepare commit of transaction: %s\n",
842 ldb_errstring(ldb)));
843 TALLOC_FREE(tmp_ctx);
847 ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num2, NULL);
848 if (ret != LDB_SUCCESS) {
849 /* restore previous schema */
850 if (used_global_schema) {
851 dsdb_set_global_schema(ldb);
852 } else if (cur_schema ) {
853 dsdb_reference_schema(ldb, cur_schema, false);
855 DEBUG(0,(__location__ " Failed to load partition uSN\n"));
856 ldb_transaction_cancel(ldb);
857 TALLOC_FREE(tmp_ctx);
861 ret = ldb_transaction_commit(ldb);
862 if (ret != LDB_SUCCESS) {
863 /* restore previous schema */
864 if (used_global_schema) {
865 dsdb_set_global_schema(ldb);
866 } else if (cur_schema ) {
867 dsdb_reference_schema(ldb, cur_schema, false);
869 DEBUG(0,(__location__ " Failed to commit transaction\n"));
870 TALLOC_FREE(tmp_ctx);
874 /* if this replication partner didn't need to be notified
875 before this transaction then it still doesn't need to be
876 notified, as the changes came from this server */
877 if (seq_num2 > seq_num1 && seq_num1 <= *notify_uSN) {
878 *notify_uSN = seq_num2;
882 * Reset the Schema used by ldb. This will lead to
883 * a schema cache being refreshed from database.
885 if (working_schema) {
886 /* Reload the schema */
887 new_schema = dsdb_get_schema(ldb, tmp_ctx);
889 * If dsdb_get_schema() fails, we just fall back
890 * to what we had. However, the database is probably
891 * unable to operate for other users from this
893 if (new_schema == NULL || new_schema == working_schema) {
894 DBG_ERR("Failed to re-load schema after commit of "
895 "transaction (working: %p/%"PRIu64", new: "
896 "%p/%"PRIu64")\n", new_schema,
898 new_schema->metadata_usn : 0,
899 working_schema, working_schema->metadata_usn);
900 dsdb_reference_schema(ldb, cur_schema, false);
901 if (used_global_schema) {
902 dsdb_set_global_schema(ldb);
904 TALLOC_FREE(tmp_ctx);
905 return WERR_INTERNAL_ERROR;
906 } else if (used_global_schema) {
907 dsdb_make_schema_global(ldb, new_schema);
911 DEBUG(2,("Replicated %u objects (%u linked attributes) for %s\n",
912 objects->num_objects, objects->linked_attributes_count,
913 ldb_dn_get_linearized(objects->partition_dn)));
915 TALLOC_FREE(tmp_ctx);
919 static WERROR dsdb_origin_object_convert(struct ldb_context *ldb,
920 const struct dsdb_schema *schema,
921 const struct drsuapi_DsReplicaObjectListItem *in,
923 struct ldb_message **_msg)
927 struct ldb_message *msg;
929 if (!in->object.identifier) {
933 if (!in->object.identifier->dn || !in->object.identifier->dn[0]) {
937 msg = ldb_msg_new(mem_ctx);
938 W_ERROR_HAVE_NO_MEMORY(msg);
940 msg->dn = ldb_dn_new(msg, ldb, in->object.identifier->dn);
941 W_ERROR_HAVE_NO_MEMORY(msg->dn);
943 msg->num_elements = in->object.attribute_ctr.num_attributes;
944 msg->elements = talloc_array(msg, struct ldb_message_element,
946 W_ERROR_HAVE_NO_MEMORY(msg->elements);
948 for (i=0; i < msg->num_elements; i++) {
949 struct drsuapi_DsReplicaAttribute *a;
950 struct ldb_message_element *e;
952 a = &in->object.attribute_ctr.attributes[i];
953 e = &msg->elements[i];
955 status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, schema->prefixmap,
956 a, msg->elements, e, NULL);
957 W_ERROR_NOT_OK_RETURN(status);
966 WERROR dsdb_origin_objects_commit(struct ldb_context *ldb,
968 const struct drsuapi_DsReplicaObjectListItem *first_object,
970 uint32_t dsdb_repl_flags,
971 struct drsuapi_DsReplicaObjectIdentifier2 **_ids)
974 const struct dsdb_schema *schema;
975 const struct drsuapi_DsReplicaObjectListItem *cur;
976 struct ldb_message **objects;
977 struct drsuapi_DsReplicaObjectIdentifier2 *ids;
979 uint32_t num_objects = 0;
980 const char * const attrs[] = {
985 struct ldb_result *res;
988 for (cur = first_object; cur; cur = cur->next_object) {
992 if (num_objects == 0) {
996 ret = ldb_transaction_start(ldb);
997 if (ret != LDB_SUCCESS) {
998 return WERR_DS_INTERNAL_FAILURE;
1001 objects = talloc_array(mem_ctx, struct ldb_message *,
1003 if (objects == NULL) {
1004 status = WERR_NOMEM;
1008 schema = dsdb_get_schema(ldb, objects);
1010 return WERR_DS_SCHEMA_NOT_LOADED;
1013 for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
1014 status = dsdb_origin_object_convert(ldb, schema, cur,
1015 objects, &objects[i]);
1016 if (!W_ERROR_IS_OK(status)) {
1021 ids = talloc_array(mem_ctx,
1022 struct drsuapi_DsReplicaObjectIdentifier2,
1025 status = WERR_NOMEM;
1029 if (dsdb_repl_flags & DSDB_REPL_FLAG_ADD_NCNAME) {
1030 /* check for possible NC creation */
1031 for (i=0; i < num_objects; i++) {
1032 struct ldb_message *msg = objects[i];
1033 struct ldb_message_element *el;
1034 struct ldb_dn *nc_dn;
1036 if (ldb_msg_check_string_attribute(msg, "objectClass", "crossRef") == 0) {
1039 el = ldb_msg_find_element(msg, "nCName");
1040 if (el == NULL || el->num_values != 1) {
1043 nc_dn = ldb_dn_from_ldb_val(objects, ldb, &el->values[0]);
1044 if (!ldb_dn_validate(nc_dn)) {
1047 ret = dsdb_create_partial_replica_NC(ldb, nc_dn);
1048 if (ret != LDB_SUCCESS) {
1049 status = WERR_DS_INTERNAL_FAILURE;
1055 for (i=0; i < num_objects; i++) {
1056 struct dom_sid *sid = NULL;
1057 struct ldb_request *add_req;
1059 DEBUG(6,(__location__ ": adding %s\n",
1060 ldb_dn_get_linearized(objects[i]->dn)));
1062 ret = ldb_build_add_req(&add_req,
1068 ldb_op_default_callback,
1070 if (ret != LDB_SUCCESS) {
1071 status = WERR_DS_INTERNAL_FAILURE;
1075 ret = ldb_request_add_control(add_req, LDB_CONTROL_RELAX_OID, true, NULL);
1076 if (ret != LDB_SUCCESS) {
1077 status = WERR_DS_INTERNAL_FAILURE;
1081 ret = ldb_request(ldb, add_req);
1082 if (ret == LDB_SUCCESS) {
1083 ret = ldb_wait(add_req->handle, LDB_WAIT_ALL);
1085 if (ret != LDB_SUCCESS) {
1086 DEBUG(0,(__location__ ": Failed add of %s - %s\n",
1087 ldb_dn_get_linearized(objects[i]->dn), ldb_errstring(ldb)));
1088 status = WERR_DS_INTERNAL_FAILURE;
1092 talloc_free(add_req);
1094 ret = ldb_search(ldb, objects, &res, objects[i]->dn,
1095 LDB_SCOPE_BASE, attrs,
1097 if (ret != LDB_SUCCESS) {
1098 status = WERR_DS_INTERNAL_FAILURE;
1101 ids[i].guid = samdb_result_guid(res->msgs[0], "objectGUID");
1102 sid = samdb_result_dom_sid(objects, res->msgs[0], "objectSid");
1106 ZERO_STRUCT(ids[i].sid);
1110 ret = ldb_transaction_commit(ldb);
1111 if (ret != LDB_SUCCESS) {
1112 return WERR_DS_INTERNAL_FAILURE;
1115 talloc_free(objects);
1117 *_num = num_objects;
1122 talloc_free(objects);
1123 ldb_transaction_cancel(ldb);