s4:blackblock/ktpass: use test specific user name
[Samba.git] / source4 / libnet / libnet_vampire.c
blobb85869e93ea7ac3b589dee927e4b0a55838c04b2
1 /*
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/>.
25 #include "includes.h"
26 #include "libnet/libnet.h"
27 #include "lib/events/events.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "../lib/util/dlinklist.h"
30 #include "lib/ldb/include/ldb.h"
31 #include "lib/ldb/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"
37 #include "ldb_wrap.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/dom_sid.h"
44 /*
45 List of tasks vampire.py must perform:
46 - Domain Join
47 - but don't write the secrets.ldb
48 - results for this should be enough to handle the provision
49 - if vampire method is samsync
50 - Provision using these results
51 - do we still want to support this NT4 technology?
52 - Start samsync with libnet code
53 - provision in the callback
54 - Write out the secrets database, using the code from libnet_Join
57 struct libnet_vampire_cb_state {
58 const char *netbios_name;
59 const char *domain_name;
60 const char *realm;
61 struct cli_credentials *machine_account;
63 /* Schema loaded from local LDIF files */
64 struct dsdb_schema *provision_schema;
66 /* 1st pass, with some OIDs/attribute names/class names not
67 * converted, because we may not know them yet */
68 struct dsdb_schema *self_made_schema;
70 /* 2nd pass, with full ID->OID->name table */
71 struct dsdb_schema *self_corrected_schema;
73 /* prefixMap in LDB format, from the remote DRS server */
74 DATA_BLOB prefixmap_blob;
75 const struct dsdb_schema *schema;
77 struct ldb_context *ldb;
79 struct {
80 uint32_t object_count;
81 struct drsuapi_DsReplicaObjectListItemEx *first_object;
82 struct drsuapi_DsReplicaObjectListItemEx *last_object;
83 } schema_part;
85 const char *targetdir;
87 struct loadparm_context *lp_ctx;
88 struct tevent_context *event_ctx;
89 unsigned total_objects;
90 char *last_partition;
93 /* Caller is expected to keep supplied pointers around for the lifetime of the structure */
94 void *libnet_vampire_cb_state_init(TALLOC_CTX *mem_ctx,
95 struct loadparm_context *lp_ctx, struct tevent_context *event_ctx,
96 const char *netbios_name, const char *domain_name, const char *realm,
97 const char *targetdir)
99 struct libnet_vampire_cb_state *s = talloc_zero(mem_ctx, struct libnet_vampire_cb_state);
100 if (!s) {
101 return NULL;
104 s->lp_ctx = lp_ctx;
105 s->event_ctx = event_ctx;
106 s->netbios_name = netbios_name;
107 s->domain_name = domain_name;
108 s->realm = realm;
109 s->targetdir = targetdir;
110 return s;
113 struct ldb_context *libnet_vampire_cb_ldb(struct libnet_vampire_cb_state *state)
115 state = talloc_get_type_abort(state, struct libnet_vampire_cb_state);
116 return state->ldb;
119 struct loadparm_context *libnet_vampire_cb_lp_ctx(struct libnet_vampire_cb_state *state)
121 state = talloc_get_type_abort(state, struct libnet_vampire_cb_state);
122 return state->lp_ctx;
125 NTSTATUS libnet_vampire_cb_prepare_db(void *private_data,
126 const struct libnet_BecomeDC_PrepareDB *p)
128 struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
129 struct provision_settings settings;
130 struct provision_result result;
131 NTSTATUS status;
133 ZERO_STRUCT(settings);
134 settings.site_name = p->dest_dsa->site_name;
135 settings.root_dn_str = p->forest->root_dn_str;
136 settings.domain_dn_str = p->domain->dn_str;
137 settings.config_dn_str = p->forest->config_dn_str;
138 settings.schema_dn_str = p->forest->schema_dn_str;
139 settings.netbios_name = p->dest_dsa->netbios_name;
140 settings.realm = s->realm;
141 settings.domain = s->domain_name;
142 settings.server_dn_str = p->dest_dsa->server_dn_str;
143 settings.machine_password = generate_random_password(s, 16, 255);
144 settings.targetdir = s->targetdir;
146 status = provision_bare(s, s->lp_ctx, &settings, &result);
148 if (!NT_STATUS_IS_OK(status)) {
149 return status;
152 s->ldb = talloc_steal(s, result.samdb);
153 s->lp_ctx = talloc_steal(s, result.lp_ctx);
154 s->provision_schema = dsdb_get_schema(s->ldb, s);
156 /* wrap the entire vapire operation in a transaction. This
157 isn't just cosmetic - we use this to ensure that linked
158 attribute back links are added at the end by relying on a
159 transaction commit hook in the linked attributes module. We
160 need to do this as the order of objects coming from the
161 server is not sufficiently deterministic to know that the
162 record that a backlink needs to be created in has itself
163 been created before the object containing the forward link
164 has come over the wire */
165 if (ldb_transaction_start(s->ldb) != LDB_SUCCESS) {
166 return NT_STATUS_FOOBAR;
169 return NT_STATUS_OK;
174 NTSTATUS libnet_vampire_cb_check_options(void *private_data,
175 const struct libnet_BecomeDC_CheckOptions *o)
177 struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
179 DEBUG(0,("Become DC [%s] of Domain[%s]/[%s]\n",
180 s->netbios_name,
181 o->domain->netbios_name, o->domain->dns_name));
183 DEBUG(0,("Promotion Partner is Server[%s] from Site[%s]\n",
184 o->source_dsa->dns_name, o->source_dsa->site_name));
186 DEBUG(0,("Options:crossRef behavior_version[%u]\n"
187 "\tschema object_version[%u]\n"
188 "\tdomain behavior_version[%u]\n"
189 "\tdomain w2k3_update_revision[%u]\n",
190 o->forest->crossref_behavior_version,
191 o->forest->schema_object_version,
192 o->domain->behavior_version,
193 o->domain->w2k3_update_revision));
195 return NT_STATUS_OK;
198 static NTSTATUS libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s,
199 const struct libnet_BecomeDC_StoreChunk *c)
201 WERROR status;
202 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
203 uint32_t object_count;
204 struct drsuapi_DsReplicaObjectListItemEx *first_object;
205 const struct drsuapi_DsReplicaObjectListItemEx *cur;
206 uint32_t linked_attributes_count;
207 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
208 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
209 struct dsdb_extended_replicated_objects *schema_objs;
210 struct repsFromTo1 *s_dsa;
211 char *tmp_dns_name;
212 struct ldb_context *schema_ldb;
213 struct ldb_message *msg;
214 struct ldb_message_element *prefixMap_el;
215 uint32_t i;
216 int ret;
217 bool ok;
218 uint64_t seq_num;
220 DEBUG(0,("Analyze and apply schema objects\n"));
222 s_dsa = talloc_zero(s, struct repsFromTo1);
223 NT_STATUS_HAVE_NO_MEMORY(s_dsa);
224 s_dsa->other_info = talloc(s_dsa, struct repsFromTo1OtherInfo);
225 NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
227 switch (c->ctr_level) {
228 case 1:
229 mapping_ctr = &c->ctr1->mapping_ctr;
230 object_count = s->schema_part.object_count;
231 first_object = s->schema_part.first_object;
232 linked_attributes_count = 0;
233 linked_attributes = NULL;
234 s_dsa->highwatermark = c->ctr1->new_highwatermark;
235 s_dsa->source_dsa_obj_guid = c->ctr1->source_dsa_guid;
236 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
237 uptodateness_vector = NULL; /* TODO: map it */
238 break;
239 case 6:
240 mapping_ctr = &c->ctr6->mapping_ctr;
241 object_count = s->schema_part.object_count;
242 first_object = s->schema_part.first_object;
243 linked_attributes_count = c->ctr6->linked_attributes_count;
244 linked_attributes = c->ctr6->linked_attributes;
245 s_dsa->highwatermark = c->ctr6->new_highwatermark;
246 s_dsa->source_dsa_obj_guid = c->ctr6->source_dsa_guid;
247 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
248 uptodateness_vector = c->ctr6->uptodateness_vector;
249 break;
250 default:
251 return NT_STATUS_INVALID_PARAMETER;
254 s_dsa->replica_flags = DRSUAPI_DRS_WRIT_REP
255 | DRSUAPI_DRS_INIT_SYNC
256 | DRSUAPI_DRS_PER_SYNC;
257 memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
259 tmp_dns_name = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
260 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
261 tmp_dns_name = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
262 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
263 s_dsa->other_info->dns_name = tmp_dns_name;
265 schema_ldb = provision_get_schema(s, s->lp_ctx, &s->prefixmap_blob);
266 if (!schema_ldb) {
267 DEBUG(0,("Failed to re-load from local provision using remote prefixMap. Will continue with local prefixMap\n"));
268 s->provision_schema = dsdb_get_schema(s->ldb, s);
269 } else {
270 s->provision_schema = dsdb_get_schema(schema_ldb, s);
271 ret = dsdb_reference_schema(s->ldb, s->provision_schema, false);
272 if (ret != LDB_SUCCESS) {
273 DEBUG(0,("Failed to attach schema from local provision using remote prefixMap."));
274 return NT_STATUS_UNSUCCESSFUL;
276 talloc_free(schema_ldb);
279 s->provision_schema->relax_OID_conversions = true;
281 /* Now convert the schema elements, using the schema we loaded locally */
282 for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
283 struct dsdb_extended_replicated_object object;
284 TALLOC_CTX *tmp_ctx = talloc_new(s);
285 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
287 /* Convert the objects into LDB messages using the
288 * provision schema, and either the provision or DRS
289 * prefix map - it should not matter, as these are
290 * just schema objects, so the critical parts. At
291 * most we would mix up the mayContain etc for new
292 * schema classes */
293 status = dsdb_convert_object_ex(s->ldb, s->provision_schema,
294 cur, c->gensec_skey,
295 tmp_ctx, &object);
296 if (!W_ERROR_IS_OK(status)) {
297 DEBUG(1,("Warning: Failed to convert schema object %s into ldb msg\n", cur->object.identifier->dn));
298 } else {
299 /* Convert the schema from ldb_message format
300 * (OIDs as OID strings) into schema, using
301 * the remote prefixMap */
302 status = dsdb_schema_set_el_from_ldb_msg(s->ldb, s->self_made_schema, object.msg);
303 if (!W_ERROR_IS_OK(status)) {
304 DEBUG(1,("Warning: failed to convert object %s into a schema element: %s\n",
305 ldb_dn_get_linearized(object.msg->dn),
306 win_errstr(status)));
309 talloc_free(tmp_ctx);
312 /* attach the schema we just brought over DRS to the ldb, so we can use it in dsdb_convert_object_ex below */
313 ret = dsdb_set_schema(s->ldb, s->self_made_schema);
314 if (ret != LDB_SUCCESS) {
315 DEBUG(0,("Failed to attach 1st pass schema from DRS.\n"));
316 return NT_STATUS_FOOBAR;
319 /* Now convert the schema elements again, using the schema we loaded over DRS */
320 for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
321 struct dsdb_extended_replicated_object object;
322 TALLOC_CTX *tmp_ctx = talloc_new(s);
323 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
325 /* Convert the objects into LDB messages using the
326 * self_made_schema, and the DRS prefix map. We now
327 * know the full schema int->OID->name mapping, so we
328 * can get it right this time */
329 status = dsdb_convert_object_ex(s->ldb, s->self_made_schema,
330 cur, c->gensec_skey,
331 tmp_ctx, &object);
332 if (!W_ERROR_IS_OK(status)) {
333 DEBUG(0,("ERROR: Failed to convert schema object %s into ldb msg\n", cur->object.identifier->dn));
334 } else {
335 /* Convert the schema from ldb_message format
336 * (OIDs as OID strings) into schema, using
337 * the remote prefixMap, now that we know
338 * names for all the schema elements (from the
339 * first conversion) */
340 status = dsdb_schema_set_el_from_ldb_msg(s->ldb, s->self_corrected_schema, object.msg);
341 if (!W_ERROR_IS_OK(status)) {
342 DEBUG(0,("ERROR: failed to convert object %s into a schema element: %s\n",
343 ldb_dn_get_linearized(object.msg->dn),
344 win_errstr(status)));
347 talloc_free(tmp_ctx);
350 /* We don't want to use the s->self_made_schema any more */
351 s->self_made_schema = NULL;
353 /* attach the schema we just brought over DRS to the ldb */
354 ret = dsdb_set_schema(s->ldb, s->self_corrected_schema);
355 if (ret != LDB_SUCCESS) {
356 DEBUG(0,("Failed to attach 2nd pass (corrected) 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_corrected_schema;
362 s->self_corrected_schema = NULL;
364 /* Now convert the schema elements again, using the schema we finalised, ready to actually import */
365 status = dsdb_extended_replicated_objects_convert(s->ldb,
366 c->partition->nc.dn,
367 mapping_ctr,
368 object_count,
369 first_object,
370 linked_attributes_count,
371 linked_attributes,
372 s_dsa,
373 uptodateness_vector,
374 c->gensec_skey,
375 s, &schema_objs);
376 if (!W_ERROR_IS_OK(status)) {
377 DEBUG(0,("Failed to convert objects when trying to import over DRS (2nd pass, to store remote schema): %s\n", win_errstr(status)));
378 return werror_to_ntstatus(status);
381 if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
382 for (i=0; i < schema_objs->num_objects; i++) {
383 struct ldb_ldif ldif;
384 fprintf(stdout, "#\n");
385 ldif.changetype = LDB_CHANGETYPE_NONE;
386 ldif.msg = schema_objs->objects[i].msg;
387 ldb_ldif_write_file(s->ldb, stdout, &ldif);
388 NDR_PRINT_DEBUG(replPropertyMetaDataBlob, schema_objs->objects[i].meta_data);
392 status = dsdb_extended_replicated_objects_commit(s->ldb, schema_objs, &seq_num);
393 if (!W_ERROR_IS_OK(status)) {
394 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
395 return werror_to_ntstatus(status);
398 msg = ldb_msg_new(schema_objs);
399 NT_STATUS_HAVE_NO_MEMORY(msg);
400 msg->dn = schema_objs->partition_dn;
402 /* We must ensure a prefixMap has been written. Unlike other
403 * attributes (including schemaInfo), it is not replicated in
404 * the normal replication stream. We can use the one from
405 * s->prefixmap_blob because we operate with one, unchanging
406 * prefixMap for this entire operation. */
407 ret = ldb_msg_add_value(msg, "prefixMap", &s->prefixmap_blob, &prefixMap_el);
408 if (ret != LDB_SUCCESS) {
409 return NT_STATUS_FOOBAR;
411 /* We want to know if a prefixMap was written already, as it
412 * would mean that the above comment was not true, and we have
413 * somehow updated the prefixMap during this transaction */
414 prefixMap_el->flags = LDB_FLAG_MOD_ADD;
416 ret = ldb_modify(s->ldb, msg);
417 if (ret != LDB_SUCCESS) {
418 DEBUG(0,("Failed to add prefixMap: %s\n", ldb_errstring(s->ldb)));
419 return NT_STATUS_FOOBAR;
422 talloc_free(s_dsa);
423 talloc_free(schema_objs);
425 /* We must set these up to ensure the replMetaData is written
426 * correctly, before our NTDS Settings entry is replicated */
427 ok = samdb_set_ntds_invocation_id(s->ldb, &c->dest_dsa->invocation_id);
428 if (!ok) {
429 DEBUG(0,("Failed to set cached ntds invocationId\n"));
430 return NT_STATUS_FOOBAR;
432 ok = samdb_set_ntds_objectGUID(s->ldb, &c->dest_dsa->ntds_guid);
433 if (!ok) {
434 DEBUG(0,("Failed to set cached ntds objectGUID\n"));
435 return NT_STATUS_FOOBAR;
438 s->schema = dsdb_get_schema(s->ldb, s);
439 if (!s->schema) {
440 DEBUG(0,("Failed to get loaded dsdb_schema\n"));
441 return NT_STATUS_FOOBAR;
444 return NT_STATUS_OK;
447 NTSTATUS libnet_vampire_cb_schema_chunk(void *private_data,
448 const struct libnet_BecomeDC_StoreChunk *c)
450 struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
451 WERROR status;
452 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
453 uint32_t nc_object_count;
454 uint32_t object_count;
455 struct drsuapi_DsReplicaObjectListItemEx *first_object;
456 struct drsuapi_DsReplicaObjectListItemEx *cur;
457 uint32_t nc_linked_attributes_count;
458 uint32_t linked_attributes_count;
459 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
461 switch (c->ctr_level) {
462 case 1:
463 mapping_ctr = &c->ctr1->mapping_ctr;
464 nc_object_count = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
465 object_count = c->ctr1->object_count;
466 first_object = c->ctr1->first_object;
467 nc_linked_attributes_count = 0;
468 linked_attributes_count = 0;
469 linked_attributes = NULL;
470 break;
471 case 6:
472 mapping_ctr = &c->ctr6->mapping_ctr;
473 nc_object_count = c->ctr6->nc_object_count;
474 object_count = c->ctr6->object_count;
475 first_object = c->ctr6->first_object;
476 nc_linked_attributes_count = c->ctr6->nc_linked_attributes_count;
477 linked_attributes_count = c->ctr6->linked_attributes_count;
478 linked_attributes = c->ctr6->linked_attributes;
479 break;
480 default:
481 return NT_STATUS_INVALID_PARAMETER;
484 if (nc_object_count) {
485 DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n",
486 c->partition->nc.dn, object_count, nc_object_count,
487 linked_attributes_count, nc_linked_attributes_count));
488 } else {
489 DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u]\n",
490 c->partition->nc.dn, object_count, linked_attributes_count));
493 if (!s->self_made_schema) {
494 WERROR werr;
495 struct drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr_without_schema_info;
496 /* Put the DRS prefixmap aside for the schema we are
497 * about to load in the provision, and into the one we
498 * are making with the help of DRS */
500 mapping_ctr_without_schema_info = *mapping_ctr;
502 /* This strips off the 0xFF schema info from the end,
503 * because we don't want it in the blob */
504 if (mapping_ctr_without_schema_info.num_mappings > 0) {
505 mapping_ctr_without_schema_info.num_mappings--;
507 werr = dsdb_get_drsuapi_prefixmap_as_blob(&mapping_ctr_without_schema_info, s, &s->prefixmap_blob);
508 if (!W_ERROR_IS_OK(werr)) {
509 return werror_to_ntstatus(werr);
512 /* Set up two manually-constructed schema - the local
513 * schema from the provision will be used to build
514 * one, which will then in turn be used to build the
515 * other. */
516 s->self_made_schema = dsdb_new_schema(s);
517 NT_STATUS_HAVE_NO_MEMORY(s->self_made_schema);
518 s->self_corrected_schema = dsdb_new_schema(s);
519 NT_STATUS_HAVE_NO_MEMORY(s->self_corrected_schema);
521 status = dsdb_load_prefixmap_from_drsuapi(s->self_made_schema, mapping_ctr);
522 if (!W_ERROR_IS_OK(status)) {
523 return werror_to_ntstatus(status);
526 status = dsdb_load_prefixmap_from_drsuapi(s->self_corrected_schema, mapping_ctr);
527 if (!W_ERROR_IS_OK(status)) {
528 return werror_to_ntstatus(status);
530 } else {
531 status = dsdb_schema_pfm_contains_drsuapi_pfm(s->self_made_schema->prefixmap, mapping_ctr);
532 if (!W_ERROR_IS_OK(status)) {
533 return werror_to_ntstatus(status);
537 if (!s->schema_part.first_object) {
538 s->schema_part.object_count = object_count;
539 s->schema_part.first_object = talloc_steal(s, first_object);
540 } else {
541 s->schema_part.object_count += object_count;
542 s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
543 first_object);
545 for (cur = first_object; cur->next_object; cur = cur->next_object) {}
546 s->schema_part.last_object = cur;
548 if (!c->partition->more_data) {
549 return libnet_vampire_cb_apply_schema(s, c);
552 return NT_STATUS_OK;
555 NTSTATUS libnet_vampire_cb_store_chunk(void *private_data,
556 const struct libnet_BecomeDC_StoreChunk *c)
558 struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
559 WERROR status;
560 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
561 uint32_t nc_object_count;
562 uint32_t object_count;
563 struct drsuapi_DsReplicaObjectListItemEx *first_object;
564 uint32_t nc_linked_attributes_count;
565 uint32_t linked_attributes_count;
566 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
567 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
568 struct dsdb_extended_replicated_objects *objs;
569 struct repsFromTo1 *s_dsa;
570 char *tmp_dns_name;
571 uint32_t i;
572 uint64_t seq_num;
574 s_dsa = talloc_zero(s, struct repsFromTo1);
575 NT_STATUS_HAVE_NO_MEMORY(s_dsa);
576 s_dsa->other_info = talloc(s_dsa, struct repsFromTo1OtherInfo);
577 NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
579 switch (c->ctr_level) {
580 case 1:
581 mapping_ctr = &c->ctr1->mapping_ctr;
582 nc_object_count = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
583 object_count = c->ctr1->object_count;
584 first_object = c->ctr1->first_object;
585 nc_linked_attributes_count = 0;
586 linked_attributes_count = 0;
587 linked_attributes = NULL;
588 s_dsa->highwatermark = c->ctr1->new_highwatermark;
589 s_dsa->source_dsa_obj_guid = c->ctr1->source_dsa_guid;
590 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
591 uptodateness_vector = NULL; /* TODO: map it */
592 break;
593 case 6:
594 mapping_ctr = &c->ctr6->mapping_ctr;
595 nc_object_count = c->ctr6->nc_object_count;
596 object_count = c->ctr6->object_count;
597 first_object = c->ctr6->first_object;
598 nc_linked_attributes_count = c->ctr6->nc_linked_attributes_count;
599 linked_attributes_count = c->ctr6->linked_attributes_count;
600 linked_attributes = c->ctr6->linked_attributes;
601 s_dsa->highwatermark = c->ctr6->new_highwatermark;
602 s_dsa->source_dsa_obj_guid = c->ctr6->source_dsa_guid;
603 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
604 uptodateness_vector = c->ctr6->uptodateness_vector;
605 break;
606 default:
607 return NT_STATUS_INVALID_PARAMETER;
610 s_dsa->replica_flags = DRSUAPI_DRS_WRIT_REP
611 | DRSUAPI_DRS_INIT_SYNC
612 | DRSUAPI_DRS_PER_SYNC;
613 memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
615 tmp_dns_name = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
616 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
617 tmp_dns_name = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
618 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
619 s_dsa->other_info->dns_name = tmp_dns_name;
621 /* we want to show a count per partition */
622 if (!s->last_partition || strcmp(s->last_partition, c->partition->nc.dn) != 0) {
623 s->total_objects = 0;
624 talloc_free(s->last_partition);
625 s->last_partition = talloc_strdup(s, c->partition->nc.dn);
627 s->total_objects += object_count;
629 if (nc_object_count) {
630 DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n",
631 c->partition->nc.dn, s->total_objects, nc_object_count,
632 linked_attributes_count, nc_linked_attributes_count));
633 } else {
634 DEBUG(0,("Partition[%s] objects[%u] linked_values[%u]\n",
635 c->partition->nc.dn, s->total_objects, linked_attributes_count));
639 status = dsdb_extended_replicated_objects_convert(s->ldb,
640 c->partition->nc.dn,
641 mapping_ctr,
642 object_count,
643 first_object,
644 linked_attributes_count,
645 linked_attributes,
646 s_dsa,
647 uptodateness_vector,
648 c->gensec_skey,
649 s, &objs);
650 if (!W_ERROR_IS_OK(status)) {
651 DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status)));
652 return werror_to_ntstatus(status);
655 if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
656 for (i=0; i < objs->num_objects; i++) {
657 struct ldb_ldif ldif;
658 fprintf(stdout, "#\n");
659 ldif.changetype = LDB_CHANGETYPE_NONE;
660 ldif.msg = objs->objects[i].msg;
661 ldb_ldif_write_file(s->ldb, stdout, &ldif);
662 NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
665 status = dsdb_extended_replicated_objects_commit(s->ldb,
666 objs, &seq_num);
667 if (!W_ERROR_IS_OK(status)) {
668 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
669 return werror_to_ntstatus(status);
672 talloc_free(s_dsa);
673 talloc_free(objs);
675 for (i=0; i < linked_attributes_count; i++) {
676 const struct dsdb_attribute *sa;
678 if (!linked_attributes[i].identifier) {
679 return NT_STATUS_FOOBAR;
682 if (!linked_attributes[i].value.blob) {
683 return NT_STATUS_FOOBAR;
686 sa = dsdb_attribute_by_attributeID_id(s->schema,
687 linked_attributes[i].attid);
688 if (!sa) {
689 return NT_STATUS_FOOBAR;
692 if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
693 DEBUG(0,("# %s\n", sa->lDAPDisplayName));
694 NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, &linked_attributes[i]);
695 dump_data(0,
696 linked_attributes[i].value.blob->data,
697 linked_attributes[i].value.blob->length);
701 return NT_STATUS_OK;
704 NTSTATUS libnet_Vampire(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
705 struct libnet_Vampire *r)
707 struct libnet_JoinDomain *join;
708 struct provision_store_self_join_settings *set_secrets;
709 struct libnet_BecomeDC b;
710 struct libnet_vampire_cb_state *s;
711 struct ldb_message *msg;
712 const char *error_string;
713 int ldb_ret;
714 uint32_t i;
715 NTSTATUS status;
717 const char *account_name;
718 const char *netbios_name;
720 r->out.error_string = NULL;
722 join = talloc_zero(mem_ctx, struct libnet_JoinDomain);
723 if (!join) {
724 return NT_STATUS_NO_MEMORY;
727 if (r->in.netbios_name != NULL) {
728 netbios_name = r->in.netbios_name;
729 } else {
730 netbios_name = talloc_reference(join, lpcfg_netbios_name(ctx->lp_ctx));
731 if (!netbios_name) {
732 talloc_free(join);
733 r->out.error_string = NULL;
734 return NT_STATUS_NO_MEMORY;
738 account_name = talloc_asprintf(join, "%s$", netbios_name);
739 if (!account_name) {
740 talloc_free(join);
741 r->out.error_string = NULL;
742 return NT_STATUS_NO_MEMORY;
745 /* Re-use the domain we are joining as the domain for the user
746 * to be authenticated with, unless they specified
747 * otherwise */
748 cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
750 join->in.domain_name = r->in.domain_name;
751 join->in.account_name = account_name;
752 join->in.netbios_name = netbios_name;
753 join->in.level = LIBNET_JOINDOMAIN_AUTOMATIC;
754 join->in.acct_type = ACB_WSTRUST;
755 join->in.recreate_account = false;
756 status = libnet_JoinDomain(ctx, join, join);
757 if (!NT_STATUS_IS_OK(status)) {
758 r->out.error_string = talloc_steal(mem_ctx, join->out.error_string);
759 talloc_free(join);
760 return status;
763 s = libnet_vampire_cb_state_init(mem_ctx, ctx->lp_ctx, ctx->event_ctx,
764 netbios_name, join->out.domain_name, join->out.realm,
765 r->in.targetdir);
766 if (!s) {
767 return NT_STATUS_NO_MEMORY;
769 talloc_steal(s, join);
771 ZERO_STRUCT(b);
773 /* Be more robust:
774 * We now know the domain and realm for sure - if they didn't
775 * put one on the command line, use this for the rest of the
776 * join */
777 cli_credentials_set_realm(ctx->cred, join->out.realm, CRED_GUESS_ENV);
778 cli_credentials_set_domain(ctx->cred, join->out.domain_name, CRED_GUESS_ENV);
780 /* Now set these values into the smb.conf - we probably had
781 * empty or useless defaults here from whatever smb.conf we
782 * started with */
783 lpcfg_set_cmdline(s->lp_ctx, "realm", join->out.realm);
784 lpcfg_set_cmdline(s->lp_ctx, "workgroup", join->out.domain_name);
786 b.in.domain_dns_name = join->out.realm;
787 b.in.domain_netbios_name = join->out.domain_name;
788 b.in.domain_sid = join->out.domain_sid;
789 b.in.source_dsa_address = join->out.samr_binding->host;
790 b.in.dest_dsa_netbios_name = netbios_name;
792 b.in.callbacks.private_data = s;
793 b.in.callbacks.check_options = libnet_vampire_cb_check_options;
794 b.in.callbacks.prepare_db = libnet_vampire_cb_prepare_db;
795 b.in.callbacks.schema_chunk = libnet_vampire_cb_schema_chunk;
796 b.in.callbacks.config_chunk = libnet_vampire_cb_store_chunk;
797 b.in.callbacks.domain_chunk = libnet_vampire_cb_store_chunk;
799 b.in.rodc_join = lpcfg_parm_bool(s->lp_ctx, NULL, "repl", "RODC", false);
801 status = libnet_BecomeDC(ctx, s, &b);
802 if (!NT_STATUS_IS_OK(status)) {
803 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
804 talloc_free(s);
805 return status;
808 msg = ldb_msg_new(s);
809 if (!msg) {
810 printf("ldb_msg_new() failed\n");
811 talloc_free(s);
812 return NT_STATUS_NO_MEMORY;
814 msg->dn = ldb_dn_new(msg, s->ldb, "@ROOTDSE");
815 if (!msg->dn) {
816 printf("ldb_msg_new(@ROOTDSE) failed\n");
817 talloc_free(s);
818 return NT_STATUS_NO_MEMORY;
821 ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE");
822 if (ldb_ret != LDB_SUCCESS) {
823 printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret);
824 talloc_free(s);
825 return NT_STATUS_NO_MEMORY;
828 for (i=0; i < msg->num_elements; i++) {
829 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
832 printf("mark ROOTDSE with isSynchronized=TRUE\n");
833 ldb_ret = ldb_modify(s->ldb, msg);
834 if (ldb_ret != LDB_SUCCESS) {
835 printf("ldb_modify() failed: %d : %s\n", ldb_ret, ldb_errstring(s->ldb));
836 talloc_free(s);
837 return NT_STATUS_INTERNAL_DB_ERROR;
840 /* prepare the transaction - this prepares to commit all the changes in
841 the ldb from the whole vampire. Note that this
842 triggers the writing of the linked attribute backlinks.
844 if (ldb_transaction_prepare_commit(s->ldb) != LDB_SUCCESS) {
845 printf("Failed to prepare_commit vampire transaction: %s\n", ldb_errstring(s->ldb));
846 return NT_STATUS_INTERNAL_DB_ERROR;
849 set_secrets = talloc(s, struct provision_store_self_join_settings);
850 if (!set_secrets) {
851 r->out.error_string = NULL;
852 talloc_free(s);
853 return NT_STATUS_NO_MEMORY;
856 ZERO_STRUCTP(set_secrets);
857 set_secrets->domain_name = join->out.domain_name;
858 set_secrets->realm = join->out.realm;
859 set_secrets->netbios_name = netbios_name;
860 set_secrets->secure_channel_type = SEC_CHAN_BDC;
861 set_secrets->machine_password = join->out.join_password;
862 set_secrets->key_version_number = join->out.kvno;
863 set_secrets->domain_sid = join->out.domain_sid;
865 status = provision_store_self_join(ctx, s->lp_ctx, ctx->event_ctx, set_secrets, &error_string);
866 if (!NT_STATUS_IS_OK(status)) {
867 r->out.error_string = talloc_steal(mem_ctx, error_string);
868 talloc_free(s);
869 return status;
872 r->out.domain_name = talloc_steal(mem_ctx, join->out.domain_name);
873 r->out.domain_sid = dom_sid_dup(mem_ctx, join->out.domain_sid);
875 /* commit the transaction now we know the secrets were written
876 * out properly
878 if (ldb_transaction_commit(s->ldb) != LDB_SUCCESS) {
879 printf("Failed to commit vampire transaction\n");
880 return NT_STATUS_INTERNAL_DB_ERROR;
883 talloc_free(s);
885 return NT_STATUS_OK;