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 drsuapi_DsReplicaAttribute
*name_a
= NULL
;
361 struct drsuapi_DsReplicaMetaData
*name_d
= NULL
;
362 struct replPropertyMetaData1
*rdn_m
= NULL
;
363 struct dom_sid
*sid
= NULL
;
368 if (!in
->object
.identifier
) {
372 if (!in
->object
.identifier
->dn
|| !in
->object
.identifier
->dn
[0]) {
376 if (in
->object
.attribute_ctr
.num_attributes
!= 0 && !in
->meta_data_ctr
) {
380 if (in
->object
.attribute_ctr
.num_attributes
!= in
->meta_data_ctr
->count
) {
384 sid
= &in
->object
.identifier
->sid
;
385 if (sid
->num_auths
> 0) {
386 rid
= sid
->sub_auths
[sid
->num_auths
- 1];
389 msg
= ldb_msg_new(mem_ctx
);
390 W_ERROR_HAVE_NO_MEMORY(msg
);
392 msg
->dn
= ldb_dn_new(msg
, ldb
, in
->object
.identifier
->dn
);
393 W_ERROR_HAVE_NO_MEMORY(msg
->dn
);
395 msg
->num_elements
= in
->object
.attribute_ctr
.num_attributes
;
396 msg
->elements
= talloc_array(msg
, struct ldb_message_element
,
397 msg
->num_elements
+ 1); /* +1 because of the RDN attribute */
398 W_ERROR_HAVE_NO_MEMORY(msg
->elements
);
400 md
= talloc(mem_ctx
, struct replPropertyMetaDataBlob
);
401 W_ERROR_HAVE_NO_MEMORY(md
);
405 md
->ctr
.ctr1
.count
= in
->meta_data_ctr
->count
;
406 md
->ctr
.ctr1
.reserved
= 0;
407 md
->ctr
.ctr1
.array
= talloc_array(mem_ctx
,
408 struct replPropertyMetaData1
,
409 md
->ctr
.ctr1
.count
+ 1); /* +1 because of the RDN attribute */
410 W_ERROR_HAVE_NO_MEMORY(md
->ctr
.ctr1
.array
);
412 for (i
=0, attr_count
=0; i
< in
->meta_data_ctr
->count
; i
++, attr_count
++) {
413 struct drsuapi_DsReplicaAttribute
*a
;
414 struct drsuapi_DsReplicaMetaData
*d
;
415 struct replPropertyMetaData1
*m
;
416 struct ldb_message_element
*e
;
419 a
= &in
->object
.attribute_ctr
.attributes
[i
];
420 d
= &in
->meta_data_ctr
->meta_data
[i
];
421 m
= &md
->ctr
.ctr1
.array
[attr_count
];
422 e
= &msg
->elements
[attr_count
];
424 if (dsdb_attid_in_list(ignore_attids
, a
->attid
)) {
429 if (GUID_all_zero(&d
->originating_invocation_id
)) {
430 status
= WERR_DS_SRC_GUID_MISMATCH
;
431 DEBUG(0, ("Refusing replication of object containing invalid zero invocationID on attribute %d of %s: %s\n",
433 ldb_dn_get_linearized(msg
->dn
),
434 win_errstr(status
)));
438 if (a
->attid
== DRSUAPI_ATTID_instanceType
) {
439 if (instanceType_e
!= NULL
) {
445 for (j
=0; j
<a
->value_ctr
.num_values
; j
++) {
446 status
= drsuapi_decrypt_attribute(a
->value_ctr
.values
[j
].blob
,
449 if (!W_ERROR_IS_OK(status
)) {
453 if (W_ERROR_EQUAL(status
, WERR_TOO_MANY_SECRETS
)) {
454 WERROR get_name_status
= dsdb_attribute_drsuapi_to_ldb(ldb
, schema
, pfm_remote
,
455 a
, msg
->elements
, e
, NULL
);
456 if (W_ERROR_IS_OK(get_name_status
)) {
457 DEBUG(0, ("Unxpectedly got secret value %s on %s from DRS server\n",
458 e
->name
, ldb_dn_get_linearized(msg
->dn
)));
460 DEBUG(0, ("Unxpectedly got secret value on %s from DRS server",
461 ldb_dn_get_linearized(msg
->dn
)));
463 } else if (!W_ERROR_IS_OK(status
)) {
468 * This function also fills in the local attid value,
469 * based on comparing the remote and local prefixMap
470 * tables. If we don't convert the value, then we can
471 * have invalid values in the replPropertyMetaData we
472 * store on disk, as the prefixMap is per host, not
473 * per-domain. This may be why Microsoft added the
474 * msDS-IntID feature, however this is not used for
475 * extra attributes in the schema partition itself.
477 status
= dsdb_attribute_drsuapi_to_ldb(ldb
, schema
, pfm_remote
,
480 W_ERROR_NOT_OK_RETURN(status
);
482 m
->version
= d
->version
;
483 m
->originating_change_time
= d
->originating_change_time
;
484 m
->originating_invocation_id
= d
->originating_invocation_id
;
485 m
->originating_usn
= d
->originating_usn
;
488 if (d
->originating_change_time
> whenChanged
) {
489 whenChanged
= d
->originating_change_time
;
492 if (a
->attid
== DRSUAPI_ATTID_name
) {
498 msg
->num_elements
= attr_count
;
499 md
->ctr
.ctr1
.count
= attr_count
;
501 rdn_m
= &md
->ctr
.ctr1
.array
[md
->ctr
.ctr1
.count
];
505 struct ldb_message_element
*el
;
506 const char *rdn_name
= NULL
;
507 const struct ldb_val
*rdn_value
= NULL
;
508 const struct dsdb_attribute
*rdn_attr
= NULL
;
512 * We only need the schema calls for the RDN in this
513 * codepath, and by doing this we avoid needing to
514 * have the dsdb_attribute_by_lDAPDisplayName accessor
515 * working during the schema load.
517 rdn_name
= ldb_dn_get_rdn_name(msg
->dn
);
518 rdn_attr
= dsdb_attribute_by_lDAPDisplayName(schema
, rdn_name
);
522 rdn_attid
= rdn_attr
->attributeID_id
;
523 rdn_value
= ldb_dn_get_rdn_val(msg
->dn
);
525 el
= ldb_msg_find_element(msg
, rdn_attr
->lDAPDisplayName
);
527 ret
= ldb_msg_add_value(msg
, rdn_attr
->lDAPDisplayName
, rdn_value
, NULL
);
528 if (ret
!= LDB_SUCCESS
) {
532 if (el
->num_values
!= 1) {
533 DEBUG(0,(__location__
": Unexpected num_values=%u\n",
537 if (!ldb_val_equal_exact(&el
->values
[0], rdn_value
)) {
538 DEBUG(0,(__location__
": RDN value changed? '%*.*s' '%*.*s'\n",
539 (int)el
->values
[0].length
, (int)el
->values
[0].length
, el
->values
[0].data
,
540 (int)rdn_value
->length
, (int)rdn_value
->length
, rdn_value
->data
));
545 rdn_m
->attid
= rdn_attid
;
546 rdn_m
->version
= name_d
->version
;
547 rdn_m
->originating_change_time
= name_d
->originating_change_time
;
548 rdn_m
->originating_invocation_id
= name_d
->originating_invocation_id
;
549 rdn_m
->originating_usn
= name_d
->originating_usn
;
550 rdn_m
->local_usn
= 0;
551 md
->ctr
.ctr1
.count
++;
555 if (instanceType_e
== NULL
) {
559 instanceType
= ldb_msg_find_attr_as_int(msg
, "instanceType", 0);
561 if ((instanceType
& INSTANCE_TYPE_IS_NC_HEAD
)
562 && partition_dn
!= NULL
) {
563 int partition_dn_cmp
= ldb_dn_compare(partition_dn
, msg
->dn
);
564 if (partition_dn_cmp
!= 0) {
565 DEBUG(4, ("Remote server advised us of a new partition %s while processing %s, ignoring\n",
566 ldb_dn_get_linearized(msg
->dn
),
567 ldb_dn_get_linearized(partition_dn
)));
568 return WERR_DS_ADD_REPLICA_INHIBITED
;
572 if (dsdb_repl_flags
& DSDB_REPL_FLAG_PARTIAL_REPLICA
) {
573 /* the instanceType type for partial_replica
574 replication is sent via DRS with TYPE_WRITE set, but
575 must be used on the client with TYPE_WRITE removed
577 if (instanceType
& INSTANCE_TYPE_WRITE
) {
579 * Make sure we do not change the order
583 * instanceType_e->num_values = 0
585 * ldb_msg_remove_attr(msg, "instanceType");
587 struct ldb_message_element
*e
;
589 e
= ldb_msg_find_element(msg
, "instanceType");
590 if (e
!= instanceType_e
) {
591 DEBUG(0,("instanceType_e[%p] changed to e[%p]\n",
596 instanceType_e
->num_values
= 0;
598 instanceType
&= ~INSTANCE_TYPE_WRITE
;
599 if (ldb_msg_add_fmt(msg
, "instanceType", "%d", instanceType
) != LDB_SUCCESS
) {
600 return WERR_INTERNAL_ERROR
;
604 if (!(instanceType
& INSTANCE_TYPE_WRITE
)) {
605 DEBUG(0, ("Refusing to replicate %s from a read-only repilca into a read-write replica!\n",
606 ldb_dn_get_linearized(msg
->dn
)));
607 return WERR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA
;
611 whenChanged_t
= nt_time_to_unix(whenChanged
);
612 whenChanged_s
= ldb_timestring(msg
, whenChanged_t
);
613 W_ERROR_HAVE_NO_MEMORY(whenChanged_s
);
615 out
->object_guid
= in
->object
.identifier
->guid
;
617 if (in
->parent_object_guid
== NULL
) {
618 out
->parent_guid
= NULL
;
620 out
->parent_guid
= talloc(mem_ctx
, struct GUID
);
621 W_ERROR_HAVE_NO_MEMORY(out
->parent_guid
);
622 *out
->parent_guid
= *in
->parent_object_guid
;
626 out
->when_changed
= whenChanged_s
;
631 WERROR
dsdb_replicated_objects_convert(struct ldb_context
*ldb
,
632 const struct dsdb_schema
*schema
,
633 struct ldb_dn
*partition_dn
,
634 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
,
635 uint32_t object_count
,
636 const struct drsuapi_DsReplicaObjectListItemEx
*first_object
,
637 uint32_t linked_attributes_count
,
638 const struct drsuapi_DsReplicaLinkedAttribute
*linked_attributes
,
639 const struct repsFromTo1
*source_dsa
,
640 const struct drsuapi_DsReplicaCursor2CtrEx
*uptodateness_vector
,
641 const DATA_BLOB
*gensec_skey
,
642 uint32_t dsdb_repl_flags
,
644 struct dsdb_extended_replicated_objects
**objects
)
647 struct dsdb_schema_prefixmap
*pfm_remote
;
648 struct dsdb_extended_replicated_objects
*out
;
649 const struct drsuapi_DsReplicaObjectListItemEx
*cur
;
652 out
= talloc_zero(mem_ctx
, struct dsdb_extended_replicated_objects
);
653 W_ERROR_HAVE_NO_MEMORY(out
);
654 out
->version
= DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION
;
655 out
->dsdb_repl_flags
= dsdb_repl_flags
;
658 * Ensure schema is kept valid for as long as 'out'
659 * which may contain pointers to it
661 schema
= talloc_reference(out
, schema
);
662 W_ERROR_HAVE_NO_MEMORY(schema
);
664 status
= dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr
, true,
665 out
, &pfm_remote
, NULL
);
666 if (!W_ERROR_IS_OK(status
)) {
667 DEBUG(0,(__location__
": Failed to decode remote prefixMap: %s",
668 win_errstr(status
)));
673 if (ldb_dn_compare(partition_dn
, ldb_get_schema_basedn(ldb
)) != 0) {
675 * check for schema changes in case
676 * we are not replicating Schema NC
678 status
= dsdb_schema_info_cmp(schema
, mapping_ctr
);
679 if (!W_ERROR_IS_OK(status
)) {
680 DEBUG(4,("Can't replicate %s because remote schema has changed since we last replicated the schema\n",
681 ldb_dn_get_linearized(partition_dn
)));
687 out
->partition_dn
= partition_dn
;
689 out
->source_dsa
= source_dsa
;
690 out
->uptodateness_vector
= uptodateness_vector
;
692 out
->num_objects
= 0;
693 out
->objects
= talloc_array(out
,
694 struct dsdb_extended_replicated_object
,
696 W_ERROR_HAVE_NO_MEMORY_AND_FREE(out
->objects
, out
);
698 /* pass the linked attributes down to the repl_meta_data
700 out
->linked_attributes_count
= linked_attributes_count
;
701 out
->linked_attributes
= linked_attributes
;
703 for (i
=0, cur
= first_object
; cur
; cur
= cur
->next_object
, i
++) {
704 if (i
== object_count
) {
709 status
= dsdb_convert_object_ex(ldb
, schema
, out
->partition_dn
,
715 &out
->objects
[out
->num_objects
]);
718 * Check to see if we have been advised of a
719 * subdomain or new application partition. We don't
720 * want to start on that here, instead the caller
721 * should consider if it would like to replicate it
722 * based on the cross-ref object.
724 if (W_ERROR_EQUAL(status
, WERR_DS_ADD_REPLICA_INHIBITED
)) {
728 if (!W_ERROR_IS_OK(status
)) {
730 DEBUG(0,("Failed to convert object %s: %s\n",
731 cur
->object
.identifier
->dn
,
732 win_errstr(status
)));
736 /* Assuming we didn't skip or error, increment the number of objects */
739 out
->objects
= talloc_realloc(out
, out
->objects
,
740 struct dsdb_extended_replicated_object
,
742 if (out
->num_objects
!= 0 && out
->objects
== NULL
) {
746 if (i
!= object_count
) {
751 /* free pfm_remote, we won't need it anymore */
752 talloc_free(pfm_remote
);
759 * Commits a list of replicated objects.
761 * @param working_schema dsdb_schema to be used for resolving
762 * Classes/Attributes during Schema replication. If not NULL,
763 * it will be set on ldb and used while committing replicated objects
765 WERROR
dsdb_replicated_objects_commit(struct ldb_context
*ldb
,
766 struct dsdb_schema
*working_schema
,
767 struct dsdb_extended_replicated_objects
*objects
,
768 uint64_t *notify_uSN
)
771 struct ldb_result
*ext_res
;
772 struct dsdb_schema
*cur_schema
= NULL
;
773 struct dsdb_schema
*new_schema
= NULL
;
775 uint64_t seq_num1
, seq_num2
;
776 bool used_global_schema
= false;
778 TALLOC_CTX
*tmp_ctx
= talloc_new(objects
);
780 DEBUG(0,("Failed to start talloc\n"));
784 /* TODO: handle linked attributes */
786 /* wrap the extended operation in a transaction
787 See [MS-DRSR] 3.3.2 Transactions
789 ret
= ldb_transaction_start(ldb
);
790 if (ret
!= LDB_SUCCESS
) {
791 DEBUG(0,(__location__
" Failed to start transaction\n"));
795 ret
= dsdb_load_partition_usn(ldb
, objects
->partition_dn
, &seq_num1
, NULL
);
796 if (ret
!= LDB_SUCCESS
) {
797 DEBUG(0,(__location__
" Failed to load partition uSN\n"));
798 ldb_transaction_cancel(ldb
);
799 TALLOC_FREE(tmp_ctx
);
804 * Set working_schema for ldb in case we are replicating from Schema NC.
805 * Schema won't be reloaded during Replicated Objects commit, as it is
806 * done in a transaction. So we need some way to search for newly
807 * added Classes and Attributes
809 if (working_schema
) {
810 /* store current schema so we can fall back in case of failure */
811 cur_schema
= dsdb_get_schema(ldb
, tmp_ctx
);
812 used_global_schema
= dsdb_uses_global_schema(ldb
);
814 ret
= dsdb_reference_schema(ldb
, working_schema
, false);
815 if (ret
!= LDB_SUCCESS
) {
816 DEBUG(0,(__location__
"Failed to reference working schema - %s\n",
818 /* TODO: Map LDB Error to NTSTATUS? */
819 ldb_transaction_cancel(ldb
);
820 TALLOC_FREE(tmp_ctx
);
821 return WERR_INTERNAL_ERROR
;
825 ret
= ldb_extended(ldb
, DSDB_EXTENDED_REPLICATED_OBJECTS_OID
, objects
, &ext_res
);
826 if (ret
!= LDB_SUCCESS
) {
827 /* restore previous schema */
828 if (used_global_schema
) {
829 dsdb_set_global_schema(ldb
);
830 } else if (cur_schema
) {
831 dsdb_reference_schema(ldb
, cur_schema
, false);
834 DEBUG(0,("Failed to apply records: %s: %s\n",
835 ldb_errstring(ldb
), ldb_strerror(ret
)));
836 ldb_transaction_cancel(ldb
);
837 TALLOC_FREE(tmp_ctx
);
839 if (!W_ERROR_IS_OK(objects
->error
)) {
840 return objects
->error
;
844 talloc_free(ext_res
);
846 /* Save our updated prefixMap */
847 if (working_schema
) {
848 werr
= dsdb_write_prefixes_from_schema_to_ldb(working_schema
,
851 if (!W_ERROR_IS_OK(werr
)) {
852 /* restore previous schema */
853 if (used_global_schema
) {
854 dsdb_set_global_schema(ldb
);
855 } else if (cur_schema
) {
856 dsdb_reference_schema(ldb
, cur_schema
, false);
858 DEBUG(0,("Failed to save updated prefixMap: %s\n",
860 TALLOC_FREE(tmp_ctx
);
865 ret
= ldb_transaction_prepare_commit(ldb
);
866 if (ret
!= LDB_SUCCESS
) {
867 /* restore previous schema */
868 if (used_global_schema
) {
869 dsdb_set_global_schema(ldb
);
870 } else if (cur_schema
) {
871 dsdb_reference_schema(ldb
, cur_schema
, false);
873 DEBUG(0,(__location__
" Failed to prepare commit of transaction: %s\n",
874 ldb_errstring(ldb
)));
875 TALLOC_FREE(tmp_ctx
);
879 ret
= dsdb_load_partition_usn(ldb
, objects
->partition_dn
, &seq_num2
, NULL
);
880 if (ret
!= LDB_SUCCESS
) {
881 /* restore previous schema */
882 if (used_global_schema
) {
883 dsdb_set_global_schema(ldb
);
884 } else if (cur_schema
) {
885 dsdb_reference_schema(ldb
, cur_schema
, false);
887 DEBUG(0,(__location__
" Failed to load partition uSN\n"));
888 ldb_transaction_cancel(ldb
);
889 TALLOC_FREE(tmp_ctx
);
893 ret
= ldb_transaction_commit(ldb
);
894 if (ret
!= LDB_SUCCESS
) {
895 /* restore previous schema */
896 if (used_global_schema
) {
897 dsdb_set_global_schema(ldb
);
898 } else if (cur_schema
) {
899 dsdb_reference_schema(ldb
, cur_schema
, false);
901 DEBUG(0,(__location__
" Failed to commit transaction\n"));
902 TALLOC_FREE(tmp_ctx
);
906 /* if this replication partner didn't need to be notified
907 before this transaction then it still doesn't need to be
908 notified, as the changes came from this server */
909 if (seq_num2
> seq_num1
&& seq_num1
<= *notify_uSN
) {
910 *notify_uSN
= seq_num2
;
914 * Reset the Schema used by ldb. This will lead to
915 * a schema cache being refreshed from database.
917 if (working_schema
) {
918 struct ldb_message
*msg
;
919 struct ldb_request
*req
;
922 working_schema
->last_refresh
= 0;
923 new_schema
= dsdb_get_schema(ldb
, tmp_ctx
);
925 * If dsdb_get_schema() fails, we just fall back
926 * to what we had. However, the database is probably
927 * unable to operate for other users from this
929 if (new_schema
&& used_global_schema
) {
930 dsdb_make_schema_global(ldb
, new_schema
);
931 } else if (used_global_schema
) {
932 DEBUG(0,("Failed to re-load schema after commit of transaction\n"));
933 dsdb_set_global_schema(ldb
);
934 TALLOC_FREE(tmp_ctx
);
935 return WERR_INTERNAL_ERROR
;
937 DEBUG(0,("Failed to re-load schema after commit of transaction\n"));
938 dsdb_reference_schema(ldb
, cur_schema
, false);
939 TALLOC_FREE(tmp_ctx
);
940 return WERR_INTERNAL_ERROR
;
942 msg
= ldb_msg_new(tmp_ctx
);
944 TALLOC_FREE(tmp_ctx
);
947 msg
->dn
= ldb_dn_new(msg
, ldb
, "");
948 if (msg
->dn
== NULL
) {
949 TALLOC_FREE(tmp_ctx
);
953 ret
= ldb_msg_add_string(msg
, "schemaUpdateNow", "1");
954 if (ret
!= LDB_SUCCESS
) {
955 TALLOC_FREE(tmp_ctx
);
956 return WERR_INTERNAL_ERROR
;
959 ret
= ldb_build_mod_req(&req
, ldb
, objects
,
963 ldb_op_default_callback
,
966 if (ret
!= LDB_SUCCESS
) {
967 TALLOC_FREE(tmp_ctx
);
968 return WERR_DS_DRA_INTERNAL_ERROR
;
971 ret
= ldb_transaction_start(ldb
);
972 if (ret
!= LDB_SUCCESS
) {
973 TALLOC_FREE(tmp_ctx
);
974 DEBUG(0, ("Autotransaction start failed\n"));
975 return WERR_DS_DRA_INTERNAL_ERROR
;
978 ret
= ldb_request(ldb
, req
);
979 if (ret
== LDB_SUCCESS
) {
980 ret
= ldb_wait(req
->handle
, LDB_WAIT_ALL
);
983 if (ret
== LDB_SUCCESS
) {
984 ret
= ldb_transaction_commit(ldb
);
986 DEBUG(0, ("Schema update now failed: %s\n",
987 ldb_errstring(ldb
)));
988 ldb_transaction_cancel(ldb
);
991 if (ret
!= LDB_SUCCESS
) {
992 DEBUG(0, ("Commit failed: %s\n", ldb_errstring(ldb
)));
993 TALLOC_FREE(tmp_ctx
);
994 return WERR_DS_INTERNAL_FAILURE
;
998 DEBUG(2,("Replicated %u objects (%u linked attributes) for %s\n",
999 objects
->num_objects
, objects
->linked_attributes_count
,
1000 ldb_dn_get_linearized(objects
->partition_dn
)));
1002 TALLOC_FREE(tmp_ctx
);
1006 static WERROR
dsdb_origin_object_convert(struct ldb_context
*ldb
,
1007 const struct dsdb_schema
*schema
,
1008 const struct drsuapi_DsReplicaObjectListItem
*in
,
1009 TALLOC_CTX
*mem_ctx
,
1010 struct ldb_message
**_msg
)
1014 struct ldb_message
*msg
;
1016 if (!in
->object
.identifier
) {
1020 if (!in
->object
.identifier
->dn
|| !in
->object
.identifier
->dn
[0]) {
1024 msg
= ldb_msg_new(mem_ctx
);
1025 W_ERROR_HAVE_NO_MEMORY(msg
);
1027 msg
->dn
= ldb_dn_new(msg
, ldb
, in
->object
.identifier
->dn
);
1028 W_ERROR_HAVE_NO_MEMORY(msg
->dn
);
1030 msg
->num_elements
= in
->object
.attribute_ctr
.num_attributes
;
1031 msg
->elements
= talloc_array(msg
, struct ldb_message_element
,
1033 W_ERROR_HAVE_NO_MEMORY(msg
->elements
);
1035 for (i
=0; i
< msg
->num_elements
; i
++) {
1036 struct drsuapi_DsReplicaAttribute
*a
;
1037 struct ldb_message_element
*e
;
1039 a
= &in
->object
.attribute_ctr
.attributes
[i
];
1040 e
= &msg
->elements
[i
];
1042 status
= dsdb_attribute_drsuapi_to_ldb(ldb
, schema
, schema
->prefixmap
,
1043 a
, msg
->elements
, e
, NULL
);
1044 W_ERROR_NOT_OK_RETURN(status
);
1053 WERROR
dsdb_origin_objects_commit(struct ldb_context
*ldb
,
1054 TALLOC_CTX
*mem_ctx
,
1055 const struct drsuapi_DsReplicaObjectListItem
*first_object
,
1057 uint32_t dsdb_repl_flags
,
1058 struct drsuapi_DsReplicaObjectIdentifier2
**_ids
)
1061 const struct dsdb_schema
*schema
;
1062 const struct drsuapi_DsReplicaObjectListItem
*cur
;
1063 struct ldb_message
**objects
;
1064 struct drsuapi_DsReplicaObjectIdentifier2
*ids
;
1066 uint32_t num_objects
= 0;
1067 const char * const attrs
[] = {
1072 struct ldb_result
*res
;
1075 for (cur
= first_object
; cur
; cur
= cur
->next_object
) {
1079 if (num_objects
== 0) {
1083 ret
= ldb_transaction_start(ldb
);
1084 if (ret
!= LDB_SUCCESS
) {
1085 return WERR_DS_INTERNAL_FAILURE
;
1088 objects
= talloc_array(mem_ctx
, struct ldb_message
*,
1090 if (objects
== NULL
) {
1091 status
= WERR_NOMEM
;
1095 schema
= dsdb_get_schema(ldb
, objects
);
1097 return WERR_DS_SCHEMA_NOT_LOADED
;
1100 for (i
=0, cur
= first_object
; cur
; cur
= cur
->next_object
, i
++) {
1101 status
= dsdb_origin_object_convert(ldb
, schema
, cur
,
1102 objects
, &objects
[i
]);
1103 if (!W_ERROR_IS_OK(status
)) {
1108 ids
= talloc_array(mem_ctx
,
1109 struct drsuapi_DsReplicaObjectIdentifier2
,
1112 status
= WERR_NOMEM
;
1116 if (dsdb_repl_flags
& DSDB_REPL_FLAG_ADD_NCNAME
) {
1117 /* check for possible NC creation */
1118 for (i
=0; i
< num_objects
; i
++) {
1119 struct ldb_message
*msg
= objects
[i
];
1120 struct ldb_message_element
*el
;
1121 struct ldb_dn
*nc_dn
;
1123 if (ldb_msg_check_string_attribute(msg
, "objectClass", "crossRef") == 0) {
1126 el
= ldb_msg_find_element(msg
, "nCName");
1127 if (el
== NULL
|| el
->num_values
!= 1) {
1130 nc_dn
= ldb_dn_from_ldb_val(objects
, ldb
, &el
->values
[0]);
1131 if (!ldb_dn_validate(nc_dn
)) {
1134 ret
= dsdb_create_partial_replica_NC(ldb
, nc_dn
);
1135 if (ret
!= LDB_SUCCESS
) {
1136 status
= WERR_DS_INTERNAL_FAILURE
;
1142 for (i
=0; i
< num_objects
; i
++) {
1143 struct dom_sid
*sid
= NULL
;
1144 struct ldb_request
*add_req
;
1146 DEBUG(6,(__location__
": adding %s\n",
1147 ldb_dn_get_linearized(objects
[i
]->dn
)));
1149 ret
= ldb_build_add_req(&add_req
,
1155 ldb_op_default_callback
,
1157 if (ret
!= LDB_SUCCESS
) {
1158 status
= WERR_DS_INTERNAL_FAILURE
;
1162 ret
= ldb_request_add_control(add_req
, LDB_CONTROL_RELAX_OID
, true, NULL
);
1163 if (ret
!= LDB_SUCCESS
) {
1164 status
= WERR_DS_INTERNAL_FAILURE
;
1168 ret
= ldb_request(ldb
, add_req
);
1169 if (ret
== LDB_SUCCESS
) {
1170 ret
= ldb_wait(add_req
->handle
, LDB_WAIT_ALL
);
1172 if (ret
!= LDB_SUCCESS
) {
1173 DEBUG(0,(__location__
": Failed add of %s - %s\n",
1174 ldb_dn_get_linearized(objects
[i
]->dn
), ldb_errstring(ldb
)));
1175 status
= WERR_DS_INTERNAL_FAILURE
;
1179 talloc_free(add_req
);
1181 ret
= ldb_search(ldb
, objects
, &res
, objects
[i
]->dn
,
1182 LDB_SCOPE_BASE
, attrs
,
1184 if (ret
!= LDB_SUCCESS
) {
1185 status
= WERR_DS_INTERNAL_FAILURE
;
1188 ids
[i
].guid
= samdb_result_guid(res
->msgs
[0], "objectGUID");
1189 sid
= samdb_result_dom_sid(objects
, res
->msgs
[0], "objectSid");
1193 ZERO_STRUCT(ids
[i
].sid
);
1197 ret
= ldb_transaction_commit(ldb
);
1198 if (ret
!= LDB_SUCCESS
) {
1199 return WERR_DS_INTERNAL_FAILURE
;
1202 talloc_free(objects
);
1204 *_num
= num_objects
;
1209 talloc_free(objects
);
1210 ldb_transaction_cancel(ldb
);