tdb: allow reads after prepare commit
[Samba/aatanasov.git] / source4 / libnet / libnet_vampire.c
blob5e516afaee4157213f79ef86305fd9bbc98f7376
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 "lib/ldb_wrap.h"
38 #include "auth/auth.h"
39 #include "param/param.h"
40 #include "param/provision.h"
42 /*
43 List of tasks vampire.py must perform:
44 - Domain Join
45 - but don't write the secrets.ldb
46 - results for this should be enough to handle the provision
47 - if vampire method is samsync
48 - Provision using these results
49 - do we still want to support this NT4 technology?
50 - Start samsync with libnet code
51 - provision in the callback
52 - Write out the secrets database, using the code from libnet_Join
55 struct vampire_state {
56 const char *netbios_name;
57 struct libnet_JoinDomain *join;
58 struct cli_credentials *machine_account;
59 struct dsdb_schema *self_made_schema;
60 const struct dsdb_schema *schema;
62 struct ldb_context *ldb;
64 struct {
65 uint32_t object_count;
66 struct drsuapi_DsReplicaObjectListItemEx *first_object;
67 struct drsuapi_DsReplicaObjectListItemEx *last_object;
68 } schema_part;
70 const char *targetdir;
72 struct loadparm_context *lp_ctx;
73 struct tevent_context *event_ctx;
74 unsigned total_objects;
75 char *last_partition;
78 static NTSTATUS vampire_prepare_db(void *private_data,
79 const struct libnet_BecomeDC_PrepareDB *p)
81 struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
82 struct provision_settings settings;
83 struct provision_result result;
84 NTSTATUS status;
86 ZERO_STRUCT(settings);
87 settings.site_name = p->dest_dsa->site_name;
88 settings.root_dn_str = p->forest->root_dn_str;
89 settings.domain_dn_str = p->domain->dn_str;
90 settings.config_dn_str = p->forest->config_dn_str;
91 settings.schema_dn_str = p->forest->schema_dn_str;
92 settings.netbios_name = p->dest_dsa->netbios_name;
93 settings.realm = s->join->out.realm;
94 settings.domain = s->join->out.domain_name;
95 settings.server_dn_str = p->dest_dsa->server_dn_str;
96 settings.machine_password = generate_random_str(s, 16);
97 settings.targetdir = s->targetdir;
99 status = provision_bare(s, s->lp_ctx, &settings, &result);
101 if (!NT_STATUS_IS_OK(status)) {
102 return status;
105 s->ldb = result.samdb;
106 s->lp_ctx = result.lp_ctx;
108 /* wrap the entire vapire operation in a transaction. This
109 isn't just cosmetic - we use this to ensure that linked
110 attribute back links are added at the end by relying on a
111 transaction commit hook in the linked attributes module. We
112 need to do this as the order of objects coming from the
113 server is not sufficiently deterministic to know that the
114 record that a backlink needs to be created in has itself
115 been created before the object containing the forward link
116 has come over the wire */
117 if (ldb_transaction_start(s->ldb) != LDB_SUCCESS) {
118 return NT_STATUS_FOOBAR;
121 return NT_STATUS_OK;
126 static NTSTATUS vampire_check_options(void *private_data,
127 const struct libnet_BecomeDC_CheckOptions *o)
129 struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
131 DEBUG(0,("Become DC [%s] of Domain[%s]/[%s]\n",
132 s->netbios_name,
133 o->domain->netbios_name, o->domain->dns_name));
135 DEBUG(0,("Promotion Partner is Server[%s] from Site[%s]\n",
136 o->source_dsa->dns_name, o->source_dsa->site_name));
138 DEBUG(0,("Options:crossRef behavior_version[%u]\n"
139 "\tschema object_version[%u]\n"
140 "\tdomain behavior_version[%u]\n"
141 "\tdomain w2k3_update_revision[%u]\n",
142 o->forest->crossref_behavior_version,
143 o->forest->schema_object_version,
144 o->domain->behavior_version,
145 o->domain->w2k3_update_revision));
147 return NT_STATUS_OK;
150 static NTSTATUS vampire_apply_schema(struct vampire_state *s,
151 const struct libnet_BecomeDC_StoreChunk *c)
153 WERROR status;
154 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
155 uint32_t object_count;
156 struct drsuapi_DsReplicaObjectListItemEx *first_object;
157 struct drsuapi_DsReplicaObjectListItemEx *cur;
158 uint32_t linked_attributes_count;
159 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
160 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
161 struct dsdb_extended_replicated_objects *objs;
162 struct repsFromTo1 *s_dsa;
163 char *tmp_dns_name;
164 struct ldb_message *msg;
165 struct ldb_val prefixMap_val;
166 struct ldb_message_element *prefixMap_el;
167 struct ldb_val schemaInfo_val;
168 uint32_t i;
169 int ret;
170 bool ok;
172 DEBUG(0,("Analyze and apply schema objects\n"));
174 s_dsa = talloc_zero(s, struct repsFromTo1);
175 NT_STATUS_HAVE_NO_MEMORY(s_dsa);
176 s_dsa->other_info = talloc(s_dsa, struct repsFromTo1OtherInfo);
177 NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
179 switch (c->ctr_level) {
180 case 1:
181 mapping_ctr = &c->ctr1->mapping_ctr;
182 object_count = s->schema_part.object_count;
183 first_object = s->schema_part.first_object;
184 linked_attributes_count = 0;
185 linked_attributes = NULL;
186 s_dsa->highwatermark = c->ctr1->new_highwatermark;
187 s_dsa->source_dsa_obj_guid = c->ctr1->source_dsa_guid;
188 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
189 uptodateness_vector = NULL; /* TODO: map it */
190 break;
191 case 6:
192 mapping_ctr = &c->ctr6->mapping_ctr;
193 object_count = s->schema_part.object_count;
194 first_object = s->schema_part.first_object;
195 linked_attributes_count = c->ctr6->linked_attributes_count;
196 linked_attributes = c->ctr6->linked_attributes;
197 s_dsa->highwatermark = c->ctr6->new_highwatermark;
198 s_dsa->source_dsa_obj_guid = c->ctr6->source_dsa_guid;
199 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
200 uptodateness_vector = c->ctr6->uptodateness_vector;
201 break;
202 default:
203 return NT_STATUS_INVALID_PARAMETER;
206 s_dsa->replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
207 | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
208 | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS;
209 memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
211 tmp_dns_name = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
212 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
213 tmp_dns_name = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
214 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
215 s_dsa->other_info->dns_name = tmp_dns_name;
217 for (cur = first_object; cur; cur = cur->next_object) {
218 bool is_attr = false;
219 bool is_class = false;
221 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
222 struct drsuapi_DsReplicaAttribute *a;
223 uint32_t j;
224 const char *oid = NULL;
226 a = &cur->object.attribute_ctr.attributes[i];
227 status = dsdb_map_int2oid(s->self_made_schema, a->attid, s, &oid);
228 if (!W_ERROR_IS_OK(status)) {
229 return werror_to_ntstatus(status);
232 switch (a->attid) {
233 case DRSUAPI_ATTRIBUTE_objectClass:
234 for (j=0; j < a->value_ctr.num_values; j++) {
235 uint32_t val = 0xFFFFFFFF;
237 if (a->value_ctr.values[j].blob
238 && a->value_ctr.values[j].blob->length == 4) {
239 val = IVAL(a->value_ctr.values[j].blob->data,0);
242 if (val == DRSUAPI_OBJECTCLASS_attributeSchema) {
243 is_attr = true;
245 if (val == DRSUAPI_OBJECTCLASS_classSchema) {
246 is_class = true;
250 break;
251 default:
252 break;
256 if (is_attr) {
257 struct dsdb_attribute *sa;
259 sa = talloc_zero(s->self_made_schema, struct dsdb_attribute);
260 NT_STATUS_HAVE_NO_MEMORY(sa);
262 status = dsdb_attribute_from_drsuapi(s->ldb, s->self_made_schema, &cur->object, s, sa);
263 if (!W_ERROR_IS_OK(status)) {
264 return werror_to_ntstatus(status);
267 DLIST_ADD_END(s->self_made_schema->attributes, sa, struct dsdb_attribute *);
270 if (is_class) {
271 struct dsdb_class *sc;
273 sc = talloc_zero(s->self_made_schema, struct dsdb_class);
274 NT_STATUS_HAVE_NO_MEMORY(sc);
276 status = dsdb_class_from_drsuapi(s->self_made_schema, &cur->object, s, sc);
277 if (!W_ERROR_IS_OK(status)) {
278 return werror_to_ntstatus(status);
281 DLIST_ADD_END(s->self_made_schema->classes, sc, struct dsdb_class *);
285 /* attach the schema to the ldb */
286 ret = dsdb_set_schema(s->ldb, s->self_made_schema);
287 if (ret != LDB_SUCCESS) {
288 return NT_STATUS_FOOBAR;
290 /* we don't want to access the self made schema anymore */
291 s->self_made_schema = NULL;
292 s->schema = dsdb_get_schema(s->ldb);
294 status = dsdb_extended_replicated_objects_commit(s->ldb,
295 c->partition->nc.dn,
296 mapping_ctr,
297 object_count,
298 first_object,
299 linked_attributes_count,
300 linked_attributes,
301 s_dsa,
302 uptodateness_vector,
303 c->gensec_skey,
304 s, &objs);
305 if (!W_ERROR_IS_OK(status)) {
306 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
307 return werror_to_ntstatus(status);
310 if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
311 for (i=0; i < objs->num_objects; i++) {
312 struct ldb_ldif ldif;
313 fprintf(stdout, "#\n");
314 ldif.changetype = LDB_CHANGETYPE_NONE;
315 ldif.msg = objs->objects[i].msg;
316 ldb_ldif_write_file(s->ldb, stdout, &ldif);
317 NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
321 msg = ldb_msg_new(objs);
322 NT_STATUS_HAVE_NO_MEMORY(msg);
323 msg->dn = objs->partition_dn;
325 status = dsdb_get_oid_mappings_ldb(s->schema, msg, &prefixMap_val, &schemaInfo_val);
326 if (!W_ERROR_IS_OK(status)) {
327 DEBUG(0,("Failed dsdb_get_oid_mappings_ldb(%s)\n", win_errstr(status)));
328 return werror_to_ntstatus(status);
331 /* we only add prefixMap here, because schemaInfo is a replicated attribute and already applied */
332 ret = ldb_msg_add_value(msg, "prefixMap", &prefixMap_val, &prefixMap_el);
333 if (ret != LDB_SUCCESS) {
334 return NT_STATUS_FOOBAR;
336 prefixMap_el->flags = LDB_FLAG_MOD_REPLACE;
338 ret = ldb_modify(s->ldb, msg);
339 if (ret != LDB_SUCCESS) {
340 DEBUG(0,("Failed to add prefixMap and schemaInfo %s\n", ldb_strerror(ret)));
341 return NT_STATUS_FOOBAR;
344 talloc_free(s_dsa);
345 talloc_free(objs);
347 /* We must set these up to ensure the replMetaData is written
348 * correctly, before our NTDS Settings entry is replicated */
349 ok = samdb_set_ntds_invocation_id(s->ldb, &c->dest_dsa->invocation_id);
350 if (!ok) {
351 DEBUG(0,("Failed to set cached ntds invocationId\n"));
352 return NT_STATUS_FOOBAR;
354 ok = samdb_set_ntds_objectGUID(s->ldb, &c->dest_dsa->ntds_guid);
355 if (!ok) {
356 DEBUG(0,("Failed to set cached ntds objectGUID\n"));
357 return NT_STATUS_FOOBAR;
360 s->schema = dsdb_get_schema(s->ldb);
361 if (!s->schema) {
362 DEBUG(0,("Failed to get loaded dsdb_schema\n"));
363 return NT_STATUS_FOOBAR;
366 return NT_STATUS_OK;
369 static NTSTATUS vampire_schema_chunk(void *private_data,
370 const struct libnet_BecomeDC_StoreChunk *c)
372 struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
373 WERROR status;
374 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
375 uint32_t nc_object_count;
376 uint32_t object_count;
377 struct drsuapi_DsReplicaObjectListItemEx *first_object;
378 struct drsuapi_DsReplicaObjectListItemEx *cur;
379 uint32_t nc_linked_attributes_count;
380 uint32_t linked_attributes_count;
381 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
383 switch (c->ctr_level) {
384 case 1:
385 mapping_ctr = &c->ctr1->mapping_ctr;
386 nc_object_count = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
387 object_count = c->ctr1->object_count;
388 first_object = c->ctr1->first_object;
389 nc_linked_attributes_count = 0;
390 linked_attributes_count = 0;
391 linked_attributes = NULL;
392 break;
393 case 6:
394 mapping_ctr = &c->ctr6->mapping_ctr;
395 nc_object_count = c->ctr6->nc_object_count;
396 object_count = c->ctr6->object_count;
397 first_object = c->ctr6->first_object;
398 nc_linked_attributes_count = c->ctr6->nc_linked_attributes_count;
399 linked_attributes_count = c->ctr6->linked_attributes_count;
400 linked_attributes = c->ctr6->linked_attributes;
401 break;
402 default:
403 return NT_STATUS_INVALID_PARAMETER;
406 if (nc_object_count) {
407 DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n",
408 c->partition->nc.dn, object_count, nc_object_count,
409 linked_attributes_count, nc_linked_attributes_count));
410 } else {
411 DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u\n",
412 c->partition->nc.dn, object_count, linked_attributes_count));
415 if (!s->schema) {
416 s->self_made_schema = dsdb_new_schema(s, lp_iconv_convenience(s->lp_ctx));
418 NT_STATUS_HAVE_NO_MEMORY(s->self_made_schema);
420 status = dsdb_load_oid_mappings_drsuapi(s->self_made_schema, mapping_ctr);
421 if (!W_ERROR_IS_OK(status)) {
422 return werror_to_ntstatus(status);
425 s->schema = s->self_made_schema;
426 } else {
427 status = dsdb_verify_oid_mappings_drsuapi(s->schema, mapping_ctr);
428 if (!W_ERROR_IS_OK(status)) {
429 return werror_to_ntstatus(status);
433 if (!s->schema_part.first_object) {
434 s->schema_part.object_count = object_count;
435 s->schema_part.first_object = talloc_steal(s, first_object);
436 } else {
437 s->schema_part.object_count += object_count;
438 s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
439 first_object);
441 for (cur = first_object; cur->next_object; cur = cur->next_object) {}
442 s->schema_part.last_object = cur;
444 if (!c->partition->more_data) {
445 return vampire_apply_schema(s, c);
448 return NT_STATUS_OK;
451 static NTSTATUS vampire_store_chunk(void *private_data,
452 const struct libnet_BecomeDC_StoreChunk *c)
454 struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
455 WERROR status;
456 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
457 uint32_t nc_object_count;
458 uint32_t object_count;
459 struct drsuapi_DsReplicaObjectListItemEx *first_object;
460 uint32_t nc_linked_attributes_count;
461 uint32_t linked_attributes_count;
462 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
463 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
464 struct dsdb_extended_replicated_objects *objs;
465 struct repsFromTo1 *s_dsa;
466 char *tmp_dns_name;
467 uint32_t i;
469 s_dsa = talloc_zero(s, struct repsFromTo1);
470 NT_STATUS_HAVE_NO_MEMORY(s_dsa);
471 s_dsa->other_info = talloc(s_dsa, struct repsFromTo1OtherInfo);
472 NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
474 switch (c->ctr_level) {
475 case 1:
476 mapping_ctr = &c->ctr1->mapping_ctr;
477 nc_object_count = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
478 object_count = c->ctr1->object_count;
479 first_object = c->ctr1->first_object;
480 nc_linked_attributes_count = 0;
481 linked_attributes_count = 0;
482 linked_attributes = NULL;
483 s_dsa->highwatermark = c->ctr1->new_highwatermark;
484 s_dsa->source_dsa_obj_guid = c->ctr1->source_dsa_guid;
485 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
486 uptodateness_vector = NULL; /* TODO: map it */
487 break;
488 case 6:
489 mapping_ctr = &c->ctr6->mapping_ctr;
490 nc_object_count = c->ctr6->nc_object_count;
491 object_count = c->ctr6->object_count;
492 first_object = c->ctr6->first_object;
493 nc_linked_attributes_count = c->ctr6->nc_linked_attributes_count;
494 linked_attributes_count = c->ctr6->linked_attributes_count;
495 linked_attributes = c->ctr6->linked_attributes;
496 s_dsa->highwatermark = c->ctr6->new_highwatermark;
497 s_dsa->source_dsa_obj_guid = c->ctr6->source_dsa_guid;
498 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
499 uptodateness_vector = c->ctr6->uptodateness_vector;
500 break;
501 default:
502 return NT_STATUS_INVALID_PARAMETER;
505 s_dsa->replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
506 | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
507 | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS;
508 memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
510 tmp_dns_name = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
511 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
512 tmp_dns_name = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
513 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
514 s_dsa->other_info->dns_name = tmp_dns_name;
516 /* we want to show a count per partition */
517 if (!s->last_partition || strcmp(s->last_partition, c->partition->nc.dn) != 0) {
518 s->total_objects = 0;
519 talloc_free(s->last_partition);
520 s->last_partition = talloc_strdup(s, c->partition->nc.dn);
522 s->total_objects += object_count;
524 if (nc_object_count) {
525 DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n",
526 c->partition->nc.dn, s->total_objects, nc_object_count,
527 linked_attributes_count, nc_linked_attributes_count));
528 } else {
529 DEBUG(0,("Partition[%s] objects[%u] linked_values[%u\n",
530 c->partition->nc.dn, s->total_objects, linked_attributes_count));
534 status = dsdb_extended_replicated_objects_commit(s->ldb,
535 c->partition->nc.dn,
536 mapping_ctr,
537 object_count,
538 first_object,
539 linked_attributes_count,
540 linked_attributes,
541 s_dsa,
542 uptodateness_vector,
543 c->gensec_skey,
544 s, &objs);
545 if (!W_ERROR_IS_OK(status)) {
546 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
547 return werror_to_ntstatus(status);
550 if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
551 for (i=0; i < objs->num_objects; i++) {
552 struct ldb_ldif ldif;
553 fprintf(stdout, "#\n");
554 ldif.changetype = LDB_CHANGETYPE_NONE;
555 ldif.msg = objs->objects[i].msg;
556 ldb_ldif_write_file(s->ldb, stdout, &ldif);
557 NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
560 talloc_free(s_dsa);
561 talloc_free(objs);
563 for (i=0; i < linked_attributes_count; i++) {
564 const struct dsdb_attribute *sa;
566 if (!linked_attributes[i].identifier) {
567 return NT_STATUS_FOOBAR;
570 if (!linked_attributes[i].value.blob) {
571 return NT_STATUS_FOOBAR;
574 sa = dsdb_attribute_by_attributeID_id(s->schema,
575 linked_attributes[i].attid);
576 if (!sa) {
577 return NT_STATUS_FOOBAR;
580 if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
581 DEBUG(0,("# %s\n", sa->lDAPDisplayName));
582 NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, &linked_attributes[i]);
583 dump_data(0,
584 linked_attributes[i].value.blob->data,
585 linked_attributes[i].value.blob->length);
589 return NT_STATUS_OK;
592 NTSTATUS libnet_Vampire(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
593 struct libnet_Vampire *r)
595 struct libnet_JoinDomain *join;
596 struct libnet_set_join_secrets *set_secrets;
597 struct libnet_BecomeDC b;
598 struct vampire_state *s;
599 struct ldb_message *msg;
600 int ldb_ret;
601 uint32_t i;
602 NTSTATUS status;
604 const char *account_name;
605 const char *netbios_name;
607 r->out.error_string = NULL;
609 s = talloc_zero(mem_ctx, struct vampire_state);
610 if (!s) {
611 return NT_STATUS_NO_MEMORY;
614 s->lp_ctx = ctx->lp_ctx;
615 s->event_ctx = ctx->event_ctx;
617 join = talloc_zero(s, struct libnet_JoinDomain);
618 if (!join) {
619 return NT_STATUS_NO_MEMORY;
622 if (r->in.netbios_name != NULL) {
623 netbios_name = r->in.netbios_name;
624 } else {
625 netbios_name = talloc_reference(join, lp_netbios_name(ctx->lp_ctx));
626 if (!netbios_name) {
627 r->out.error_string = NULL;
628 talloc_free(s);
629 return NT_STATUS_NO_MEMORY;
633 account_name = talloc_asprintf(join, "%s$", netbios_name);
634 if (!account_name) {
635 r->out.error_string = NULL;
636 talloc_free(s);
637 return NT_STATUS_NO_MEMORY;
640 join->in.domain_name = r->in.domain_name;
641 join->in.account_name = account_name;
642 join->in.netbios_name = netbios_name;
643 join->in.level = LIBNET_JOINDOMAIN_AUTOMATIC;
644 join->in.acct_type = ACB_WSTRUST;
645 join->in.recreate_account = false;
646 status = libnet_JoinDomain(ctx, join, join);
647 if (!NT_STATUS_IS_OK(status)) {
648 r->out.error_string = talloc_steal(mem_ctx, join->out.error_string);
649 talloc_free(s);
650 return status;
653 s->join = join;
655 s->targetdir = r->in.targetdir;
657 ZERO_STRUCT(b);
658 b.in.domain_dns_name = join->out.realm;
659 b.in.domain_netbios_name = join->out.domain_name;
660 b.in.domain_sid = join->out.domain_sid;
661 b.in.source_dsa_address = join->out.samr_binding->host;
662 b.in.dest_dsa_netbios_name = netbios_name;
664 b.in.callbacks.private_data = s;
665 b.in.callbacks.check_options = vampire_check_options;
666 b.in.callbacks.prepare_db = vampire_prepare_db;
667 b.in.callbacks.schema_chunk = vampire_schema_chunk;
668 b.in.callbacks.config_chunk = vampire_store_chunk;
669 b.in.callbacks.domain_chunk = vampire_store_chunk;
671 status = libnet_BecomeDC(ctx, s, &b);
672 if (!NT_STATUS_IS_OK(status)) {
673 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
674 talloc_free(s);
675 return status;
678 msg = ldb_msg_new(s);
679 if (!msg) {
680 printf("ldb_msg_new() failed\n");
681 talloc_free(s);
682 return NT_STATUS_NO_MEMORY;
684 msg->dn = ldb_dn_new(msg, s->ldb, "@ROOTDSE");
685 if (!msg->dn) {
686 printf("ldb_msg_new(@ROOTDSE) failed\n");
687 talloc_free(s);
688 return NT_STATUS_NO_MEMORY;
691 ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE");
692 if (ldb_ret != LDB_SUCCESS) {
693 printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret);
694 talloc_free(s);
695 return NT_STATUS_NO_MEMORY;
698 for (i=0; i < msg->num_elements; i++) {
699 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
702 printf("mark ROOTDSE with isSynchronized=TRUE\n");
703 ldb_ret = ldb_modify(s->ldb, msg);
704 if (ldb_ret != LDB_SUCCESS) {
705 printf("ldb_modify() failed: %d\n", ldb_ret);
706 talloc_free(s);
707 return NT_STATUS_INTERNAL_DB_ERROR;
710 /* commit the transaction - this commits all the changes in
711 the ldb from the whole vampire. Note that this commit
712 triggers the writing of the linked attribute backlinks.
714 if (ldb_transaction_commit(s->ldb) != LDB_SUCCESS) {
715 printf("Failed to commit vampire transaction\n");
716 return NT_STATUS_INTERNAL_DB_ERROR;
719 set_secrets = talloc_zero(s, struct libnet_set_join_secrets);
720 if (!set_secrets) {
721 return NT_STATUS_NO_MEMORY;
724 set_secrets->in.domain_name = join->out.domain_name;
725 set_secrets->in.realm = join->out.realm;
726 set_secrets->in.account_name = account_name;
727 set_secrets->in.netbios_name = netbios_name;
728 set_secrets->in.join_type = SEC_CHAN_BDC;
729 set_secrets->in.join_password = join->out.join_password;
730 set_secrets->in.kvno = join->out.kvno;
731 set_secrets->in.domain_sid = join->out.domain_sid;
733 status = libnet_set_join_secrets(ctx, set_secrets, set_secrets);
734 if (!NT_STATUS_IS_OK(status)) {
735 r->out.error_string = talloc_steal(mem_ctx, set_secrets->out.error_string);
736 talloc_free(s);
737 return status;
740 r->out.domain_name = talloc_steal(r, join->out.domain_name);
741 r->out.domain_sid = talloc_steal(r, join->out.domain_sid);
742 talloc_free(s);
744 return NT_STATUS_OK;