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
, struct schema_list
);
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
,
195 schema_list_item
, &object
);
196 if (!W_ERROR_IS_OK(werr
)) {
197 DEBUG(4,("debug: Failed to convert schema "
198 "object %s into ldb msg, "
199 "will try during next loop\n",
200 cur
->object
.identifier
->dn
));
205 * Convert the schema from ldb_message format
206 * (OIDs as OID strings) into schema, using
207 * the remote prefixMap
209 * It's not likely, but possible to get the
210 * same object twice and we should keep
213 werr
= dsdb_schema_set_el_from_ldb_msg_dups(ldb
,
217 if (!W_ERROR_IS_OK(werr
)) {
218 DEBUG(4,("debug: failed to convert "
219 "object %s into a schema element, "
220 "will try during next loop: %s\n",
221 ldb_dn_get_linearized(object
.msg
->dn
),
225 DEBUG(8,("Converted object %s into a schema element\n",
226 ldb_dn_get_linearized(object
.msg
->dn
)));
227 DLIST_REMOVE(schema_list
, schema_list_item
);
228 TALLOC_FREE(schema_list_item
);
229 converted_obj_count
++;
234 DEBUG(4,("Schema load pass %d: converted %d, %d of %d objects left to be converted.\n",
235 pass_no
, converted_obj_count
, failed_obj_count
, object_count
));
237 /* check if we converted any objects in this pass */
238 if (converted_obj_count
== 0) {
239 DEBUG(0,("Can't continue Schema load: "
240 "didn't manage to convert any objects: "
241 "all %d remaining of %d objects "
242 "failed to convert\n",
243 failed_obj_count
, object_count
));
244 return WERR_INTERNAL_ERROR
;
248 * Don't try to load the schema if there is missing object
249 * _and_ we are on the first pass as some critical objects
252 if (failed_obj_count
== 0 || pass_no
> cycle_before_switching
) {
253 /* prepare for another cycle */
254 working_schema
= resulting_schema
;
256 ret
= dsdb_setup_sorted_accessors(ldb
, working_schema
);
257 if (LDB_SUCCESS
!= ret
) {
258 DEBUG(0,("Failed to create schema-cache indexes!\n"));
259 return WERR_INTERNAL_ERROR
;
269 * Multi-pass working schema creation
271 * - shallow copy initial schema supplied
272 * - create a working schema in multiple passes
273 * until all objects are resolved
274 * Working schema is a schema with Attributes, Classes
275 * and indexes, but w/o subClassOf, possibleSupperiors etc.
276 * It is to be used just us cache for converting attribute values.
278 WERROR
dsdb_repl_make_working_schema(struct ldb_context
*ldb
,
279 const struct dsdb_schema
*initial_schema
,
280 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
,
281 uint32_t object_count
,
282 const struct drsuapi_DsReplicaObjectListItemEx
*first_object
,
283 const DATA_BLOB
*gensec_skey
,
285 struct dsdb_schema
**_schema_out
)
288 struct dsdb_schema_prefixmap
*pfm_remote
;
289 struct dsdb_schema
*working_schema
;
291 /* make a copy of the iniatial_scheam so we don't mess with it */
292 working_schema
= dsdb_schema_copy_shallow(mem_ctx
, ldb
, initial_schema
);
293 if (!working_schema
) {
294 DEBUG(0,(__location__
": schema copy failed!\n"));
298 /* we are going to need remote prefixMap for decoding */
299 werr
= dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr
, true,
300 mem_ctx
, &pfm_remote
, NULL
);
301 if (!W_ERROR_IS_OK(werr
)) {
302 DEBUG(0,(__location__
": Failed to decode remote prefixMap: %s",
307 werr
= dsdb_repl_resolve_working_schema(ldb
, mem_ctx
,
309 0, /* cycle_before_switching */
314 if (!W_ERROR_IS_OK(werr
)) {
315 DEBUG(0, ("%s: dsdb_repl_resolve_working_schema() failed: %s",
316 __location__
, win_errstr(werr
)));
320 *_schema_out
= working_schema
;
325 static bool dsdb_attid_in_list(const uint32_t attid_list
[], uint32_t attid
)
331 for (cur
= attid_list
; *cur
!= DRSUAPI_ATTID_INVALID
; cur
++) {
339 WERROR
dsdb_convert_object_ex(struct ldb_context
*ldb
,
340 const struct dsdb_schema
*schema
,
341 const struct dsdb_schema_prefixmap
*pfm_remote
,
342 const struct drsuapi_DsReplicaObjectListItemEx
*in
,
343 const DATA_BLOB
*gensec_skey
,
344 const uint32_t *ignore_attids
,
345 uint32_t dsdb_repl_flags
,
347 struct dsdb_extended_replicated_object
*out
)
352 struct ldb_message
*msg
;
353 struct replPropertyMetaDataBlob
*md
;
355 struct ldb_message_element
*instanceType_e
= NULL
;
356 struct ldb_val guid_value
;
357 struct ldb_val parent_guid_value
;
358 NTTIME whenChanged
= 0;
359 time_t whenChanged_t
;
360 const char *whenChanged_s
;
361 struct drsuapi_DsReplicaAttribute
*name_a
= NULL
;
362 struct drsuapi_DsReplicaMetaData
*name_d
= NULL
;
363 struct replPropertyMetaData1
*rdn_m
= NULL
;
364 struct dom_sid
*sid
= NULL
;
369 if (!in
->object
.identifier
) {
373 if (!in
->object
.identifier
->dn
|| !in
->object
.identifier
->dn
[0]) {
377 if (in
->object
.attribute_ctr
.num_attributes
!= 0 && !in
->meta_data_ctr
) {
381 if (in
->object
.attribute_ctr
.num_attributes
!= in
->meta_data_ctr
->count
) {
385 sid
= &in
->object
.identifier
->sid
;
386 if (sid
->num_auths
> 0) {
387 rid
= sid
->sub_auths
[sid
->num_auths
- 1];
390 msg
= ldb_msg_new(mem_ctx
);
391 W_ERROR_HAVE_NO_MEMORY(msg
);
393 msg
->dn
= ldb_dn_new(msg
, ldb
, in
->object
.identifier
->dn
);
394 W_ERROR_HAVE_NO_MEMORY(msg
->dn
);
396 msg
->num_elements
= in
->object
.attribute_ctr
.num_attributes
;
397 msg
->elements
= talloc_array(msg
, struct ldb_message_element
,
398 msg
->num_elements
+ 1); /* +1 because of the RDN attribute */
399 W_ERROR_HAVE_NO_MEMORY(msg
->elements
);
401 md
= talloc(mem_ctx
, struct replPropertyMetaDataBlob
);
402 W_ERROR_HAVE_NO_MEMORY(md
);
406 md
->ctr
.ctr1
.count
= in
->meta_data_ctr
->count
;
407 md
->ctr
.ctr1
.reserved
= 0;
408 md
->ctr
.ctr1
.array
= talloc_array(mem_ctx
,
409 struct replPropertyMetaData1
,
410 md
->ctr
.ctr1
.count
+ 1); /* +1 because of the RDN attribute */
411 W_ERROR_HAVE_NO_MEMORY(md
->ctr
.ctr1
.array
);
413 for (i
=0, attr_count
=0; i
< in
->meta_data_ctr
->count
; i
++, attr_count
++) {
414 struct drsuapi_DsReplicaAttribute
*a
;
415 struct drsuapi_DsReplicaMetaData
*d
;
416 struct replPropertyMetaData1
*m
;
417 struct ldb_message_element
*e
;
420 a
= &in
->object
.attribute_ctr
.attributes
[i
];
421 d
= &in
->meta_data_ctr
->meta_data
[i
];
422 m
= &md
->ctr
.ctr1
.array
[attr_count
];
423 e
= &msg
->elements
[attr_count
];
425 if (dsdb_attid_in_list(ignore_attids
, a
->attid
)) {
430 if (GUID_all_zero(&d
->originating_invocation_id
)) {
431 status
= WERR_DS_SRC_GUID_MISMATCH
;
432 DEBUG(0, ("Refusing replication of object containing invalid zero invocationID on attribute %d of %s: %s\n",
434 ldb_dn_get_linearized(msg
->dn
),
435 win_errstr(status
)));
439 if (a
->attid
== DRSUAPI_ATTID_instanceType
) {
440 if (instanceType_e
!= NULL
) {
446 for (j
=0; j
<a
->value_ctr
.num_values
; j
++) {
447 status
= drsuapi_decrypt_attribute(a
->value_ctr
.values
[j
].blob
, gensec_skey
, rid
, a
);
448 W_ERROR_NOT_OK_RETURN(status
);
451 status
= dsdb_attribute_drsuapi_to_ldb(ldb
, schema
, pfm_remote
,
452 a
, msg
->elements
, e
);
453 W_ERROR_NOT_OK_RETURN(status
);
456 m
->version
= d
->version
;
457 m
->originating_change_time
= d
->originating_change_time
;
458 m
->originating_invocation_id
= d
->originating_invocation_id
;
459 m
->originating_usn
= d
->originating_usn
;
462 if (d
->originating_change_time
> whenChanged
) {
463 whenChanged
= d
->originating_change_time
;
466 if (a
->attid
== DRSUAPI_ATTID_name
) {
472 msg
->num_elements
= attr_count
;
473 md
->ctr
.ctr1
.count
= attr_count
;
475 rdn_m
= &md
->ctr
.ctr1
.array
[md
->ctr
.ctr1
.count
];
479 struct ldb_message_element
*el
;
480 const char *rdn_name
= NULL
;
481 const struct ldb_val
*rdn_value
= NULL
;
482 const struct dsdb_attribute
*rdn_attr
= NULL
;
486 * We only need the schema calls for the RDN in this
487 * codepath, and by doing this we avoid needing to
488 * have the dsdb_attribute_by_lDAPDisplayName accessor
489 * working during the schema load.
491 rdn_name
= ldb_dn_get_rdn_name(msg
->dn
);
492 rdn_attr
= dsdb_attribute_by_lDAPDisplayName(schema
, rdn_name
);
496 rdn_attid
= rdn_attr
->attributeID_id
;
497 rdn_value
= ldb_dn_get_rdn_val(msg
->dn
);
499 el
= ldb_msg_find_element(msg
, rdn_attr
->lDAPDisplayName
);
501 ret
= ldb_msg_add_value(msg
, rdn_attr
->lDAPDisplayName
, rdn_value
, NULL
);
502 if (ret
!= LDB_SUCCESS
) {
506 if (el
->num_values
!= 1) {
507 DEBUG(0,(__location__
": Unexpected num_values=%u\n",
511 if (!ldb_val_equal_exact(&el
->values
[0], rdn_value
)) {
512 DEBUG(0,(__location__
": RDN value changed? '%*.*s' '%*.*s'\n",
513 (int)el
->values
[0].length
, (int)el
->values
[0].length
, el
->values
[0].data
,
514 (int)rdn_value
->length
, (int)rdn_value
->length
, rdn_value
->data
));
519 rdn_m
->attid
= rdn_attid
;
520 rdn_m
->version
= name_d
->version
;
521 rdn_m
->originating_change_time
= name_d
->originating_change_time
;
522 rdn_m
->originating_invocation_id
= name_d
->originating_invocation_id
;
523 rdn_m
->originating_usn
= name_d
->originating_usn
;
524 rdn_m
->local_usn
= 0;
525 md
->ctr
.ctr1
.count
++;
529 if (instanceType_e
== NULL
) {
533 instanceType
= ldb_msg_find_attr_as_int(msg
, "instanceType", 0);
534 if (dsdb_repl_flags
& DSDB_REPL_FLAG_PARTIAL_REPLICA
) {
535 /* the instanceType type for partial_replica
536 replication is sent via DRS with TYPE_WRITE set, but
537 must be used on the client with TYPE_WRITE removed
539 if (instanceType
& INSTANCE_TYPE_WRITE
) {
541 * Make sure we do not change the order
545 * instanceType_e->num_values = 0
547 * ldb_msg_remove_attr(msg, "instanceType");
549 struct ldb_message_element
*e
;
551 e
= ldb_msg_find_element(msg
, "instanceType");
552 if (e
!= instanceType_e
) {
553 DEBUG(0,("instanceType_e[%p] changed to e[%p]\n",
558 instanceType_e
->num_values
= 0;
560 instanceType
&= ~INSTANCE_TYPE_WRITE
;
561 if (ldb_msg_add_fmt(msg
, "instanceType", "%d", instanceType
) != LDB_SUCCESS
) {
562 return WERR_INTERNAL_ERROR
;
566 if (!(instanceType
& INSTANCE_TYPE_WRITE
)) {
567 DEBUG(0, ("Refusing to replicate %s from a read-only repilca into a read-write replica!\n",
568 ldb_dn_get_linearized(msg
->dn
)));
569 return WERR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA
;
573 whenChanged_t
= nt_time_to_unix(whenChanged
);
574 whenChanged_s
= ldb_timestring(msg
, whenChanged_t
);
575 W_ERROR_HAVE_NO_MEMORY(whenChanged_s
);
577 nt_status
= GUID_to_ndr_blob(&in
->object
.identifier
->guid
, msg
, &guid_value
);
578 if (!NT_STATUS_IS_OK(nt_status
)) {
579 return ntstatus_to_werror(nt_status
);
582 if (in
->parent_object_guid
) {
583 nt_status
= GUID_to_ndr_blob(in
->parent_object_guid
, msg
, &parent_guid_value
);
584 if (!NT_STATUS_IS_OK(nt_status
)) {
585 return ntstatus_to_werror(nt_status
);
588 parent_guid_value
= data_blob_null
;
592 out
->guid_value
= guid_value
;
593 out
->parent_guid_value
= parent_guid_value
;
594 out
->when_changed
= whenChanged_s
;
599 WERROR
dsdb_replicated_objects_convert(struct ldb_context
*ldb
,
600 const struct dsdb_schema
*schema
,
601 const char *partition_dn_str
,
602 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
,
603 uint32_t object_count
,
604 const struct drsuapi_DsReplicaObjectListItemEx
*first_object
,
605 uint32_t linked_attributes_count
,
606 const struct drsuapi_DsReplicaLinkedAttribute
*linked_attributes
,
607 const struct repsFromTo1
*source_dsa
,
608 const struct drsuapi_DsReplicaCursor2CtrEx
*uptodateness_vector
,
609 const DATA_BLOB
*gensec_skey
,
610 uint32_t dsdb_repl_flags
,
612 struct dsdb_extended_replicated_objects
**objects
)
615 struct ldb_dn
*partition_dn
;
616 struct dsdb_schema_prefixmap
*pfm_remote
;
617 struct dsdb_extended_replicated_objects
*out
;
618 const struct drsuapi_DsReplicaObjectListItemEx
*cur
;
621 out
= talloc_zero(mem_ctx
, struct dsdb_extended_replicated_objects
);
622 W_ERROR_HAVE_NO_MEMORY(out
);
623 out
->version
= DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION
;
624 out
->dsdb_repl_flags
= dsdb_repl_flags
;
627 * Ensure schema is kept valid for as long as 'out'
628 * which may contain pointers to it
630 schema
= talloc_reference(out
, schema
);
631 W_ERROR_HAVE_NO_MEMORY(schema
);
633 partition_dn
= ldb_dn_new(out
, ldb
, partition_dn_str
);
634 W_ERROR_HAVE_NO_MEMORY_AND_FREE(partition_dn
, out
);
636 status
= dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr
, true,
637 out
, &pfm_remote
, NULL
);
638 if (!W_ERROR_IS_OK(status
)) {
639 DEBUG(0,(__location__
": Failed to decode remote prefixMap: %s",
640 win_errstr(status
)));
645 if (ldb_dn_compare(partition_dn
, ldb_get_schema_basedn(ldb
)) != 0) {
647 * check for schema changes in case
648 * we are not replicating Schema NC
650 status
= dsdb_schema_info_cmp(schema
, mapping_ctr
);
651 if (!W_ERROR_IS_OK(status
)) {
652 DEBUG(1,("Remote schema has changed while replicating %s\n",
659 out
->partition_dn
= partition_dn
;
661 out
->source_dsa
= source_dsa
;
662 out
->uptodateness_vector
= uptodateness_vector
;
664 out
->num_objects
= object_count
;
665 out
->objects
= talloc_array(out
,
666 struct dsdb_extended_replicated_object
,
668 W_ERROR_HAVE_NO_MEMORY_AND_FREE(out
->objects
, out
);
670 /* pass the linked attributes down to the repl_meta_data
672 out
->linked_attributes_count
= linked_attributes_count
;
673 out
->linked_attributes
= linked_attributes
;
675 for (i
=0, cur
= first_object
; cur
; cur
= cur
->next_object
, i
++) {
676 if (i
== out
->num_objects
) {
681 status
= dsdb_convert_object_ex(ldb
, schema
, pfm_remote
,
685 out
->objects
, &out
->objects
[i
]);
686 if (!W_ERROR_IS_OK(status
)) {
688 DEBUG(0,("Failed to convert object %s: %s\n",
689 cur
->object
.identifier
->dn
,
690 win_errstr(status
)));
694 if (i
!= out
->num_objects
) {
699 /* free pfm_remote, we won't need it anymore */
700 talloc_free(pfm_remote
);
707 * Commits a list of replicated objects.
709 * @param working_schema dsdb_schema to be used for resolving
710 * Classes/Attributes during Schema replication. If not NULL,
711 * it will be set on ldb and used while committing replicated objects
713 WERROR
dsdb_replicated_objects_commit(struct ldb_context
*ldb
,
714 struct dsdb_schema
*working_schema
,
715 struct dsdb_extended_replicated_objects
*objects
,
716 uint64_t *notify_uSN
)
719 struct ldb_result
*ext_res
;
720 struct dsdb_schema
*cur_schema
= NULL
;
721 struct dsdb_schema
*new_schema
= NULL
;
723 uint64_t seq_num1
, seq_num2
;
724 bool used_global_schema
= false;
726 TALLOC_CTX
*tmp_ctx
= talloc_new(objects
);
728 DEBUG(0,("Failed to start talloc\n"));
732 /* TODO: handle linked attributes */
734 /* wrap the extended operation in a transaction
735 See [MS-DRSR] 3.3.2 Transactions
737 ret
= ldb_transaction_start(ldb
);
738 if (ret
!= LDB_SUCCESS
) {
739 DEBUG(0,(__location__
" Failed to start transaction\n"));
743 ret
= dsdb_load_partition_usn(ldb
, objects
->partition_dn
, &seq_num1
, NULL
);
744 if (ret
!= LDB_SUCCESS
) {
745 DEBUG(0,(__location__
" Failed to load partition uSN\n"));
746 ldb_transaction_cancel(ldb
);
747 TALLOC_FREE(tmp_ctx
);
752 * Set working_schema for ldb in case we are replicating from Schema NC.
753 * Schema won't be reloaded during Replicated Objects commit, as it is
754 * done in a transaction. So we need some way to search for newly
755 * added Classes and Attributes
757 if (working_schema
) {
758 /* store current schema so we can fall back in case of failure */
759 cur_schema
= dsdb_get_schema(ldb
, tmp_ctx
);
760 used_global_schema
= dsdb_uses_global_schema(ldb
);
762 ret
= dsdb_reference_schema(ldb
, working_schema
, false);
763 if (ret
!= LDB_SUCCESS
) {
764 DEBUG(0,(__location__
"Failed to reference working schema - %s\n",
766 /* TODO: Map LDB Error to NTSTATUS? */
767 ldb_transaction_cancel(ldb
);
768 TALLOC_FREE(tmp_ctx
);
769 return WERR_INTERNAL_ERROR
;
773 ret
= ldb_extended(ldb
, DSDB_EXTENDED_REPLICATED_OBJECTS_OID
, objects
, &ext_res
);
774 if (ret
!= LDB_SUCCESS
) {
775 /* restore previous schema */
776 if (used_global_schema
) {
777 dsdb_set_global_schema(ldb
);
778 } else if (cur_schema
) {
779 dsdb_reference_schema(ldb
, cur_schema
, false);
782 DEBUG(0,("Failed to apply records: %s: %s\n",
783 ldb_errstring(ldb
), ldb_strerror(ret
)));
784 ldb_transaction_cancel(ldb
);
785 TALLOC_FREE(tmp_ctx
);
788 talloc_free(ext_res
);
790 /* Save our updated prefixMap */
791 if (working_schema
) {
792 werr
= dsdb_write_prefixes_from_schema_to_ldb(working_schema
,
795 if (!W_ERROR_IS_OK(werr
)) {
796 /* restore previous schema */
797 if (used_global_schema
) {
798 dsdb_set_global_schema(ldb
);
799 } else if (cur_schema
) {
800 dsdb_reference_schema(ldb
, cur_schema
, false);
802 DEBUG(0,("Failed to save updated prefixMap: %s\n",
804 TALLOC_FREE(tmp_ctx
);
809 ret
= ldb_transaction_prepare_commit(ldb
);
810 if (ret
!= LDB_SUCCESS
) {
811 /* restore previous schema */
812 if (used_global_schema
) {
813 dsdb_set_global_schema(ldb
);
814 } else if (cur_schema
) {
815 dsdb_reference_schema(ldb
, cur_schema
, false);
817 DEBUG(0,(__location__
" Failed to prepare commit of transaction: %s\n",
818 ldb_errstring(ldb
)));
819 TALLOC_FREE(tmp_ctx
);
823 ret
= dsdb_load_partition_usn(ldb
, objects
->partition_dn
, &seq_num2
, NULL
);
824 if (ret
!= LDB_SUCCESS
) {
825 /* restore previous schema */
826 if (used_global_schema
) {
827 dsdb_set_global_schema(ldb
);
828 } else if (cur_schema
) {
829 dsdb_reference_schema(ldb
, cur_schema
, false);
831 DEBUG(0,(__location__
" Failed to load partition uSN\n"));
832 ldb_transaction_cancel(ldb
);
833 TALLOC_FREE(tmp_ctx
);
837 ret
= ldb_transaction_commit(ldb
);
838 if (ret
!= LDB_SUCCESS
) {
839 /* restore previous schema */
840 if (used_global_schema
) {
841 dsdb_set_global_schema(ldb
);
842 } else if (cur_schema
) {
843 dsdb_reference_schema(ldb
, cur_schema
, false);
845 DEBUG(0,(__location__
" Failed to commit transaction\n"));
846 TALLOC_FREE(tmp_ctx
);
850 /* if this replication partner didn't need to be notified
851 before this transaction then it still doesn't need to be
852 notified, as the changes came from this server */
853 if (seq_num2
> seq_num1
&& seq_num1
<= *notify_uSN
) {
854 *notify_uSN
= seq_num2
;
858 * Reset the Schema used by ldb. This will lead to
859 * a schema cache being refreshed from database.
861 if (working_schema
) {
862 struct ldb_message
*msg
;
863 struct ldb_request
*req
;
866 working_schema
->last_refresh
= 0;
867 new_schema
= dsdb_get_schema(ldb
, tmp_ctx
);
869 * If dsdb_get_schema() fails, we just fall back
870 * to what we had. However, the database is probably
871 * unable to operate for other users from this
873 if (new_schema
&& used_global_schema
) {
874 dsdb_make_schema_global(ldb
, new_schema
);
875 } else if (used_global_schema
) {
876 DEBUG(0,("Failed to re-load schema after commit of transaction\n"));
877 dsdb_set_global_schema(ldb
);
878 TALLOC_FREE(tmp_ctx
);
879 return WERR_INTERNAL_ERROR
;
881 DEBUG(0,("Failed to re-load schema after commit of transaction\n"));
882 dsdb_reference_schema(ldb
, cur_schema
, false);
883 TALLOC_FREE(tmp_ctx
);
884 return WERR_INTERNAL_ERROR
;
886 msg
= ldb_msg_new(tmp_ctx
);
888 TALLOC_FREE(tmp_ctx
);
891 msg
->dn
= ldb_dn_new(msg
, ldb
, "");
892 if (msg
->dn
== NULL
) {
893 TALLOC_FREE(tmp_ctx
);
897 ret
= ldb_msg_add_string(msg
, "schemaUpdateNow", "1");
898 if (ret
!= LDB_SUCCESS
) {
899 TALLOC_FREE(tmp_ctx
);
900 return WERR_INTERNAL_ERROR
;
903 ret
= ldb_build_mod_req(&req
, ldb
, objects
,
907 ldb_op_default_callback
,
910 if (ret
!= LDB_SUCCESS
) {
911 TALLOC_FREE(tmp_ctx
);
912 return WERR_DS_DRA_INTERNAL_ERROR
;
915 ret
= ldb_transaction_start(ldb
);
916 if (ret
!= LDB_SUCCESS
) {
917 TALLOC_FREE(tmp_ctx
);
918 DEBUG(0, ("Autotransaction start failed\n"));
919 return WERR_DS_DRA_INTERNAL_ERROR
;
922 ret
= ldb_request(ldb
, req
);
923 if (ret
== LDB_SUCCESS
) {
924 ret
= ldb_wait(req
->handle
, LDB_WAIT_ALL
);
927 if (ret
== LDB_SUCCESS
) {
928 ret
= ldb_transaction_commit(ldb
);
930 DEBUG(0, ("Schema update now failed: %s\n",
931 ldb_errstring(ldb
)));
932 ldb_transaction_cancel(ldb
);
935 if (ret
!= LDB_SUCCESS
) {
936 DEBUG(0, ("Commit failed: %s\n", ldb_errstring(ldb
)));
937 TALLOC_FREE(tmp_ctx
);
938 return WERR_DS_INTERNAL_FAILURE
;
942 DEBUG(2,("Replicated %u objects (%u linked attributes) for %s\n",
943 objects
->num_objects
, objects
->linked_attributes_count
,
944 ldb_dn_get_linearized(objects
->partition_dn
)));
946 TALLOC_FREE(tmp_ctx
);
950 static WERROR
dsdb_origin_object_convert(struct ldb_context
*ldb
,
951 const struct dsdb_schema
*schema
,
952 const struct drsuapi_DsReplicaObjectListItem
*in
,
954 struct ldb_message
**_msg
)
958 struct ldb_message
*msg
;
960 if (!in
->object
.identifier
) {
964 if (!in
->object
.identifier
->dn
|| !in
->object
.identifier
->dn
[0]) {
968 msg
= ldb_msg_new(mem_ctx
);
969 W_ERROR_HAVE_NO_MEMORY(msg
);
971 msg
->dn
= ldb_dn_new(msg
, ldb
, in
->object
.identifier
->dn
);
972 W_ERROR_HAVE_NO_MEMORY(msg
->dn
);
974 msg
->num_elements
= in
->object
.attribute_ctr
.num_attributes
;
975 msg
->elements
= talloc_array(msg
, struct ldb_message_element
,
977 W_ERROR_HAVE_NO_MEMORY(msg
->elements
);
979 for (i
=0; i
< msg
->num_elements
; i
++) {
980 struct drsuapi_DsReplicaAttribute
*a
;
981 struct ldb_message_element
*e
;
983 a
= &in
->object
.attribute_ctr
.attributes
[i
];
984 e
= &msg
->elements
[i
];
986 status
= dsdb_attribute_drsuapi_to_ldb(ldb
, schema
, schema
->prefixmap
,
987 a
, msg
->elements
, e
);
988 W_ERROR_NOT_OK_RETURN(status
);
997 WERROR
dsdb_origin_objects_commit(struct ldb_context
*ldb
,
999 const struct drsuapi_DsReplicaObjectListItem
*first_object
,
1001 uint32_t dsdb_repl_flags
,
1002 struct drsuapi_DsReplicaObjectIdentifier2
**_ids
)
1005 const struct dsdb_schema
*schema
;
1006 const struct drsuapi_DsReplicaObjectListItem
*cur
;
1007 struct ldb_message
**objects
;
1008 struct drsuapi_DsReplicaObjectIdentifier2
*ids
;
1010 uint32_t num_objects
= 0;
1011 const char * const attrs
[] = {
1016 struct ldb_result
*res
;
1019 for (cur
= first_object
; cur
; cur
= cur
->next_object
) {
1023 if (num_objects
== 0) {
1027 ret
= ldb_transaction_start(ldb
);
1028 if (ret
!= LDB_SUCCESS
) {
1029 return WERR_DS_INTERNAL_FAILURE
;
1032 objects
= talloc_array(mem_ctx
, struct ldb_message
*,
1034 if (objects
== NULL
) {
1035 status
= WERR_NOMEM
;
1039 schema
= dsdb_get_schema(ldb
, objects
);
1041 return WERR_DS_SCHEMA_NOT_LOADED
;
1044 for (i
=0, cur
= first_object
; cur
; cur
= cur
->next_object
, i
++) {
1045 status
= dsdb_origin_object_convert(ldb
, schema
, cur
,
1046 objects
, &objects
[i
]);
1047 if (!W_ERROR_IS_OK(status
)) {
1052 ids
= talloc_array(mem_ctx
,
1053 struct drsuapi_DsReplicaObjectIdentifier2
,
1056 status
= WERR_NOMEM
;
1060 if (dsdb_repl_flags
& DSDB_REPL_FLAG_ADD_NCNAME
) {
1061 /* check for possible NC creation */
1062 for (i
=0; i
< num_objects
; i
++) {
1063 struct ldb_message
*msg
= objects
[i
];
1064 struct ldb_message_element
*el
;
1065 struct ldb_dn
*nc_dn
;
1067 if (ldb_msg_check_string_attribute(msg
, "objectClass", "crossRef") == 0) {
1070 el
= ldb_msg_find_element(msg
, "nCName");
1071 if (el
== NULL
|| el
->num_values
!= 1) {
1074 nc_dn
= ldb_dn_from_ldb_val(objects
, ldb
, &el
->values
[0]);
1075 if (!ldb_dn_validate(nc_dn
)) {
1078 ret
= dsdb_create_partial_replica_NC(ldb
, nc_dn
);
1079 if (ret
!= LDB_SUCCESS
) {
1080 status
= WERR_DS_INTERNAL_FAILURE
;
1086 for (i
=0; i
< num_objects
; i
++) {
1087 struct dom_sid
*sid
= NULL
;
1088 struct ldb_request
*add_req
;
1090 DEBUG(6,(__location__
": adding %s\n",
1091 ldb_dn_get_linearized(objects
[i
]->dn
)));
1093 ret
= ldb_build_add_req(&add_req
,
1099 ldb_op_default_callback
,
1101 if (ret
!= LDB_SUCCESS
) {
1102 status
= WERR_DS_INTERNAL_FAILURE
;
1106 ret
= ldb_request_add_control(add_req
, LDB_CONTROL_RELAX_OID
, true, NULL
);
1107 if (ret
!= LDB_SUCCESS
) {
1108 status
= WERR_DS_INTERNAL_FAILURE
;
1112 ret
= ldb_request(ldb
, add_req
);
1113 if (ret
== LDB_SUCCESS
) {
1114 ret
= ldb_wait(add_req
->handle
, LDB_WAIT_ALL
);
1116 if (ret
!= LDB_SUCCESS
) {
1117 DEBUG(0,(__location__
": Failed add of %s - %s\n",
1118 ldb_dn_get_linearized(objects
[i
]->dn
), ldb_errstring(ldb
)));
1119 status
= WERR_DS_INTERNAL_FAILURE
;
1123 talloc_free(add_req
);
1125 ret
= ldb_search(ldb
, objects
, &res
, objects
[i
]->dn
,
1126 LDB_SCOPE_BASE
, attrs
,
1128 if (ret
!= LDB_SUCCESS
) {
1129 status
= WERR_DS_INTERNAL_FAILURE
;
1132 ids
[i
].guid
= samdb_result_guid(res
->msgs
[0], "objectGUID");
1133 sid
= samdb_result_dom_sid(objects
, res
->msgs
[0], "objectSid");
1137 ZERO_STRUCT(ids
[i
].sid
);
1141 ret
= ldb_transaction_commit(ldb
);
1142 if (ret
!= LDB_SUCCESS
) {
1143 return WERR_DS_INTERNAL_FAILURE
;
1146 talloc_free(objects
);
1148 *_num
= num_objects
;
1153 talloc_free(objects
);
1154 ldb_transaction_cancel(ldb
);