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 * Multi-pass working schema creation
37 * - shallow copy initial schema supplied
38 * - create a working schema in multiple passes
39 * until all objects are resolved
40 * Working schema is a schema with Attributes, Classes
41 * and indexes, but w/o subClassOf, possibleSupperiors etc.
42 * It is to be used just us cache for converting attribute values.
44 WERROR
dsdb_repl_make_working_schema(struct ldb_context
*ldb
,
45 const struct dsdb_schema
*initial_schema
,
46 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
,
47 uint32_t object_count
,
48 const struct drsuapi_DsReplicaObjectListItemEx
*first_object
,
49 const DATA_BLOB
*gensec_skey
,
51 struct dsdb_schema
**_schema_out
)
54 struct schema_list
*next
, *prev
;
55 const struct drsuapi_DsReplicaObjectListItemEx
*obj
;
59 struct dsdb_schema_prefixmap
*pfm_remote
;
60 struct schema_list
*schema_list
= NULL
, *schema_list_item
, *schema_list_next_item
;
61 struct dsdb_schema
*working_schema
;
62 const struct drsuapi_DsReplicaObjectListItemEx
*cur
;
64 uint32_t ignore_attids
[] = {
65 DRSUAPI_ATTID_auxiliaryClass
,
66 DRSUAPI_ATTID_mayContain
,
67 DRSUAPI_ATTID_mustContain
,
68 DRSUAPI_ATTID_possSuperiors
,
69 DRSUAPI_ATTID_systemPossSuperiors
,
73 /* make a copy of the iniatial_scheam so we don't mess with it */
74 working_schema
= dsdb_schema_copy_shallow(mem_ctx
, ldb
, initial_schema
);
75 if (!working_schema
) {
76 DEBUG(0,(__location__
": schema copy failed!\n"));
80 /* we are going to need remote prefixMap for decoding */
81 werr
= dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr
, true,
82 mem_ctx
, &pfm_remote
, NULL
);
83 if (!W_ERROR_IS_OK(werr
)) {
84 DEBUG(0,(__location__
": Failed to decode remote prefixMap: %s",
89 /* create a list of objects yet to be converted */
90 for (cur
= first_object
; cur
; cur
= cur
->next_object
) {
91 schema_list_item
= talloc(mem_ctx
, struct schema_list
);
92 schema_list_item
->obj
= cur
;
93 DLIST_ADD_END(schema_list
, schema_list_item
, struct schema_list
);
96 /* resolve objects until all are resolved and in local schema */
100 uint32_t converted_obj_count
= 0;
101 uint32_t failed_obj_count
= 0;
102 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
103 W_ERROR_HAVE_NO_MEMORY(tmp_ctx
);
105 for (schema_list_item
= schema_list
; schema_list_item
; schema_list_item
=schema_list_next_item
) {
106 struct dsdb_extended_replicated_object object
;
108 cur
= schema_list_item
->obj
;
110 /* Save the next item, now we have saved out
111 * the current one, so we can DLIST_REMOVE it
113 schema_list_next_item
= schema_list_item
->next
;
116 * Convert the objects into LDB messages using the
117 * schema we have so far. It's ok if we fail to convert
118 * an object. We should convert more objects on next pass.
120 werr
= dsdb_convert_object_ex(ldb
, working_schema
, pfm_remote
,
125 if (!W_ERROR_IS_OK(werr
)) {
126 DEBUG(4,("debug: Failed to convert schema object %s into ldb msg, will try during next loop\n",
127 cur
->object
.identifier
->dn
));
132 * Convert the schema from ldb_message format
133 * (OIDs as OID strings) into schema, using
134 * the remote prefixMap
136 werr
= dsdb_schema_set_el_from_ldb_msg_dups(ldb
,
140 if (!W_ERROR_IS_OK(werr
)) {
141 DEBUG(4,("debug: failed to convert object %s into a schema element, will try during next loop: %s\n",
142 ldb_dn_get_linearized(object
.msg
->dn
),
146 DLIST_REMOVE(schema_list
, schema_list_item
);
147 talloc_free(schema_list_item
);
148 converted_obj_count
++;
152 talloc_free(tmp_ctx
);
154 DEBUG(4,("Schema load pass %d: converted %d, %d of %d objects left to be converted.\n",
155 pass_no
, converted_obj_count
, failed_obj_count
, object_count
));
158 /* check if we converted any objects in this pass */
159 if (converted_obj_count
== 0) {
160 DEBUG(0,("Can't continue Schema load: didn't manage to convert any objects: all %d remaining of %d objects failed to convert\n", failed_obj_count
, object_count
));
161 return WERR_INTERNAL_ERROR
;
164 /* rebuild indexes */
165 ret
= dsdb_setup_sorted_accessors(ldb
, working_schema
);
166 if (LDB_SUCCESS
!= ret
) {
167 DEBUG(0,("Failed to create schema-cache indexes!\n"));
168 return WERR_INTERNAL_ERROR
;
172 *_schema_out
= working_schema
;
177 static bool dsdb_attid_in_list(const uint32_t attid_list
[], uint32_t attid
)
183 for (cur
= attid_list
; *cur
!= DRSUAPI_ATTID_INVALID
; cur
++) {
191 WERROR
dsdb_convert_object_ex(struct ldb_context
*ldb
,
192 const struct dsdb_schema
*schema
,
193 const struct dsdb_schema_prefixmap
*pfm_remote
,
194 const struct drsuapi_DsReplicaObjectListItemEx
*in
,
195 const DATA_BLOB
*gensec_skey
,
196 const uint32_t *ignore_attids
,
197 uint32_t dsdb_repl_flags
,
199 struct dsdb_extended_replicated_object
*out
)
204 struct ldb_message
*msg
;
205 struct replPropertyMetaDataBlob
*md
;
207 struct ldb_message_element
*instanceType_e
= NULL
;
208 struct ldb_val guid_value
;
209 struct ldb_val parent_guid_value
;
210 NTTIME whenChanged
= 0;
211 time_t whenChanged_t
;
212 const char *whenChanged_s
;
213 struct drsuapi_DsReplicaAttribute
*name_a
= NULL
;
214 struct drsuapi_DsReplicaMetaData
*name_d
= NULL
;
215 struct replPropertyMetaData1
*rdn_m
= NULL
;
216 struct dom_sid
*sid
= NULL
;
221 if (!in
->object
.identifier
) {
225 if (!in
->object
.identifier
->dn
|| !in
->object
.identifier
->dn
[0]) {
229 if (in
->object
.attribute_ctr
.num_attributes
!= 0 && !in
->meta_data_ctr
) {
233 if (in
->object
.attribute_ctr
.num_attributes
!= in
->meta_data_ctr
->count
) {
237 sid
= &in
->object
.identifier
->sid
;
238 if (sid
->num_auths
> 0) {
239 rid
= sid
->sub_auths
[sid
->num_auths
- 1];
242 msg
= ldb_msg_new(mem_ctx
);
243 W_ERROR_HAVE_NO_MEMORY(msg
);
245 msg
->dn
= ldb_dn_new(msg
, ldb
, in
->object
.identifier
->dn
);
246 W_ERROR_HAVE_NO_MEMORY(msg
->dn
);
248 msg
->num_elements
= in
->object
.attribute_ctr
.num_attributes
;
249 msg
->elements
= talloc_array(msg
, struct ldb_message_element
,
250 msg
->num_elements
+ 1); /* +1 because of the RDN attribute */
251 W_ERROR_HAVE_NO_MEMORY(msg
->elements
);
253 md
= talloc(mem_ctx
, struct replPropertyMetaDataBlob
);
254 W_ERROR_HAVE_NO_MEMORY(md
);
258 md
->ctr
.ctr1
.count
= in
->meta_data_ctr
->count
;
259 md
->ctr
.ctr1
.reserved
= 0;
260 md
->ctr
.ctr1
.array
= talloc_array(mem_ctx
,
261 struct replPropertyMetaData1
,
262 md
->ctr
.ctr1
.count
+ 1); /* +1 because of the RDN attribute */
263 W_ERROR_HAVE_NO_MEMORY(md
->ctr
.ctr1
.array
);
265 for (i
=0, attr_count
=0; i
< in
->meta_data_ctr
->count
; i
++, attr_count
++) {
266 struct drsuapi_DsReplicaAttribute
*a
;
267 struct drsuapi_DsReplicaMetaData
*d
;
268 struct replPropertyMetaData1
*m
;
269 struct ldb_message_element
*e
;
272 a
= &in
->object
.attribute_ctr
.attributes
[i
];
273 d
= &in
->meta_data_ctr
->meta_data
[i
];
274 m
= &md
->ctr
.ctr1
.array
[attr_count
];
275 e
= &msg
->elements
[attr_count
];
277 if (dsdb_attid_in_list(ignore_attids
, a
->attid
)) {
282 if (a
->attid
== DRSUAPI_ATTID_instanceType
) {
283 if (instanceType_e
!= NULL
) {
289 for (j
=0; j
<a
->value_ctr
.num_values
; j
++) {
290 status
= drsuapi_decrypt_attribute(a
->value_ctr
.values
[j
].blob
, gensec_skey
, rid
, a
);
291 W_ERROR_NOT_OK_RETURN(status
);
294 status
= dsdb_attribute_drsuapi_to_ldb(ldb
, schema
, pfm_remote
,
295 a
, msg
->elements
, e
);
296 W_ERROR_NOT_OK_RETURN(status
);
299 m
->version
= d
->version
;
300 m
->originating_change_time
= d
->originating_change_time
;
301 m
->originating_invocation_id
= d
->originating_invocation_id
;
302 m
->originating_usn
= d
->originating_usn
;
305 if (d
->originating_change_time
> whenChanged
) {
306 whenChanged
= d
->originating_change_time
;
309 if (a
->attid
== DRSUAPI_ATTID_name
) {
315 msg
->num_elements
= attr_count
;
316 md
->ctr
.ctr1
.count
= attr_count
;
318 rdn_m
= &md
->ctr
.ctr1
.array
[md
->ctr
.ctr1
.count
];
322 struct ldb_message_element
*el
;
323 const char *rdn_name
= NULL
;
324 const struct ldb_val
*rdn_value
= NULL
;
325 const struct dsdb_attribute
*rdn_attr
= NULL
;
329 * We only need the schema calls for the RDN in this
330 * codepath, and by doing this we avoid needing to
331 * have the dsdb_attribute_by_lDAPDisplayName accessor
332 * working during the schema load.
334 rdn_name
= ldb_dn_get_rdn_name(msg
->dn
);
335 rdn_attr
= dsdb_attribute_by_lDAPDisplayName(schema
, rdn_name
);
339 rdn_attid
= rdn_attr
->attributeID_id
;
340 rdn_value
= ldb_dn_get_rdn_val(msg
->dn
);
342 el
= ldb_msg_find_element(msg
, rdn_attr
->lDAPDisplayName
);
344 ret
= ldb_msg_add_value(msg
, rdn_attr
->lDAPDisplayName
, rdn_value
, NULL
);
345 if (ret
!= LDB_SUCCESS
) {
349 if (el
->num_values
!= 1) {
350 DEBUG(0,(__location__
": Unexpected num_values=%u\n",
354 if (!ldb_val_equal_exact(&el
->values
[0], rdn_value
)) {
355 DEBUG(0,(__location__
": RDN value changed? '%*.*s' '%*.*s'\n",
356 (int)el
->values
[0].length
, (int)el
->values
[0].length
, el
->values
[0].data
,
357 (int)rdn_value
->length
, (int)rdn_value
->length
, rdn_value
->data
));
362 rdn_m
->attid
= rdn_attid
;
363 rdn_m
->version
= name_d
->version
;
364 rdn_m
->originating_change_time
= name_d
->originating_change_time
;
365 rdn_m
->originating_invocation_id
= name_d
->originating_invocation_id
;
366 rdn_m
->originating_usn
= name_d
->originating_usn
;
367 rdn_m
->local_usn
= 0;
368 md
->ctr
.ctr1
.count
++;
372 if (instanceType_e
== NULL
) {
376 instanceType
= ldb_msg_find_attr_as_int(msg
, "instanceType", 0);
377 if (dsdb_repl_flags
& DSDB_REPL_FLAG_PARTIAL_REPLICA
) {
378 /* the instanceType type for partial_replica
379 replication is sent via DRS with TYPE_WRITE set, but
380 must be used on the client with TYPE_WRITE removed
382 if (instanceType
& INSTANCE_TYPE_WRITE
) {
384 * Make sure we do not change the order
388 * instanceType_e->num_values = 0
390 * ldb_msg_remove_attr(msg, "instanceType");
392 struct ldb_message_element
*e
;
394 e
= ldb_msg_find_element(msg
, "instanceType");
395 if (e
!= instanceType_e
) {
396 DEBUG(0,("instanceType_e[%p] changed to e[%p]\n",
401 instanceType_e
->num_values
= 0;
403 instanceType
&= ~INSTANCE_TYPE_WRITE
;
404 if (ldb_msg_add_fmt(msg
, "instanceType", "%d", instanceType
) != LDB_SUCCESS
) {
405 return WERR_INTERNAL_ERROR
;
409 if (!(instanceType
& INSTANCE_TYPE_WRITE
)) {
410 DEBUG(0, ("Refusing to replicate %s from a read-only repilca into a read-write replica!\n",
411 ldb_dn_get_linearized(msg
->dn
)));
412 return WERR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA
;
416 whenChanged_t
= nt_time_to_unix(whenChanged
);
417 whenChanged_s
= ldb_timestring(msg
, whenChanged_t
);
418 W_ERROR_HAVE_NO_MEMORY(whenChanged_s
);
420 nt_status
= GUID_to_ndr_blob(&in
->object
.identifier
->guid
, msg
, &guid_value
);
421 if (!NT_STATUS_IS_OK(nt_status
)) {
422 return ntstatus_to_werror(nt_status
);
425 if (in
->parent_object_guid
) {
426 nt_status
= GUID_to_ndr_blob(in
->parent_object_guid
, msg
, &parent_guid_value
);
427 if (!NT_STATUS_IS_OK(nt_status
)) {
428 return ntstatus_to_werror(nt_status
);
431 parent_guid_value
= data_blob_null
;
435 out
->guid_value
= guid_value
;
436 out
->parent_guid_value
= parent_guid_value
;
437 out
->when_changed
= whenChanged_s
;
442 WERROR
dsdb_replicated_objects_convert(struct ldb_context
*ldb
,
443 const struct dsdb_schema
*schema
,
444 const char *partition_dn_str
,
445 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
,
446 uint32_t object_count
,
447 const struct drsuapi_DsReplicaObjectListItemEx
*first_object
,
448 uint32_t linked_attributes_count
,
449 const struct drsuapi_DsReplicaLinkedAttribute
*linked_attributes
,
450 const struct repsFromTo1
*source_dsa
,
451 const struct drsuapi_DsReplicaCursor2CtrEx
*uptodateness_vector
,
452 const DATA_BLOB
*gensec_skey
,
453 uint32_t dsdb_repl_flags
,
455 struct dsdb_extended_replicated_objects
**objects
)
458 struct ldb_dn
*partition_dn
;
459 struct dsdb_schema_prefixmap
*pfm_remote
;
460 struct dsdb_extended_replicated_objects
*out
;
461 const struct drsuapi_DsReplicaObjectListItemEx
*cur
;
464 out
= talloc_zero(mem_ctx
, struct dsdb_extended_replicated_objects
);
465 W_ERROR_HAVE_NO_MEMORY(out
);
466 out
->version
= DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION
;
467 out
->dsdb_repl_flags
= dsdb_repl_flags
;
470 * Ensure schema is kept valid for as long as 'out'
471 * which may contain pointers to it
473 schema
= talloc_reference(out
, schema
);
474 W_ERROR_HAVE_NO_MEMORY(schema
);
476 partition_dn
= ldb_dn_new(out
, ldb
, partition_dn_str
);
477 W_ERROR_HAVE_NO_MEMORY_AND_FREE(partition_dn
, out
);
479 status
= dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr
, true,
480 out
, &pfm_remote
, NULL
);
481 if (!W_ERROR_IS_OK(status
)) {
482 DEBUG(0,(__location__
": Failed to decode remote prefixMap: %s",
483 win_errstr(status
)));
488 if (ldb_dn_compare(partition_dn
, ldb_get_schema_basedn(ldb
)) != 0) {
490 * check for schema changes in case
491 * we are not replicating Schema NC
493 status
= dsdb_schema_info_cmp(schema
, mapping_ctr
);
494 if (!W_ERROR_IS_OK(status
)) {
495 DEBUG(1,("Remote schema has changed while replicating %s\n",
502 out
->partition_dn
= partition_dn
;
504 out
->source_dsa
= source_dsa
;
505 out
->uptodateness_vector
= uptodateness_vector
;
507 out
->num_objects
= object_count
;
508 out
->objects
= talloc_array(out
,
509 struct dsdb_extended_replicated_object
,
511 W_ERROR_HAVE_NO_MEMORY_AND_FREE(out
->objects
, out
);
513 /* pass the linked attributes down to the repl_meta_data
515 out
->linked_attributes_count
= linked_attributes_count
;
516 out
->linked_attributes
= linked_attributes
;
518 for (i
=0, cur
= first_object
; cur
; cur
= cur
->next_object
, i
++) {
519 if (i
== out
->num_objects
) {
524 status
= dsdb_convert_object_ex(ldb
, schema
, pfm_remote
,
528 out
->objects
, &out
->objects
[i
]);
529 if (!W_ERROR_IS_OK(status
)) {
531 DEBUG(0,("Failed to convert object %s: %s\n",
532 cur
->object
.identifier
->dn
,
533 win_errstr(status
)));
537 if (i
!= out
->num_objects
) {
542 /* free pfm_remote, we won't need it anymore */
543 talloc_free(pfm_remote
);
550 * Commits a list of replicated objects.
552 * @param working_schema dsdb_schema to be used for resolving
553 * Classes/Attributes during Schema replication. If not NULL,
554 * it will be set on ldb and used while committing replicated objects
556 WERROR
dsdb_replicated_objects_commit(struct ldb_context
*ldb
,
557 struct dsdb_schema
*working_schema
,
558 struct dsdb_extended_replicated_objects
*objects
,
559 uint64_t *notify_uSN
)
562 struct ldb_result
*ext_res
;
563 struct dsdb_schema
*cur_schema
= NULL
;
564 struct dsdb_schema
*new_schema
= NULL
;
566 uint64_t seq_num1
, seq_num2
;
567 bool used_global_schema
= false;
569 TALLOC_CTX
*tmp_ctx
= talloc_new(objects
);
571 DEBUG(0,("Failed to start talloc\n"));
575 /* TODO: handle linked attributes */
577 /* wrap the extended operation in a transaction
578 See [MS-DRSR] 3.3.2 Transactions
580 ret
= ldb_transaction_start(ldb
);
581 if (ret
!= LDB_SUCCESS
) {
582 DEBUG(0,(__location__
" Failed to start transaction\n"));
586 ret
= dsdb_load_partition_usn(ldb
, objects
->partition_dn
, &seq_num1
, NULL
);
587 if (ret
!= LDB_SUCCESS
) {
588 DEBUG(0,(__location__
" Failed to load partition uSN\n"));
589 ldb_transaction_cancel(ldb
);
590 TALLOC_FREE(tmp_ctx
);
595 * Set working_schema for ldb in case we are replicating from Schema NC.
596 * Schema won't be reloaded during Replicated Objects commit, as it is
597 * done in a transaction. So we need some way to search for newly
598 * added Classes and Attributes
600 if (working_schema
) {
601 /* store current schema so we can fall back in case of failure */
602 cur_schema
= dsdb_get_schema(ldb
, tmp_ctx
);
603 used_global_schema
= dsdb_uses_global_schema(ldb
);
605 ret
= dsdb_reference_schema(ldb
, working_schema
, false);
606 if (ret
!= LDB_SUCCESS
) {
607 DEBUG(0,(__location__
"Failed to reference working schema - %s\n",
609 /* TODO: Map LDB Error to NTSTATUS? */
610 ldb_transaction_cancel(ldb
);
611 TALLOC_FREE(tmp_ctx
);
612 return WERR_INTERNAL_ERROR
;
616 ret
= ldb_extended(ldb
, DSDB_EXTENDED_REPLICATED_OBJECTS_OID
, objects
, &ext_res
);
617 if (ret
!= LDB_SUCCESS
) {
618 /* restore previous schema */
619 if (used_global_schema
) {
620 dsdb_set_global_schema(ldb
);
621 } else if (cur_schema
) {
622 dsdb_reference_schema(ldb
, cur_schema
, false);
625 DEBUG(0,("Failed to apply records: %s: %s\n",
626 ldb_errstring(ldb
), ldb_strerror(ret
)));
627 ldb_transaction_cancel(ldb
);
628 TALLOC_FREE(tmp_ctx
);
631 talloc_free(ext_res
);
633 /* Save our updated prefixMap */
634 if (working_schema
) {
635 werr
= dsdb_write_prefixes_from_schema_to_ldb(working_schema
,
638 if (!W_ERROR_IS_OK(werr
)) {
639 /* restore previous schema */
640 if (used_global_schema
) {
641 dsdb_set_global_schema(ldb
);
642 } else if (cur_schema
) {
643 dsdb_reference_schema(ldb
, cur_schema
, false);
645 DEBUG(0,("Failed to save updated prefixMap: %s\n",
647 TALLOC_FREE(tmp_ctx
);
652 ret
= ldb_transaction_prepare_commit(ldb
);
653 if (ret
!= LDB_SUCCESS
) {
654 /* restore previous schema */
655 if (used_global_schema
) {
656 dsdb_set_global_schema(ldb
);
657 } else if (cur_schema
) {
658 dsdb_reference_schema(ldb
, cur_schema
, false);
660 DEBUG(0,(__location__
" Failed to prepare commit of transaction: %s\n",
661 ldb_errstring(ldb
)));
662 TALLOC_FREE(tmp_ctx
);
666 ret
= dsdb_load_partition_usn(ldb
, objects
->partition_dn
, &seq_num2
, NULL
);
667 if (ret
!= LDB_SUCCESS
) {
668 /* restore previous schema */
669 if (used_global_schema
) {
670 dsdb_set_global_schema(ldb
);
671 } else if (cur_schema
) {
672 dsdb_reference_schema(ldb
, cur_schema
, false);
674 DEBUG(0,(__location__
" Failed to load partition uSN\n"));
675 ldb_transaction_cancel(ldb
);
676 TALLOC_FREE(tmp_ctx
);
680 /* if this replication partner didn't need to be notified
681 before this transaction then it still doesn't need to be
682 notified, as the changes came from this server */
683 if (seq_num2
> seq_num1
&& seq_num1
<= *notify_uSN
) {
684 *notify_uSN
= seq_num2
;
687 ret
= ldb_transaction_commit(ldb
);
688 if (ret
!= LDB_SUCCESS
) {
689 /* restore previous schema */
690 if (used_global_schema
) {
691 dsdb_set_global_schema(ldb
);
692 } else if (cur_schema
) {
693 dsdb_reference_schema(ldb
, cur_schema
, false);
695 DEBUG(0,(__location__
" Failed to commit transaction\n"));
696 TALLOC_FREE(tmp_ctx
);
701 * Reset the Schema used by ldb. This will lead to
702 * a schema cache being refreshed from database.
704 if (working_schema
) {
705 struct ldb_message
*msg
;
706 struct ldb_request
*req
;
709 working_schema
->last_refresh
= 0;
710 new_schema
= dsdb_get_schema(ldb
, tmp_ctx
);
712 * If dsdb_get_schema() fails, we just fall back
713 * to what we had. However, the database is probably
714 * unable to operate for other users from this
716 if (new_schema
&& used_global_schema
) {
717 dsdb_make_schema_global(ldb
, new_schema
);
718 } else if (used_global_schema
) {
719 DEBUG(0,("Failed to re-load schema after commit of transaction\n"));
720 dsdb_set_global_schema(ldb
);
721 TALLOC_FREE(tmp_ctx
);
722 return WERR_INTERNAL_ERROR
;
724 DEBUG(0,("Failed to re-load schema after commit of transaction\n"));
725 dsdb_reference_schema(ldb
, cur_schema
, false);
726 TALLOC_FREE(tmp_ctx
);
727 return WERR_INTERNAL_ERROR
;
729 msg
= ldb_msg_new(tmp_ctx
);
731 TALLOC_FREE(tmp_ctx
);
734 msg
->dn
= ldb_dn_new(msg
, ldb
, "");
735 if (msg
->dn
== NULL
) {
736 TALLOC_FREE(tmp_ctx
);
740 ret
= ldb_msg_add_string(msg
, "schemaUpdateNow", "1");
741 if (ret
!= LDB_SUCCESS
) {
742 TALLOC_FREE(tmp_ctx
);
743 return WERR_INTERNAL_ERROR
;
746 ret
= ldb_build_mod_req(&req
, ldb
, objects
,
750 ldb_op_default_callback
,
753 if (ret
!= LDB_SUCCESS
) {
754 TALLOC_FREE(tmp_ctx
);
755 return WERR_DS_DRA_INTERNAL_ERROR
;
758 ret
= ldb_transaction_start(ldb
);
759 if (ret
!= LDB_SUCCESS
) {
760 TALLOC_FREE(tmp_ctx
);
761 DEBUG(0, ("Autotransaction start failed\n"));
762 return WERR_DS_DRA_INTERNAL_ERROR
;
765 ret
= ldb_request(ldb
, req
);
766 if (ret
== LDB_SUCCESS
) {
767 ret
= ldb_wait(req
->handle
, LDB_WAIT_ALL
);
770 if (ret
== LDB_SUCCESS
) {
771 ret
= ldb_transaction_commit(ldb
);
773 DEBUG(0, ("Schema update now failed: %s\n",
774 ldb_errstring(ldb
)));
775 ldb_transaction_cancel(ldb
);
778 if (ret
!= LDB_SUCCESS
) {
779 DEBUG(0, ("Commit failed: %s\n", ldb_errstring(ldb
)));
780 TALLOC_FREE(tmp_ctx
);
781 return WERR_DS_INTERNAL_FAILURE
;
785 DEBUG(2,("Replicated %u objects (%u linked attributes) for %s\n",
786 objects
->num_objects
, objects
->linked_attributes_count
,
787 ldb_dn_get_linearized(objects
->partition_dn
)));
789 TALLOC_FREE(tmp_ctx
);
793 static WERROR
dsdb_origin_object_convert(struct ldb_context
*ldb
,
794 const struct dsdb_schema
*schema
,
795 const struct drsuapi_DsReplicaObjectListItem
*in
,
797 struct ldb_message
**_msg
)
801 struct ldb_message
*msg
;
803 if (!in
->object
.identifier
) {
807 if (!in
->object
.identifier
->dn
|| !in
->object
.identifier
->dn
[0]) {
811 msg
= ldb_msg_new(mem_ctx
);
812 W_ERROR_HAVE_NO_MEMORY(msg
);
814 msg
->dn
= ldb_dn_new(msg
, ldb
, in
->object
.identifier
->dn
);
815 W_ERROR_HAVE_NO_MEMORY(msg
->dn
);
817 msg
->num_elements
= in
->object
.attribute_ctr
.num_attributes
;
818 msg
->elements
= talloc_array(msg
, struct ldb_message_element
,
820 W_ERROR_HAVE_NO_MEMORY(msg
->elements
);
822 for (i
=0; i
< msg
->num_elements
; i
++) {
823 struct drsuapi_DsReplicaAttribute
*a
;
824 struct ldb_message_element
*e
;
826 a
= &in
->object
.attribute_ctr
.attributes
[i
];
827 e
= &msg
->elements
[i
];
829 status
= dsdb_attribute_drsuapi_to_ldb(ldb
, schema
, schema
->prefixmap
,
830 a
, msg
->elements
, e
);
831 W_ERROR_NOT_OK_RETURN(status
);
840 WERROR
dsdb_origin_objects_commit(struct ldb_context
*ldb
,
842 const struct drsuapi_DsReplicaObjectListItem
*first_object
,
844 uint32_t dsdb_repl_flags
,
845 struct drsuapi_DsReplicaObjectIdentifier2
**_ids
)
848 const struct dsdb_schema
*schema
;
849 const struct drsuapi_DsReplicaObjectListItem
*cur
;
850 struct ldb_message
**objects
;
851 struct drsuapi_DsReplicaObjectIdentifier2
*ids
;
853 uint32_t num_objects
= 0;
854 const char * const attrs
[] = {
859 struct ldb_result
*res
;
862 for (cur
= first_object
; cur
; cur
= cur
->next_object
) {
866 if (num_objects
== 0) {
870 ret
= ldb_transaction_start(ldb
);
871 if (ret
!= LDB_SUCCESS
) {
872 return WERR_DS_INTERNAL_FAILURE
;
875 objects
= talloc_array(mem_ctx
, struct ldb_message
*,
877 if (objects
== NULL
) {
882 schema
= dsdb_get_schema(ldb
, objects
);
884 return WERR_DS_SCHEMA_NOT_LOADED
;
887 for (i
=0, cur
= first_object
; cur
; cur
= cur
->next_object
, i
++) {
888 status
= dsdb_origin_object_convert(ldb
, schema
, cur
,
889 objects
, &objects
[i
]);
890 if (!W_ERROR_IS_OK(status
)) {
895 ids
= talloc_array(mem_ctx
,
896 struct drsuapi_DsReplicaObjectIdentifier2
,
903 if (dsdb_repl_flags
& DSDB_REPL_FLAG_ADD_NCNAME
) {
904 /* check for possible NC creation */
905 for (i
=0; i
< num_objects
; i
++) {
906 struct ldb_message
*msg
= objects
[i
];
907 struct ldb_message_element
*el
;
908 struct ldb_dn
*nc_dn
;
910 if (ldb_msg_check_string_attribute(msg
, "objectClass", "crossRef") == 0) {
913 el
= ldb_msg_find_element(msg
, "nCName");
914 if (el
== NULL
|| el
->num_values
!= 1) {
917 nc_dn
= ldb_dn_from_ldb_val(objects
, ldb
, &el
->values
[0]);
918 if (!ldb_dn_validate(nc_dn
)) {
921 ret
= dsdb_create_partial_replica_NC(ldb
, nc_dn
);
922 if (ret
!= LDB_SUCCESS
) {
923 status
= WERR_DS_INTERNAL_FAILURE
;
929 for (i
=0; i
< num_objects
; i
++) {
930 struct dom_sid
*sid
= NULL
;
931 struct ldb_request
*add_req
;
933 DEBUG(6,(__location__
": adding %s\n",
934 ldb_dn_get_linearized(objects
[i
]->dn
)));
936 ret
= ldb_build_add_req(&add_req
,
942 ldb_op_default_callback
,
944 if (ret
!= LDB_SUCCESS
) {
945 status
= WERR_DS_INTERNAL_FAILURE
;
949 ret
= ldb_request_add_control(add_req
, LDB_CONTROL_RELAX_OID
, true, NULL
);
950 if (ret
!= LDB_SUCCESS
) {
951 status
= WERR_DS_INTERNAL_FAILURE
;
955 ret
= ldb_request(ldb
, add_req
);
956 if (ret
== LDB_SUCCESS
) {
957 ret
= ldb_wait(add_req
->handle
, LDB_WAIT_ALL
);
959 if (ret
!= LDB_SUCCESS
) {
960 DEBUG(0,(__location__
": Failed add of %s - %s\n",
961 ldb_dn_get_linearized(objects
[i
]->dn
), ldb_errstring(ldb
)));
962 status
= WERR_DS_INTERNAL_FAILURE
;
966 talloc_free(add_req
);
968 ret
= ldb_search(ldb
, objects
, &res
, objects
[i
]->dn
,
969 LDB_SCOPE_BASE
, attrs
,
971 if (ret
!= LDB_SUCCESS
) {
972 status
= WERR_DS_INTERNAL_FAILURE
;
975 ids
[i
].guid
= samdb_result_guid(res
->msgs
[0], "objectGUID");
976 sid
= samdb_result_dom_sid(objects
, res
->msgs
[0], "objectSid");
980 ZERO_STRUCT(ids
[i
].sid
);
984 ret
= ldb_transaction_commit(ldb
);
985 if (ret
!= LDB_SUCCESS
) {
986 return WERR_DS_INTERNAL_FAILURE
;
989 talloc_free(objects
);
996 talloc_free(objects
);
997 ldb_transaction_cancel(ldb
);