s4/drs-tests: Add a base class to hold common functionality for all DRS python tests
[Samba.git] / source4 / libnet / libnet_vampire.c
blob91a11eec67fa90f14b845be0d045c34a012efa57
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 <ldb.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"
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/security.h"
43 #include "dsdb/common/util.h"
45 /*
46 List of tasks vampire.py must perform:
47 - Domain Join
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;
61 const char *realm;
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;
77 struct {
78 uint32_t object_count;
79 struct drsuapi_DsReplicaObjectListItemEx *first_object;
80 struct drsuapi_DsReplicaObjectListItemEx *last_object;
81 } schema_part;
83 const char *targetdir;
85 struct loadparm_context *lp_ctx;
86 struct tevent_context *event_ctx;
87 unsigned total_objects;
88 char *last_partition;
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);
98 if (!s) {
99 return NULL;
102 s->ldb = samdb;
103 s->lp_ctx = lp_ctx;
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);
110 return s;
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);
120 if (!s) {
121 return NULL;
124 s->lp_ctx = lp_ctx;
125 s->event_ctx = event_ctx;
126 s->netbios_name = netbios_name;
127 s->domain_name = domain_name;
128 s->realm = realm;
129 s->targetdir = targetdir;
130 return s;
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);
136 return state->ldb;
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;
151 NTSTATUS status;
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)) {
169 return 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;
190 return NT_STATUS_OK;
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",
201 s->netbios_name,
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));
216 return NT_STATUS_OK;
219 static NTSTATUS libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s,
220 const struct libnet_BecomeDC_StoreChunk *c)
222 struct schema_list {
223 struct schema_list *next, *prev;
224 const struct drsuapi_DsReplicaObjectListItemEx *obj;
227 WERROR status;
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;
241 char *tmp_dns_name;
242 struct ldb_context *schema_ldb;
243 struct ldb_message *msg;
244 struct ldb_message_element *prefixMap_el;
245 uint32_t i;
246 int ret, pass_no;
247 bool ok;
248 uint64_t seq_num;
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) {
258 case 1:
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 */
268 break;
269 case 6:
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;
279 break;
280 default:
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);
304 if (!schema_ldb) {
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);
308 } else {
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 */
326 pass_no = 1;
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
342 * safely */
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,
351 cur, c->gensec_skey,
352 tmp_ctx, &object);
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));
357 failed_obj_count++;
358 } else {
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,
365 s->self_made_schema,
366 object.msg);
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)));
371 failed_obj_count++;
372 } else {
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));
382 pass_no++;
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;
390 if (schema_list) {
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,
422 s->schema,
423 c->partition->nc.dn,
424 mapping_ctr,
425 object_count,
426 first_object,
427 linked_attributes_count,
428 linked_attributes,
429 s_dsa,
430 uptodateness_vector,
431 c->gensec_skey,
432 s, &schema_objs);
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;
479 talloc_free(s_dsa);
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);
485 if (!ok) {
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);
490 if (!ok) {
491 DEBUG(0,("Failed to set cached ntds objectGUID\n"));
492 return NT_STATUS_FOOBAR;
495 s->schema = dsdb_get_schema(s->ldb, s);
496 if (!s->schema) {
497 DEBUG(0,("Failed to get loaded dsdb_schema\n"));
498 return NT_STATUS_FOOBAR;
501 return NT_STATUS_OK;
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);
508 WERROR status;
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) {
519 case 1:
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;
527 break;
528 case 6:
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;
536 break;
537 default:
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));
545 } else {
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) {
551 WERROR werr;
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
572 * other. */
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);
580 } else {
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);
590 } else {
591 s->schema_part.object_count += object_count;
592 s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
593 first_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);
602 return NT_STATUS_OK;
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);
609 WERROR status;
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;
621 char *tmp_dns_name;
622 uint32_t i;
623 uint64_t seq_num;
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) {
631 case 1:
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 */
643 break;
644 case 6:
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;
656 break;
657 default:
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));
684 } else {
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);
691 if (!schema) {
692 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
693 return NT_STATUS_INTERNAL_ERROR;
696 status = dsdb_replicated_objects_convert(s->ldb,
697 schema,
698 c->partition->nc.dn,
699 mapping_ctr,
700 object_count,
701 first_object,
702 linked_attributes_count,
703 linked_attributes,
704 s_dsa,
705 uptodateness_vector,
706 c->gensec_skey,
707 s, &objs);
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);
729 talloc_free(s_dsa);
730 talloc_free(objs);
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);
745 if (!sa) {
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]);
752 dump_data(0,
753 linked_attributes[i].value.blob->data,
754 linked_attributes[i].value.blob->length);
758 return NT_STATUS_OK;
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,
765 const char *realm)
767 int ret;
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,
773 "%s.%s",
774 netbios_name,
775 realm));
776 msg = ldb_msg_new(mem_ctx);
777 if (msg == NULL) {
778 return NT_STATUS_NO_MEMORY;
781 server_dn = ldb_dn_new(mem_ctx, ldb, server_dn_str);
782 if (!server_dn) {
783 return NT_STATUS_INTERNAL_ERROR;
786 msg->dn = server_dn;
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,
793 "dNSHostName",
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;
806 return NT_STATUS_OK;
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;
815 NTSTATUS status;
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);
823 if (!join) {
824 return NT_STATUS_NO_MEMORY;
827 if (r->in.netbios_name != NULL) {
828 netbios_name = r->in.netbios_name;
829 } else {
830 netbios_name = talloc_reference(join, lpcfg_netbios_name(ctx->lp_ctx));
831 if (!netbios_name) {
832 talloc_free(join);
833 r->out.error_string = NULL;
834 return NT_STATUS_NO_MEMORY;
838 account_name = talloc_asprintf(join, "%s$", netbios_name);
839 if (!account_name) {
840 talloc_free(join);
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
847 * otherwise */
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);
859 talloc_free(join);
860 return status;
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;
878 return status;
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;
891 int ldb_ret;
892 uint32_t i;
893 NTSTATUS status;
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);
902 if (!account_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
910 * otherwise */
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,
915 r->in.targetdir);
916 if (!s) {
917 return NT_STATUS_NO_MEMORY;
919 talloc_steal(s, tmp_ctx);
921 ZERO_STRUCT(b);
923 /* Be more robust:
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
926 * join */
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
932 * started with */
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));
954 talloc_free(s);
955 return status;
958 msg = ldb_msg_new(s);
959 if (!msg) {
960 printf("ldb_msg_new() failed\n");
961 talloc_free(s);
962 return NT_STATUS_NO_MEMORY;
964 msg->dn = ldb_dn_new(msg, s->ldb, "@ROOTDSE");
965 if (!msg->dn) {
966 printf("ldb_msg_new(@ROOTDSE) failed\n");
967 talloc_free(s);
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);
974 talloc_free(s);
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));
986 talloc_free(s);
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));
995 talloc_free(s);
996 return 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);
1008 if (!set_secrets) {
1009 r->out.error_string = NULL;
1010 talloc_free(s);
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);
1026 talloc_free(s);
1027 return status;
1030 /* commit the transaction now we know the secrets were written
1031 * out properly
1033 if (ldb_transaction_commit(s->ldb) != LDB_SUCCESS) {
1034 printf("Failed to commit vampire transaction\n");
1035 return NT_STATUS_INTERNAL_DB_ERROR;
1038 talloc_free(s);
1040 return NT_STATUS_OK;