2 Unix SMB/CIFS implementation.
4 Extract the user/system database from a remote server
6 Copyright (C) Stefan Metzmacher 2004-2006
7 Copyright (C) Brad Henry 2005
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2008
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "libnet/libnet.h"
27 #include "lib/events/events.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "../lib/util/dlinklist.h"
31 #include <ldb_errors.h>
32 #include "librpc/ndr/libndr.h"
33 #include "librpc/gen_ndr/ndr_drsuapi.h"
34 #include "librpc/gen_ndr/ndr_drsblobs.h"
35 #include "librpc/gen_ndr/ndr_misc.h"
36 #include "system/time.h"
38 #include "auth/auth.h"
39 #include "auth/credentials/credentials.h"
40 #include "param/param.h"
41 #include "param/provision.h"
42 #include "libcli/security/security.h"
43 #include "dsdb/common/util.h"
46 List of tasks vampire.py must perform:
48 - but don't write the secrets.ldb
49 - results for this should be enough to handle the provision
50 - if vampire method is samsync
51 - Provision using these results
52 - do we still want to support this NT4 technology?
53 - Start samsync with libnet code
54 - provision in the callback
55 - Write out the secrets database, using the code from libnet_Join
58 struct libnet_vampire_cb_state
{
59 const char *netbios_name
;
60 const char *domain_name
;
62 struct cli_credentials
*machine_account
;
64 /* Schema loaded from local LDIF files */
65 struct dsdb_schema
*provision_schema
;
67 /* 1st pass, with some OIDs/attribute names/class names not
68 * converted, because we may not know them yet */
69 struct dsdb_schema
*self_made_schema
;
71 /* prefixMap in LDB format, from the remote DRS server */
72 DATA_BLOB prefixmap_blob
;
73 const struct dsdb_schema
*schema
;
75 struct ldb_context
*ldb
;
78 uint32_t object_count
;
79 struct drsuapi_DsReplicaObjectListItemEx
*first_object
;
80 struct drsuapi_DsReplicaObjectListItemEx
*last_object
;
83 const char *targetdir
;
85 struct loadparm_context
*lp_ctx
;
86 struct tevent_context
*event_ctx
;
87 unsigned total_objects
;
89 const char *server_dn_str
;
92 /* initialise a state structure ready for replication of chunks */
93 void *libnet_vampire_replicate_init(TALLOC_CTX
*mem_ctx
,
94 struct ldb_context
*samdb
,
95 struct loadparm_context
*lp_ctx
)
97 struct libnet_vampire_cb_state
*s
= talloc_zero(mem_ctx
, struct libnet_vampire_cb_state
);
104 s
->provision_schema
= dsdb_get_schema(s
->ldb
, s
);
105 s
->schema
= s
->provision_schema
;
106 s
->netbios_name
= lpcfg_netbios_name(lp_ctx
);
107 s
->domain_name
= lpcfg_workgroup(lp_ctx
);
108 s
->realm
= lpcfg_realm(lp_ctx
);
113 /* Caller is expected to keep supplied pointers around for the lifetime of the structure */
114 void *libnet_vampire_cb_state_init(TALLOC_CTX
*mem_ctx
,
115 struct loadparm_context
*lp_ctx
, struct tevent_context
*event_ctx
,
116 const char *netbios_name
, const char *domain_name
, const char *realm
,
117 const char *targetdir
)
119 struct libnet_vampire_cb_state
*s
= talloc_zero(mem_ctx
, struct libnet_vampire_cb_state
);
125 s
->event_ctx
= event_ctx
;
126 s
->netbios_name
= netbios_name
;
127 s
->domain_name
= domain_name
;
129 s
->targetdir
= targetdir
;
133 struct ldb_context
*libnet_vampire_cb_ldb(struct libnet_vampire_cb_state
*state
)
135 state
= talloc_get_type_abort(state
, struct libnet_vampire_cb_state
);
139 struct loadparm_context
*libnet_vampire_cb_lp_ctx(struct libnet_vampire_cb_state
*state
)
141 state
= talloc_get_type_abort(state
, struct libnet_vampire_cb_state
);
142 return state
->lp_ctx
;
145 NTSTATUS
libnet_vampire_cb_prepare_db(void *private_data
,
146 const struct libnet_BecomeDC_PrepareDB
*p
)
148 struct libnet_vampire_cb_state
*s
= talloc_get_type(private_data
, struct libnet_vampire_cb_state
);
149 struct provision_settings settings
;
150 struct provision_result result
;
153 ZERO_STRUCT(settings
);
154 settings
.site_name
= p
->dest_dsa
->site_name
;
155 settings
.root_dn_str
= p
->forest
->root_dn_str
;
156 settings
.domain_dn_str
= p
->domain
->dn_str
;
157 settings
.config_dn_str
= p
->forest
->config_dn_str
;
158 settings
.schema_dn_str
= p
->forest
->schema_dn_str
;
159 settings
.netbios_name
= p
->dest_dsa
->netbios_name
;
160 settings
.realm
= s
->realm
;
161 settings
.domain
= s
->domain_name
;
162 settings
.server_dn_str
= p
->dest_dsa
->server_dn_str
;
163 settings
.machine_password
= generate_random_password(s
, 16, 255);
164 settings
.targetdir
= s
->targetdir
;
165 settings
.use_ntvfs
= true;
166 status
= provision_bare(s
, s
->lp_ctx
, &settings
, &result
);
168 if (!NT_STATUS_IS_OK(status
)) {
172 s
->ldb
= talloc_steal(s
, result
.samdb
);
173 s
->lp_ctx
= talloc_reparent(talloc_parent(result
.lp_ctx
), s
, result
.lp_ctx
);
174 s
->provision_schema
= dsdb_get_schema(s
->ldb
, s
);
175 s
->server_dn_str
= talloc_steal(s
, p
->dest_dsa
->server_dn_str
);
177 /* wrap the entire vapire operation in a transaction. This
178 isn't just cosmetic - we use this to ensure that linked
179 attribute back links are added at the end by relying on a
180 transaction commit hook in the linked attributes module. We
181 need to do this as the order of objects coming from the
182 server is not sufficiently deterministic to know that the
183 record that a backlink needs to be created in has itself
184 been created before the object containing the forward link
185 has come over the wire */
186 if (ldb_transaction_start(s
->ldb
) != LDB_SUCCESS
) {
187 return NT_STATUS_FOOBAR
;
195 NTSTATUS
libnet_vampire_cb_check_options(void *private_data
,
196 const struct libnet_BecomeDC_CheckOptions
*o
)
198 struct libnet_vampire_cb_state
*s
= talloc_get_type(private_data
, struct libnet_vampire_cb_state
);
200 DEBUG(0,("Become DC [%s] of Domain[%s]/[%s]\n",
202 o
->domain
->netbios_name
, o
->domain
->dns_name
));
204 DEBUG(0,("Promotion Partner is Server[%s] from Site[%s]\n",
205 o
->source_dsa
->dns_name
, o
->source_dsa
->site_name
));
207 DEBUG(0,("Options:crossRef behavior_version[%u]\n"
208 "\tschema object_version[%u]\n"
209 "\tdomain behavior_version[%u]\n"
210 "\tdomain w2k3_update_revision[%u]\n",
211 o
->forest
->crossref_behavior_version
,
212 o
->forest
->schema_object_version
,
213 o
->domain
->behavior_version
,
214 o
->domain
->w2k3_update_revision
));
219 static NTSTATUS
libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state
*s
,
220 const struct libnet_BecomeDC_StoreChunk
*c
)
223 struct schema_list
*next
, *prev
;
224 const struct drsuapi_DsReplicaObjectListItemEx
*obj
;
228 struct dsdb_schema_prefixmap
*pfm_remote
;
229 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
;
230 struct schema_list
*schema_list
= NULL
, *schema_list_item
, *schema_list_next_item
;
231 struct dsdb_schema
*working_schema
;
232 struct dsdb_schema
*provision_schema
;
233 uint32_t object_count
= 0;
234 struct drsuapi_DsReplicaObjectListItemEx
*first_object
;
235 const struct drsuapi_DsReplicaObjectListItemEx
*cur
;
236 uint32_t linked_attributes_count
;
237 struct drsuapi_DsReplicaLinkedAttribute
*linked_attributes
;
238 const struct drsuapi_DsReplicaCursor2CtrEx
*uptodateness_vector
;
239 struct dsdb_extended_replicated_objects
*schema_objs
;
240 struct repsFromTo1
*s_dsa
;
242 struct ldb_context
*schema_ldb
;
243 struct ldb_message
*msg
;
244 struct ldb_message_element
*prefixMap_el
;
249 uint32_t ignore_attids
[] = {
250 DRSUAPI_ATTID_auxiliaryClass
,
251 DRSUAPI_ATTID_mayContain
,
252 DRSUAPI_ATTID_mustContain
,
253 DRSUAPI_ATTID_possSuperiors
,
254 DRSUAPI_ATTID_systemPossSuperiors
,
255 DRSUAPI_ATTID_INVALID
258 DEBUG(0,("Analyze and apply schema objects\n"));
260 s_dsa
= talloc_zero(s
, struct repsFromTo1
);
261 NT_STATUS_HAVE_NO_MEMORY(s_dsa
);
262 s_dsa
->other_info
= talloc(s_dsa
, struct repsFromTo1OtherInfo
);
263 NT_STATUS_HAVE_NO_MEMORY(s_dsa
->other_info
);
265 switch (c
->ctr_level
) {
267 mapping_ctr
= &c
->ctr1
->mapping_ctr
;
268 object_count
= s
->schema_part
.object_count
;
269 first_object
= s
->schema_part
.first_object
;
270 linked_attributes_count
= 0;
271 linked_attributes
= NULL
;
272 s_dsa
->highwatermark
= c
->ctr1
->new_highwatermark
;
273 s_dsa
->source_dsa_obj_guid
= c
->ctr1
->source_dsa_guid
;
274 s_dsa
->source_dsa_invocation_id
= c
->ctr1
->source_dsa_invocation_id
;
275 uptodateness_vector
= NULL
; /* TODO: map it */
278 mapping_ctr
= &c
->ctr6
->mapping_ctr
;
279 object_count
= s
->schema_part
.object_count
;
280 first_object
= s
->schema_part
.first_object
;
281 linked_attributes_count
= c
->ctr6
->linked_attributes_count
;
282 linked_attributes
= c
->ctr6
->linked_attributes
;
283 s_dsa
->highwatermark
= c
->ctr6
->new_highwatermark
;
284 s_dsa
->source_dsa_obj_guid
= c
->ctr6
->source_dsa_guid
;
285 s_dsa
->source_dsa_invocation_id
= c
->ctr6
->source_dsa_invocation_id
;
286 uptodateness_vector
= c
->ctr6
->uptodateness_vector
;
289 return NT_STATUS_INVALID_PARAMETER
;
291 /* We must set these up to ensure the replMetaData is written
292 * correctly, before our NTDS Settings entry is replicated */
293 ok
= samdb_set_ntds_invocation_id(s
->ldb
, &c
->dest_dsa
->invocation_id
);
295 DEBUG(0,("Failed to set cached ntds invocationId\n"));
296 return NT_STATUS_FOOBAR
;
298 ok
= samdb_set_ntds_objectGUID(s
->ldb
, &c
->dest_dsa
->ntds_guid
);
300 DEBUG(0,("Failed to set cached ntds objectGUID\n"));
301 return NT_STATUS_FOOBAR
;
305 status
= dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr
, true,
306 s
, &pfm_remote
, NULL
);
307 if (!W_ERROR_IS_OK(status
)) {
308 DEBUG(0,(__location__
": Failed to decode remote prefixMap: %s",
309 win_errstr(status
)));
310 return werror_to_ntstatus(status
);
313 s_dsa
->replica_flags
= DRSUAPI_DRS_WRIT_REP
314 | DRSUAPI_DRS_INIT_SYNC
315 | DRSUAPI_DRS_PER_SYNC
;
316 memset(s_dsa
->schedule
, 0x11, sizeof(s_dsa
->schedule
));
318 tmp_dns_name
= GUID_string(s_dsa
->other_info
, &s_dsa
->source_dsa_obj_guid
);
319 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name
);
320 tmp_dns_name
= talloc_asprintf_append_buffer(tmp_dns_name
, "._msdcs.%s", c
->forest
->dns_name
);
321 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name
);
322 s_dsa
->other_info
->dns_name
= tmp_dns_name
;
324 schema_ldb
= provision_get_schema(s
, s
->lp_ctx
,
325 c
->forest
->schema_dn_str
,
328 DEBUG(0,("Failed to re-load from local provision using remote prefixMap. "
329 "Will continue with local prefixMap\n"));
330 provision_schema
= dsdb_get_schema(s
->ldb
, s
);
332 provision_schema
= dsdb_get_schema(schema_ldb
, s
);
333 ret
= dsdb_reference_schema(s
->ldb
, provision_schema
, false);
334 if (ret
!= LDB_SUCCESS
) {
335 DEBUG(0,("Failed to attach schema from local provision using remote prefixMap."));
336 return NT_STATUS_UNSUCCESSFUL
;
338 talloc_free(schema_ldb
);
341 /* create a list of objects yet to be converted */
342 for (cur
= first_object
; cur
; cur
= cur
->next_object
) {
343 schema_list_item
= talloc(s
, struct schema_list
);
344 schema_list_item
->obj
= cur
;
345 DLIST_ADD_END(schema_list
, schema_list_item
, struct schema_list
);
348 /* resolve objects until all are resolved and in local schema */
350 working_schema
= provision_schema
;
352 while (schema_list
) {
353 uint32_t converted_obj_count
= 0;
354 uint32_t failed_obj_count
= 0;
355 TALLOC_CTX
*tmp_ctx
= talloc_new(s
);
356 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
358 for (schema_list_item
= schema_list
; schema_list_item
; schema_list_item
=schema_list_next_item
) {
359 struct dsdb_extended_replicated_object object
;
361 cur
= schema_list_item
->obj
;
363 /* Save the next item, now we have saved out
364 * the current one, so we can DLIST_REMOVE it
366 schema_list_next_item
= schema_list_item
->next
;
369 * Convert the objects into LDB messages using the
370 * schema we have so far. It's ok if we fail to convert
371 * an object. We should convert more objects on next pass.
373 status
= dsdb_convert_object_ex(s
->ldb
, working_schema
, pfm_remote
,
378 if (!W_ERROR_IS_OK(status
)) {
379 DEBUG(1,("Warning: Failed to convert schema object %s into ldb msg\n",
380 cur
->object
.identifier
->dn
));
385 * Convert the schema from ldb_message format
386 * (OIDs as OID strings) into schema, using
387 * the remote prefixMap
389 status
= dsdb_schema_set_el_from_ldb_msg(s
->ldb
,
392 if (!W_ERROR_IS_OK(status
)) {
393 DEBUG(1,("Warning: failed to convert object %s into a schema element: %s\n",
394 ldb_dn_get_linearized(object
.msg
->dn
),
395 win_errstr(status
)));
398 DLIST_REMOVE(schema_list
, schema_list_item
);
399 converted_obj_count
++;
403 talloc_free(tmp_ctx
);
405 DEBUG(4,("Schema load pass %d: %d/%d of %d objects left to be converted.\n",
406 pass_no
, failed_obj_count
, converted_obj_count
, object_count
));
409 /* check if we converted any objects in this pass */
410 if (converted_obj_count
== 0) {
411 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
));
412 return NT_STATUS_INTERNAL_ERROR
;
416 /* prepare for another cycle */
417 working_schema
= s
->self_made_schema
;
419 ret
= dsdb_setup_sorted_accessors(s
->ldb
, working_schema
);
420 if (LDB_SUCCESS
!= ret
) {
421 DEBUG(0,("Failed to create schema-cache indexes!\n"));
422 return NT_STATUS_INTERNAL_ERROR
;
427 /* free temp objects for 1st conversion phase */
428 talloc_unlink(s
, provision_schema
);
429 TALLOC_FREE(schema_list
);
432 * attach the schema we just brought over DRS to the ldb,
433 * so we can use it in dsdb_convert_object_ex below
435 ret
= dsdb_set_schema(s
->ldb
, s
->self_made_schema
);
436 if (ret
!= LDB_SUCCESS
) {
437 DEBUG(0,("Failed to attach working schema from DRS.\n"));
438 return NT_STATUS_FOOBAR
;
441 /* we don't want to access the self made schema anymore */
442 s
->schema
= s
->self_made_schema
;
443 s
->self_made_schema
= NULL
;
445 /* Now convert the schema elements again, using the schema we finalised, ready to actually import */
446 status
= dsdb_replicated_objects_convert(s
->ldb
,
452 linked_attributes_count
,
459 if (!W_ERROR_IS_OK(status
)) {
460 DEBUG(0,("Failed to convert objects when trying to import over DRS (2nd pass, to store remote schema): %s\n", win_errstr(status
)));
461 return werror_to_ntstatus(status
);
464 if (lpcfg_parm_bool(s
->lp_ctx
, NULL
, "become dc", "dump objects", false)) {
465 for (i
=0; i
< schema_objs
->num_objects
; i
++) {
466 struct ldb_ldif ldif
;
467 fprintf(stdout
, "#\n");
468 ldif
.changetype
= LDB_CHANGETYPE_NONE
;
469 ldif
.msg
= schema_objs
->objects
[i
].msg
;
470 ldb_ldif_write_file(s
->ldb
, stdout
, &ldif
);
471 NDR_PRINT_DEBUG(replPropertyMetaDataBlob
, schema_objs
->objects
[i
].meta_data
);
475 status
= dsdb_replicated_objects_commit(s
->ldb
, NULL
, schema_objs
, &seq_num
);
476 if (!W_ERROR_IS_OK(status
)) {
477 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status
)));
478 return werror_to_ntstatus(status
);
481 msg
= ldb_msg_new(schema_objs
);
482 NT_STATUS_HAVE_NO_MEMORY(msg
);
483 msg
->dn
= schema_objs
->partition_dn
;
485 /* We must ensure a prefixMap has been written. Unlike other
486 * attributes (including schemaInfo), it is not replicated in
487 * the normal replication stream. We can use the one from
488 * s->prefixmap_blob because we operate with one, unchanging
489 * prefixMap for this entire operation. */
490 ret
= ldb_msg_add_value(msg
, "prefixMap", &s
->prefixmap_blob
, &prefixMap_el
);
491 if (ret
!= LDB_SUCCESS
) {
492 return NT_STATUS_FOOBAR
;
494 /* We want to know if a prefixMap was written already, as it
495 * would mean that the above comment was not true, and we have
496 * somehow updated the prefixMap during this transaction */
497 prefixMap_el
->flags
= LDB_FLAG_MOD_ADD
;
499 ret
= dsdb_modify(s
->ldb
, msg
, DSDB_FLAG_AS_SYSTEM
);
500 if (ret
!= LDB_SUCCESS
) {
501 DEBUG(0,("Failed to add prefixMap: %s\n", ldb_errstring(s
->ldb
)));
502 return NT_STATUS_FOOBAR
;
506 talloc_free(schema_objs
);
508 s
->schema
= dsdb_get_schema(s
->ldb
, s
);
510 DEBUG(0,("Failed to get loaded dsdb_schema\n"));
511 return NT_STATUS_FOOBAR
;
517 NTSTATUS
libnet_vampire_cb_schema_chunk(void *private_data
,
518 const struct libnet_BecomeDC_StoreChunk
*c
)
520 struct libnet_vampire_cb_state
*s
= talloc_get_type(private_data
, struct libnet_vampire_cb_state
);
522 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
;
523 uint32_t nc_object_count
;
524 uint32_t nc_total_received
= 0;
525 uint32_t object_count
;
526 struct drsuapi_DsReplicaObjectListItemEx
*first_object
;
527 struct drsuapi_DsReplicaObjectListItemEx
*cur
;
528 uint32_t nc_linked_attributes_count
;
529 uint32_t linked_attributes_count
;
531 switch (c
->ctr_level
) {
533 mapping_ctr
= &c
->ctr1
->mapping_ctr
;
534 nc_object_count
= c
->ctr1
->extended_ret
; /* maybe w2k send this unexpected? */
535 object_count
= c
->ctr1
->object_count
;
536 first_object
= c
->ctr1
->first_object
;
537 nc_linked_attributes_count
= 0;
538 linked_attributes_count
= 0;
541 mapping_ctr
= &c
->ctr6
->mapping_ctr
;
542 nc_object_count
= c
->ctr6
->nc_object_count
;
543 object_count
= c
->ctr6
->object_count
;
544 first_object
= c
->ctr6
->first_object
;
545 nc_linked_attributes_count
= c
->ctr6
->nc_linked_attributes_count
;
546 linked_attributes_count
= c
->ctr6
->linked_attributes_count
;
549 return NT_STATUS_INVALID_PARAMETER
;
552 if (!s
->schema_part
.first_object
) {
553 nc_total_received
= object_count
;
555 nc_total_received
= s
->schema_part
.object_count
+ object_count
;
557 if (nc_object_count
) {
558 DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n",
559 c
->partition
->nc
.dn
, nc_total_received
, nc_object_count
,
560 linked_attributes_count
, nc_linked_attributes_count
));
562 DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u]\n",
563 c
->partition
->nc
.dn
, nc_total_received
, linked_attributes_count
));
566 if (!s
->self_made_schema
) {
568 struct drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr_without_schema_info
;
569 /* Put the DRS prefixmap aside for the schema we are
570 * about to load in the provision, and into the one we
571 * are making with the help of DRS */
573 mapping_ctr_without_schema_info
= *mapping_ctr
;
575 /* This strips off the 0xFF schema info from the end,
576 * because we don't want it in the blob */
577 if (mapping_ctr_without_schema_info
.num_mappings
> 0) {
578 mapping_ctr_without_schema_info
.num_mappings
--;
580 werr
= dsdb_get_drsuapi_prefixmap_as_blob(&mapping_ctr_without_schema_info
, s
, &s
->prefixmap_blob
);
581 if (!W_ERROR_IS_OK(werr
)) {
582 return werror_to_ntstatus(werr
);
585 /* Set up two manually-constructed schema - the local
586 * schema from the provision will be used to build
587 * one, which will then in turn be used to build the
589 s
->self_made_schema
= dsdb_new_schema(s
);
590 NT_STATUS_HAVE_NO_MEMORY(s
->self_made_schema
);
592 s
->self_made_schema
->base_dn
= ldb_dn_new(s
->self_made_schema
,
594 c
->forest
->schema_dn_str
);
595 NT_STATUS_HAVE_NO_MEMORY(s
->self_made_schema
->base_dn
);
597 status
= dsdb_load_prefixmap_from_drsuapi(s
->self_made_schema
, mapping_ctr
);
598 if (!W_ERROR_IS_OK(status
)) {
599 return werror_to_ntstatus(status
);
602 status
= dsdb_schema_pfm_contains_drsuapi_pfm(s
->self_made_schema
->prefixmap
, mapping_ctr
);
603 if (!W_ERROR_IS_OK(status
)) {
604 return werror_to_ntstatus(status
);
608 if (!s
->schema_part
.first_object
) {
609 s
->schema_part
.object_count
= object_count
;
610 s
->schema_part
.first_object
= talloc_steal(s
, first_object
);
612 s
->schema_part
.object_count
+= object_count
;
613 s
->schema_part
.last_object
->next_object
= talloc_steal(s
->schema_part
.last_object
,
616 for (cur
= first_object
; cur
->next_object
; cur
= cur
->next_object
) {}
617 s
->schema_part
.last_object
= cur
;
619 if (!c
->partition
->more_data
) {
620 return libnet_vampire_cb_apply_schema(s
, c
);
626 NTSTATUS
libnet_vampire_cb_store_chunk(void *private_data
,
627 const struct libnet_BecomeDC_StoreChunk
*c
)
629 struct libnet_vampire_cb_state
*s
= talloc_get_type(private_data
, struct libnet_vampire_cb_state
);
631 struct dsdb_schema
*schema
;
632 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
;
633 uint32_t nc_object_count
;
634 uint32_t object_count
;
635 struct drsuapi_DsReplicaObjectListItemEx
*first_object
;
636 uint32_t nc_linked_attributes_count
;
637 uint32_t linked_attributes_count
;
638 struct drsuapi_DsReplicaLinkedAttribute
*linked_attributes
;
639 const struct drsuapi_DsReplicaCursor2CtrEx
*uptodateness_vector
;
640 struct dsdb_extended_replicated_objects
*objs
;
641 uint32_t req_replica_flags
;
642 struct repsFromTo1
*s_dsa
;
646 bool is_exop
= false;
648 s_dsa
= talloc_zero(s
, struct repsFromTo1
);
649 NT_STATUS_HAVE_NO_MEMORY(s_dsa
);
650 s_dsa
->other_info
= talloc(s_dsa
, struct repsFromTo1OtherInfo
);
651 NT_STATUS_HAVE_NO_MEMORY(s_dsa
->other_info
);
653 switch (c
->ctr_level
) {
655 mapping_ctr
= &c
->ctr1
->mapping_ctr
;
656 nc_object_count
= c
->ctr1
->extended_ret
; /* maybe w2k send this unexpected? */
657 object_count
= c
->ctr1
->object_count
;
658 first_object
= c
->ctr1
->first_object
;
659 nc_linked_attributes_count
= 0;
660 linked_attributes_count
= 0;
661 linked_attributes
= NULL
;
662 s_dsa
->highwatermark
= c
->ctr1
->new_highwatermark
;
663 s_dsa
->source_dsa_obj_guid
= c
->ctr1
->source_dsa_guid
;
664 s_dsa
->source_dsa_invocation_id
= c
->ctr1
->source_dsa_invocation_id
;
665 uptodateness_vector
= NULL
; /* TODO: map it */
668 mapping_ctr
= &c
->ctr6
->mapping_ctr
;
669 nc_object_count
= c
->ctr6
->nc_object_count
;
670 object_count
= c
->ctr6
->object_count
;
671 first_object
= c
->ctr6
->first_object
;
672 nc_linked_attributes_count
= c
->ctr6
->nc_linked_attributes_count
;
673 linked_attributes_count
= c
->ctr6
->linked_attributes_count
;
674 linked_attributes
= c
->ctr6
->linked_attributes
;
675 s_dsa
->highwatermark
= c
->ctr6
->new_highwatermark
;
676 s_dsa
->source_dsa_obj_guid
= c
->ctr6
->source_dsa_guid
;
677 s_dsa
->source_dsa_invocation_id
= c
->ctr6
->source_dsa_invocation_id
;
678 uptodateness_vector
= c
->ctr6
->uptodateness_vector
;
681 return NT_STATUS_INVALID_PARAMETER
;
684 switch (c
->req_level
) {
687 req_replica_flags
= 0;
690 if (c
->req5
->extended_op
!= DRSUAPI_EXOP_NONE
) {
693 req_replica_flags
= c
->req5
->replica_flags
;
696 if (c
->req8
->extended_op
!= DRSUAPI_EXOP_NONE
) {
699 req_replica_flags
= c
->req8
->replica_flags
;
702 if (c
->req10
->extended_op
!= DRSUAPI_EXOP_NONE
) {
705 req_replica_flags
= c
->req10
->replica_flags
;
708 return NT_STATUS_INVALID_PARAMETER
;
711 if (req_replica_flags
& DRSUAPI_DRS_CRITICAL_ONLY
) {
713 * If we only replicate the critical objects
714 * we should not remember what we already
715 * got, as it is incomplete.
717 ZERO_STRUCT(s_dsa
->highwatermark
);
718 uptodateness_vector
= NULL
;
721 /* TODO: avoid hardcoded flags */
722 s_dsa
->replica_flags
= DRSUAPI_DRS_WRIT_REP
723 | DRSUAPI_DRS_INIT_SYNC
724 | DRSUAPI_DRS_PER_SYNC
;
725 memset(s_dsa
->schedule
, 0x11, sizeof(s_dsa
->schedule
));
727 tmp_dns_name
= GUID_string(s_dsa
->other_info
, &s_dsa
->source_dsa_obj_guid
);
728 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name
);
729 tmp_dns_name
= talloc_asprintf_append_buffer(tmp_dns_name
, "._msdcs.%s", c
->forest
->dns_name
);
730 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name
);
731 s_dsa
->other_info
->dns_name
= tmp_dns_name
;
733 /* we want to show a count per partition */
734 if (!s
->last_partition
|| strcmp(s
->last_partition
, c
->partition
->nc
.dn
) != 0) {
735 s
->total_objects
= 0;
736 talloc_free(s
->last_partition
);
737 s
->last_partition
= talloc_strdup(s
, c
->partition
->nc
.dn
);
739 s
->total_objects
+= object_count
;
742 if (nc_object_count
) {
743 DEBUG(0,("Exop on[%s] objects[%u/%u] linked_values[%u/%u]\n",
744 c
->partition
->nc
.dn
, s
->total_objects
, nc_object_count
,
745 linked_attributes_count
, nc_linked_attributes_count
));
747 DEBUG(0,("Exop on[%s] objects[%u] linked_values[%u]\n",
748 c
->partition
->nc
.dn
, s
->total_objects
, linked_attributes_count
));
751 if (nc_object_count
) {
752 DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n",
753 c
->partition
->nc
.dn
, s
->total_objects
, nc_object_count
,
754 linked_attributes_count
, nc_linked_attributes_count
));
756 DEBUG(0,("Partition[%s] objects[%u] linked_values[%u]\n",
757 c
->partition
->nc
.dn
, s
->total_objects
, linked_attributes_count
));
762 schema
= dsdb_get_schema(s
->ldb
, NULL
);
764 DEBUG(0,(__location__
": Schema is not loaded yet!\n"));
765 return NT_STATUS_INTERNAL_ERROR
;
768 status
= dsdb_replicated_objects_convert(s
->ldb
,
774 linked_attributes_count
,
781 if (!W_ERROR_IS_OK(status
)) {
782 DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status
)));
783 return werror_to_ntstatus(status
);
786 if (lpcfg_parm_bool(s
->lp_ctx
, NULL
, "become dc", "dump objects", false)) {
787 for (i
=0; i
< objs
->num_objects
; i
++) {
788 struct ldb_ldif ldif
;
789 fprintf(stdout
, "#\n");
790 ldif
.changetype
= LDB_CHANGETYPE_NONE
;
791 ldif
.msg
= objs
->objects
[i
].msg
;
792 ldb_ldif_write_file(s
->ldb
, stdout
, &ldif
);
793 NDR_PRINT_DEBUG(replPropertyMetaDataBlob
, objs
->objects
[i
].meta_data
);
796 status
= dsdb_replicated_objects_commit(s
->ldb
, NULL
, objs
, &seq_num
);
797 if (!W_ERROR_IS_OK(status
)) {
798 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status
)));
799 return werror_to_ntstatus(status
);
805 for (i
=0; i
< linked_attributes_count
; i
++) {
806 const struct dsdb_attribute
*sa
;
808 if (!linked_attributes
[i
].identifier
) {
809 DEBUG(0, ("No linked attribute identifier\n"));
810 return NT_STATUS_FOOBAR
;
813 if (!linked_attributes
[i
].value
.blob
) {
814 DEBUG(0, ("No linked attribute value\n"));
815 return NT_STATUS_FOOBAR
;
818 sa
= dsdb_attribute_by_attributeID_id(s
->schema
,
819 linked_attributes
[i
].attid
);
821 DEBUG(0, ("Unable to find attribute via attribute id %d\n", linked_attributes
[i
].attid
));
822 return NT_STATUS_FOOBAR
;
825 if (lpcfg_parm_bool(s
->lp_ctx
, NULL
, "become dc", "dump objects", false)) {
826 DEBUG(0,("# %s\n", sa
->lDAPDisplayName
));
827 NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute
, &linked_attributes
[i
]);
829 linked_attributes
[i
].value
.blob
->data
,
830 linked_attributes
[i
].value
.blob
->length
);
837 static NTSTATUS
update_dnshostname_for_server(TALLOC_CTX
*mem_ctx
,
838 struct ldb_context
*ldb
,
839 const char *server_dn_str
,
840 const char *netbios_name
,
844 struct ldb_message
*msg
;
845 struct ldb_message_element
*el
;
846 struct ldb_dn
*server_dn
;
847 const char *dNSHostName
= strlower_talloc(mem_ctx
,
848 talloc_asprintf(mem_ctx
,
852 msg
= ldb_msg_new(mem_ctx
);
854 return NT_STATUS_NO_MEMORY
;
857 server_dn
= ldb_dn_new(mem_ctx
, ldb
, server_dn_str
);
859 return NT_STATUS_INTERNAL_ERROR
;
863 ret
= ldb_msg_add_empty(msg
, "dNSHostName", LDB_FLAG_MOD_ADD
, &el
);
864 if (ret
!= LDB_SUCCESS
) {
865 return NT_STATUS_INTERNAL_ERROR
;
868 ret
= ldb_msg_add_steal_string(msg
,
870 talloc_asprintf(el
->values
, "%s", dNSHostName
));
871 if (ret
!= LDB_SUCCESS
) {
872 return NT_STATUS_INTERNAL_ERROR
;
875 ret
= dsdb_modify(ldb
, msg
, DSDB_MODIFY_PERMISSIVE
);
876 if (ret
!= LDB_SUCCESS
) {
877 DEBUG(0,(__location__
": Failed to add dnsHostName to the Server object: %s\n",
878 ldb_errstring(ldb
)));
879 return NT_STATUS_INTERNAL_ERROR
;
886 NTSTATUS
libnet_Vampire(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
887 struct libnet_Vampire
*r
)
889 struct libnet_JoinDomain
*join
;
890 struct libnet_Replicate rep
;
893 const char *account_name
;
894 const char *netbios_name
;
896 r
->out
.error_string
= NULL
;
898 join
= talloc_zero(mem_ctx
, struct libnet_JoinDomain
);
900 return NT_STATUS_NO_MEMORY
;
903 if (r
->in
.netbios_name
!= NULL
) {
904 netbios_name
= r
->in
.netbios_name
;
906 netbios_name
= talloc_reference(join
, lpcfg_netbios_name(ctx
->lp_ctx
));
909 r
->out
.error_string
= NULL
;
910 return NT_STATUS_NO_MEMORY
;
914 account_name
= talloc_asprintf(join
, "%s$", netbios_name
);
917 r
->out
.error_string
= NULL
;
918 return NT_STATUS_NO_MEMORY
;
921 /* Re-use the domain we are joining as the domain for the user
922 * to be authenticated with, unless they specified
924 cli_credentials_set_domain(ctx
->cred
, r
->in
.domain_name
, CRED_GUESS_ENV
);
926 join
->in
.domain_name
= r
->in
.domain_name
;
927 join
->in
.account_name
= account_name
;
928 join
->in
.netbios_name
= netbios_name
;
929 join
->in
.level
= LIBNET_JOINDOMAIN_AUTOMATIC
;
930 join
->in
.acct_type
= ACB_WSTRUST
;
931 join
->in
.recreate_account
= false;
932 status
= libnet_JoinDomain(ctx
, join
, join
);
933 if (!NT_STATUS_IS_OK(status
)) {
934 r
->out
.error_string
= talloc_steal(mem_ctx
, join
->out
.error_string
);
939 rep
.in
.domain_name
= join
->out
.domain_name
;
940 rep
.in
.netbios_name
= netbios_name
;
941 rep
.in
.targetdir
= r
->in
.targetdir
;
942 rep
.in
.domain_sid
= join
->out
.domain_sid
;
943 rep
.in
.realm
= join
->out
.realm
;
944 rep
.in
.server
= join
->out
.samr_binding
->host
;
945 rep
.in
.join_password
= join
->out
.join_password
;
946 rep
.in
.kvno
= join
->out
.kvno
;
948 status
= libnet_Replicate(ctx
, mem_ctx
, &rep
);
950 r
->out
.domain_sid
= join
->out
.domain_sid
;
951 r
->out
.domain_name
= join
->out
.domain_name
;
952 r
->out
.error_string
= rep
.out
.error_string
;
959 NTSTATUS
libnet_Replicate(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
960 struct libnet_Replicate
*r
)
962 struct provision_store_self_join_settings
*set_secrets
;
963 struct libnet_BecomeDC b
;
964 struct libnet_vampire_cb_state
*s
;
965 struct ldb_message
*msg
;
966 const char *error_string
;
970 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
971 const char *account_name
;
972 const char *netbios_name
;
974 r
->out
.error_string
= NULL
;
976 netbios_name
= r
->in
.netbios_name
;
977 account_name
= talloc_asprintf(tmp_ctx
, "%s$", netbios_name
);
979 talloc_free(tmp_ctx
);
980 r
->out
.error_string
= NULL
;
981 return NT_STATUS_NO_MEMORY
;
984 /* Re-use the domain we are joining as the domain for the user
985 * to be authenticated with, unless they specified
987 cli_credentials_set_domain(ctx
->cred
, r
->in
.domain_name
, CRED_GUESS_ENV
);
989 s
= libnet_vampire_cb_state_init(mem_ctx
, ctx
->lp_ctx
, ctx
->event_ctx
,
990 netbios_name
, r
->in
.domain_name
, r
->in
.realm
,
993 return NT_STATUS_NO_MEMORY
;
995 talloc_steal(s
, tmp_ctx
);
1000 * We now know the domain and realm for sure - if they didn't
1001 * put one on the command line, use this for the rest of the
1003 cli_credentials_set_realm(ctx
->cred
, r
->in
.realm
, CRED_GUESS_ENV
);
1004 cli_credentials_set_domain(ctx
->cred
, r
->in
.domain_name
, CRED_GUESS_ENV
);
1006 /* Now set these values into the smb.conf - we probably had
1007 * empty or useless defaults here from whatever smb.conf we
1009 lpcfg_set_cmdline(s
->lp_ctx
, "realm", r
->in
.realm
);
1010 lpcfg_set_cmdline(s
->lp_ctx
, "workgroup", r
->in
.domain_name
);
1012 b
.in
.domain_dns_name
= r
->in
.realm
;
1013 b
.in
.domain_netbios_name
= r
->in
.domain_name
;
1014 b
.in
.domain_sid
= r
->in
.domain_sid
;
1015 b
.in
.source_dsa_address
= r
->in
.server
;
1016 b
.in
.dest_dsa_netbios_name
= netbios_name
;
1018 b
.in
.callbacks
.private_data
= s
;
1019 b
.in
.callbacks
.check_options
= libnet_vampire_cb_check_options
;
1020 b
.in
.callbacks
.prepare_db
= libnet_vampire_cb_prepare_db
;
1021 b
.in
.callbacks
.schema_chunk
= libnet_vampire_cb_schema_chunk
;
1022 b
.in
.callbacks
.config_chunk
= libnet_vampire_cb_store_chunk
;
1023 b
.in
.callbacks
.domain_chunk
= libnet_vampire_cb_store_chunk
;
1025 b
.in
.rodc_join
= lpcfg_parm_bool(s
->lp_ctx
, NULL
, "repl", "RODC", false);
1027 status
= libnet_BecomeDC(ctx
, s
, &b
);
1028 if (!NT_STATUS_IS_OK(status
)) {
1029 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status
));
1034 msg
= ldb_msg_new(s
);
1036 printf("ldb_msg_new() failed\n");
1038 return NT_STATUS_NO_MEMORY
;
1040 msg
->dn
= ldb_dn_new(msg
, s
->ldb
, "@ROOTDSE");
1042 printf("ldb_msg_new(@ROOTDSE) failed\n");
1044 return NT_STATUS_NO_MEMORY
;
1047 ldb_ret
= ldb_msg_add_string(msg
, "isSynchronized", "TRUE");
1048 if (ldb_ret
!= LDB_SUCCESS
) {
1049 printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret
);
1051 return NT_STATUS_NO_MEMORY
;
1054 for (i
=0; i
< msg
->num_elements
; i
++) {
1055 msg
->elements
[i
].flags
= LDB_FLAG_MOD_REPLACE
;
1058 printf("mark ROOTDSE with isSynchronized=TRUE\n");
1059 ldb_ret
= ldb_modify(s
->ldb
, msg
);
1060 if (ldb_ret
!= LDB_SUCCESS
) {
1061 printf("ldb_modify() failed: %d : %s\n", ldb_ret
, ldb_errstring(s
->ldb
));
1063 return NT_STATUS_INTERNAL_DB_ERROR
;
1065 /* during dcpromo the 2nd computer adds dNSHostName attribute to his Server object
1066 * the attribute appears on the original DC after replication
1068 status
= update_dnshostname_for_server(s
, s
->ldb
, s
->server_dn_str
, s
->netbios_name
, s
->realm
);
1069 if (!NT_STATUS_IS_OK(status
)) {
1070 printf("Failed to update dNSHostName on Server object - %s\n", nt_errstr(status
));
1074 /* prepare the transaction - this prepares to commit all the changes in
1075 the ldb from the whole vampire. Note that this
1076 triggers the writing of the linked attribute backlinks.
1078 if (ldb_transaction_prepare_commit(s
->ldb
) != LDB_SUCCESS
) {
1079 printf("Failed to prepare_commit vampire transaction: %s\n", ldb_errstring(s
->ldb
));
1080 return NT_STATUS_INTERNAL_DB_ERROR
;
1083 set_secrets
= talloc(s
, struct provision_store_self_join_settings
);
1085 r
->out
.error_string
= NULL
;
1087 return NT_STATUS_NO_MEMORY
;
1090 ZERO_STRUCTP(set_secrets
);
1091 set_secrets
->domain_name
= r
->in
.domain_name
;
1092 set_secrets
->realm
= r
->in
.realm
;
1093 set_secrets
->netbios_name
= netbios_name
;
1094 set_secrets
->secure_channel_type
= SEC_CHAN_BDC
;
1095 set_secrets
->machine_password
= r
->in
.join_password
;
1096 set_secrets
->key_version_number
= r
->in
.kvno
;
1097 set_secrets
->domain_sid
= r
->in
.domain_sid
;
1099 status
= provision_store_self_join(ctx
, s
->lp_ctx
, ctx
->event_ctx
, set_secrets
, &error_string
);
1100 if (!NT_STATUS_IS_OK(status
)) {
1101 r
->out
.error_string
= talloc_steal(mem_ctx
, error_string
);
1106 /* commit the transaction now we know the secrets were written
1109 if (ldb_transaction_commit(s
->ldb
) != LDB_SUCCESS
) {
1110 printf("Failed to commit vampire transaction\n");
1111 return NT_STATUS_INTERNAL_DB_ERROR
;
1116 return NT_STATUS_OK
;