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
;
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
;
250 DEBUG(0,("Analyze and apply schema objects\n"));
252 s_dsa
= talloc_zero(s
, struct repsFromTo1
);
253 NT_STATUS_HAVE_NO_MEMORY(s_dsa
);
254 s_dsa
->other_info
= talloc(s_dsa
, struct repsFromTo1OtherInfo
);
255 NT_STATUS_HAVE_NO_MEMORY(s_dsa
->other_info
);
257 switch (c
->ctr_level
) {
259 mapping_ctr
= &c
->ctr1
->mapping_ctr
;
260 object_count
= s
->schema_part
.object_count
;
261 first_object
= s
->schema_part
.first_object
;
262 linked_attributes_count
= 0;
263 linked_attributes
= NULL
;
264 s_dsa
->highwatermark
= c
->ctr1
->new_highwatermark
;
265 s_dsa
->source_dsa_obj_guid
= c
->ctr1
->source_dsa_guid
;
266 s_dsa
->source_dsa_invocation_id
= c
->ctr1
->source_dsa_invocation_id
;
267 uptodateness_vector
= NULL
; /* TODO: map it */
270 mapping_ctr
= &c
->ctr6
->mapping_ctr
;
271 object_count
= s
->schema_part
.object_count
;
272 first_object
= s
->schema_part
.first_object
;
273 linked_attributes_count
= c
->ctr6
->linked_attributes_count
;
274 linked_attributes
= c
->ctr6
->linked_attributes
;
275 s_dsa
->highwatermark
= c
->ctr6
->new_highwatermark
;
276 s_dsa
->source_dsa_obj_guid
= c
->ctr6
->source_dsa_guid
;
277 s_dsa
->source_dsa_invocation_id
= c
->ctr6
->source_dsa_invocation_id
;
278 uptodateness_vector
= c
->ctr6
->uptodateness_vector
;
281 return NT_STATUS_INVALID_PARAMETER
;
284 status
= dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr
, true,
285 s
, &pfm_remote
, NULL
);
286 if (!W_ERROR_IS_OK(status
)) {
287 DEBUG(0,(__location__
": Failed to decode remote prefixMap: %s",
288 win_errstr(status
)));
289 return werror_to_ntstatus(status
);
292 s_dsa
->replica_flags
= DRSUAPI_DRS_WRIT_REP
293 | DRSUAPI_DRS_INIT_SYNC
294 | DRSUAPI_DRS_PER_SYNC
;
295 memset(s_dsa
->schedule
, 0x11, sizeof(s_dsa
->schedule
));
297 tmp_dns_name
= GUID_string(s_dsa
->other_info
, &s_dsa
->source_dsa_obj_guid
);
298 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name
);
299 tmp_dns_name
= talloc_asprintf_append_buffer(tmp_dns_name
, "._msdcs.%s", c
->forest
->dns_name
);
300 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name
);
301 s_dsa
->other_info
->dns_name
= tmp_dns_name
;
303 schema_ldb
= provision_get_schema(s
, s
->lp_ctx
, &s
->prefixmap_blob
);
305 DEBUG(0,("Failed to re-load from local provision using remote prefixMap. "
306 "Will continue with local prefixMap\n"));
307 provision_schema
= dsdb_get_schema(s
->ldb
, s
);
309 provision_schema
= dsdb_get_schema(schema_ldb
, s
);
310 ret
= dsdb_reference_schema(s
->ldb
, provision_schema
, false);
311 if (ret
!= LDB_SUCCESS
) {
312 DEBUG(0,("Failed to attach schema from local provision using remote prefixMap."));
313 return NT_STATUS_UNSUCCESSFUL
;
315 talloc_free(schema_ldb
);
318 /* create a list of objects yet to be converted */
319 for (cur
= first_object
; cur
; cur
= cur
->next_object
) {
320 schema_list_item
= talloc(s
, struct schema_list
);
321 schema_list_item
->obj
= cur
;
322 DLIST_ADD_END(schema_list
, schema_list_item
, struct schema_list
);
325 /* resolve objects until all are resolved and in local schema */
327 working_schema
= provision_schema
;
329 while (schema_list
) {
330 uint32_t converted_obj_count
= 0;
331 uint32_t failed_obj_count
= 0;
332 TALLOC_CTX
*tmp_ctx
= talloc_new(s
);
333 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
335 for (schema_list_item
= schema_list
; schema_list_item
; schema_list_item
=schema_list_next_item
) {
336 struct dsdb_extended_replicated_object object
;
338 cur
= schema_list_item
->obj
;
340 /* Save the next item, now we have saved out
341 * the current one, so we can DLIST_REMOVE it
343 schema_list_next_item
= schema_list_item
->next
;
346 * Convert the objects into LDB messages using the
347 * schema we have so far. It's ok if we fail to convert
348 * an object. We should convert more objects on next pass.
350 status
= dsdb_convert_object_ex(s
->ldb
, working_schema
, pfm_remote
,
353 if (!W_ERROR_IS_OK(status
)) {
354 DEBUG(1,("Warning: Failed to convert schema object %s into ldb msg\n",
355 cur
->object
.identifier
->dn
));
360 * Convert the schema from ldb_message format
361 * (OIDs as OID strings) into schema, using
362 * the remote prefixMap
364 status
= dsdb_schema_set_el_from_ldb_msg(s
->ldb
,
367 if (!W_ERROR_IS_OK(status
)) {
368 DEBUG(1,("Warning: failed to convert object %s into a schema element: %s\n",
369 ldb_dn_get_linearized(object
.msg
->dn
),
370 win_errstr(status
)));
373 DLIST_REMOVE(schema_list
, schema_list_item
);
374 converted_obj_count
++;
378 talloc_free(tmp_ctx
);
380 DEBUG(4,("Schema load pass %d: %d/%d of %d objects left to be converted.\n",
381 pass_no
, failed_obj_count
, converted_obj_count
, object_count
));
384 /* check if we converted any objects in this pass */
385 if (converted_obj_count
== 0) {
386 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
));
387 return NT_STATUS_INTERNAL_ERROR
;
391 /* prepare for another cycle */
392 working_schema
= s
->self_made_schema
;
394 ret
= dsdb_setup_sorted_accessors(s
->ldb
, working_schema
);
395 if (LDB_SUCCESS
!= ret
) {
396 DEBUG(0,("Failed to create schema-cache indexes!\n"));
397 return NT_STATUS_INTERNAL_ERROR
;
402 /* free temp objects for 1st conversion phase */
403 talloc_unlink(s
, provision_schema
);
404 TALLOC_FREE(schema_list
);
407 * attach the schema we just brought over DRS to the ldb,
408 * so we can use it in dsdb_convert_object_ex below
410 ret
= dsdb_set_schema(s
->ldb
, s
->self_made_schema
);
411 if (ret
!= LDB_SUCCESS
) {
412 DEBUG(0,("Failed to attach working schema from DRS.\n"));
413 return NT_STATUS_FOOBAR
;
416 /* we don't want to access the self made schema anymore */
417 s
->schema
= s
->self_made_schema
;
418 s
->self_made_schema
= NULL
;
420 /* Now convert the schema elements again, using the schema we finalised, ready to actually import */
421 status
= dsdb_replicated_objects_convert(s
->ldb
,
427 linked_attributes_count
,
433 if (!W_ERROR_IS_OK(status
)) {
434 DEBUG(0,("Failed to convert objects when trying to import over DRS (2nd pass, to store remote schema): %s\n", win_errstr(status
)));
435 return werror_to_ntstatus(status
);
438 if (lpcfg_parm_bool(s
->lp_ctx
, NULL
, "become dc", "dump objects", false)) {
439 for (i
=0; i
< schema_objs
->num_objects
; i
++) {
440 struct ldb_ldif ldif
;
441 fprintf(stdout
, "#\n");
442 ldif
.changetype
= LDB_CHANGETYPE_NONE
;
443 ldif
.msg
= schema_objs
->objects
[i
].msg
;
444 ldb_ldif_write_file(s
->ldb
, stdout
, &ldif
);
445 NDR_PRINT_DEBUG(replPropertyMetaDataBlob
, schema_objs
->objects
[i
].meta_data
);
449 status
= dsdb_replicated_objects_commit(s
->ldb
, NULL
, schema_objs
, &seq_num
);
450 if (!W_ERROR_IS_OK(status
)) {
451 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status
)));
452 return werror_to_ntstatus(status
);
455 msg
= ldb_msg_new(schema_objs
);
456 NT_STATUS_HAVE_NO_MEMORY(msg
);
457 msg
->dn
= schema_objs
->partition_dn
;
459 /* We must ensure a prefixMap has been written. Unlike other
460 * attributes (including schemaInfo), it is not replicated in
461 * the normal replication stream. We can use the one from
462 * s->prefixmap_blob because we operate with one, unchanging
463 * prefixMap for this entire operation. */
464 ret
= ldb_msg_add_value(msg
, "prefixMap", &s
->prefixmap_blob
, &prefixMap_el
);
465 if (ret
!= LDB_SUCCESS
) {
466 return NT_STATUS_FOOBAR
;
468 /* We want to know if a prefixMap was written already, as it
469 * would mean that the above comment was not true, and we have
470 * somehow updated the prefixMap during this transaction */
471 prefixMap_el
->flags
= LDB_FLAG_MOD_ADD
;
473 ret
= ldb_modify(s
->ldb
, msg
);
474 if (ret
!= LDB_SUCCESS
) {
475 DEBUG(0,("Failed to add prefixMap: %s\n", ldb_errstring(s
->ldb
)));
476 return NT_STATUS_FOOBAR
;
480 talloc_free(schema_objs
);
482 /* We must set these up to ensure the replMetaData is written
483 * correctly, before our NTDS Settings entry is replicated */
484 ok
= samdb_set_ntds_invocation_id(s
->ldb
, &c
->dest_dsa
->invocation_id
);
486 DEBUG(0,("Failed to set cached ntds invocationId\n"));
487 return NT_STATUS_FOOBAR
;
489 ok
= samdb_set_ntds_objectGUID(s
->ldb
, &c
->dest_dsa
->ntds_guid
);
491 DEBUG(0,("Failed to set cached ntds objectGUID\n"));
492 return NT_STATUS_FOOBAR
;
495 s
->schema
= dsdb_get_schema(s
->ldb
, s
);
497 DEBUG(0,("Failed to get loaded dsdb_schema\n"));
498 return NT_STATUS_FOOBAR
;
504 NTSTATUS
libnet_vampire_cb_schema_chunk(void *private_data
,
505 const struct libnet_BecomeDC_StoreChunk
*c
)
507 struct libnet_vampire_cb_state
*s
= talloc_get_type(private_data
, struct libnet_vampire_cb_state
);
509 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
;
510 uint32_t nc_object_count
;
511 uint32_t object_count
;
512 struct drsuapi_DsReplicaObjectListItemEx
*first_object
;
513 struct drsuapi_DsReplicaObjectListItemEx
*cur
;
514 uint32_t nc_linked_attributes_count
;
515 uint32_t linked_attributes_count
;
516 struct drsuapi_DsReplicaLinkedAttribute
*linked_attributes
;
518 switch (c
->ctr_level
) {
520 mapping_ctr
= &c
->ctr1
->mapping_ctr
;
521 nc_object_count
= c
->ctr1
->extended_ret
; /* maybe w2k send this unexpected? */
522 object_count
= c
->ctr1
->object_count
;
523 first_object
= c
->ctr1
->first_object
;
524 nc_linked_attributes_count
= 0;
525 linked_attributes_count
= 0;
526 linked_attributes
= NULL
;
529 mapping_ctr
= &c
->ctr6
->mapping_ctr
;
530 nc_object_count
= c
->ctr6
->nc_object_count
;
531 object_count
= c
->ctr6
->object_count
;
532 first_object
= c
->ctr6
->first_object
;
533 nc_linked_attributes_count
= c
->ctr6
->nc_linked_attributes_count
;
534 linked_attributes_count
= c
->ctr6
->linked_attributes_count
;
535 linked_attributes
= c
->ctr6
->linked_attributes
;
538 return NT_STATUS_INVALID_PARAMETER
;
541 if (nc_object_count
) {
542 DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n",
543 c
->partition
->nc
.dn
, object_count
, nc_object_count
,
544 linked_attributes_count
, nc_linked_attributes_count
));
546 DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u]\n",
547 c
->partition
->nc
.dn
, object_count
, linked_attributes_count
));
550 if (!s
->self_made_schema
) {
552 struct drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr_without_schema_info
;
553 /* Put the DRS prefixmap aside for the schema we are
554 * about to load in the provision, and into the one we
555 * are making with the help of DRS */
557 mapping_ctr_without_schema_info
= *mapping_ctr
;
559 /* This strips off the 0xFF schema info from the end,
560 * because we don't want it in the blob */
561 if (mapping_ctr_without_schema_info
.num_mappings
> 0) {
562 mapping_ctr_without_schema_info
.num_mappings
--;
564 werr
= dsdb_get_drsuapi_prefixmap_as_blob(&mapping_ctr_without_schema_info
, s
, &s
->prefixmap_blob
);
565 if (!W_ERROR_IS_OK(werr
)) {
566 return werror_to_ntstatus(werr
);
569 /* Set up two manually-constructed schema - the local
570 * schema from the provision will be used to build
571 * one, which will then in turn be used to build the
573 s
->self_made_schema
= dsdb_new_schema(s
);
574 NT_STATUS_HAVE_NO_MEMORY(s
->self_made_schema
);
576 status
= dsdb_load_prefixmap_from_drsuapi(s
->self_made_schema
, mapping_ctr
);
577 if (!W_ERROR_IS_OK(status
)) {
578 return werror_to_ntstatus(status
);
581 status
= dsdb_schema_pfm_contains_drsuapi_pfm(s
->self_made_schema
->prefixmap
, mapping_ctr
);
582 if (!W_ERROR_IS_OK(status
)) {
583 return werror_to_ntstatus(status
);
587 if (!s
->schema_part
.first_object
) {
588 s
->schema_part
.object_count
= object_count
;
589 s
->schema_part
.first_object
= talloc_steal(s
, first_object
);
591 s
->schema_part
.object_count
+= object_count
;
592 s
->schema_part
.last_object
->next_object
= talloc_steal(s
->schema_part
.last_object
,
595 for (cur
= first_object
; cur
->next_object
; cur
= cur
->next_object
) {}
596 s
->schema_part
.last_object
= cur
;
598 if (!c
->partition
->more_data
) {
599 return libnet_vampire_cb_apply_schema(s
, c
);
605 NTSTATUS
libnet_vampire_cb_store_chunk(void *private_data
,
606 const struct libnet_BecomeDC_StoreChunk
*c
)
608 struct libnet_vampire_cb_state
*s
= talloc_get_type(private_data
, struct libnet_vampire_cb_state
);
610 struct dsdb_schema
*schema
;
611 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
;
612 uint32_t nc_object_count
;
613 uint32_t object_count
;
614 struct drsuapi_DsReplicaObjectListItemEx
*first_object
;
615 uint32_t nc_linked_attributes_count
;
616 uint32_t linked_attributes_count
;
617 struct drsuapi_DsReplicaLinkedAttribute
*linked_attributes
;
618 const struct drsuapi_DsReplicaCursor2CtrEx
*uptodateness_vector
;
619 struct dsdb_extended_replicated_objects
*objs
;
620 struct repsFromTo1
*s_dsa
;
625 s_dsa
= talloc_zero(s
, struct repsFromTo1
);
626 NT_STATUS_HAVE_NO_MEMORY(s_dsa
);
627 s_dsa
->other_info
= talloc(s_dsa
, struct repsFromTo1OtherInfo
);
628 NT_STATUS_HAVE_NO_MEMORY(s_dsa
->other_info
);
630 switch (c
->ctr_level
) {
632 mapping_ctr
= &c
->ctr1
->mapping_ctr
;
633 nc_object_count
= c
->ctr1
->extended_ret
; /* maybe w2k send this unexpected? */
634 object_count
= c
->ctr1
->object_count
;
635 first_object
= c
->ctr1
->first_object
;
636 nc_linked_attributes_count
= 0;
637 linked_attributes_count
= 0;
638 linked_attributes
= NULL
;
639 s_dsa
->highwatermark
= c
->ctr1
->new_highwatermark
;
640 s_dsa
->source_dsa_obj_guid
= c
->ctr1
->source_dsa_guid
;
641 s_dsa
->source_dsa_invocation_id
= c
->ctr1
->source_dsa_invocation_id
;
642 uptodateness_vector
= NULL
; /* TODO: map it */
645 mapping_ctr
= &c
->ctr6
->mapping_ctr
;
646 nc_object_count
= c
->ctr6
->nc_object_count
;
647 object_count
= c
->ctr6
->object_count
;
648 first_object
= c
->ctr6
->first_object
;
649 nc_linked_attributes_count
= c
->ctr6
->nc_linked_attributes_count
;
650 linked_attributes_count
= c
->ctr6
->linked_attributes_count
;
651 linked_attributes
= c
->ctr6
->linked_attributes
;
652 s_dsa
->highwatermark
= c
->ctr6
->new_highwatermark
;
653 s_dsa
->source_dsa_obj_guid
= c
->ctr6
->source_dsa_guid
;
654 s_dsa
->source_dsa_invocation_id
= c
->ctr6
->source_dsa_invocation_id
;
655 uptodateness_vector
= c
->ctr6
->uptodateness_vector
;
658 return NT_STATUS_INVALID_PARAMETER
;
661 s_dsa
->replica_flags
= DRSUAPI_DRS_WRIT_REP
662 | DRSUAPI_DRS_INIT_SYNC
663 | DRSUAPI_DRS_PER_SYNC
;
664 memset(s_dsa
->schedule
, 0x11, sizeof(s_dsa
->schedule
));
666 tmp_dns_name
= GUID_string(s_dsa
->other_info
, &s_dsa
->source_dsa_obj_guid
);
667 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name
);
668 tmp_dns_name
= talloc_asprintf_append_buffer(tmp_dns_name
, "._msdcs.%s", c
->forest
->dns_name
);
669 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name
);
670 s_dsa
->other_info
->dns_name
= tmp_dns_name
;
672 /* we want to show a count per partition */
673 if (!s
->last_partition
|| strcmp(s
->last_partition
, c
->partition
->nc
.dn
) != 0) {
674 s
->total_objects
= 0;
675 talloc_free(s
->last_partition
);
676 s
->last_partition
= talloc_strdup(s
, c
->partition
->nc
.dn
);
678 s
->total_objects
+= object_count
;
680 if (nc_object_count
) {
681 DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n",
682 c
->partition
->nc
.dn
, s
->total_objects
, nc_object_count
,
683 linked_attributes_count
, nc_linked_attributes_count
));
685 DEBUG(0,("Partition[%s] objects[%u] linked_values[%u]\n",
686 c
->partition
->nc
.dn
, s
->total_objects
, linked_attributes_count
));
690 schema
= dsdb_get_schema(s
->ldb
, NULL
);
692 DEBUG(0,(__location__
": Schema is not loaded yet!\n"));
693 return NT_STATUS_INTERNAL_ERROR
;
696 status
= dsdb_replicated_objects_convert(s
->ldb
,
702 linked_attributes_count
,
708 if (!W_ERROR_IS_OK(status
)) {
709 DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status
)));
710 return werror_to_ntstatus(status
);
713 if (lpcfg_parm_bool(s
->lp_ctx
, NULL
, "become dc", "dump objects", false)) {
714 for (i
=0; i
< objs
->num_objects
; i
++) {
715 struct ldb_ldif ldif
;
716 fprintf(stdout
, "#\n");
717 ldif
.changetype
= LDB_CHANGETYPE_NONE
;
718 ldif
.msg
= objs
->objects
[i
].msg
;
719 ldb_ldif_write_file(s
->ldb
, stdout
, &ldif
);
720 NDR_PRINT_DEBUG(replPropertyMetaDataBlob
, objs
->objects
[i
].meta_data
);
723 status
= dsdb_replicated_objects_commit(s
->ldb
, NULL
, objs
, &seq_num
);
724 if (!W_ERROR_IS_OK(status
)) {
725 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status
)));
726 return werror_to_ntstatus(status
);
732 for (i
=0; i
< linked_attributes_count
; i
++) {
733 const struct dsdb_attribute
*sa
;
735 if (!linked_attributes
[i
].identifier
) {
736 return NT_STATUS_FOOBAR
;
739 if (!linked_attributes
[i
].value
.blob
) {
740 return NT_STATUS_FOOBAR
;
743 sa
= dsdb_attribute_by_attributeID_id(s
->schema
,
744 linked_attributes
[i
].attid
);
746 return NT_STATUS_FOOBAR
;
749 if (lpcfg_parm_bool(s
->lp_ctx
, NULL
, "become dc", "dump objects", false)) {
750 DEBUG(0,("# %s\n", sa
->lDAPDisplayName
));
751 NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute
, &linked_attributes
[i
]);
753 linked_attributes
[i
].value
.blob
->data
,
754 linked_attributes
[i
].value
.blob
->length
);
761 static NTSTATUS
update_dnshostname_for_server(TALLOC_CTX
*mem_ctx
,
762 struct ldb_context
*ldb
,
763 const char *server_dn_str
,
764 const char *netbios_name
,
768 struct ldb_message
*msg
;
769 struct ldb_message_element
*el
;
770 struct ldb_dn
*server_dn
;
771 const char *dNSHostName
= strlower_talloc(mem_ctx
,
772 talloc_asprintf(mem_ctx
,
776 msg
= ldb_msg_new(mem_ctx
);
778 return NT_STATUS_NO_MEMORY
;
781 server_dn
= ldb_dn_new(mem_ctx
, ldb
, server_dn_str
);
783 return NT_STATUS_INTERNAL_ERROR
;
787 ret
= ldb_msg_add_empty(msg
, "dNSHostName", LDB_FLAG_MOD_ADD
, &el
);
788 if (ret
!= LDB_SUCCESS
) {
789 return NT_STATUS_INTERNAL_ERROR
;
792 ret
= ldb_msg_add_steal_string(msg
,
794 talloc_asprintf(el
->values
, "%s", dNSHostName
));
795 if (ret
!= LDB_SUCCESS
) {
796 return NT_STATUS_INTERNAL_ERROR
;
799 ret
= dsdb_modify(ldb
, msg
, DSDB_MODIFY_PERMISSIVE
);
800 if (ret
!= LDB_SUCCESS
) {
801 DEBUG(0,(__location__
": Failed to add dnsHostName to the Server object: %s\n",
802 ldb_errstring(ldb
)));
803 return NT_STATUS_INTERNAL_ERROR
;
810 NTSTATUS
libnet_Vampire(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
811 struct libnet_Vampire
*r
)
813 struct libnet_JoinDomain
*join
;
814 struct libnet_Replicate rep
;
817 const char *account_name
;
818 const char *netbios_name
;
820 r
->out
.error_string
= NULL
;
822 join
= talloc_zero(mem_ctx
, struct libnet_JoinDomain
);
824 return NT_STATUS_NO_MEMORY
;
827 if (r
->in
.netbios_name
!= NULL
) {
828 netbios_name
= r
->in
.netbios_name
;
830 netbios_name
= talloc_reference(join
, lpcfg_netbios_name(ctx
->lp_ctx
));
833 r
->out
.error_string
= NULL
;
834 return NT_STATUS_NO_MEMORY
;
838 account_name
= talloc_asprintf(join
, "%s$", netbios_name
);
841 r
->out
.error_string
= NULL
;
842 return NT_STATUS_NO_MEMORY
;
845 /* Re-use the domain we are joining as the domain for the user
846 * to be authenticated with, unless they specified
848 cli_credentials_set_domain(ctx
->cred
, r
->in
.domain_name
, CRED_GUESS_ENV
);
850 join
->in
.domain_name
= r
->in
.domain_name
;
851 join
->in
.account_name
= account_name
;
852 join
->in
.netbios_name
= netbios_name
;
853 join
->in
.level
= LIBNET_JOINDOMAIN_AUTOMATIC
;
854 join
->in
.acct_type
= ACB_WSTRUST
;
855 join
->in
.recreate_account
= false;
856 status
= libnet_JoinDomain(ctx
, join
, join
);
857 if (!NT_STATUS_IS_OK(status
)) {
858 r
->out
.error_string
= talloc_steal(mem_ctx
, join
->out
.error_string
);
863 rep
.in
.domain_name
= join
->out
.domain_name
;
864 rep
.in
.netbios_name
= netbios_name
;
865 rep
.in
.targetdir
= r
->in
.targetdir
;
866 rep
.in
.domain_sid
= join
->out
.domain_sid
;
867 rep
.in
.realm
= join
->out
.realm
;
868 rep
.in
.server
= join
->out
.samr_binding
->host
;
869 rep
.in
.join_password
= join
->out
.join_password
;
870 rep
.in
.kvno
= join
->out
.kvno
;
872 status
= libnet_Replicate(ctx
, mem_ctx
, &rep
);
874 r
->out
.domain_sid
= join
->out
.domain_sid
;
875 r
->out
.domain_name
= join
->out
.domain_name
;
876 r
->out
.error_string
= rep
.out
.error_string
;
883 NTSTATUS
libnet_Replicate(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
884 struct libnet_Replicate
*r
)
886 struct provision_store_self_join_settings
*set_secrets
;
887 struct libnet_BecomeDC b
;
888 struct libnet_vampire_cb_state
*s
;
889 struct ldb_message
*msg
;
890 const char *error_string
;
894 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
895 const char *account_name
;
896 const char *netbios_name
;
898 r
->out
.error_string
= NULL
;
900 netbios_name
= r
->in
.netbios_name
;
901 account_name
= talloc_asprintf(tmp_ctx
, "%s$", netbios_name
);
903 talloc_free(tmp_ctx
);
904 r
->out
.error_string
= NULL
;
905 return NT_STATUS_NO_MEMORY
;
908 /* Re-use the domain we are joining as the domain for the user
909 * to be authenticated with, unless they specified
911 cli_credentials_set_domain(ctx
->cred
, r
->in
.domain_name
, CRED_GUESS_ENV
);
913 s
= libnet_vampire_cb_state_init(mem_ctx
, ctx
->lp_ctx
, ctx
->event_ctx
,
914 netbios_name
, r
->in
.domain_name
, r
->in
.realm
,
917 return NT_STATUS_NO_MEMORY
;
919 talloc_steal(s
, tmp_ctx
);
924 * We now know the domain and realm for sure - if they didn't
925 * put one on the command line, use this for the rest of the
927 cli_credentials_set_realm(ctx
->cred
, r
->in
.realm
, CRED_GUESS_ENV
);
928 cli_credentials_set_domain(ctx
->cred
, r
->in
.domain_name
, CRED_GUESS_ENV
);
930 /* Now set these values into the smb.conf - we probably had
931 * empty or useless defaults here from whatever smb.conf we
933 lpcfg_set_cmdline(s
->lp_ctx
, "realm", r
->in
.realm
);
934 lpcfg_set_cmdline(s
->lp_ctx
, "workgroup", r
->in
.domain_name
);
936 b
.in
.domain_dns_name
= r
->in
.realm
;
937 b
.in
.domain_netbios_name
= r
->in
.domain_name
;
938 b
.in
.domain_sid
= r
->in
.domain_sid
;
939 b
.in
.source_dsa_address
= r
->in
.server
;
940 b
.in
.dest_dsa_netbios_name
= netbios_name
;
942 b
.in
.callbacks
.private_data
= s
;
943 b
.in
.callbacks
.check_options
= libnet_vampire_cb_check_options
;
944 b
.in
.callbacks
.prepare_db
= libnet_vampire_cb_prepare_db
;
945 b
.in
.callbacks
.schema_chunk
= libnet_vampire_cb_schema_chunk
;
946 b
.in
.callbacks
.config_chunk
= libnet_vampire_cb_store_chunk
;
947 b
.in
.callbacks
.domain_chunk
= libnet_vampire_cb_store_chunk
;
949 b
.in
.rodc_join
= lpcfg_parm_bool(s
->lp_ctx
, NULL
, "repl", "RODC", false);
951 status
= libnet_BecomeDC(ctx
, s
, &b
);
952 if (!NT_STATUS_IS_OK(status
)) {
953 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status
));
958 msg
= ldb_msg_new(s
);
960 printf("ldb_msg_new() failed\n");
962 return NT_STATUS_NO_MEMORY
;
964 msg
->dn
= ldb_dn_new(msg
, s
->ldb
, "@ROOTDSE");
966 printf("ldb_msg_new(@ROOTDSE) failed\n");
968 return NT_STATUS_NO_MEMORY
;
971 ldb_ret
= ldb_msg_add_string(msg
, "isSynchronized", "TRUE");
972 if (ldb_ret
!= LDB_SUCCESS
) {
973 printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret
);
975 return NT_STATUS_NO_MEMORY
;
978 for (i
=0; i
< msg
->num_elements
; i
++) {
979 msg
->elements
[i
].flags
= LDB_FLAG_MOD_REPLACE
;
982 printf("mark ROOTDSE with isSynchronized=TRUE\n");
983 ldb_ret
= ldb_modify(s
->ldb
, msg
);
984 if (ldb_ret
!= LDB_SUCCESS
) {
985 printf("ldb_modify() failed: %d : %s\n", ldb_ret
, ldb_errstring(s
->ldb
));
987 return NT_STATUS_INTERNAL_DB_ERROR
;
989 /* during dcpromo the 2nd computer adds dNSHostName attribute to his Server object
990 * the attribute appears on the original DC after replication
992 status
= update_dnshostname_for_server(s
, s
->ldb
, s
->server_dn_str
, s
->netbios_name
, s
->realm
);
993 if (!NT_STATUS_IS_OK(status
)) {
994 printf("Failed to update dNSHostName on Server object - %s\n", nt_errstr(status
));
998 /* prepare the transaction - this prepares to commit all the changes in
999 the ldb from the whole vampire. Note that this
1000 triggers the writing of the linked attribute backlinks.
1002 if (ldb_transaction_prepare_commit(s
->ldb
) != LDB_SUCCESS
) {
1003 printf("Failed to prepare_commit vampire transaction: %s\n", ldb_errstring(s
->ldb
));
1004 return NT_STATUS_INTERNAL_DB_ERROR
;
1007 set_secrets
= talloc(s
, struct provision_store_self_join_settings
);
1009 r
->out
.error_string
= NULL
;
1011 return NT_STATUS_NO_MEMORY
;
1014 ZERO_STRUCTP(set_secrets
);
1015 set_secrets
->domain_name
= r
->in
.domain_name
;
1016 set_secrets
->realm
= r
->in
.realm
;
1017 set_secrets
->netbios_name
= netbios_name
;
1018 set_secrets
->secure_channel_type
= SEC_CHAN_BDC
;
1019 set_secrets
->machine_password
= r
->in
.join_password
;
1020 set_secrets
->key_version_number
= r
->in
.kvno
;
1021 set_secrets
->domain_sid
= r
->in
.domain_sid
;
1023 status
= provision_store_self_join(ctx
, s
->lp_ctx
, ctx
->event_ctx
, set_secrets
, &error_string
);
1024 if (!NT_STATUS_IS_OK(status
)) {
1025 r
->out
.error_string
= talloc_steal(mem_ctx
, error_string
);
1030 /* commit the transaction now we know the secrets were written
1033 if (ldb_transaction_commit(s
->ldb
) != LDB_SUCCESS
) {
1034 printf("Failed to commit vampire transaction\n");
1035 return NT_STATUS_INTERNAL_DB_ERROR
;
1040 return NT_STATUS_OK
;