/* Unix SMB/CIFS implementation. Extract the user/system database from a remote server Copyright (C) Stefan Metzmacher 2004-2006 Copyright (C) Brad Henry 2005 Copyright (C) Andrew Bartlett 2005-2008 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "includes.h" #include "libnet/libnet.h" #include "lib/events/events.h" #include "dsdb/samdb/samdb.h" #include "../lib/util/dlinklist.h" #include "lib/ldb/include/ldb.h" #include "lib/ldb/include/ldb_errors.h" #include "librpc/ndr/libndr.h" #include "librpc/gen_ndr/ndr_drsuapi.h" #include "librpc/gen_ndr/ndr_drsblobs.h" #include "librpc/gen_ndr/ndr_misc.h" #include "system/time.h" #include "lib/ldb_wrap.h" #include "auth/auth.h" #include "auth/credentials/credentials.h" #include "param/param.h" #include "param/provision.h" #include "libcli/security/dom_sid.h" /* List of tasks vampire.py must perform: - Domain Join - but don't write the secrets.ldb - results for this should be enough to handle the provision - if vampire method is samsync - Provision using these results - do we still want to support this NT4 technology? - Start samsync with libnet code - provision in the callback - Write out the secrets database, using the code from libnet_Join */ struct libnet_vampire_cb_state { const char *netbios_name; const char *domain_name; const char *realm; struct cli_credentials *machine_account; struct dsdb_schema *self_made_schema; const struct dsdb_schema *schema; struct ldb_context *ldb; struct { uint32_t object_count; struct drsuapi_DsReplicaObjectListItemEx *first_object; struct drsuapi_DsReplicaObjectListItemEx *last_object; } schema_part; const char *targetdir; struct loadparm_context *lp_ctx; struct tevent_context *event_ctx; unsigned total_objects; char *last_partition; }; /* Caller is expected to keep supplied pointers around for the lifetime of the structure */ void *libnet_vampire_cb_state_init(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct tevent_context *event_ctx, const char *netbios_name, const char *domain_name, const char *realm, const char *targetdir) { struct libnet_vampire_cb_state *s = talloc_zero(mem_ctx, struct libnet_vampire_cb_state); if (!s) { return NULL; } s->lp_ctx = lp_ctx; s->event_ctx = event_ctx; s->netbios_name = netbios_name; s->domain_name = domain_name; s->realm = realm; s->targetdir = targetdir; return s; } struct ldb_context *libnet_vampire_cb_ldb(struct libnet_vampire_cb_state *state) { state = talloc_get_type_abort(state, struct libnet_vampire_cb_state); return state->ldb; } struct loadparm_context *libnet_vampire_cb_lp_ctx(struct libnet_vampire_cb_state *state) { state = talloc_get_type_abort(state, struct libnet_vampire_cb_state); return state->lp_ctx; } NTSTATUS libnet_vampire_cb_prepare_db(void *private_data, const struct libnet_BecomeDC_PrepareDB *p) { struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state); struct provision_settings settings; struct provision_result result; NTSTATUS status; ZERO_STRUCT(settings); settings.site_name = p->dest_dsa->site_name; settings.root_dn_str = p->forest->root_dn_str; settings.domain_dn_str = p->domain->dn_str; settings.config_dn_str = p->forest->config_dn_str; settings.schema_dn_str = p->forest->schema_dn_str; settings.netbios_name = p->dest_dsa->netbios_name; settings.realm = s->realm; settings.domain = s->domain_name; settings.server_dn_str = p->dest_dsa->server_dn_str; settings.machine_password = generate_random_password(s, 16, 255); settings.targetdir = s->targetdir; status = provision_bare(s, s->lp_ctx, &settings, &result); if (!NT_STATUS_IS_OK(status)) { return status; } s->ldb = talloc_steal(s, result.samdb); s->lp_ctx = talloc_steal(s, result.lp_ctx); /* wrap the entire vapire operation in a transaction. This isn't just cosmetic - we use this to ensure that linked attribute back links are added at the end by relying on a transaction commit hook in the linked attributes module. We need to do this as the order of objects coming from the server is not sufficiently deterministic to know that the record that a backlink needs to be created in has itself been created before the object containing the forward link has come over the wire */ if (ldb_transaction_start(s->ldb) != LDB_SUCCESS) { return NT_STATUS_FOOBAR; } return NT_STATUS_OK; } NTSTATUS libnet_vampire_cb_check_options(void *private_data, const struct libnet_BecomeDC_CheckOptions *o) { struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state); DEBUG(0,("Become DC [%s] of Domain[%s]/[%s]\n", s->netbios_name, o->domain->netbios_name, o->domain->dns_name)); DEBUG(0,("Promotion Partner is Server[%s] from Site[%s]\n", o->source_dsa->dns_name, o->source_dsa->site_name)); DEBUG(0,("Options:crossRef behavior_version[%u]\n" "\tschema object_version[%u]\n" "\tdomain behavior_version[%u]\n" "\tdomain w2k3_update_revision[%u]\n", o->forest->crossref_behavior_version, o->forest->schema_object_version, o->domain->behavior_version, o->domain->w2k3_update_revision)); return NT_STATUS_OK; } static NTSTATUS libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s, const struct libnet_BecomeDC_StoreChunk *c) { WERROR status; const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr; uint32_t object_count; struct drsuapi_DsReplicaObjectListItemEx *first_object; uint32_t linked_attributes_count; struct drsuapi_DsReplicaLinkedAttribute *linked_attributes; const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector; struct dsdb_extended_replicated_objects *schema_objs_1, *schema_objs_2; struct repsFromTo1 *s_dsa; char *tmp_dns_name; struct ldb_message *msg; struct ldb_val prefixMap_val; struct ldb_message_element *prefixMap_el; struct ldb_val schemaInfo_val; uint32_t i; int ret; bool ok; uint64_t seq_num; DEBUG(0,("Analyze and apply schema objects\n")); s_dsa = talloc_zero(s, struct repsFromTo1); NT_STATUS_HAVE_NO_MEMORY(s_dsa); s_dsa->other_info = talloc(s_dsa, struct repsFromTo1OtherInfo); NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info); switch (c->ctr_level) { case 1: mapping_ctr = &c->ctr1->mapping_ctr; object_count = s->schema_part.object_count; first_object = s->schema_part.first_object; linked_attributes_count = 0; linked_attributes = NULL; s_dsa->highwatermark = c->ctr1->new_highwatermark; s_dsa->source_dsa_obj_guid = c->ctr1->source_dsa_guid; s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id; uptodateness_vector = NULL; /* TODO: map it */ break; case 6: mapping_ctr = &c->ctr6->mapping_ctr; object_count = s->schema_part.object_count; first_object = s->schema_part.first_object; linked_attributes_count = c->ctr6->linked_attributes_count; linked_attributes = c->ctr6->linked_attributes; s_dsa->highwatermark = c->ctr6->new_highwatermark; s_dsa->source_dsa_obj_guid = c->ctr6->source_dsa_guid; s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id; uptodateness_vector = c->ctr6->uptodateness_vector; break; default: return NT_STATUS_INVALID_PARAMETER; } s_dsa->replica_flags = DRSUAPI_DRS_WRIT_REP | DRSUAPI_DRS_INIT_SYNC | DRSUAPI_DRS_PER_SYNC; memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule)); tmp_dns_name = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid); NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name); tmp_dns_name = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name); NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name); s_dsa->other_info->dns_name = tmp_dns_name; /* Now convert the schema elements again, using the schema we just imported */ status = dsdb_extended_replicated_objects_convert(s->ldb, c->partition->nc.dn, mapping_ctr, object_count, first_object, linked_attributes_count, linked_attributes, s_dsa, uptodateness_vector, c->gensec_skey, s, &schema_objs_1); if (!W_ERROR_IS_OK(status)) { DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status))); return werror_to_ntstatus(status); } for (i=0; i < schema_objs_1->num_objects; i++) { status = dsdb_schema_set_el_from_ldb_msg(s->ldb, s->self_made_schema, schema_objs_1->objects[i].msg); if (!W_ERROR_IS_OK(status)) { DEBUG(0,("Failed to convert object %s into a schema element: %s\n", ldb_dn_get_linearized(schema_objs_1->objects[i].msg->dn), win_errstr(status))); return werror_to_ntstatus(status); } } /* We don't need the first conversion of the schema any more */ talloc_free(schema_objs_1); /* attach the schema we just brought over DRS to the ldb */ ret = dsdb_set_schema(s->ldb, s->self_made_schema); if (ret != LDB_SUCCESS) { DEBUG(0,("Failed to attach schema from DRS.\n")); return NT_STATUS_FOOBAR; } /* we don't want to access the self made schema anymore */ s->schema = s->self_made_schema; s->self_made_schema = NULL; /* Now convert the schema elements again, using the schema we just imported - we do this 'just in case' the schema in our LDIF was wrong, but correct enough to read a valid schema */ status = dsdb_extended_replicated_objects_convert(s->ldb, c->partition->nc.dn, mapping_ctr, object_count, first_object, linked_attributes_count, linked_attributes, s_dsa, uptodateness_vector, c->gensec_skey, s, &schema_objs_2); if (!W_ERROR_IS_OK(status)) { DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status))); return werror_to_ntstatus(status); } if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) { for (i=0; i < schema_objs_2->num_objects; i++) { struct ldb_ldif ldif; fprintf(stdout, "#\n"); ldif.changetype = LDB_CHANGETYPE_NONE; ldif.msg = schema_objs_2->objects[i].msg; ldb_ldif_write_file(s->ldb, stdout, &ldif); NDR_PRINT_DEBUG(replPropertyMetaDataBlob, schema_objs_2->objects[i].meta_data); } } status = dsdb_extended_replicated_objects_commit(s->ldb, schema_objs_2, &seq_num); if (!W_ERROR_IS_OK(status)) { DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status))); return werror_to_ntstatus(status); } msg = ldb_msg_new(schema_objs_2); NT_STATUS_HAVE_NO_MEMORY(msg); msg->dn = schema_objs_2->partition_dn; status = dsdb_get_oid_mappings_ldb(s->schema, msg, &prefixMap_val, &schemaInfo_val); if (!W_ERROR_IS_OK(status)) { DEBUG(0,("Failed dsdb_get_oid_mappings_ldb(%s)\n", win_errstr(status))); return werror_to_ntstatus(status); } /* we only add prefixMap here, because schemaInfo is a replicated attribute and already applied */ ret = ldb_msg_add_value(msg, "prefixMap", &prefixMap_val, &prefixMap_el); if (ret != LDB_SUCCESS) { return NT_STATUS_FOOBAR; } prefixMap_el->flags = LDB_FLAG_MOD_REPLACE; ret = ldb_modify(s->ldb, msg); if (ret != LDB_SUCCESS) { DEBUG(0,("Failed to add prefixMap: %s\n", ldb_strerror(ret))); return NT_STATUS_FOOBAR; } talloc_free(s_dsa); talloc_free(schema_objs_2); /* We must set these up to ensure the replMetaData is written * correctly, before our NTDS Settings entry is replicated */ ok = samdb_set_ntds_invocation_id(s->ldb, &c->dest_dsa->invocation_id); if (!ok) { DEBUG(0,("Failed to set cached ntds invocationId\n")); return NT_STATUS_FOOBAR; } ok = samdb_set_ntds_objectGUID(s->ldb, &c->dest_dsa->ntds_guid); if (!ok) { DEBUG(0,("Failed to set cached ntds objectGUID\n")); return NT_STATUS_FOOBAR; } s->schema = dsdb_get_schema(s->ldb, s); if (!s->schema) { DEBUG(0,("Failed to get loaded dsdb_schema\n")); return NT_STATUS_FOOBAR; } return NT_STATUS_OK; } NTSTATUS libnet_vampire_cb_schema_chunk(void *private_data, const struct libnet_BecomeDC_StoreChunk *c) { struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state); WERROR status; const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr; uint32_t nc_object_count; uint32_t object_count; struct drsuapi_DsReplicaObjectListItemEx *first_object; struct drsuapi_DsReplicaObjectListItemEx *cur; uint32_t nc_linked_attributes_count; uint32_t linked_attributes_count; struct drsuapi_DsReplicaLinkedAttribute *linked_attributes; switch (c->ctr_level) { case 1: mapping_ctr = &c->ctr1->mapping_ctr; nc_object_count = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */ object_count = c->ctr1->object_count; first_object = c->ctr1->first_object; nc_linked_attributes_count = 0; linked_attributes_count = 0; linked_attributes = NULL; break; case 6: mapping_ctr = &c->ctr6->mapping_ctr; nc_object_count = c->ctr6->nc_object_count; object_count = c->ctr6->object_count; first_object = c->ctr6->first_object; nc_linked_attributes_count = c->ctr6->nc_linked_attributes_count; linked_attributes_count = c->ctr6->linked_attributes_count; linked_attributes = c->ctr6->linked_attributes; break; default: return NT_STATUS_INVALID_PARAMETER; } if (nc_object_count) { DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n", c->partition->nc.dn, object_count, nc_object_count, linked_attributes_count, nc_linked_attributes_count)); } else { DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u]\n", c->partition->nc.dn, object_count, linked_attributes_count)); } if (!s->schema) { s->self_made_schema = dsdb_new_schema(s); NT_STATUS_HAVE_NO_MEMORY(s->self_made_schema); status = dsdb_load_prefixmap_from_drsuapi(s->self_made_schema, mapping_ctr); if (!W_ERROR_IS_OK(status)) { return werror_to_ntstatus(status); } s->schema = s->self_made_schema; } else { status = dsdb_schema_pfm_contains_drsuapi_pfm(s->schema->prefixmap, mapping_ctr); if (!W_ERROR_IS_OK(status)) { return werror_to_ntstatus(status); } } if (!s->schema_part.first_object) { s->schema_part.object_count = object_count; s->schema_part.first_object = talloc_steal(s, first_object); } else { s->schema_part.object_count += object_count; s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object, first_object); } for (cur = first_object; cur->next_object; cur = cur->next_object) {} s->schema_part.last_object = cur; if (!c->partition->more_data) { return libnet_vampire_cb_apply_schema(s, c); } return NT_STATUS_OK; } NTSTATUS libnet_vampire_cb_store_chunk(void *private_data, const struct libnet_BecomeDC_StoreChunk *c) { struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state); WERROR status; const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr; uint32_t nc_object_count; uint32_t object_count; struct drsuapi_DsReplicaObjectListItemEx *first_object; uint32_t nc_linked_attributes_count; uint32_t linked_attributes_count; struct drsuapi_DsReplicaLinkedAttribute *linked_attributes; const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector; struct dsdb_extended_replicated_objects *objs; struct repsFromTo1 *s_dsa; char *tmp_dns_name; uint32_t i; uint64_t seq_num; s_dsa = talloc_zero(s, struct repsFromTo1); NT_STATUS_HAVE_NO_MEMORY(s_dsa); s_dsa->other_info = talloc(s_dsa, struct repsFromTo1OtherInfo); NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info); switch (c->ctr_level) { case 1: mapping_ctr = &c->ctr1->mapping_ctr; nc_object_count = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */ object_count = c->ctr1->object_count; first_object = c->ctr1->first_object; nc_linked_attributes_count = 0; linked_attributes_count = 0; linked_attributes = NULL; s_dsa->highwatermark = c->ctr1->new_highwatermark; s_dsa->source_dsa_obj_guid = c->ctr1->source_dsa_guid; s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id; uptodateness_vector = NULL; /* TODO: map it */ break; case 6: mapping_ctr = &c->ctr6->mapping_ctr; nc_object_count = c->ctr6->nc_object_count; object_count = c->ctr6->object_count; first_object = c->ctr6->first_object; nc_linked_attributes_count = c->ctr6->nc_linked_attributes_count; linked_attributes_count = c->ctr6->linked_attributes_count; linked_attributes = c->ctr6->linked_attributes; s_dsa->highwatermark = c->ctr6->new_highwatermark; s_dsa->source_dsa_obj_guid = c->ctr6->source_dsa_guid; s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id; uptodateness_vector = c->ctr6->uptodateness_vector; break; default: return NT_STATUS_INVALID_PARAMETER; } s_dsa->replica_flags = DRSUAPI_DRS_WRIT_REP | DRSUAPI_DRS_INIT_SYNC | DRSUAPI_DRS_PER_SYNC; memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule)); tmp_dns_name = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid); NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name); tmp_dns_name = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name); NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name); s_dsa->other_info->dns_name = tmp_dns_name; /* we want to show a count per partition */ if (!s->last_partition || strcmp(s->last_partition, c->partition->nc.dn) != 0) { s->total_objects = 0; talloc_free(s->last_partition); s->last_partition = talloc_strdup(s, c->partition->nc.dn); } s->total_objects += object_count; if (nc_object_count) { DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n", c->partition->nc.dn, s->total_objects, nc_object_count, linked_attributes_count, nc_linked_attributes_count)); } else { DEBUG(0,("Partition[%s] objects[%u] linked_values[%u]\n", c->partition->nc.dn, s->total_objects, linked_attributes_count)); } status = dsdb_extended_replicated_objects_convert(s->ldb, c->partition->nc.dn, mapping_ctr, object_count, first_object, linked_attributes_count, linked_attributes, s_dsa, uptodateness_vector, c->gensec_skey, s, &objs); if (!W_ERROR_IS_OK(status)) { DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status))); return werror_to_ntstatus(status); } if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) { for (i=0; i < objs->num_objects; i++) { struct ldb_ldif ldif; fprintf(stdout, "#\n"); ldif.changetype = LDB_CHANGETYPE_NONE; ldif.msg = objs->objects[i].msg; ldb_ldif_write_file(s->ldb, stdout, &ldif); NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data); } } status = dsdb_extended_replicated_objects_commit(s->ldb, objs, &seq_num); if (!W_ERROR_IS_OK(status)) { DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status))); return werror_to_ntstatus(status); } talloc_free(s_dsa); talloc_free(objs); for (i=0; i < linked_attributes_count; i++) { const struct dsdb_attribute *sa; if (!linked_attributes[i].identifier) { return NT_STATUS_FOOBAR; } if (!linked_attributes[i].value.blob) { return NT_STATUS_FOOBAR; } sa = dsdb_attribute_by_attributeID_id(s->schema, linked_attributes[i].attid); if (!sa) { return NT_STATUS_FOOBAR; } if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) { DEBUG(0,("# %s\n", sa->lDAPDisplayName)); NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, &linked_attributes[i]); dump_data(0, linked_attributes[i].value.blob->data, linked_attributes[i].value.blob->length); } } return NT_STATUS_OK; } NTSTATUS libnet_Vampire(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_Vampire *r) { struct libnet_JoinDomain *join; struct provision_store_self_join_settings *set_secrets; struct libnet_BecomeDC b; struct libnet_vampire_cb_state *s; struct ldb_message *msg; const char *error_string; int ldb_ret; uint32_t i; NTSTATUS status; const char *account_name; const char *netbios_name; r->out.error_string = NULL; join = talloc_zero(mem_ctx, struct libnet_JoinDomain); if (!join) { return NT_STATUS_NO_MEMORY; } if (r->in.netbios_name != NULL) { netbios_name = r->in.netbios_name; } else { netbios_name = talloc_reference(join, lp_netbios_name(ctx->lp_ctx)); if (!netbios_name) { talloc_free(join); r->out.error_string = NULL; return NT_STATUS_NO_MEMORY; } } account_name = talloc_asprintf(join, "%s$", netbios_name); if (!account_name) { talloc_free(join); r->out.error_string = NULL; return NT_STATUS_NO_MEMORY; } /* Re-use the domain we are joining as the domain for the user * to be authenticated with, unless they specified * otherwise */ cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV); join->in.domain_name = r->in.domain_name; join->in.account_name = account_name; join->in.netbios_name = netbios_name; join->in.level = LIBNET_JOINDOMAIN_AUTOMATIC; join->in.acct_type = ACB_WSTRUST; join->in.recreate_account = false; status = libnet_JoinDomain(ctx, join, join); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_steal(mem_ctx, join->out.error_string); talloc_free(join); return status; } s = libnet_vampire_cb_state_init(mem_ctx, ctx->lp_ctx, ctx->event_ctx, netbios_name, join->out.domain_name, join->out.realm, r->in.targetdir); if (!s) { return NT_STATUS_NO_MEMORY; } talloc_steal(s, join); ZERO_STRUCT(b); /* Be more robust: * We now know the domain and realm for sure - if they didn't * put one on the command line, use this for the rest of the * join */ cli_credentials_set_realm(ctx->cred, join->out.realm, CRED_GUESS_ENV); cli_credentials_set_domain(ctx->cred, join->out.domain_name, CRED_GUESS_ENV); /* Now set these values into the smb.conf - we probably had * empty or useless defaults here from whatever smb.conf we * started with */ lp_set_cmdline(s->lp_ctx, "realm", join->out.realm); lp_set_cmdline(s->lp_ctx, "workgroup", join->out.domain_name); b.in.domain_dns_name = join->out.realm; b.in.domain_netbios_name = join->out.domain_name; b.in.domain_sid = join->out.domain_sid; b.in.source_dsa_address = join->out.samr_binding->host; b.in.dest_dsa_netbios_name = netbios_name; b.in.callbacks.private_data = s; b.in.callbacks.check_options = libnet_vampire_cb_check_options; b.in.callbacks.prepare_db = libnet_vampire_cb_prepare_db; b.in.callbacks.schema_chunk = libnet_vampire_cb_schema_chunk; b.in.callbacks.config_chunk = libnet_vampire_cb_store_chunk; b.in.callbacks.domain_chunk = libnet_vampire_cb_store_chunk; b.in.rodc_join = lp_parm_bool(s->lp_ctx, NULL, "repl", "RODC", false); status = libnet_BecomeDC(ctx, s, &b); if (!NT_STATUS_IS_OK(status)) { printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status)); talloc_free(s); return status; } msg = ldb_msg_new(s); if (!msg) { printf("ldb_msg_new() failed\n"); talloc_free(s); return NT_STATUS_NO_MEMORY; } msg->dn = ldb_dn_new(msg, s->ldb, "@ROOTDSE"); if (!msg->dn) { printf("ldb_msg_new(@ROOTDSE) failed\n"); talloc_free(s); return NT_STATUS_NO_MEMORY; } ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE"); if (ldb_ret != LDB_SUCCESS) { printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret); talloc_free(s); return NT_STATUS_NO_MEMORY; } for (i=0; i < msg->num_elements; i++) { msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; } printf("mark ROOTDSE with isSynchronized=TRUE\n"); ldb_ret = ldb_modify(s->ldb, msg); if (ldb_ret != LDB_SUCCESS) { printf("ldb_modify() failed: %d : %s\n", ldb_ret, ldb_errstring(s->ldb)); talloc_free(s); return NT_STATUS_INTERNAL_DB_ERROR; } /* prepare the transaction - this prepares to commit all the changes in the ldb from the whole vampire. Note that this triggers the writing of the linked attribute backlinks. */ if (ldb_transaction_prepare_commit(s->ldb) != LDB_SUCCESS) { printf("Failed to prepare_commit vampire transaction: %s\n", ldb_errstring(s->ldb)); return NT_STATUS_INTERNAL_DB_ERROR; } set_secrets = talloc(s, struct provision_store_self_join_settings); if (!set_secrets) { r->out.error_string = NULL; talloc_free(s); return NT_STATUS_NO_MEMORY; } ZERO_STRUCTP(set_secrets); set_secrets->domain_name = join->out.domain_name; set_secrets->realm = join->out.realm; set_secrets->netbios_name = netbios_name; set_secrets->secure_channel_type = SEC_CHAN_BDC; set_secrets->machine_password = join->out.join_password; set_secrets->key_version_number = join->out.kvno; set_secrets->domain_sid = join->out.domain_sid; status = provision_store_self_join(ctx, s->lp_ctx, ctx->event_ctx, set_secrets, &error_string); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_steal(mem_ctx, error_string); talloc_free(s); return status; } r->out.domain_name = talloc_steal(mem_ctx, join->out.domain_name); r->out.domain_sid = dom_sid_dup(mem_ctx, join->out.domain_sid); /* commit the transaction now we know the secrets were written * out properly */ if (ldb_transaction_commit(s->ldb) != LDB_SUCCESS) { printf("Failed to commit vampire transaction\n"); return NT_STATUS_INTERNAL_DB_ERROR; } talloc_free(s); return NT_STATUS_OK; }