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 dsdb_schema_prefixmap
*pfm_remote
;
224 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
;
225 struct dsdb_schema
*provision_schema
;
226 uint32_t object_count
= 0;
227 struct drsuapi_DsReplicaObjectListItemEx
*first_object
;
228 uint32_t linked_attributes_count
;
229 struct drsuapi_DsReplicaLinkedAttribute
*linked_attributes
;
230 const struct drsuapi_DsReplicaCursor2CtrEx
*uptodateness_vector
;
231 struct dsdb_extended_replicated_objects
*schema_objs
;
232 struct repsFromTo1
*s_dsa
;
234 struct ldb_context
*schema_ldb
;
235 struct ldb_message
*msg
;
236 struct ldb_message_element
*prefixMap_el
;
241 uint32_t cycle_before_switching
;
243 DEBUG(0,("Analyze and apply schema objects\n"));
245 s_dsa
= talloc_zero(s
, struct repsFromTo1
);
246 NT_STATUS_HAVE_NO_MEMORY(s_dsa
);
247 s_dsa
->other_info
= talloc(s_dsa
, struct repsFromTo1OtherInfo
);
248 NT_STATUS_HAVE_NO_MEMORY(s_dsa
->other_info
);
250 switch (c
->ctr_level
) {
252 mapping_ctr
= &c
->ctr1
->mapping_ctr
;
253 object_count
= s
->schema_part
.object_count
;
254 first_object
= s
->schema_part
.first_object
;
255 linked_attributes_count
= 0;
256 linked_attributes
= NULL
;
257 s_dsa
->highwatermark
= c
->ctr1
->new_highwatermark
;
258 s_dsa
->source_dsa_obj_guid
= c
->ctr1
->source_dsa_guid
;
259 s_dsa
->source_dsa_invocation_id
= c
->ctr1
->source_dsa_invocation_id
;
260 uptodateness_vector
= NULL
; /* TODO: map it */
263 mapping_ctr
= &c
->ctr6
->mapping_ctr
;
264 object_count
= s
->schema_part
.object_count
;
265 first_object
= s
->schema_part
.first_object
;
266 linked_attributes_count
= c
->ctr6
->linked_attributes_count
;
267 linked_attributes
= c
->ctr6
->linked_attributes
;
268 s_dsa
->highwatermark
= c
->ctr6
->new_highwatermark
;
269 s_dsa
->source_dsa_obj_guid
= c
->ctr6
->source_dsa_guid
;
270 s_dsa
->source_dsa_invocation_id
= c
->ctr6
->source_dsa_invocation_id
;
271 uptodateness_vector
= c
->ctr6
->uptodateness_vector
;
274 return NT_STATUS_INVALID_PARAMETER
;
276 /* We must set these up to ensure the replMetaData is written
277 * correctly, before our NTDS Settings entry is replicated */
278 ok
= samdb_set_ntds_invocation_id(s
->ldb
, &c
->dest_dsa
->invocation_id
);
280 DEBUG(0,("Failed to set cached ntds invocationId\n"));
281 return NT_STATUS_FOOBAR
;
283 ok
= samdb_set_ntds_objectGUID(s
->ldb
, &c
->dest_dsa
->ntds_guid
);
285 DEBUG(0,("Failed to set cached ntds objectGUID\n"));
286 return NT_STATUS_FOOBAR
;
289 status
= dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr
, true,
290 s
, &pfm_remote
, NULL
);
291 if (!W_ERROR_IS_OK(status
)) {
292 DEBUG(0,(__location__
": Failed to decode remote prefixMap: %s",
293 win_errstr(status
)));
294 return werror_to_ntstatus(status
);
297 s_dsa
->replica_flags
= DRSUAPI_DRS_WRIT_REP
298 | DRSUAPI_DRS_INIT_SYNC
299 | DRSUAPI_DRS_PER_SYNC
;
300 memset(s_dsa
->schedule
, 0x11, sizeof(s_dsa
->schedule
));
302 tmp_dns_name
= GUID_string(s_dsa
->other_info
, &s_dsa
->source_dsa_obj_guid
);
303 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name
);
304 tmp_dns_name
= talloc_asprintf_append_buffer(tmp_dns_name
, "._msdcs.%s", c
->forest
->dns_name
);
305 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name
);
306 s_dsa
->other_info
->dns_name
= tmp_dns_name
;
308 if (s
->self_made_schema
== NULL
) {
309 DEBUG(0,("libnet_vampire_cb_apply_schema: called with out self_made_schema\n"));
310 return NT_STATUS_INTERNAL_ERROR
;
313 schema_ldb
= provision_get_schema(s
, s
->lp_ctx
,
314 c
->forest
->schema_dn_str
,
317 DEBUG(0,("Failed to re-load from local provision using remote prefixMap. "
318 "Will continue with local prefixMap\n"));
319 provision_schema
= dsdb_get_schema(s
->ldb
, s
);
321 provision_schema
= dsdb_get_schema(schema_ldb
, s
);
322 ret
= dsdb_reference_schema(s
->ldb
, provision_schema
, false);
323 if (ret
!= LDB_SUCCESS
) {
324 DEBUG(0,("Failed to attach schema from local provision using remote prefixMap."));
325 return NT_STATUS_UNSUCCESSFUL
;
327 talloc_free(schema_ldb
);
330 cycle_before_switching
= lpcfg_parm_long(s
->lp_ctx
, NULL
,
332 "schema convert retrial", 1);
334 status
= dsdb_repl_resolve_working_schema(s
->ldb
, s
,
336 cycle_before_switching
,
341 if (!W_ERROR_IS_OK(status
)) {
342 DEBUG(0, ("%s: dsdb_repl_resolve_working_schema() failed: %s",
343 __location__
, win_errstr(status
)));
344 return werror_to_ntstatus(status
);
347 /* free temp objects for 1st conversion phase */
348 talloc_unlink(s
, provision_schema
);
351 * attach the schema we just brought over DRS to the ldb,
352 * so we can use it in dsdb_convert_object_ex below
354 ret
= dsdb_set_schema(s
->ldb
, s
->self_made_schema
);
355 if (ret
!= LDB_SUCCESS
) {
356 DEBUG(0,("Failed to attach working schema from DRS.\n"));
357 return NT_STATUS_FOOBAR
;
360 /* we don't want to access the self made schema anymore */
361 s
->schema
= s
->self_made_schema
;
362 s
->self_made_schema
= NULL
;
364 /* Now convert the schema elements again, using the schema we finalised, ready to actually import */
365 status
= dsdb_replicated_objects_convert(s
->ldb
,
371 linked_attributes_count
,
378 if (!W_ERROR_IS_OK(status
)) {
379 DEBUG(0,("Failed to convert objects when trying to import over DRS (2nd pass, to store remote schema): %s\n", win_errstr(status
)));
380 return werror_to_ntstatus(status
);
383 if (lpcfg_parm_bool(s
->lp_ctx
, NULL
, "become dc", "dump objects", false)) {
384 for (i
=0; i
< schema_objs
->num_objects
; i
++) {
385 struct ldb_ldif ldif
;
386 fprintf(stdout
, "#\n");
387 ldif
.changetype
= LDB_CHANGETYPE_NONE
;
388 ldif
.msg
= schema_objs
->objects
[i
].msg
;
389 ldb_ldif_write_file(s
->ldb
, stdout
, &ldif
);
390 NDR_PRINT_DEBUG(replPropertyMetaDataBlob
, schema_objs
->objects
[i
].meta_data
);
394 status
= dsdb_replicated_objects_commit(s
->ldb
, NULL
, schema_objs
, &seq_num
);
395 if (!W_ERROR_IS_OK(status
)) {
396 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status
)));
397 return werror_to_ntstatus(status
);
400 msg
= ldb_msg_new(schema_objs
);
401 NT_STATUS_HAVE_NO_MEMORY(msg
);
402 msg
->dn
= schema_objs
->partition_dn
;
404 /* We must ensure a prefixMap has been written. Unlike other
405 * attributes (including schemaInfo), it is not replicated in
406 * the normal replication stream. We can use the one from
407 * s->prefixmap_blob because we operate with one, unchanging
408 * prefixMap for this entire operation. */
409 ret
= ldb_msg_add_value(msg
, "prefixMap", &s
->prefixmap_blob
, &prefixMap_el
);
410 if (ret
!= LDB_SUCCESS
) {
411 return NT_STATUS_FOOBAR
;
413 /* We want to know if a prefixMap was written already, as it
414 * would mean that the above comment was not true, and we have
415 * somehow updated the prefixMap during this transaction */
416 prefixMap_el
->flags
= LDB_FLAG_MOD_ADD
;
418 ret
= dsdb_modify(s
->ldb
, msg
, DSDB_FLAG_AS_SYSTEM
);
419 if (ret
!= LDB_SUCCESS
) {
420 DEBUG(0,("Failed to add prefixMap: %s\n", ldb_errstring(s
->ldb
)));
421 return NT_STATUS_FOOBAR
;
425 talloc_free(schema_objs
);
427 s
->schema
= dsdb_get_schema(s
->ldb
, s
);
429 DEBUG(0,("Failed to get loaded dsdb_schema\n"));
430 return NT_STATUS_FOOBAR
;
436 NTSTATUS
libnet_vampire_cb_schema_chunk(void *private_data
,
437 const struct libnet_BecomeDC_StoreChunk
*c
)
439 struct libnet_vampire_cb_state
*s
= talloc_get_type(private_data
, struct libnet_vampire_cb_state
);
441 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
;
442 uint32_t nc_object_count
;
443 uint32_t nc_total_received
= 0;
444 uint32_t object_count
;
445 struct drsuapi_DsReplicaObjectListItemEx
*first_object
;
446 struct drsuapi_DsReplicaObjectListItemEx
*cur
;
447 uint32_t nc_linked_attributes_count
;
448 uint32_t linked_attributes_count
;
450 switch (c
->ctr_level
) {
452 mapping_ctr
= &c
->ctr1
->mapping_ctr
;
453 nc_object_count
= c
->ctr1
->extended_ret
; /* maybe w2k send this unexpected? */
454 object_count
= c
->ctr1
->object_count
;
455 first_object
= c
->ctr1
->first_object
;
456 nc_linked_attributes_count
= 0;
457 linked_attributes_count
= 0;
460 mapping_ctr
= &c
->ctr6
->mapping_ctr
;
461 nc_object_count
= c
->ctr6
->nc_object_count
;
462 object_count
= c
->ctr6
->object_count
;
463 first_object
= c
->ctr6
->first_object
;
464 nc_linked_attributes_count
= c
->ctr6
->nc_linked_attributes_count
;
465 linked_attributes_count
= c
->ctr6
->linked_attributes_count
;
468 return NT_STATUS_INVALID_PARAMETER
;
471 if (!s
->schema_part
.first_object
) {
472 nc_total_received
= object_count
;
474 nc_total_received
= s
->schema_part
.object_count
+ object_count
;
476 if (nc_object_count
) {
477 DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n",
478 c
->partition
->nc
.dn
, nc_total_received
, nc_object_count
,
479 linked_attributes_count
, nc_linked_attributes_count
));
481 DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u]\n",
482 c
->partition
->nc
.dn
, nc_total_received
, linked_attributes_count
));
485 if (!s
->self_made_schema
) {
487 struct drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr_without_schema_info
;
488 /* Put the DRS prefixmap aside for the schema we are
489 * about to load in the provision, and into the one we
490 * are making with the help of DRS */
492 mapping_ctr_without_schema_info
= *mapping_ctr
;
494 /* This strips off the 0xFF schema info from the end,
495 * because we don't want it in the blob */
496 if (mapping_ctr_without_schema_info
.num_mappings
> 0) {
497 mapping_ctr_without_schema_info
.num_mappings
--;
499 werr
= dsdb_get_drsuapi_prefixmap_as_blob(&mapping_ctr_without_schema_info
, s
, &s
->prefixmap_blob
);
500 if (!W_ERROR_IS_OK(werr
)) {
501 return werror_to_ntstatus(werr
);
504 /* Set up two manually-constructed schema - the local
505 * schema from the provision will be used to build
506 * one, which will then in turn be used to build the
508 s
->self_made_schema
= dsdb_new_schema(s
);
509 NT_STATUS_HAVE_NO_MEMORY(s
->self_made_schema
);
511 s
->self_made_schema
->base_dn
= ldb_dn_new(s
->self_made_schema
,
513 c
->forest
->schema_dn_str
);
514 NT_STATUS_HAVE_NO_MEMORY(s
->self_made_schema
->base_dn
);
516 status
= dsdb_load_prefixmap_from_drsuapi(s
->self_made_schema
, mapping_ctr
);
517 if (!W_ERROR_IS_OK(status
)) {
518 return werror_to_ntstatus(status
);
521 status
= dsdb_schema_pfm_contains_drsuapi_pfm(s
->self_made_schema
->prefixmap
, mapping_ctr
);
522 if (!W_ERROR_IS_OK(status
)) {
523 return werror_to_ntstatus(status
);
527 if (!s
->schema_part
.first_object
) {
528 s
->schema_part
.object_count
= object_count
;
529 s
->schema_part
.first_object
= talloc_steal(s
, first_object
);
531 s
->schema_part
.object_count
+= object_count
;
532 s
->schema_part
.last_object
->next_object
= talloc_steal(s
->schema_part
.last_object
,
535 for (cur
= first_object
; cur
->next_object
; cur
= cur
->next_object
) {}
536 s
->schema_part
.last_object
= cur
;
538 if (!c
->partition
->more_data
) {
539 return libnet_vampire_cb_apply_schema(s
, c
);
545 NTSTATUS
libnet_vampire_cb_store_chunk(void *private_data
,
546 const struct libnet_BecomeDC_StoreChunk
*c
)
548 struct libnet_vampire_cb_state
*s
= talloc_get_type(private_data
, struct libnet_vampire_cb_state
);
550 struct dsdb_schema
*schema
;
551 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
;
552 uint32_t nc_object_count
;
553 uint32_t object_count
;
554 struct drsuapi_DsReplicaObjectListItemEx
*first_object
;
555 uint32_t nc_linked_attributes_count
;
556 uint32_t linked_attributes_count
;
557 struct drsuapi_DsReplicaLinkedAttribute
*linked_attributes
;
558 const struct drsuapi_DsReplicaCursor2CtrEx
*uptodateness_vector
;
559 struct dsdb_extended_replicated_objects
*objs
;
560 uint32_t req_replica_flags
;
561 struct repsFromTo1
*s_dsa
;
565 bool is_exop
= false;
567 s_dsa
= talloc_zero(s
, struct repsFromTo1
);
568 NT_STATUS_HAVE_NO_MEMORY(s_dsa
);
569 s_dsa
->other_info
= talloc(s_dsa
, struct repsFromTo1OtherInfo
);
570 NT_STATUS_HAVE_NO_MEMORY(s_dsa
->other_info
);
572 switch (c
->ctr_level
) {
574 mapping_ctr
= &c
->ctr1
->mapping_ctr
;
575 nc_object_count
= c
->ctr1
->extended_ret
; /* maybe w2k send this unexpected? */
576 object_count
= c
->ctr1
->object_count
;
577 first_object
= c
->ctr1
->first_object
;
578 nc_linked_attributes_count
= 0;
579 linked_attributes_count
= 0;
580 linked_attributes
= NULL
;
581 s_dsa
->highwatermark
= c
->ctr1
->new_highwatermark
;
582 s_dsa
->source_dsa_obj_guid
= c
->ctr1
->source_dsa_guid
;
583 s_dsa
->source_dsa_invocation_id
= c
->ctr1
->source_dsa_invocation_id
;
584 uptodateness_vector
= NULL
; /* TODO: map it */
587 mapping_ctr
= &c
->ctr6
->mapping_ctr
;
588 nc_object_count
= c
->ctr6
->nc_object_count
;
589 object_count
= c
->ctr6
->object_count
;
590 first_object
= c
->ctr6
->first_object
;
591 nc_linked_attributes_count
= c
->ctr6
->nc_linked_attributes_count
;
592 linked_attributes_count
= c
->ctr6
->linked_attributes_count
;
593 linked_attributes
= c
->ctr6
->linked_attributes
;
594 s_dsa
->highwatermark
= c
->ctr6
->new_highwatermark
;
595 s_dsa
->source_dsa_obj_guid
= c
->ctr6
->source_dsa_guid
;
596 s_dsa
->source_dsa_invocation_id
= c
->ctr6
->source_dsa_invocation_id
;
597 uptodateness_vector
= c
->ctr6
->uptodateness_vector
;
600 return NT_STATUS_INVALID_PARAMETER
;
603 switch (c
->req_level
) {
606 req_replica_flags
= 0;
609 if (c
->req5
->extended_op
!= DRSUAPI_EXOP_NONE
) {
612 req_replica_flags
= c
->req5
->replica_flags
;
615 if (c
->req8
->extended_op
!= DRSUAPI_EXOP_NONE
) {
618 req_replica_flags
= c
->req8
->replica_flags
;
621 if (c
->req10
->extended_op
!= DRSUAPI_EXOP_NONE
) {
624 req_replica_flags
= c
->req10
->replica_flags
;
627 return NT_STATUS_INVALID_PARAMETER
;
630 if (req_replica_flags
& DRSUAPI_DRS_CRITICAL_ONLY
) {
632 * If we only replicate the critical objects
633 * we should not remember what we already
634 * got, as it is incomplete.
636 ZERO_STRUCT(s_dsa
->highwatermark
);
637 uptodateness_vector
= NULL
;
640 /* TODO: avoid hardcoded flags */
641 s_dsa
->replica_flags
= DRSUAPI_DRS_WRIT_REP
642 | DRSUAPI_DRS_INIT_SYNC
643 | DRSUAPI_DRS_PER_SYNC
;
644 memset(s_dsa
->schedule
, 0x11, sizeof(s_dsa
->schedule
));
646 tmp_dns_name
= GUID_string(s_dsa
->other_info
, &s_dsa
->source_dsa_obj_guid
);
647 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name
);
648 tmp_dns_name
= talloc_asprintf_append_buffer(tmp_dns_name
, "._msdcs.%s", c
->forest
->dns_name
);
649 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name
);
650 s_dsa
->other_info
->dns_name
= tmp_dns_name
;
652 /* we want to show a count per partition */
653 if (!s
->last_partition
|| strcmp(s
->last_partition
, c
->partition
->nc
.dn
) != 0) {
654 s
->total_objects
= 0;
655 talloc_free(s
->last_partition
);
656 s
->last_partition
= talloc_strdup(s
, c
->partition
->nc
.dn
);
658 s
->total_objects
+= object_count
;
661 if (nc_object_count
) {
662 DEBUG(0,("Exop on[%s] objects[%u/%u] linked_values[%u/%u]\n",
663 c
->partition
->nc
.dn
, s
->total_objects
, nc_object_count
,
664 linked_attributes_count
, nc_linked_attributes_count
));
666 DEBUG(0,("Exop on[%s] objects[%u] linked_values[%u]\n",
667 c
->partition
->nc
.dn
, s
->total_objects
, linked_attributes_count
));
670 if (nc_object_count
) {
671 DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n",
672 c
->partition
->nc
.dn
, s
->total_objects
, nc_object_count
,
673 linked_attributes_count
, nc_linked_attributes_count
));
675 DEBUG(0,("Partition[%s] objects[%u] linked_values[%u]\n",
676 c
->partition
->nc
.dn
, s
->total_objects
, linked_attributes_count
));
681 schema
= dsdb_get_schema(s
->ldb
, NULL
);
683 DEBUG(0,(__location__
": Schema is not loaded yet!\n"));
684 return NT_STATUS_INTERNAL_ERROR
;
687 status
= dsdb_replicated_objects_convert(s
->ldb
,
693 linked_attributes_count
,
700 if (!W_ERROR_IS_OK(status
)) {
701 DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status
)));
702 return werror_to_ntstatus(status
);
705 if (lpcfg_parm_bool(s
->lp_ctx
, NULL
, "become dc", "dump objects", false)) {
706 for (i
=0; i
< objs
->num_objects
; i
++) {
707 struct ldb_ldif ldif
;
708 fprintf(stdout
, "#\n");
709 ldif
.changetype
= LDB_CHANGETYPE_NONE
;
710 ldif
.msg
= objs
->objects
[i
].msg
;
711 ldb_ldif_write_file(s
->ldb
, stdout
, &ldif
);
712 NDR_PRINT_DEBUG(replPropertyMetaDataBlob
, objs
->objects
[i
].meta_data
);
715 status
= dsdb_replicated_objects_commit(s
->ldb
, NULL
, objs
, &seq_num
);
716 if (!W_ERROR_IS_OK(status
)) {
717 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status
)));
718 return werror_to_ntstatus(status
);
724 for (i
=0; i
< linked_attributes_count
; i
++) {
725 const struct dsdb_attribute
*sa
;
727 if (!linked_attributes
[i
].identifier
) {
728 DEBUG(0, ("No linked attribute identifier\n"));
729 return NT_STATUS_FOOBAR
;
732 if (!linked_attributes
[i
].value
.blob
) {
733 DEBUG(0, ("No linked attribute value\n"));
734 return NT_STATUS_FOOBAR
;
737 sa
= dsdb_attribute_by_attributeID_id(s
->schema
,
738 linked_attributes
[i
].attid
);
740 DEBUG(0, ("Unable to find attribute via attribute id %d\n", linked_attributes
[i
].attid
));
741 return NT_STATUS_FOOBAR
;
744 if (lpcfg_parm_bool(s
->lp_ctx
, NULL
, "become dc", "dump objects", false)) {
745 DEBUG(0,("# %s\n", sa
->lDAPDisplayName
));
746 NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute
, &linked_attributes
[i
]);
748 linked_attributes
[i
].value
.blob
->data
,
749 linked_attributes
[i
].value
.blob
->length
);
756 static NTSTATUS
update_dnshostname_for_server(TALLOC_CTX
*mem_ctx
,
757 struct ldb_context
*ldb
,
758 const char *server_dn_str
,
759 const char *netbios_name
,
763 struct ldb_message
*msg
;
764 struct ldb_message_element
*el
;
765 struct ldb_dn
*server_dn
;
766 const char *dNSHostName
= strlower_talloc(mem_ctx
,
767 talloc_asprintf(mem_ctx
,
771 msg
= ldb_msg_new(mem_ctx
);
773 return NT_STATUS_NO_MEMORY
;
776 server_dn
= ldb_dn_new(mem_ctx
, ldb
, server_dn_str
);
778 return NT_STATUS_INTERNAL_ERROR
;
782 ret
= ldb_msg_add_empty(msg
, "dNSHostName", LDB_FLAG_MOD_ADD
, &el
);
783 if (ret
!= LDB_SUCCESS
) {
784 return NT_STATUS_INTERNAL_ERROR
;
787 ret
= ldb_msg_add_steal_string(msg
,
789 talloc_asprintf(el
->values
, "%s", dNSHostName
));
790 if (ret
!= LDB_SUCCESS
) {
791 return NT_STATUS_INTERNAL_ERROR
;
794 ret
= dsdb_modify(ldb
, msg
, DSDB_MODIFY_PERMISSIVE
);
795 if (ret
!= LDB_SUCCESS
) {
796 DEBUG(0,(__location__
": Failed to add dnsHostName to the Server object: %s\n",
797 ldb_errstring(ldb
)));
798 return NT_STATUS_INTERNAL_ERROR
;
805 NTSTATUS
libnet_Vampire(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
806 struct libnet_Vampire
*r
)
808 struct libnet_JoinDomain
*join
;
809 struct libnet_Replicate rep
;
812 const char *account_name
;
813 const char *netbios_name
;
815 r
->out
.error_string
= NULL
;
817 join
= talloc_zero(mem_ctx
, struct libnet_JoinDomain
);
819 return NT_STATUS_NO_MEMORY
;
822 if (r
->in
.netbios_name
!= NULL
) {
823 netbios_name
= r
->in
.netbios_name
;
825 netbios_name
= talloc_reference(join
, lpcfg_netbios_name(ctx
->lp_ctx
));
828 r
->out
.error_string
= NULL
;
829 return NT_STATUS_NO_MEMORY
;
833 account_name
= talloc_asprintf(join
, "%s$", netbios_name
);
836 r
->out
.error_string
= NULL
;
837 return NT_STATUS_NO_MEMORY
;
840 /* Re-use the domain we are joining as the domain for the user
841 * to be authenticated with, unless they specified
843 cli_credentials_set_domain(ctx
->cred
, r
->in
.domain_name
, CRED_GUESS_ENV
);
845 join
->in
.domain_name
= r
->in
.domain_name
;
846 join
->in
.account_name
= account_name
;
847 join
->in
.netbios_name
= netbios_name
;
848 join
->in
.level
= LIBNET_JOINDOMAIN_AUTOMATIC
;
849 join
->in
.acct_type
= ACB_WSTRUST
;
850 join
->in
.recreate_account
= false;
851 status
= libnet_JoinDomain(ctx
, join
, join
);
852 if (!NT_STATUS_IS_OK(status
)) {
853 r
->out
.error_string
= talloc_steal(mem_ctx
, join
->out
.error_string
);
858 rep
.in
.domain_name
= join
->out
.domain_name
;
859 rep
.in
.netbios_name
= netbios_name
;
860 rep
.in
.targetdir
= r
->in
.targetdir
;
861 rep
.in
.domain_sid
= join
->out
.domain_sid
;
862 rep
.in
.realm
= join
->out
.realm
;
863 rep
.in
.server
= join
->out
.samr_binding
->host
;
864 rep
.in
.join_password
= join
->out
.join_password
;
865 rep
.in
.kvno
= join
->out
.kvno
;
867 status
= libnet_Replicate(ctx
, mem_ctx
, &rep
);
869 r
->out
.domain_sid
= join
->out
.domain_sid
;
870 r
->out
.domain_name
= join
->out
.domain_name
;
871 r
->out
.error_string
= rep
.out
.error_string
;
878 NTSTATUS
libnet_Replicate(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
879 struct libnet_Replicate
*r
)
881 struct provision_store_self_join_settings
*set_secrets
;
882 struct libnet_BecomeDC b
;
883 struct libnet_vampire_cb_state
*s
;
884 struct ldb_message
*msg
;
885 const char *error_string
;
889 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
890 const char *account_name
;
891 const char *netbios_name
;
893 r
->out
.error_string
= NULL
;
895 netbios_name
= r
->in
.netbios_name
;
896 account_name
= talloc_asprintf(tmp_ctx
, "%s$", netbios_name
);
898 talloc_free(tmp_ctx
);
899 r
->out
.error_string
= NULL
;
900 return NT_STATUS_NO_MEMORY
;
903 /* Re-use the domain we are joining as the domain for the user
904 * to be authenticated with, unless they specified
906 cli_credentials_set_domain(ctx
->cred
, r
->in
.domain_name
, CRED_GUESS_ENV
);
908 s
= libnet_vampire_cb_state_init(mem_ctx
, ctx
->lp_ctx
, ctx
->event_ctx
,
909 netbios_name
, r
->in
.domain_name
, r
->in
.realm
,
912 return NT_STATUS_NO_MEMORY
;
914 talloc_steal(s
, tmp_ctx
);
919 * We now know the domain and realm for sure - if they didn't
920 * put one on the command line, use this for the rest of the
922 cli_credentials_set_realm(ctx
->cred
, r
->in
.realm
, CRED_GUESS_ENV
);
923 cli_credentials_set_domain(ctx
->cred
, r
->in
.domain_name
, CRED_GUESS_ENV
);
925 /* Now set these values into the smb.conf - we probably had
926 * empty or useless defaults here from whatever smb.conf we
928 lpcfg_set_cmdline(s
->lp_ctx
, "realm", r
->in
.realm
);
929 lpcfg_set_cmdline(s
->lp_ctx
, "workgroup", r
->in
.domain_name
);
931 b
.in
.domain_dns_name
= r
->in
.realm
;
932 b
.in
.domain_netbios_name
= r
->in
.domain_name
;
933 b
.in
.domain_sid
= r
->in
.domain_sid
;
934 b
.in
.source_dsa_address
= r
->in
.server
;
935 b
.in
.dest_dsa_netbios_name
= netbios_name
;
937 b
.in
.callbacks
.private_data
= s
;
938 b
.in
.callbacks
.check_options
= libnet_vampire_cb_check_options
;
939 b
.in
.callbacks
.prepare_db
= libnet_vampire_cb_prepare_db
;
940 b
.in
.callbacks
.schema_chunk
= libnet_vampire_cb_schema_chunk
;
941 b
.in
.callbacks
.config_chunk
= libnet_vampire_cb_store_chunk
;
942 b
.in
.callbacks
.domain_chunk
= libnet_vampire_cb_store_chunk
;
944 b
.in
.rodc_join
= lpcfg_parm_bool(s
->lp_ctx
, NULL
, "repl", "RODC", false);
946 status
= libnet_BecomeDC(ctx
, s
, &b
);
947 if (!NT_STATUS_IS_OK(status
)) {
948 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status
));
953 msg
= ldb_msg_new(s
);
955 printf("ldb_msg_new() failed\n");
957 return NT_STATUS_NO_MEMORY
;
959 msg
->dn
= ldb_dn_new(msg
, s
->ldb
, "@ROOTDSE");
961 printf("ldb_msg_new(@ROOTDSE) failed\n");
963 return NT_STATUS_NO_MEMORY
;
966 ldb_ret
= ldb_msg_add_string(msg
, "isSynchronized", "TRUE");
967 if (ldb_ret
!= LDB_SUCCESS
) {
968 printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret
);
970 return NT_STATUS_NO_MEMORY
;
973 for (i
=0; i
< msg
->num_elements
; i
++) {
974 msg
->elements
[i
].flags
= LDB_FLAG_MOD_REPLACE
;
977 printf("mark ROOTDSE with isSynchronized=TRUE\n");
978 ldb_ret
= ldb_modify(s
->ldb
, msg
);
979 if (ldb_ret
!= LDB_SUCCESS
) {
980 printf("ldb_modify() failed: %d : %s\n", ldb_ret
, ldb_errstring(s
->ldb
));
982 return NT_STATUS_INTERNAL_DB_ERROR
;
984 /* during dcpromo the 2nd computer adds dNSHostName attribute to his Server object
985 * the attribute appears on the original DC after replication
987 status
= update_dnshostname_for_server(s
, s
->ldb
, s
->server_dn_str
, s
->netbios_name
, s
->realm
);
988 if (!NT_STATUS_IS_OK(status
)) {
989 printf("Failed to update dNSHostName on Server object - %s\n", nt_errstr(status
));
993 /* prepare the transaction - this prepares to commit all the changes in
994 the ldb from the whole vampire. Note that this
995 triggers the writing of the linked attribute backlinks.
997 if (ldb_transaction_prepare_commit(s
->ldb
) != LDB_SUCCESS
) {
998 printf("Failed to prepare_commit vampire transaction: %s\n", ldb_errstring(s
->ldb
));
999 return NT_STATUS_INTERNAL_DB_ERROR
;
1002 set_secrets
= talloc(s
, struct provision_store_self_join_settings
);
1004 r
->out
.error_string
= NULL
;
1006 return NT_STATUS_NO_MEMORY
;
1009 ZERO_STRUCTP(set_secrets
);
1010 set_secrets
->domain_name
= r
->in
.domain_name
;
1011 set_secrets
->realm
= r
->in
.realm
;
1012 set_secrets
->netbios_name
= netbios_name
;
1013 set_secrets
->secure_channel_type
= SEC_CHAN_BDC
;
1014 set_secrets
->machine_password
= r
->in
.join_password
;
1015 set_secrets
->key_version_number
= r
->in
.kvno
;
1016 set_secrets
->domain_sid
= r
->in
.domain_sid
;
1018 status
= provision_store_self_join(ctx
, s
->lp_ctx
, ctx
->event_ctx
, set_secrets
, &error_string
);
1019 if (!NT_STATUS_IS_OK(status
)) {
1020 r
->out
.error_string
= talloc_steal(mem_ctx
, error_string
);
1025 /* commit the transaction now we know the secrets were written
1028 if (ldb_transaction_commit(s
->ldb
) != LDB_SUCCESS
) {
1029 printf("Failed to commit vampire transaction\n");
1030 return NT_STATUS_INTERNAL_DB_ERROR
;
1035 return NT_STATUS_OK
;