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"
35 #define DBGC_CLASS DBGC_DRS_REPL
37 static WERROR dsdb_repl_merge_working_schema(struct ldb_context *ldb,
38 struct dsdb_schema *dest_schema,
39 const struct dsdb_schema *ref_schema)
41 const struct dsdb_class *cur_class = NULL;
42 const struct dsdb_attribute *cur_attr = NULL;
45 for (cur_class = ref_schema->classes;
47 cur_class = cur_class->next)
49 const struct dsdb_class *tmp1;
50 struct dsdb_class *tmp2;
52 tmp1 = dsdb_class_by_governsID_id(dest_schema,
53 cur_class->governsID_id);
59 * Do a shallow copy so that original next and prev are
60 * not modified, we don't need to do a deep copy
61 * as the rest won't be modified and this is for
62 * a short lived object.
64 tmp2 = talloc(dest_schema, struct dsdb_class);
66 return WERR_NOT_ENOUGH_MEMORY;
69 DLIST_ADD(dest_schema->classes, tmp2);
72 for (cur_attr = ref_schema->attributes;
74 cur_attr = cur_attr->next)
76 const struct dsdb_attribute *tmp1;
77 struct dsdb_attribute *tmp2;
79 tmp1 = dsdb_attribute_by_attributeID_id(dest_schema,
80 cur_attr->attributeID_id);
86 * Do a shallow copy so that original next and prev are
87 * not modified, we don't need to do a deep copy
88 * as the rest won't be modified and this is for
89 * a short lived object.
91 tmp2 = talloc(dest_schema, struct dsdb_attribute);
93 return WERR_NOT_ENOUGH_MEMORY;
96 DLIST_ADD(dest_schema->attributes, tmp2);
99 ret = dsdb_setup_sorted_accessors(ldb, dest_schema);
100 if (LDB_SUCCESS != ret) {
101 DEBUG(0,("Failed to add new attribute to reference schema!\n"));
102 return WERR_INTERNAL_ERROR;
108 WERROR dsdb_repl_resolve_working_schema(struct ldb_context *ldb,
109 struct dsdb_schema_prefixmap *pfm_remote,
110 uint32_t cycle_before_switching,
111 struct dsdb_schema *initial_schema,
112 struct dsdb_schema *resulting_schema,
113 uint32_t object_count,
114 const struct drsuapi_DsReplicaObjectListItemEx *first_object)
117 struct schema_list *next, *prev;
118 const struct drsuapi_DsReplicaObjectListItemEx *obj;
120 struct schema_list *schema_list = NULL, *schema_list_item, *schema_list_next_item;
122 struct dsdb_schema *working_schema;
123 const struct drsuapi_DsReplicaObjectListItemEx *cur;
124 DATA_BLOB empty_key = data_blob_null;
126 uint32_t ignore_attids[] = {
127 DRSUAPI_ATTID_auxiliaryClass,
128 DRSUAPI_ATTID_mayContain,
129 DRSUAPI_ATTID_mustContain,
130 DRSUAPI_ATTID_possSuperiors,
131 DRSUAPI_ATTID_systemPossSuperiors,
132 DRSUAPI_ATTID_INVALID
134 TALLOC_CTX *frame = talloc_stackframe();
136 /* create a list of objects yet to be converted */
137 for (cur = first_object; cur; cur = cur->next_object) {
138 schema_list_item = talloc(frame, struct schema_list);
139 if (schema_list_item == NULL) {
140 return WERR_NOT_ENOUGH_MEMORY;
143 schema_list_item->obj = cur;
144 DLIST_ADD_END(schema_list, schema_list_item);
147 /* resolve objects until all are resolved and in local schema */
149 working_schema = initial_schema;
151 while (schema_list) {
152 uint32_t converted_obj_count = 0;
153 uint32_t failed_obj_count = 0;
155 if (resulting_schema != working_schema) {
157 * If the selfmade schema is not the schema used to
158 * translate and validate replicated object,
159 * Which means that we are using the bootstrap schema
160 * Then we add attributes and classes that were already
161 * translated to the working schema, the idea is that
162 * we might need to add new attributes and classes
163 * to be able to translate critical replicated objects
164 * and without that we wouldn't be able to translate them
166 werr = dsdb_repl_merge_working_schema(ldb,
169 if (!W_ERROR_IS_OK(werr)) {
175 for (schema_list_item = schema_list;
177 schema_list_item=schema_list_next_item) {
178 struct dsdb_extended_replicated_object object;
180 cur = schema_list_item->obj;
183 * Save the next item, now we have saved out
184 * the current one, so we can DLIST_REMOVE it
187 schema_list_next_item = schema_list_item->next;
190 * Convert the objects into LDB messages using the
191 * schema we have so far. It's ok if we fail to convert
192 * an object. We should convert more objects on next pass.
194 werr = dsdb_convert_object_ex(ldb, working_schema,
200 schema_list_item, &object);
201 if (!W_ERROR_IS_OK(werr)) {
202 DEBUG(4,("debug: Failed to convert schema "
203 "object %s into ldb msg, "
204 "will try during next loop\n",
205 cur->object.identifier->dn));
210 * Convert the schema from ldb_message format
211 * (OIDs as OID strings) into schema, using
212 * the remote prefixMap
214 * It's not likely, but possible to get the
215 * same object twice and we should keep
218 werr = dsdb_schema_set_el_from_ldb_msg_dups(ldb,
222 if (!W_ERROR_IS_OK(werr)) {
223 DEBUG(4,("debug: failed to convert "
224 "object %s into a schema element, "
225 "will try during next loop: %s\n",
226 ldb_dn_get_linearized(object.msg->dn),
230 DEBUG(8,("Converted object %s into a schema element\n",
231 ldb_dn_get_linearized(object.msg->dn)));
232 DLIST_REMOVE(schema_list, schema_list_item);
233 TALLOC_FREE(schema_list_item);
234 converted_obj_count++;
239 DEBUG(4,("Schema load pass %d: converted %d, %d of %d objects left to be converted.\n",
240 pass_no, converted_obj_count, failed_obj_count, object_count));
242 /* check if we converted any objects in this pass */
243 if (converted_obj_count == 0) {
244 DEBUG(0,("Can't continue Schema load: "
245 "didn't manage to convert any objects: "
246 "all %d remaining of %d objects "
247 "failed to convert\n",
248 failed_obj_count, object_count));
250 return WERR_INTERNAL_ERROR;
254 * Don't try to load the schema if there is missing object
255 * _and_ we are on the first pass as some critical objects
258 if (failed_obj_count == 0 || pass_no > cycle_before_switching) {
259 /* prepare for another cycle */
260 working_schema = resulting_schema;
262 ret = dsdb_setup_sorted_accessors(ldb, working_schema);
263 if (LDB_SUCCESS != ret) {
264 DEBUG(0,("Failed to create schema-cache indexes!\n"));
266 return WERR_INTERNAL_ERROR;
277 * Multi-pass working schema creation
279 * - shallow copy initial schema supplied
280 * - create a working schema in multiple passes
281 * until all objects are resolved
282 * Working schema is a schema with Attributes, Classes
283 * and indexes, but w/o subClassOf, possibleSupperiors etc.
284 * It is to be used just us cache for converting attribute values.
286 WERROR dsdb_repl_make_working_schema(struct ldb_context *ldb,
287 const struct dsdb_schema *initial_schema,
288 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr,
289 uint32_t object_count,
290 const struct drsuapi_DsReplicaObjectListItemEx *first_object,
291 const DATA_BLOB *gensec_skey,
293 struct dsdb_schema **_schema_out)
296 struct dsdb_schema_prefixmap *pfm_remote;
298 struct dsdb_schema *working_schema;
300 /* make a copy of the iniatial_scheam so we don't mess with it */
301 working_schema = dsdb_schema_copy_shallow(mem_ctx, ldb, initial_schema);
302 if (!working_schema) {
303 DEBUG(0,(__location__ ": schema copy failed!\n"));
304 return WERR_NOT_ENOUGH_MEMORY;
306 working_schema->resolving_in_progress = true;
308 /* we are going to need remote prefixMap for decoding */
309 werr = dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr, true,
310 working_schema, &pfm_remote, NULL);
311 if (!W_ERROR_IS_OK(werr)) {
312 DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s\n",
314 talloc_free(working_schema);
318 for (r=0; r < pfm_remote->length; r++) {
319 const struct dsdb_schema_prefixmap_oid *rm = &pfm_remote->prefixes[r];
320 bool found_oid = false;
323 for (l=0; l < working_schema->prefixmap->length; l++) {
324 const struct dsdb_schema_prefixmap_oid *lm = &working_schema->prefixmap->prefixes[l];
327 cmp = data_blob_cmp(&rm->bin_oid, &lm->bin_oid);
339 * We prefer the same is as we got from the remote peer
340 * if there's no conflict.
342 werr = dsdb_schema_pfm_add_entry(working_schema->prefixmap,
343 rm->bin_oid, &rm->id, NULL);
344 if (!W_ERROR_IS_OK(werr)) {
345 DEBUG(0,(__location__ ": Failed to merge remote prefixMap: %s",
347 talloc_free(working_schema);
352 werr = dsdb_repl_resolve_working_schema(ldb,
354 0, /* cycle_before_switching */
359 if (!W_ERROR_IS_OK(werr)) {
360 DEBUG(0, ("%s: dsdb_repl_resolve_working_schema() failed: %s",
361 __location__, win_errstr(werr)));
362 talloc_free(working_schema);
366 working_schema->resolving_in_progress = false;
368 *_schema_out = working_schema;
373 static bool dsdb_attid_in_list(const uint32_t attid_list[], uint32_t attid)
379 for (cur = attid_list; *cur != DRSUAPI_ATTID_INVALID; cur++) {
387 static WERROR dsdb_verify_repl_meta_data(const struct drsuapi_DsReplicaMetaData *d,
388 const struct GUID *dst_invocation_id,
389 const struct GUID *src_invocation_id,
390 uint64_t src_last_hwm,
391 const * const char *error_hint)
397 match = GUID_all_zero(&d->originating_invocation_id);
399 *error_hint = "got zero invocationID";
400 return WERR_DS_SRC_GUID_MISMATCH;
403 // TODO detect restored backup on source or destination dsa
404 // ERROR_DS_DRA_SOURCE_REINSTALLED
405 // ERROR_DS_EPOCH_MISMATCH
406 // ERROR_DS_SRC_GUID_MISMATCH
407 // ERROR_DS_OUT_OF_VERSION_STORE
408 // ERROR_DS_DIFFERENT_REPL_EPOCHS
409 // ERROR_DS_DRS_EXTENSIONS_CHANGED
410 // ERROR_DS_DUPLICATE_ID_FOUND
411 // ERROR_DS_DRA_OUT_SCHEDULE_WINDOW
412 // ERROR_DS_REPL_LIFETIME_EXCEEDED
413 // ERROR_DS_NO_NTDSA_OBJECT
414 // ERROR_DS_DRA_SOURCE_REINSTALLED
415 // ERROR_DS_DRA_INCONSISTENT_DIT
417 if (dst_invocation_id != NULL) {
418 match = GUID_equal(&d->originating_invocation_id,
421 *error_hint = "got destination(local) invocationID";
422 return WERR_DS_DRA_INCONSISTENT_DIT;
426 if (src_invocation_id != NULL) {
427 match = GUID_equal(&d->originating_invocation_id,
429 if (match && d->originating_usn < src_last_hwm) {
430 *error_hint = "got old source(remote) dsa stamp";
431 return WERR_DS_DRA_SOURCE_REINSTALLED;
438 WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
439 const struct dsdb_schema *schema,
440 struct ldb_dn *partition_dn,
441 const struct dsdb_schema_prefixmap *pfm_remote,
442 const struct drsuapi_DsReplicaObjectListItemEx *in,
443 const DATA_BLOB *gensec_skey,
444 const uint32_t *ignore_attids,
445 uint32_t dsdb_repl_flags,
447 struct dsdb_extended_replicated_object *out)
449 WERROR status = WERR_OK;
451 struct ldb_message *msg;
452 struct replPropertyMetaDataBlob *md;
454 struct ldb_message_element *instanceType_e = NULL;
455 NTTIME whenChanged = 0;
456 time_t whenChanged_t;
457 const char *whenChanged_s;
458 struct dom_sid *sid = NULL;
462 if (!in->object.identifier) {
466 if (!in->object.identifier->dn || !in->object.identifier->dn[0]) {
470 if (in->object.attribute_ctr.num_attributes != 0 && !in->meta_data_ctr) {
474 if (in->object.attribute_ctr.num_attributes != in->meta_data_ctr->count) {
478 sid = &in->object.identifier->sid;
479 if (sid->num_auths > 0) {
480 rid = sid->sub_auths[sid->num_auths - 1];
483 msg = ldb_msg_new(mem_ctx);
484 W_ERROR_HAVE_NO_MEMORY(msg);
486 msg->dn = ldb_dn_new(msg, ldb, in->object.identifier->dn);
487 W_ERROR_HAVE_NO_MEMORY(msg->dn);
489 msg->num_elements = in->object.attribute_ctr.num_attributes;
490 msg->elements = talloc_array(msg, struct ldb_message_element,
492 W_ERROR_HAVE_NO_MEMORY(msg->elements);
494 md = talloc(mem_ctx, struct replPropertyMetaDataBlob);
495 W_ERROR_HAVE_NO_MEMORY(md);
499 md->ctr.ctr1.count = in->meta_data_ctr->count;
500 md->ctr.ctr1.reserved = 0;
501 md->ctr.ctr1.array = talloc_array(mem_ctx,
502 struct replPropertyMetaData1,
504 W_ERROR_HAVE_NO_MEMORY(md->ctr.ctr1.array);
506 for (i=0, attr_count=0; i < in->meta_data_ctr->count; i++, attr_count++) {
507 struct drsuapi_DsReplicaAttribute *a;
508 struct drsuapi_DsReplicaMetaData *d;
509 struct replPropertyMetaData1 *m;
510 struct ldb_message_element *e;
512 const char *error_hint = NULL;
514 a = &in->object.attribute_ctr.attributes[i];
515 d = &in->meta_data_ctr->meta_data[i];
516 m = &md->ctr.ctr1.array[attr_count];
517 e = &msg->elements[attr_count];
519 if (dsdb_attid_in_list(ignore_attids, a->attid)) {
524 status = dsdb_verify_repl_meta_data(d,
529 if (!W_ERROR_IS_OK(werr)) {
530 DEBUG(0, ("Refusing replication of object on attribute %d of %s: %s - %s\n",
532 ldb_dn_get_linearized(msg->dn),
538 if (a->attid == DRSUAPI_ATTID_instanceType) {
539 if (instanceType_e != NULL) {
545 for (j=0; j<a->value_ctr.num_values; j++) {
546 status = drsuapi_decrypt_attribute(a->value_ctr.values[j].blob,
549 if (!W_ERROR_IS_OK(status)) {
553 if (W_ERROR_EQUAL(status, WERR_TOO_MANY_SECRETS)) {
554 WERROR get_name_status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, pfm_remote,
555 a, msg->elements, e, NULL);
556 if (W_ERROR_IS_OK(get_name_status)) {
557 DEBUG(0, ("Unxpectedly got secret value %s on %s from DRS server\n",
558 e->name, ldb_dn_get_linearized(msg->dn)));
560 DEBUG(0, ("Unxpectedly got secret value on %s from DRS server",
561 ldb_dn_get_linearized(msg->dn)));
563 } else if (!W_ERROR_IS_OK(status)) {
568 * This function also fills in the local attid value,
569 * based on comparing the remote and local prefixMap
570 * tables. If we don't convert the value, then we can
571 * have invalid values in the replPropertyMetaData we
572 * store on disk, as the prefixMap is per host, not
573 * per-domain. This may be why Microsoft added the
574 * msDS-IntID feature, however this is not used for
575 * extra attributes in the schema partition itself.
577 status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, pfm_remote,
580 W_ERROR_NOT_OK_RETURN(status);
582 m->version = d->version;
583 m->originating_change_time = d->originating_change_time;
584 m->originating_invocation_id = d->originating_invocation_id;
585 m->originating_usn = d->originating_usn;
588 if (a->attid == DRSUAPI_ATTID_name) {
589 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
590 if (rdn_val == NULL) {
591 DEBUG(0, ("Unxpectedly unable to get RDN from %s for validation",
592 ldb_dn_get_linearized(msg->dn)));
595 if (e->num_values != 1) {
596 DEBUG(0, ("Unxpectedly got wrong number of attribute values (got %u, expected 1) when checking RDN against name of %s",
598 ldb_dn_get_linearized(msg->dn)));
601 if (data_blob_cmp(rdn_val,
602 &e->values[0]) != 0) {
603 DEBUG(0, ("Unxpectedly got mismatching RDN values when checking RDN against name of %s",
604 ldb_dn_get_linearized(msg->dn)));
608 if (d->originating_change_time > whenChanged) {
609 whenChanged = d->originating_change_time;
614 msg->num_elements = attr_count;
615 md->ctr.ctr1.count = attr_count;
617 if (instanceType_e == NULL) {
621 instanceType = ldb_msg_find_attr_as_int(msg, "instanceType", 0);
623 if ((instanceType & INSTANCE_TYPE_IS_NC_HEAD)
624 && partition_dn != NULL) {
625 int partition_dn_cmp = ldb_dn_compare(partition_dn, msg->dn);
626 if (partition_dn_cmp != 0) {
627 DEBUG(4, ("Remote server advised us of a new partition %s while processing %s, ignoring\n",
628 ldb_dn_get_linearized(msg->dn),
629 ldb_dn_get_linearized(partition_dn)));
630 return WERR_DS_ADD_REPLICA_INHIBITED;
634 if (dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
635 /* the instanceType type for partial_replica
636 replication is sent via DRS with TYPE_WRITE set, but
637 must be used on the client with TYPE_WRITE removed
639 if (instanceType & INSTANCE_TYPE_WRITE) {
641 * Make sure we do not change the order
645 * instanceType_e->num_values = 0
647 * ldb_msg_remove_attr(msg, "instanceType");
649 struct ldb_message_element *e;
651 e = ldb_msg_find_element(msg, "instanceType");
652 if (e != instanceType_e) {
653 DEBUG(0,("instanceType_e[%p] changed to e[%p]\n",
658 instanceType_e->num_values = 0;
660 instanceType &= ~INSTANCE_TYPE_WRITE;
661 if (ldb_msg_add_fmt(msg, "instanceType", "%d", instanceType) != LDB_SUCCESS) {
662 return WERR_INTERNAL_ERROR;
666 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
667 DBG_ERR("Refusing to replicate %s from a read-only "
668 "replica into a read-write replica!\n",
669 ldb_dn_get_linearized(msg->dn));
670 return WERR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA;
674 whenChanged_t = nt_time_to_unix(whenChanged);
675 whenChanged_s = ldb_timestring(msg, whenChanged_t);
676 W_ERROR_HAVE_NO_MEMORY(whenChanged_s);
678 out->object_guid = in->object.identifier->guid;
680 if (in->parent_object_guid == NULL) {
681 out->parent_guid = NULL;
683 out->parent_guid = talloc(mem_ctx, struct GUID);
684 W_ERROR_HAVE_NO_MEMORY(out->parent_guid);
685 *out->parent_guid = *in->parent_object_guid;
689 out->when_changed = whenChanged_s;
694 WERROR dsdb_replicated_objects_convert(struct ldb_context *ldb,
695 const struct dsdb_schema *schema,
696 struct ldb_dn *partition_dn,
697 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr,
698 uint32_t object_count,
699 const struct drsuapi_DsReplicaObjectListItemEx *first_object,
700 uint32_t linked_attributes_count,
701 const struct drsuapi_DsReplicaLinkedAttribute *linked_attributes,
702 const struct repsFromTo1 *source_dsa,
703 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector,
704 const DATA_BLOB *gensec_skey,
705 uint32_t dsdb_repl_flags,
707 struct dsdb_extended_replicated_objects **objects)
710 struct dsdb_schema_prefixmap *pfm_remote;
711 struct dsdb_extended_replicated_objects *out;
712 const struct drsuapi_DsReplicaObjectListItemEx *cur;
713 struct dsdb_syntax_ctx syntax_ctx;
716 out = talloc_zero(mem_ctx, struct dsdb_extended_replicated_objects);
717 W_ERROR_HAVE_NO_MEMORY(out);
718 out->version = DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION;
719 out->dsdb_repl_flags = dsdb_repl_flags;
722 * Ensure schema is kept valid for as long as 'out'
723 * which may contain pointers to it
725 schema = talloc_reference(out, schema);
726 W_ERROR_HAVE_NO_MEMORY(schema);
728 status = dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr, true,
729 out, &pfm_remote, NULL);
730 if (!W_ERROR_IS_OK(status)) {
731 DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s\n",
732 win_errstr(status)));
737 /* use default syntax conversion context */
738 dsdb_syntax_ctx_init(&syntax_ctx, ldb, schema);
739 syntax_ctx.pfm_remote = pfm_remote;
741 if (ldb_dn_compare(partition_dn, ldb_get_schema_basedn(ldb)) != 0) {
743 * check for schema changes in case
744 * we are not replicating Schema NC
746 status = dsdb_schema_info_cmp(schema, mapping_ctr);
747 if (!W_ERROR_IS_OK(status)) {
748 DEBUG(4,("Can't replicate %s because remote schema has changed since we last replicated the schema\n",
749 ldb_dn_get_linearized(partition_dn)));
755 out->partition_dn = partition_dn;
757 out->source_dsa = source_dsa;
758 out->uptodateness_vector= uptodateness_vector;
760 out->num_objects = 0;
761 out->objects = talloc_array(out,
762 struct dsdb_extended_replicated_object,
764 W_ERROR_HAVE_NO_MEMORY_AND_FREE(out->objects, out);
766 for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
767 if (i == object_count) {
772 status = dsdb_convert_object_ex(ldb, schema, out->partition_dn,
778 &out->objects[out->num_objects]);
781 * Check to see if we have been advised of a
782 * subdomain or new application partition. We don't
783 * want to start on that here, instead the caller
784 * should consider if it would like to replicate it
785 * based on the cross-ref object.
787 if (W_ERROR_EQUAL(status, WERR_DS_ADD_REPLICA_INHIBITED)) {
788 struct GUID_txt_buf guid_str;
789 DBG_ERR("Ignoring object outside partition %s %s: %s\n",
790 GUID_buf_string(&cur->object.identifier->guid,
792 cur->object.identifier->dn,
797 if (!W_ERROR_IS_OK(status)) {
799 DEBUG(0,("Failed to convert object %s: %s\n",
800 cur->object.identifier->dn,
801 win_errstr(status)));
805 /* Assuming we didn't skip or error, increment the number of objects */
808 out->objects = talloc_realloc(out, out->objects,
809 struct dsdb_extended_replicated_object,
811 if (out->num_objects != 0 && out->objects == NULL) {
815 if (i != object_count) {
820 out->linked_attributes = talloc_array(out,
821 struct drsuapi_DsReplicaLinkedAttribute,
822 linked_attributes_count);
823 W_ERROR_HAVE_NO_MEMORY_AND_FREE(out->linked_attributes, out);
825 for (i=0; i < linked_attributes_count; i++) {
826 const struct drsuapi_DsReplicaLinkedAttribute *ra = &linked_attributes[i];
827 struct drsuapi_DsReplicaLinkedAttribute *la = &out->linked_attributes[i];
829 if (ra->identifier == NULL) {
831 return WERR_BAD_NET_RESP;
836 la->identifier = talloc_zero(out->linked_attributes,
837 struct drsuapi_DsReplicaObjectIdentifier);
838 W_ERROR_HAVE_NO_MEMORY_AND_FREE(la->identifier, out);
841 * We typically only get the guid filled
842 * and the repl_meta_data module only cares abouf
845 la->identifier->guid = ra->identifier->guid;
847 if (ra->value.blob != NULL) {
848 la->value.blob = talloc_zero(out->linked_attributes,
850 W_ERROR_HAVE_NO_MEMORY_AND_FREE(la->value.blob, out);
852 if (ra->value.blob->length != 0) {
853 *la->value.blob = data_blob_dup_talloc(la->value.blob,
855 W_ERROR_HAVE_NO_MEMORY_AND_FREE(la->value.blob->data, out);
859 status = dsdb_attribute_drsuapi_remote_to_local(&syntax_ctx,
863 if (!W_ERROR_IS_OK(status)) {
864 DEBUG(0,(__location__": linked_attribute[%u] attid 0x%08X not found: %s\n",
865 i, ra->attid, win_errstr(status)));
869 status = dsdb_verify_repl_meta_data(&la->meta_data,
874 if (!W_ERROR_IS_OK(werr)) {
875 DEBUG(0, ("Refusing replication of linked on attribute %d of <GUID=%s>: %s - %s\n",
877 GUID_string(out, &la->identifier->guid),,
884 out->linked_attributes_count = linked_attributes_count;
886 /* free pfm_remote, we won't need it anymore */
887 talloc_free(pfm_remote);
894 * Commits a list of replicated objects.
896 * @param working_schema dsdb_schema to be used for resolving
897 * Classes/Attributes during Schema replication. If not NULL,
898 * it will be set on ldb and used while committing replicated objects
900 WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
901 struct dsdb_schema *working_schema,
902 struct dsdb_extended_replicated_objects *objects,
903 uint64_t *notify_uSN)
906 struct ldb_result *ext_res;
907 struct dsdb_schema *cur_schema = NULL;
908 struct dsdb_schema *new_schema = NULL;
910 uint64_t seq_num1, seq_num2;
911 bool used_global_schema = false;
913 TALLOC_CTX *tmp_ctx = talloc_new(objects);
915 DEBUG(0,("Failed to start talloc\n"));
916 return WERR_NOT_ENOUGH_MEMORY;
919 /* wrap the extended operation in a transaction
920 See [MS-DRSR] 3.3.2 Transactions
922 ret = ldb_transaction_start(ldb);
923 if (ret != LDB_SUCCESS) {
924 DEBUG(0,(__location__ " Failed to start transaction: %s\n",
925 ldb_errstring(ldb)));
929 ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num1, NULL);
930 if (ret != LDB_SUCCESS) {
931 DEBUG(0,(__location__ " Failed to load partition uSN\n"));
932 ldb_transaction_cancel(ldb);
933 TALLOC_FREE(tmp_ctx);
938 * Set working_schema for ldb in case we are replicating from Schema NC.
939 * Schema won't be reloaded during Replicated Objects commit, as it is
940 * done in a transaction. So we need some way to search for newly
941 * added Classes and Attributes
943 if (working_schema) {
944 /* store current schema so we can fall back in case of failure */
945 cur_schema = dsdb_get_schema(ldb, tmp_ctx);
946 used_global_schema = dsdb_uses_global_schema(ldb);
948 ret = dsdb_reference_schema(ldb, working_schema, SCHEMA_MEMORY_ONLY);
949 if (ret != LDB_SUCCESS) {
950 DEBUG(0,(__location__ "Failed to reference working schema - %s\n",
952 /* TODO: Map LDB Error to NTSTATUS? */
953 ldb_transaction_cancel(ldb);
954 TALLOC_FREE(tmp_ctx);
955 return WERR_INTERNAL_ERROR;
959 ret = ldb_extended(ldb, DSDB_EXTENDED_REPLICATED_OBJECTS_OID, objects, &ext_res);
960 if (ret != LDB_SUCCESS) {
961 /* restore previous schema */
962 if (used_global_schema) {
963 dsdb_set_global_schema(ldb);
964 } else if (cur_schema) {
965 dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
968 if (W_ERROR_EQUAL(objects->error, WERR_DS_DRA_RECYCLED_TARGET)) {
969 DEBUG(3,("Missing target while attempting to apply records: %s\n",
970 ldb_errstring(ldb)));
971 } else if (W_ERROR_EQUAL(objects->error, WERR_DS_DRA_MISSING_PARENT)) {
972 DEBUG(3,("Missing parent while attempting to apply records: %s\n",
973 ldb_errstring(ldb)));
975 DEBUG(1,("Failed to apply records: %s: %s\n",
976 ldb_errstring(ldb), ldb_strerror(ret)));
978 ldb_transaction_cancel(ldb);
979 TALLOC_FREE(tmp_ctx);
981 if (!W_ERROR_IS_OK(objects->error)) {
982 return objects->error;
986 talloc_free(ext_res);
988 /* Save our updated prefixMap and check the schema is good. */
989 if (working_schema) {
990 struct ldb_result *ext_res_2;
992 werr = dsdb_write_prefixes_from_schema_to_ldb(working_schema,
995 if (!W_ERROR_IS_OK(werr)) {
996 /* restore previous schema */
997 if (used_global_schema) {
998 dsdb_set_global_schema(ldb);
999 } else if (cur_schema ) {
1000 dsdb_reference_schema(ldb,
1002 SCHEMA_MEMORY_ONLY);
1004 DEBUG(0,("Failed to save updated prefixMap: %s\n",
1006 ldb_transaction_cancel(ldb);
1007 TALLOC_FREE(tmp_ctx);
1012 * Use dsdb_schema_from_db through dsdb extended to check we
1013 * can load the schema currently sitting in the transaction.
1014 * We need this check because someone might have written to
1015 * the schema or prefixMap before we started the transaction,
1016 * which may have caused corruption.
1018 ret = ldb_extended(ldb, DSDB_EXTENDED_SCHEMA_LOAD,
1021 if (ret != LDB_SUCCESS) {
1022 if (used_global_schema) {
1023 dsdb_set_global_schema(ldb);
1024 } else if (cur_schema) {
1025 dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
1027 DEBUG(0,("Corrupt schema write attempt detected, "
1028 "aborting schema modification operation.\n"
1029 "This probably happened due to bad timing of "
1030 "another schema edit: %s (%s)\n",
1032 ldb_strerror(ret)));
1033 ldb_transaction_cancel(ldb);
1034 TALLOC_FREE(tmp_ctx);
1039 ret = ldb_transaction_prepare_commit(ldb);
1040 if (ret != LDB_SUCCESS) {
1041 /* restore previous schema */
1042 if (used_global_schema) {
1043 dsdb_set_global_schema(ldb);
1044 } else if (cur_schema ) {
1045 dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
1047 DBG_ERR(" Failed to prepare commit of transaction: %s (%s)\n",
1050 TALLOC_FREE(tmp_ctx);
1054 ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num2, NULL);
1055 if (ret != LDB_SUCCESS) {
1056 /* restore previous schema */
1057 if (used_global_schema) {
1058 dsdb_set_global_schema(ldb);
1059 } else if (cur_schema ) {
1060 dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
1062 DEBUG(0,(__location__ " Failed to load partition uSN\n"));
1063 ldb_transaction_cancel(ldb);
1064 TALLOC_FREE(tmp_ctx);
1068 ret = ldb_transaction_commit(ldb);
1069 if (ret != LDB_SUCCESS) {
1070 /* restore previous schema */
1071 if (used_global_schema) {
1072 dsdb_set_global_schema(ldb);
1073 } else if (cur_schema ) {
1074 dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
1076 DEBUG(0,(__location__ " Failed to commit transaction\n"));
1077 TALLOC_FREE(tmp_ctx);
1081 if (seq_num1 > *notify_uSN) {
1083 * A notify was already required before
1084 * the current transaction.
1086 } else if (objects->originating_updates) {
1088 * Applying the replicated changes
1089 * required originating updates,
1090 * so a notify is required.
1094 * There's no need to notify the
1095 * server about the change we just from it.
1097 *notify_uSN = seq_num2;
1101 * Reset the Schema used by ldb. This will lead to
1102 * a schema cache being refreshed from database.
1104 if (working_schema) {
1105 /* Reload the schema */
1106 new_schema = dsdb_get_schema(ldb, tmp_ctx);
1108 * If dsdb_get_schema() fails, we just fall back
1109 * to what we had. However, the database is probably
1110 * unable to operate for other users from this
1112 if (new_schema == NULL || new_schema == working_schema) {
1113 DBG_ERR("Failed to re-load schema after commit of "
1114 "transaction (working: %p/%"PRIu64", new: "
1115 "%p/%"PRIu64")\n", new_schema,
1116 new_schema != NULL ?
1117 new_schema->metadata_usn : 0,
1118 working_schema, working_schema->metadata_usn);
1119 dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
1120 if (used_global_schema) {
1121 dsdb_set_global_schema(ldb);
1123 TALLOC_FREE(tmp_ctx);
1124 return WERR_INTERNAL_ERROR;
1125 } else if (used_global_schema) {
1126 dsdb_make_schema_global(ldb, new_schema);
1130 DEBUG(2,("Replicated %u objects (%u linked attributes) for %s\n",
1131 objects->num_objects, objects->linked_attributes_count,
1132 ldb_dn_get_linearized(objects->partition_dn)));
1134 TALLOC_FREE(tmp_ctx);
1138 static WERROR dsdb_origin_object_convert(struct ldb_context *ldb,
1139 const struct dsdb_schema *schema,
1140 const struct drsuapi_DsReplicaObjectListItem *in,
1141 TALLOC_CTX *mem_ctx,
1142 struct ldb_message **_msg)
1146 struct ldb_message *msg;
1148 if (!in->object.identifier) {
1152 if (!in->object.identifier->dn || !in->object.identifier->dn[0]) {
1156 msg = ldb_msg_new(mem_ctx);
1157 W_ERROR_HAVE_NO_MEMORY(msg);
1159 msg->dn = ldb_dn_new(msg, ldb, in->object.identifier->dn);
1160 W_ERROR_HAVE_NO_MEMORY(msg->dn);
1162 msg->num_elements = in->object.attribute_ctr.num_attributes;
1163 msg->elements = talloc_array(msg, struct ldb_message_element,
1165 W_ERROR_HAVE_NO_MEMORY(msg->elements);
1167 for (i=0; i < msg->num_elements; i++) {
1168 struct drsuapi_DsReplicaAttribute *a;
1169 struct ldb_message_element *e;
1171 a = &in->object.attribute_ctr.attributes[i];
1172 e = &msg->elements[i];
1174 status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, schema->prefixmap,
1175 a, msg->elements, e, NULL);
1176 W_ERROR_NOT_OK_RETURN(status);
1185 WERROR dsdb_origin_objects_commit(struct ldb_context *ldb,
1186 TALLOC_CTX *mem_ctx,
1187 const struct drsuapi_DsReplicaObjectListItem *first_object,
1189 uint32_t dsdb_repl_flags,
1190 struct drsuapi_DsReplicaObjectIdentifier2 **_ids)
1193 const struct dsdb_schema *schema;
1194 const struct drsuapi_DsReplicaObjectListItem *cur;
1195 struct ldb_message **objects;
1196 struct drsuapi_DsReplicaObjectIdentifier2 *ids;
1198 uint32_t num_objects = 0;
1199 const char * const attrs[] = {
1204 struct ldb_result *res;
1207 for (cur = first_object; cur; cur = cur->next_object) {
1211 if (num_objects == 0) {
1215 ret = ldb_transaction_start(ldb);
1216 if (ret != LDB_SUCCESS) {
1217 return WERR_DS_INTERNAL_FAILURE;
1220 objects = talloc_array(mem_ctx, struct ldb_message *,
1222 if (objects == NULL) {
1223 status = WERR_NOT_ENOUGH_MEMORY;
1227 schema = dsdb_get_schema(ldb, objects);
1229 return WERR_DS_SCHEMA_NOT_LOADED;
1232 for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
1233 status = dsdb_origin_object_convert(ldb, schema, cur,
1234 objects, &objects[i]);
1235 if (!W_ERROR_IS_OK(status)) {
1240 ids = talloc_array(mem_ctx,
1241 struct drsuapi_DsReplicaObjectIdentifier2,
1244 status = WERR_NOT_ENOUGH_MEMORY;
1248 if (dsdb_repl_flags & DSDB_REPL_FLAG_ADD_NCNAME) {
1249 /* check for possible NC creation */
1250 for (i=0; i < num_objects; i++) {
1251 struct ldb_message *msg = objects[i];
1252 struct ldb_message_element *el;
1253 struct ldb_dn *nc_dn;
1255 if (ldb_msg_check_string_attribute(msg, "objectClass", "crossRef") == 0) {
1258 el = ldb_msg_find_element(msg, "nCName");
1259 if (el == NULL || el->num_values != 1) {
1262 nc_dn = ldb_dn_from_ldb_val(objects, ldb, &el->values[0]);
1263 if (!ldb_dn_validate(nc_dn)) {
1266 ret = dsdb_create_partial_replica_NC(ldb, nc_dn);
1267 if (ret != LDB_SUCCESS) {
1268 status = WERR_DS_INTERNAL_FAILURE;
1274 for (i=0; i < num_objects; i++) {
1275 struct dom_sid *sid = NULL;
1276 struct ldb_request *add_req;
1278 DEBUG(6,(__location__ ": adding %s\n",
1279 ldb_dn_get_linearized(objects[i]->dn)));
1281 ret = ldb_build_add_req(&add_req,
1287 ldb_op_default_callback,
1289 if (ret != LDB_SUCCESS) {
1290 status = WERR_DS_INTERNAL_FAILURE;
1294 ret = ldb_request_add_control(add_req, LDB_CONTROL_RELAX_OID, true, NULL);
1295 if (ret != LDB_SUCCESS) {
1296 status = WERR_DS_INTERNAL_FAILURE;
1300 ret = ldb_request(ldb, add_req);
1301 if (ret == LDB_SUCCESS) {
1302 ret = ldb_wait(add_req->handle, LDB_WAIT_ALL);
1304 if (ret != LDB_SUCCESS) {
1305 DEBUG(0,(__location__ ": Failed add of %s - %s\n",
1306 ldb_dn_get_linearized(objects[i]->dn), ldb_errstring(ldb)));
1307 status = WERR_DS_INTERNAL_FAILURE;
1311 talloc_free(add_req);
1313 ret = ldb_search(ldb, objects, &res, objects[i]->dn,
1314 LDB_SCOPE_BASE, attrs,
1316 if (ret != LDB_SUCCESS) {
1317 status = WERR_DS_INTERNAL_FAILURE;
1320 ids[i].guid = samdb_result_guid(res->msgs[0], "objectGUID");
1321 sid = samdb_result_dom_sid(objects, res->msgs[0], "objectSid");
1325 ZERO_STRUCT(ids[i].sid);
1329 ret = ldb_transaction_commit(ldb);
1330 if (ret != LDB_SUCCESS) {
1331 return WERR_DS_INTERNAL_FAILURE;
1334 talloc_free(objects);
1336 *_num = num_objects;
1341 talloc_free(objects);
1342 ldb_transaction_cancel(ldb);