s4/rodc: change the libnet_become_dc code to do RODC join
[Samba/nascimento.git] / source4 / libnet / libnet_vampire.c
blob9554a63b3cc4b5b23a76233aa88904f1cfd0e177
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"
41 #include "libcli/security/dom_sid.h"
43 /*
44 List of tasks vampire.py must perform:
45 - Domain Join
46 - but don't write the secrets.ldb
47 - results for this should be enough to handle the provision
48 - if vampire method is samsync
49 - Provision using these results
50 - do we still want to support this NT4 technology?
51 - Start samsync with libnet code
52 - provision in the callback
53 - Write out the secrets database, using the code from libnet_Join
56 struct vampire_state {
57 const char *netbios_name;
58 struct libnet_JoinDomain *join;
59 struct cli_credentials *machine_account;
60 struct dsdb_schema *self_made_schema;
61 const struct dsdb_schema *schema;
63 struct ldb_context *ldb;
65 struct {
66 uint32_t object_count;
67 struct drsuapi_DsReplicaObjectListItemEx *first_object;
68 struct drsuapi_DsReplicaObjectListItemEx *last_object;
69 } schema_part;
71 const char *targetdir;
73 struct loadparm_context *lp_ctx;
74 struct tevent_context *event_ctx;
75 unsigned total_objects;
76 char *last_partition;
79 static NTSTATUS vampire_prepare_db(void *private_data,
80 const struct libnet_BecomeDC_PrepareDB *p)
82 struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
83 struct provision_settings settings;
84 struct provision_result result;
85 NTSTATUS status;
87 ZERO_STRUCT(settings);
88 settings.site_name = p->dest_dsa->site_name;
89 settings.root_dn_str = p->forest->root_dn_str;
90 settings.domain_dn_str = p->domain->dn_str;
91 settings.config_dn_str = p->forest->config_dn_str;
92 settings.schema_dn_str = p->forest->schema_dn_str;
93 settings.netbios_name = p->dest_dsa->netbios_name;
94 settings.realm = s->join->out.realm;
95 settings.domain = s->join->out.domain_name;
96 settings.server_dn_str = p->dest_dsa->server_dn_str;
97 settings.machine_password = generate_random_str(s, 16);
98 settings.targetdir = s->targetdir;
100 status = provision_bare(s, s->lp_ctx, &settings, &result);
102 if (!NT_STATUS_IS_OK(status)) {
103 return status;
106 s->ldb = result.samdb;
107 s->lp_ctx = result.lp_ctx;
109 /* wrap the entire vapire operation in a transaction. This
110 isn't just cosmetic - we use this to ensure that linked
111 attribute back links are added at the end by relying on a
112 transaction commit hook in the linked attributes module. We
113 need to do this as the order of objects coming from the
114 server is not sufficiently deterministic to know that the
115 record that a backlink needs to be created in has itself
116 been created before the object containing the forward link
117 has come over the wire */
118 if (ldb_transaction_start(s->ldb) != LDB_SUCCESS) {
119 return NT_STATUS_FOOBAR;
122 return NT_STATUS_OK;
127 static NTSTATUS vampire_check_options(void *private_data,
128 const struct libnet_BecomeDC_CheckOptions *o)
130 struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
132 DEBUG(0,("Become DC [%s] of Domain[%s]/[%s]\n",
133 s->netbios_name,
134 o->domain->netbios_name, o->domain->dns_name));
136 DEBUG(0,("Promotion Partner is Server[%s] from Site[%s]\n",
137 o->source_dsa->dns_name, o->source_dsa->site_name));
139 DEBUG(0,("Options:crossRef behavior_version[%u]\n"
140 "\tschema object_version[%u]\n"
141 "\tdomain behavior_version[%u]\n"
142 "\tdomain w2k3_update_revision[%u]\n",
143 o->forest->crossref_behavior_version,
144 o->forest->schema_object_version,
145 o->domain->behavior_version,
146 o->domain->w2k3_update_revision));
148 return NT_STATUS_OK;
151 static NTSTATUS vampire_apply_schema(struct vampire_state *s,
152 const struct libnet_BecomeDC_StoreChunk *c)
154 WERROR status;
155 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
156 uint32_t object_count;
157 struct drsuapi_DsReplicaObjectListItemEx *first_object;
158 struct drsuapi_DsReplicaObjectListItemEx *cur;
159 uint32_t linked_attributes_count;
160 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
161 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
162 struct dsdb_extended_replicated_objects *objs;
163 struct repsFromTo1 *s_dsa;
164 char *tmp_dns_name;
165 struct ldb_message *msg;
166 struct ldb_val prefixMap_val;
167 struct ldb_message_element *prefixMap_el;
168 struct ldb_val schemaInfo_val;
169 uint32_t i;
170 int ret;
171 bool ok;
172 uint64_t seq_num;
174 DEBUG(0,("Analyze and apply schema objects\n"));
176 s_dsa = talloc_zero(s, struct repsFromTo1);
177 NT_STATUS_HAVE_NO_MEMORY(s_dsa);
178 s_dsa->other_info = talloc(s_dsa, struct repsFromTo1OtherInfo);
179 NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
181 switch (c->ctr_level) {
182 case 1:
183 mapping_ctr = &c->ctr1->mapping_ctr;
184 object_count = s->schema_part.object_count;
185 first_object = s->schema_part.first_object;
186 linked_attributes_count = 0;
187 linked_attributes = NULL;
188 s_dsa->highwatermark = c->ctr1->new_highwatermark;
189 s_dsa->source_dsa_obj_guid = c->ctr1->source_dsa_guid;
190 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
191 uptodateness_vector = NULL; /* TODO: map it */
192 break;
193 case 6:
194 mapping_ctr = &c->ctr6->mapping_ctr;
195 object_count = s->schema_part.object_count;
196 first_object = s->schema_part.first_object;
197 linked_attributes_count = c->ctr6->linked_attributes_count;
198 linked_attributes = c->ctr6->linked_attributes;
199 s_dsa->highwatermark = c->ctr6->new_highwatermark;
200 s_dsa->source_dsa_obj_guid = c->ctr6->source_dsa_guid;
201 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
202 uptodateness_vector = c->ctr6->uptodateness_vector;
203 break;
204 default:
205 return NT_STATUS_INVALID_PARAMETER;
208 s_dsa->replica_flags = DRSUAPI_DRS_WRIT_REP
209 | DRSUAPI_DRS_INIT_SYNC
210 | DRSUAPI_DRS_PER_SYNC;
211 memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
213 tmp_dns_name = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
214 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
215 tmp_dns_name = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
216 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
217 s_dsa->other_info->dns_name = tmp_dns_name;
219 for (cur = first_object; cur; cur = cur->next_object) {
220 bool is_attr = false;
221 bool is_class = false;
223 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
224 struct drsuapi_DsReplicaAttribute *a;
225 uint32_t j;
226 const char *oid = NULL;
228 a = &cur->object.attribute_ctr.attributes[i];
229 status = dsdb_schema_pfm_oid_from_attid(s->self_made_schema->prefixmap,
230 a->attid, s, &oid);
231 if (!W_ERROR_IS_OK(status)) {
232 return werror_to_ntstatus(status);
235 switch (a->attid) {
236 case DRSUAPI_ATTRIBUTE_objectClass:
237 for (j=0; j < a->value_ctr.num_values; j++) {
238 uint32_t val = 0xFFFFFFFF;
240 if (a->value_ctr.values[j].blob
241 && a->value_ctr.values[j].blob->length == 4) {
242 val = IVAL(a->value_ctr.values[j].blob->data,0);
245 if (val == DRSUAPI_OBJECTCLASS_attributeSchema) {
246 is_attr = true;
248 if (val == DRSUAPI_OBJECTCLASS_classSchema) {
249 is_class = true;
253 break;
254 default:
255 break;
259 if (is_attr) {
260 struct dsdb_attribute *sa;
262 sa = talloc_zero(s->self_made_schema, struct dsdb_attribute);
263 NT_STATUS_HAVE_NO_MEMORY(sa);
265 status = dsdb_attribute_from_drsuapi(s->ldb, s->self_made_schema, &cur->object, s, sa);
266 if (!W_ERROR_IS_OK(status)) {
267 return werror_to_ntstatus(status);
270 DLIST_ADD_END(s->self_made_schema->attributes, sa, struct dsdb_attribute *);
273 if (is_class) {
274 struct dsdb_class *sc;
276 sc = talloc_zero(s->self_made_schema, struct dsdb_class);
277 NT_STATUS_HAVE_NO_MEMORY(sc);
279 status = dsdb_class_from_drsuapi(s->ldb, s->self_made_schema, &cur->object, s, sc);
280 if (!W_ERROR_IS_OK(status)) {
281 return werror_to_ntstatus(status);
283 DLIST_ADD_END(s->self_made_schema->classes, sc, struct dsdb_class *);
287 /* attach the schema to the ldb */
288 ret = dsdb_set_schema(s->ldb, s->self_made_schema);
289 if (ret != LDB_SUCCESS) {
290 return NT_STATUS_FOOBAR;
292 /* we don't want to access the self made schema anymore */
293 s->schema = s->self_made_schema;
294 s->self_made_schema = NULL;
296 /* Now convert the schema elements again, using the schema we just imported */
297 status = dsdb_extended_replicated_objects_convert(s->ldb,
298 c->partition->nc.dn,
299 mapping_ctr,
300 object_count,
301 first_object,
302 linked_attributes_count,
303 linked_attributes,
304 s_dsa,
305 uptodateness_vector,
306 c->gensec_skey,
307 s, &objs);
308 if (!W_ERROR_IS_OK(status)) {
309 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
310 return werror_to_ntstatus(status);
313 if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
314 for (i=0; i < objs->num_objects; i++) {
315 struct ldb_ldif ldif;
316 fprintf(stdout, "#\n");
317 ldif.changetype = LDB_CHANGETYPE_NONE;
318 ldif.msg = objs->objects[i].msg;
319 ldb_ldif_write_file(s->ldb, stdout, &ldif);
320 NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
324 status = dsdb_extended_replicated_objects_commit(s->ldb, objs, &seq_num);
325 if (!W_ERROR_IS_OK(status)) {
326 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
327 return werror_to_ntstatus(status);
330 msg = ldb_msg_new(objs);
331 NT_STATUS_HAVE_NO_MEMORY(msg);
332 msg->dn = objs->partition_dn;
334 status = dsdb_get_oid_mappings_ldb(s->schema, msg, &prefixMap_val, &schemaInfo_val);
335 if (!W_ERROR_IS_OK(status)) {
336 DEBUG(0,("Failed dsdb_get_oid_mappings_ldb(%s)\n", win_errstr(status)));
337 return werror_to_ntstatus(status);
340 /* we only add prefixMap here, because schemaInfo is a replicated attribute and already applied */
341 ret = ldb_msg_add_value(msg, "prefixMap", &prefixMap_val, &prefixMap_el);
342 if (ret != LDB_SUCCESS) {
343 return NT_STATUS_FOOBAR;
345 prefixMap_el->flags = LDB_FLAG_MOD_REPLACE;
347 ret = ldb_modify(s->ldb, msg);
348 if (ret != LDB_SUCCESS) {
349 DEBUG(0,("Failed to add prefixMap and schemaInfo %s\n", ldb_strerror(ret)));
350 return NT_STATUS_FOOBAR;
353 talloc_free(s_dsa);
354 talloc_free(objs);
356 /* We must set these up to ensure the replMetaData is written
357 * correctly, before our NTDS Settings entry is replicated */
358 ok = samdb_set_ntds_invocation_id(s->ldb, &c->dest_dsa->invocation_id);
359 if (!ok) {
360 DEBUG(0,("Failed to set cached ntds invocationId\n"));
361 return NT_STATUS_FOOBAR;
363 ok = samdb_set_ntds_objectGUID(s->ldb, &c->dest_dsa->ntds_guid);
364 if (!ok) {
365 DEBUG(0,("Failed to set cached ntds objectGUID\n"));
366 return NT_STATUS_FOOBAR;
369 s->schema = dsdb_get_schema(s->ldb);
370 if (!s->schema) {
371 DEBUG(0,("Failed to get loaded dsdb_schema\n"));
372 return NT_STATUS_FOOBAR;
375 return NT_STATUS_OK;
378 static NTSTATUS vampire_schema_chunk(void *private_data,
379 const struct libnet_BecomeDC_StoreChunk *c)
381 struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
382 WERROR status;
383 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
384 uint32_t nc_object_count;
385 uint32_t object_count;
386 struct drsuapi_DsReplicaObjectListItemEx *first_object;
387 struct drsuapi_DsReplicaObjectListItemEx *cur;
388 uint32_t nc_linked_attributes_count;
389 uint32_t linked_attributes_count;
390 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
392 switch (c->ctr_level) {
393 case 1:
394 mapping_ctr = &c->ctr1->mapping_ctr;
395 nc_object_count = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
396 object_count = c->ctr1->object_count;
397 first_object = c->ctr1->first_object;
398 nc_linked_attributes_count = 0;
399 linked_attributes_count = 0;
400 linked_attributes = NULL;
401 break;
402 case 6:
403 mapping_ctr = &c->ctr6->mapping_ctr;
404 nc_object_count = c->ctr6->nc_object_count;
405 object_count = c->ctr6->object_count;
406 first_object = c->ctr6->first_object;
407 nc_linked_attributes_count = c->ctr6->nc_linked_attributes_count;
408 linked_attributes_count = c->ctr6->linked_attributes_count;
409 linked_attributes = c->ctr6->linked_attributes;
410 break;
411 default:
412 return NT_STATUS_INVALID_PARAMETER;
415 if (nc_object_count) {
416 DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n",
417 c->partition->nc.dn, object_count, nc_object_count,
418 linked_attributes_count, nc_linked_attributes_count));
419 } else {
420 DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u]\n",
421 c->partition->nc.dn, object_count, linked_attributes_count));
424 if (!s->schema) {
425 s->self_made_schema = dsdb_new_schema(s, lp_iconv_convenience(s->lp_ctx));
427 NT_STATUS_HAVE_NO_MEMORY(s->self_made_schema);
429 status = dsdb_load_prefixmap_from_drsuapi(s->self_made_schema, mapping_ctr);
430 if (!W_ERROR_IS_OK(status)) {
431 return werror_to_ntstatus(status);
434 s->schema = s->self_made_schema;
435 } else {
436 status = dsdb_schema_pfm_contains_drsuapi_pfm(s->schema->prefixmap, mapping_ctr);
437 if (!W_ERROR_IS_OK(status)) {
438 return werror_to_ntstatus(status);
442 if (!s->schema_part.first_object) {
443 s->schema_part.object_count = object_count;
444 s->schema_part.first_object = talloc_steal(s, first_object);
445 } else {
446 s->schema_part.object_count += object_count;
447 s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
448 first_object);
450 for (cur = first_object; cur->next_object; cur = cur->next_object) {}
451 s->schema_part.last_object = cur;
453 if (!c->partition->more_data) {
454 return vampire_apply_schema(s, c);
457 return NT_STATUS_OK;
460 static NTSTATUS vampire_store_chunk(void *private_data,
461 const struct libnet_BecomeDC_StoreChunk *c)
463 struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
464 WERROR status;
465 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
466 uint32_t nc_object_count;
467 uint32_t object_count;
468 struct drsuapi_DsReplicaObjectListItemEx *first_object;
469 uint32_t nc_linked_attributes_count;
470 uint32_t linked_attributes_count;
471 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
472 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
473 struct dsdb_extended_replicated_objects *objs;
474 struct repsFromTo1 *s_dsa;
475 char *tmp_dns_name;
476 uint32_t i;
477 uint64_t seq_num;
479 s_dsa = talloc_zero(s, struct repsFromTo1);
480 NT_STATUS_HAVE_NO_MEMORY(s_dsa);
481 s_dsa->other_info = talloc(s_dsa, struct repsFromTo1OtherInfo);
482 NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
484 switch (c->ctr_level) {
485 case 1:
486 mapping_ctr = &c->ctr1->mapping_ctr;
487 nc_object_count = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
488 object_count = c->ctr1->object_count;
489 first_object = c->ctr1->first_object;
490 nc_linked_attributes_count = 0;
491 linked_attributes_count = 0;
492 linked_attributes = NULL;
493 s_dsa->highwatermark = c->ctr1->new_highwatermark;
494 s_dsa->source_dsa_obj_guid = c->ctr1->source_dsa_guid;
495 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
496 uptodateness_vector = NULL; /* TODO: map it */
497 break;
498 case 6:
499 mapping_ctr = &c->ctr6->mapping_ctr;
500 nc_object_count = c->ctr6->nc_object_count;
501 object_count = c->ctr6->object_count;
502 first_object = c->ctr6->first_object;
503 nc_linked_attributes_count = c->ctr6->nc_linked_attributes_count;
504 linked_attributes_count = c->ctr6->linked_attributes_count;
505 linked_attributes = c->ctr6->linked_attributes;
506 s_dsa->highwatermark = c->ctr6->new_highwatermark;
507 s_dsa->source_dsa_obj_guid = c->ctr6->source_dsa_guid;
508 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
509 uptodateness_vector = c->ctr6->uptodateness_vector;
510 break;
511 default:
512 return NT_STATUS_INVALID_PARAMETER;
515 s_dsa->replica_flags = DRSUAPI_DRS_WRIT_REP
516 | DRSUAPI_DRS_INIT_SYNC
517 | DRSUAPI_DRS_PER_SYNC;
518 memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
520 tmp_dns_name = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
521 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
522 tmp_dns_name = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
523 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
524 s_dsa->other_info->dns_name = tmp_dns_name;
526 /* we want to show a count per partition */
527 if (!s->last_partition || strcmp(s->last_partition, c->partition->nc.dn) != 0) {
528 s->total_objects = 0;
529 talloc_free(s->last_partition);
530 s->last_partition = talloc_strdup(s, c->partition->nc.dn);
532 s->total_objects += object_count;
534 if (nc_object_count) {
535 DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n",
536 c->partition->nc.dn, s->total_objects, nc_object_count,
537 linked_attributes_count, nc_linked_attributes_count));
538 } else {
539 DEBUG(0,("Partition[%s] objects[%u] linked_values[%u]\n",
540 c->partition->nc.dn, s->total_objects, linked_attributes_count));
544 status = dsdb_extended_replicated_objects_convert(s->ldb,
545 c->partition->nc.dn,
546 mapping_ctr,
547 object_count,
548 first_object,
549 linked_attributes_count,
550 linked_attributes,
551 s_dsa,
552 uptodateness_vector,
553 c->gensec_skey,
554 s, &objs);
555 if (!W_ERROR_IS_OK(status)) {
556 DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status)));
557 return werror_to_ntstatus(status);
560 if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
561 for (i=0; i < objs->num_objects; i++) {
562 struct ldb_ldif ldif;
563 fprintf(stdout, "#\n");
564 ldif.changetype = LDB_CHANGETYPE_NONE;
565 ldif.msg = objs->objects[i].msg;
566 ldb_ldif_write_file(s->ldb, stdout, &ldif);
567 NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
570 status = dsdb_extended_replicated_objects_commit(s->ldb,
571 objs, &seq_num);
572 if (!W_ERROR_IS_OK(status)) {
573 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
574 return werror_to_ntstatus(status);
577 talloc_free(s_dsa);
578 talloc_free(objs);
580 for (i=0; i < linked_attributes_count; i++) {
581 const struct dsdb_attribute *sa;
583 if (!linked_attributes[i].identifier) {
584 return NT_STATUS_FOOBAR;
587 if (!linked_attributes[i].value.blob) {
588 return NT_STATUS_FOOBAR;
591 sa = dsdb_attribute_by_attributeID_id(s->schema,
592 linked_attributes[i].attid);
593 if (!sa) {
594 return NT_STATUS_FOOBAR;
597 if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
598 DEBUG(0,("# %s\n", sa->lDAPDisplayName));
599 NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, &linked_attributes[i]);
600 dump_data(0,
601 linked_attributes[i].value.blob->data,
602 linked_attributes[i].value.blob->length);
606 return NT_STATUS_OK;
609 NTSTATUS libnet_Vampire(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
610 struct libnet_Vampire *r)
612 struct libnet_JoinDomain *join;
613 struct provision_store_self_join_settings *set_secrets;
614 struct libnet_BecomeDC b;
615 struct vampire_state *s;
616 struct ldb_message *msg;
617 const char *error_string;
618 int ldb_ret;
619 uint32_t i;
620 NTSTATUS status;
622 const char *account_name;
623 const char *netbios_name;
625 r->out.error_string = NULL;
627 s = talloc_zero(mem_ctx, struct vampire_state);
628 if (!s) {
629 return NT_STATUS_NO_MEMORY;
632 s->lp_ctx = ctx->lp_ctx;
633 s->event_ctx = ctx->event_ctx;
635 join = talloc_zero(s, struct libnet_JoinDomain);
636 if (!join) {
637 return NT_STATUS_NO_MEMORY;
640 if (r->in.netbios_name != NULL) {
641 netbios_name = r->in.netbios_name;
642 } else {
643 netbios_name = talloc_reference(join, lp_netbios_name(ctx->lp_ctx));
644 if (!netbios_name) {
645 r->out.error_string = NULL;
646 talloc_free(s);
647 return NT_STATUS_NO_MEMORY;
651 account_name = talloc_asprintf(join, "%s$", netbios_name);
652 if (!account_name) {
653 r->out.error_string = NULL;
654 talloc_free(s);
655 return NT_STATUS_NO_MEMORY;
658 join->in.domain_name = r->in.domain_name;
659 join->in.account_name = account_name;
660 join->in.netbios_name = netbios_name;
661 join->in.level = LIBNET_JOINDOMAIN_AUTOMATIC;
662 join->in.acct_type = ACB_WSTRUST;
663 join->in.recreate_account = false;
664 status = libnet_JoinDomain(ctx, join, join);
665 if (!NT_STATUS_IS_OK(status)) {
666 r->out.error_string = talloc_steal(mem_ctx, join->out.error_string);
667 talloc_free(s);
668 return status;
671 s->join = join;
673 s->targetdir = r->in.targetdir;
675 ZERO_STRUCT(b);
676 b.in.domain_dns_name = join->out.realm;
677 b.in.domain_netbios_name = join->out.domain_name;
678 b.in.domain_sid = join->out.domain_sid;
679 b.in.source_dsa_address = join->out.samr_binding->host;
680 b.in.dest_dsa_netbios_name = netbios_name;
682 b.in.callbacks.private_data = s;
683 b.in.callbacks.check_options = vampire_check_options;
684 b.in.callbacks.prepare_db = vampire_prepare_db;
685 b.in.callbacks.schema_chunk = vampire_schema_chunk;
686 b.in.callbacks.config_chunk = vampire_store_chunk;
687 b.in.callbacks.domain_chunk = vampire_store_chunk;
689 b.in.rodc_join = lp_parm_bool(s->lp_ctx, NULL, "repl", "RODC", false);
691 status = libnet_BecomeDC(ctx, s, &b);
692 if (!NT_STATUS_IS_OK(status)) {
693 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
694 talloc_free(s);
695 return status;
698 msg = ldb_msg_new(s);
699 if (!msg) {
700 printf("ldb_msg_new() failed\n");
701 talloc_free(s);
702 return NT_STATUS_NO_MEMORY;
704 msg->dn = ldb_dn_new(msg, s->ldb, "@ROOTDSE");
705 if (!msg->dn) {
706 printf("ldb_msg_new(@ROOTDSE) failed\n");
707 talloc_free(s);
708 return NT_STATUS_NO_MEMORY;
711 ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE");
712 if (ldb_ret != LDB_SUCCESS) {
713 printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret);
714 talloc_free(s);
715 return NT_STATUS_NO_MEMORY;
718 for (i=0; i < msg->num_elements; i++) {
719 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
722 printf("mark ROOTDSE with isSynchronized=TRUE\n");
723 ldb_ret = ldb_modify(s->ldb, msg);
724 if (ldb_ret != LDB_SUCCESS) {
725 printf("ldb_modify() failed: %d : %s\n", ldb_ret, ldb_errstring(s->ldb));
726 talloc_free(s);
727 return NT_STATUS_INTERNAL_DB_ERROR;
730 /* prepare the transaction - this prepares to commit all the changes in
731 the ldb from the whole vampire. Note that this
732 triggers the writing of the linked attribute backlinks.
734 if (ldb_transaction_prepare_commit(s->ldb) != LDB_SUCCESS) {
735 printf("Failed to prepare_commit vampire transaction: %s\n", ldb_errstring(s->ldb));
736 return NT_STATUS_INTERNAL_DB_ERROR;
739 set_secrets = talloc(s, struct provision_store_self_join_settings);
740 if (!set_secrets) {
741 r->out.error_string = NULL;
742 talloc_free(s);
743 return NT_STATUS_NO_MEMORY;
746 ZERO_STRUCTP(set_secrets);
747 set_secrets->domain_name = join->out.domain_name;
748 set_secrets->realm = join->out.realm;
749 set_secrets->account_name = account_name;
750 set_secrets->netbios_name = netbios_name;
751 set_secrets->secure_channel_type = SEC_CHAN_BDC;
752 set_secrets->machine_password = join->out.join_password;
753 set_secrets->key_version_number = join->out.kvno;
754 set_secrets->domain_sid = join->out.domain_sid;
756 status = provision_store_self_join(ctx, ctx->lp_ctx, ctx->event_ctx, set_secrets, &error_string);
757 if (!NT_STATUS_IS_OK(status)) {
758 r->out.error_string = talloc_steal(mem_ctx, error_string);
759 talloc_free(s);
760 return status;
763 r->out.domain_name = talloc_steal(r, join->out.domain_name);
764 r->out.domain_sid = dom_sid_dup(r, join->out.domain_sid);
766 /* commit the transaction now we know the secrets were written
767 * out properly
769 if (ldb_transaction_commit(s->ldb) != LDB_SUCCESS) {
770 printf("Failed to commit vampire transaction\n");
771 return NT_STATUS_INTERNAL_DB_ERROR;
774 talloc_free(s);
776 return NT_STATUS_OK;