WHATSNEW: Mention combined CTDB
[Samba.git] / source4 / libnet / libnet_vampire.c
blob69195af180c134ea687b04c2546c598d2076813b
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;
165 settings.use_ntvfs = true;
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 WERROR status;
223 struct dsdb_schema_prefixmap *pfm_remote;
224 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
225 struct dsdb_schema *provision_schema;
226 uint32_t object_count = 0;
227 struct drsuapi_DsReplicaObjectListItemEx *first_object;
228 uint32_t linked_attributes_count;
229 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
230 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
231 struct dsdb_extended_replicated_objects *schema_objs;
232 struct repsFromTo1 *s_dsa;
233 char *tmp_dns_name;
234 struct ldb_context *schema_ldb;
235 struct ldb_message *msg;
236 struct ldb_message_element *prefixMap_el;
237 uint32_t i;
238 int ret;
239 bool ok;
240 uint64_t seq_num;
241 uint32_t cycle_before_switching;
243 DEBUG(0,("Analyze and apply schema objects\n"));
245 s_dsa = talloc_zero(s, struct repsFromTo1);
246 NT_STATUS_HAVE_NO_MEMORY(s_dsa);
247 s_dsa->other_info = talloc(s_dsa, struct repsFromTo1OtherInfo);
248 NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
250 switch (c->ctr_level) {
251 case 1:
252 mapping_ctr = &c->ctr1->mapping_ctr;
253 object_count = s->schema_part.object_count;
254 first_object = s->schema_part.first_object;
255 linked_attributes_count = 0;
256 linked_attributes = NULL;
257 s_dsa->highwatermark = c->ctr1->new_highwatermark;
258 s_dsa->source_dsa_obj_guid = c->ctr1->source_dsa_guid;
259 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
260 uptodateness_vector = NULL; /* TODO: map it */
261 break;
262 case 6:
263 mapping_ctr = &c->ctr6->mapping_ctr;
264 object_count = s->schema_part.object_count;
265 first_object = s->schema_part.first_object;
266 linked_attributes_count = c->ctr6->linked_attributes_count;
267 linked_attributes = c->ctr6->linked_attributes;
268 s_dsa->highwatermark = c->ctr6->new_highwatermark;
269 s_dsa->source_dsa_obj_guid = c->ctr6->source_dsa_guid;
270 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
271 uptodateness_vector = c->ctr6->uptodateness_vector;
272 break;
273 default:
274 return NT_STATUS_INVALID_PARAMETER;
276 /* We must set these up to ensure the replMetaData is written
277 * correctly, before our NTDS Settings entry is replicated */
278 ok = samdb_set_ntds_invocation_id(s->ldb, &c->dest_dsa->invocation_id);
279 if (!ok) {
280 DEBUG(0,("Failed to set cached ntds invocationId\n"));
281 return NT_STATUS_FOOBAR;
283 ok = samdb_set_ntds_objectGUID(s->ldb, &c->dest_dsa->ntds_guid);
284 if (!ok) {
285 DEBUG(0,("Failed to set cached ntds objectGUID\n"));
286 return NT_STATUS_FOOBAR;
289 status = dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr, true,
290 s, &pfm_remote, NULL);
291 if (!W_ERROR_IS_OK(status)) {
292 DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s",
293 win_errstr(status)));
294 return werror_to_ntstatus(status);
297 s_dsa->replica_flags = DRSUAPI_DRS_WRIT_REP
298 | DRSUAPI_DRS_INIT_SYNC
299 | DRSUAPI_DRS_PER_SYNC;
300 memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
302 tmp_dns_name = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
303 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
304 tmp_dns_name = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
305 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
306 s_dsa->other_info->dns_name = tmp_dns_name;
308 if (s->self_made_schema == NULL) {
309 DEBUG(0,("libnet_vampire_cb_apply_schema: called with out self_made_schema\n"));
310 return NT_STATUS_INTERNAL_ERROR;
313 schema_ldb = provision_get_schema(s, s->lp_ctx,
314 c->forest->schema_dn_str,
315 &s->prefixmap_blob);
316 if (!schema_ldb) {
317 DEBUG(0,("Failed to re-load from local provision using remote prefixMap. "
318 "Will continue with local prefixMap\n"));
319 provision_schema = dsdb_get_schema(s->ldb, s);
320 } else {
321 provision_schema = dsdb_get_schema(schema_ldb, s);
322 ret = dsdb_reference_schema(s->ldb, provision_schema, false);
323 if (ret != LDB_SUCCESS) {
324 DEBUG(0,("Failed to attach schema from local provision using remote prefixMap."));
325 return NT_STATUS_UNSUCCESSFUL;
327 talloc_free(schema_ldb);
330 cycle_before_switching = lpcfg_parm_long(s->lp_ctx, NULL,
331 "become dc",
332 "schema convert retrial", 1);
334 status = dsdb_repl_resolve_working_schema(s->ldb, s,
335 pfm_remote,
336 cycle_before_switching,
337 provision_schema,
338 s->self_made_schema,
339 object_count,
340 first_object);
341 if (!W_ERROR_IS_OK(status)) {
342 DEBUG(0, ("%s: dsdb_repl_resolve_working_schema() failed: %s",
343 __location__, win_errstr(status)));
344 return werror_to_ntstatus(status);
347 /* free temp objects for 1st conversion phase */
348 talloc_unlink(s, provision_schema);
351 * attach the schema we just brought over DRS to the ldb,
352 * so we can use it in dsdb_convert_object_ex below
354 ret = dsdb_set_schema(s->ldb, s->self_made_schema);
355 if (ret != LDB_SUCCESS) {
356 DEBUG(0,("Failed to attach working schema from DRS.\n"));
357 return NT_STATUS_FOOBAR;
360 /* we don't want to access the self made schema anymore */
361 s->schema = s->self_made_schema;
362 s->self_made_schema = NULL;
364 /* Now convert the schema elements again, using the schema we finalised, ready to actually import */
365 status = dsdb_replicated_objects_convert(s->ldb,
366 s->schema,
367 c->partition->nc.dn,
368 mapping_ctr,
369 object_count,
370 first_object,
371 linked_attributes_count,
372 linked_attributes,
373 s_dsa,
374 uptodateness_vector,
375 c->gensec_skey,
377 s, &schema_objs);
378 if (!W_ERROR_IS_OK(status)) {
379 DEBUG(0,("Failed to convert objects when trying to import over DRS (2nd pass, to store remote schema): %s\n", win_errstr(status)));
380 return werror_to_ntstatus(status);
383 if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
384 for (i=0; i < schema_objs->num_objects; i++) {
385 struct ldb_ldif ldif;
386 fprintf(stdout, "#\n");
387 ldif.changetype = LDB_CHANGETYPE_NONE;
388 ldif.msg = schema_objs->objects[i].msg;
389 ldb_ldif_write_file(s->ldb, stdout, &ldif);
390 NDR_PRINT_DEBUG(replPropertyMetaDataBlob, schema_objs->objects[i].meta_data);
394 status = dsdb_replicated_objects_commit(s->ldb, NULL, schema_objs, &seq_num);
395 if (!W_ERROR_IS_OK(status)) {
396 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
397 return werror_to_ntstatus(status);
400 msg = ldb_msg_new(schema_objs);
401 NT_STATUS_HAVE_NO_MEMORY(msg);
402 msg->dn = schema_objs->partition_dn;
404 /* We must ensure a prefixMap has been written. Unlike other
405 * attributes (including schemaInfo), it is not replicated in
406 * the normal replication stream. We can use the one from
407 * s->prefixmap_blob because we operate with one, unchanging
408 * prefixMap for this entire operation. */
409 ret = ldb_msg_add_value(msg, "prefixMap", &s->prefixmap_blob, &prefixMap_el);
410 if (ret != LDB_SUCCESS) {
411 return NT_STATUS_FOOBAR;
413 /* We want to know if a prefixMap was written already, as it
414 * would mean that the above comment was not true, and we have
415 * somehow updated the prefixMap during this transaction */
416 prefixMap_el->flags = LDB_FLAG_MOD_ADD;
418 ret = dsdb_modify(s->ldb, msg, DSDB_FLAG_AS_SYSTEM);
419 if (ret != LDB_SUCCESS) {
420 DEBUG(0,("Failed to add prefixMap: %s\n", ldb_errstring(s->ldb)));
421 return NT_STATUS_FOOBAR;
424 talloc_free(s_dsa);
425 talloc_free(schema_objs);
427 s->schema = dsdb_get_schema(s->ldb, s);
428 if (!s->schema) {
429 DEBUG(0,("Failed to get loaded dsdb_schema\n"));
430 return NT_STATUS_FOOBAR;
433 return NT_STATUS_OK;
436 NTSTATUS libnet_vampire_cb_schema_chunk(void *private_data,
437 const struct libnet_BecomeDC_StoreChunk *c)
439 struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
440 WERROR status;
441 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
442 uint32_t nc_object_count;
443 uint32_t nc_total_received = 0;
444 uint32_t object_count;
445 struct drsuapi_DsReplicaObjectListItemEx *first_object;
446 struct drsuapi_DsReplicaObjectListItemEx *cur;
447 uint32_t nc_linked_attributes_count;
448 uint32_t linked_attributes_count;
450 switch (c->ctr_level) {
451 case 1:
452 mapping_ctr = &c->ctr1->mapping_ctr;
453 nc_object_count = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
454 object_count = c->ctr1->object_count;
455 first_object = c->ctr1->first_object;
456 nc_linked_attributes_count = 0;
457 linked_attributes_count = 0;
458 break;
459 case 6:
460 mapping_ctr = &c->ctr6->mapping_ctr;
461 nc_object_count = c->ctr6->nc_object_count;
462 object_count = c->ctr6->object_count;
463 first_object = c->ctr6->first_object;
464 nc_linked_attributes_count = c->ctr6->nc_linked_attributes_count;
465 linked_attributes_count = c->ctr6->linked_attributes_count;
466 break;
467 default:
468 return NT_STATUS_INVALID_PARAMETER;
471 if (!s->schema_part.first_object) {
472 nc_total_received = object_count;
473 } else {
474 nc_total_received = s->schema_part.object_count + object_count;
476 if (nc_object_count) {
477 DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n",
478 c->partition->nc.dn, nc_total_received, nc_object_count,
479 linked_attributes_count, nc_linked_attributes_count));
480 } else {
481 DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u]\n",
482 c->partition->nc.dn, nc_total_received, linked_attributes_count));
485 if (!s->self_made_schema) {
486 WERROR werr;
487 struct drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr_without_schema_info;
488 /* Put the DRS prefixmap aside for the schema we are
489 * about to load in the provision, and into the one we
490 * are making with the help of DRS */
492 mapping_ctr_without_schema_info = *mapping_ctr;
494 /* This strips off the 0xFF schema info from the end,
495 * because we don't want it in the blob */
496 if (mapping_ctr_without_schema_info.num_mappings > 0) {
497 mapping_ctr_without_schema_info.num_mappings--;
499 werr = dsdb_get_drsuapi_prefixmap_as_blob(&mapping_ctr_without_schema_info, s, &s->prefixmap_blob);
500 if (!W_ERROR_IS_OK(werr)) {
501 return werror_to_ntstatus(werr);
504 /* Set up two manually-constructed schema - the local
505 * schema from the provision will be used to build
506 * one, which will then in turn be used to build the
507 * other. */
508 s->self_made_schema = dsdb_new_schema(s);
509 NT_STATUS_HAVE_NO_MEMORY(s->self_made_schema);
511 status = dsdb_load_prefixmap_from_drsuapi(s->self_made_schema, mapping_ctr);
512 if (!W_ERROR_IS_OK(status)) {
513 return werror_to_ntstatus(status);
515 } else {
516 status = dsdb_schema_pfm_contains_drsuapi_pfm(s->self_made_schema->prefixmap, mapping_ctr);
517 if (!W_ERROR_IS_OK(status)) {
518 return werror_to_ntstatus(status);
522 if (!s->schema_part.first_object) {
523 s->schema_part.object_count = object_count;
524 s->schema_part.first_object = talloc_steal(s, first_object);
525 } else {
526 s->schema_part.object_count += object_count;
527 s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
528 first_object);
530 for (cur = first_object; cur->next_object; cur = cur->next_object) {}
531 s->schema_part.last_object = cur;
533 if (!c->partition->more_data) {
534 return libnet_vampire_cb_apply_schema(s, c);
537 return NT_STATUS_OK;
540 NTSTATUS libnet_vampire_cb_store_chunk(void *private_data,
541 const struct libnet_BecomeDC_StoreChunk *c)
543 struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
544 WERROR status;
545 struct dsdb_schema *schema;
546 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
547 uint32_t nc_object_count;
548 uint32_t object_count;
549 struct drsuapi_DsReplicaObjectListItemEx *first_object;
550 uint32_t nc_linked_attributes_count;
551 uint32_t linked_attributes_count;
552 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
553 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
554 struct dsdb_extended_replicated_objects *objs;
555 uint32_t req_replica_flags;
556 struct repsFromTo1 *s_dsa;
557 char *tmp_dns_name;
558 uint32_t i;
559 uint64_t seq_num;
560 bool is_exop = false;
562 s_dsa = talloc_zero(s, struct repsFromTo1);
563 NT_STATUS_HAVE_NO_MEMORY(s_dsa);
564 s_dsa->other_info = talloc(s_dsa, struct repsFromTo1OtherInfo);
565 NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
567 switch (c->ctr_level) {
568 case 1:
569 mapping_ctr = &c->ctr1->mapping_ctr;
570 nc_object_count = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
571 object_count = c->ctr1->object_count;
572 first_object = c->ctr1->first_object;
573 nc_linked_attributes_count = 0;
574 linked_attributes_count = 0;
575 linked_attributes = NULL;
576 s_dsa->highwatermark = c->ctr1->new_highwatermark;
577 s_dsa->source_dsa_obj_guid = c->ctr1->source_dsa_guid;
578 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
579 uptodateness_vector = NULL; /* TODO: map it */
580 break;
581 case 6:
582 mapping_ctr = &c->ctr6->mapping_ctr;
583 nc_object_count = c->ctr6->nc_object_count;
584 object_count = c->ctr6->object_count;
585 first_object = c->ctr6->first_object;
586 nc_linked_attributes_count = c->ctr6->nc_linked_attributes_count;
587 linked_attributes_count = c->ctr6->linked_attributes_count;
588 linked_attributes = c->ctr6->linked_attributes;
589 s_dsa->highwatermark = c->ctr6->new_highwatermark;
590 s_dsa->source_dsa_obj_guid = c->ctr6->source_dsa_guid;
591 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
592 uptodateness_vector = c->ctr6->uptodateness_vector;
593 break;
594 default:
595 return NT_STATUS_INVALID_PARAMETER;
598 switch (c->req_level) {
599 case 0:
600 /* none */
601 req_replica_flags = 0;
602 break;
603 case 5:
604 if (c->req5->extended_op != DRSUAPI_EXOP_NONE) {
605 is_exop = true;
607 req_replica_flags = c->req5->replica_flags;
608 break;
609 case 8:
610 if (c->req8->extended_op != DRSUAPI_EXOP_NONE) {
611 is_exop = true;
613 req_replica_flags = c->req8->replica_flags;
614 break;
615 case 10:
616 if (c->req10->extended_op != DRSUAPI_EXOP_NONE) {
617 is_exop = true;
619 req_replica_flags = c->req10->replica_flags;
620 break;
621 default:
622 return NT_STATUS_INVALID_PARAMETER;
625 if (req_replica_flags & DRSUAPI_DRS_CRITICAL_ONLY) {
627 * If we only replicate the critical objects
628 * we should not remember what we already
629 * got, as it is incomplete.
631 ZERO_STRUCT(s_dsa->highwatermark);
632 uptodateness_vector = NULL;
635 /* TODO: avoid hardcoded flags */
636 s_dsa->replica_flags = DRSUAPI_DRS_WRIT_REP
637 | DRSUAPI_DRS_INIT_SYNC
638 | DRSUAPI_DRS_PER_SYNC;
639 memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
641 tmp_dns_name = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
642 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
643 tmp_dns_name = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
644 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
645 s_dsa->other_info->dns_name = tmp_dns_name;
647 /* we want to show a count per partition */
648 if (!s->last_partition || strcmp(s->last_partition, c->partition->nc.dn) != 0) {
649 s->total_objects = 0;
650 talloc_free(s->last_partition);
651 s->last_partition = talloc_strdup(s, c->partition->nc.dn);
653 s->total_objects += object_count;
655 if (is_exop) {
656 if (nc_object_count) {
657 DEBUG(0,("Exop on[%s] objects[%u/%u] linked_values[%u/%u]\n",
658 c->partition->nc.dn, s->total_objects, nc_object_count,
659 linked_attributes_count, nc_linked_attributes_count));
660 } else {
661 DEBUG(0,("Exop on[%s] objects[%u] linked_values[%u]\n",
662 c->partition->nc.dn, s->total_objects, linked_attributes_count));
664 } else {
665 if (nc_object_count) {
666 DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n",
667 c->partition->nc.dn, s->total_objects, nc_object_count,
668 linked_attributes_count, nc_linked_attributes_count));
669 } else {
670 DEBUG(0,("Partition[%s] objects[%u] linked_values[%u]\n",
671 c->partition->nc.dn, s->total_objects, linked_attributes_count));
676 schema = dsdb_get_schema(s->ldb, NULL);
677 if (!schema) {
678 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
679 return NT_STATUS_INTERNAL_ERROR;
682 status = dsdb_replicated_objects_convert(s->ldb,
683 schema,
684 c->partition->nc.dn,
685 mapping_ctr,
686 object_count,
687 first_object,
688 linked_attributes_count,
689 linked_attributes,
690 s_dsa,
691 uptodateness_vector,
692 c->gensec_skey,
694 s, &objs);
695 if (!W_ERROR_IS_OK(status)) {
696 DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status)));
697 return werror_to_ntstatus(status);
700 if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
701 for (i=0; i < objs->num_objects; i++) {
702 struct ldb_ldif ldif;
703 fprintf(stdout, "#\n");
704 ldif.changetype = LDB_CHANGETYPE_NONE;
705 ldif.msg = objs->objects[i].msg;
706 ldb_ldif_write_file(s->ldb, stdout, &ldif);
707 NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
710 status = dsdb_replicated_objects_commit(s->ldb, NULL, objs, &seq_num);
711 if (!W_ERROR_IS_OK(status)) {
712 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
713 return werror_to_ntstatus(status);
716 talloc_free(s_dsa);
717 talloc_free(objs);
719 for (i=0; i < linked_attributes_count; i++) {
720 const struct dsdb_attribute *sa;
722 if (!linked_attributes[i].identifier) {
723 DEBUG(0, ("No linked attribute identifier\n"));
724 return NT_STATUS_FOOBAR;
727 if (!linked_attributes[i].value.blob) {
728 DEBUG(0, ("No linked attribute value\n"));
729 return NT_STATUS_FOOBAR;
732 sa = dsdb_attribute_by_attributeID_id(s->schema,
733 linked_attributes[i].attid);
734 if (!sa) {
735 DEBUG(0, ("Unable to find attribute via attribute id %d\n", linked_attributes[i].attid));
736 return NT_STATUS_FOOBAR;
739 if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
740 DEBUG(0,("# %s\n", sa->lDAPDisplayName));
741 NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, &linked_attributes[i]);
742 dump_data(0,
743 linked_attributes[i].value.blob->data,
744 linked_attributes[i].value.blob->length);
748 return NT_STATUS_OK;
751 static NTSTATUS update_dnshostname_for_server(TALLOC_CTX *mem_ctx,
752 struct ldb_context *ldb,
753 const char *server_dn_str,
754 const char *netbios_name,
755 const char *realm)
757 int ret;
758 struct ldb_message *msg;
759 struct ldb_message_element *el;
760 struct ldb_dn *server_dn;
761 const char *dNSHostName = strlower_talloc(mem_ctx,
762 talloc_asprintf(mem_ctx,
763 "%s.%s",
764 netbios_name,
765 realm));
766 msg = ldb_msg_new(mem_ctx);
767 if (msg == NULL) {
768 return NT_STATUS_NO_MEMORY;
771 server_dn = ldb_dn_new(mem_ctx, ldb, server_dn_str);
772 if (!server_dn) {
773 return NT_STATUS_INTERNAL_ERROR;
776 msg->dn = server_dn;
777 ret = ldb_msg_add_empty(msg, "dNSHostName", LDB_FLAG_MOD_ADD, &el);
778 if (ret != LDB_SUCCESS) {
779 return NT_STATUS_INTERNAL_ERROR;
782 ret = ldb_msg_add_steal_string(msg,
783 "dNSHostName",
784 talloc_asprintf(el->values, "%s", dNSHostName));
785 if (ret != LDB_SUCCESS) {
786 return NT_STATUS_INTERNAL_ERROR;
789 ret = dsdb_modify(ldb, msg, DSDB_MODIFY_PERMISSIVE);
790 if (ret != LDB_SUCCESS) {
791 DEBUG(0,(__location__ ": Failed to add dnsHostName to the Server object: %s\n",
792 ldb_errstring(ldb)));
793 return NT_STATUS_INTERNAL_ERROR;
796 return NT_STATUS_OK;
800 NTSTATUS libnet_Vampire(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
801 struct libnet_Vampire *r)
803 struct libnet_JoinDomain *join;
804 struct libnet_Replicate rep;
805 NTSTATUS status;
807 const char *account_name;
808 const char *netbios_name;
810 r->out.error_string = NULL;
812 join = talloc_zero(mem_ctx, struct libnet_JoinDomain);
813 if (!join) {
814 return NT_STATUS_NO_MEMORY;
817 if (r->in.netbios_name != NULL) {
818 netbios_name = r->in.netbios_name;
819 } else {
820 netbios_name = talloc_reference(join, lpcfg_netbios_name(ctx->lp_ctx));
821 if (!netbios_name) {
822 talloc_free(join);
823 r->out.error_string = NULL;
824 return NT_STATUS_NO_MEMORY;
828 account_name = talloc_asprintf(join, "%s$", netbios_name);
829 if (!account_name) {
830 talloc_free(join);
831 r->out.error_string = NULL;
832 return NT_STATUS_NO_MEMORY;
835 /* Re-use the domain we are joining as the domain for the user
836 * to be authenticated with, unless they specified
837 * otherwise */
838 cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
840 join->in.domain_name = r->in.domain_name;
841 join->in.account_name = account_name;
842 join->in.netbios_name = netbios_name;
843 join->in.level = LIBNET_JOINDOMAIN_AUTOMATIC;
844 join->in.acct_type = ACB_WSTRUST;
845 join->in.recreate_account = false;
846 status = libnet_JoinDomain(ctx, join, join);
847 if (!NT_STATUS_IS_OK(status)) {
848 r->out.error_string = talloc_steal(mem_ctx, join->out.error_string);
849 talloc_free(join);
850 return status;
853 rep.in.domain_name = join->out.domain_name;
854 rep.in.netbios_name = netbios_name;
855 rep.in.targetdir = r->in.targetdir;
856 rep.in.domain_sid = join->out.domain_sid;
857 rep.in.realm = join->out.realm;
858 rep.in.server = dcerpc_binding_get_string_option(join->out.samr_binding,
859 "host");
860 rep.in.join_password = join->out.join_password;
861 rep.in.kvno = join->out.kvno;
863 status = libnet_Replicate(ctx, mem_ctx, &rep);
865 r->out.domain_sid = join->out.domain_sid;
866 r->out.domain_name = join->out.domain_name;
867 r->out.error_string = rep.out.error_string;
869 return status;
874 NTSTATUS libnet_Replicate(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
875 struct libnet_Replicate *r)
877 struct provision_store_self_join_settings *set_secrets;
878 struct libnet_BecomeDC b;
879 struct libnet_vampire_cb_state *s;
880 struct ldb_message *msg;
881 const char *error_string;
882 int ldb_ret;
883 uint32_t i;
884 NTSTATUS status;
885 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
886 const char *account_name;
887 const char *netbios_name;
889 r->out.error_string = NULL;
891 netbios_name = r->in.netbios_name;
892 account_name = talloc_asprintf(tmp_ctx, "%s$", netbios_name);
893 if (!account_name) {
894 talloc_free(tmp_ctx);
895 r->out.error_string = NULL;
896 return NT_STATUS_NO_MEMORY;
899 /* Re-use the domain we are joining as the domain for the user
900 * to be authenticated with, unless they specified
901 * otherwise */
902 cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
904 s = libnet_vampire_cb_state_init(mem_ctx, ctx->lp_ctx, ctx->event_ctx,
905 netbios_name, r->in.domain_name, r->in.realm,
906 r->in.targetdir);
907 if (!s) {
908 return NT_STATUS_NO_MEMORY;
910 talloc_steal(s, tmp_ctx);
912 ZERO_STRUCT(b);
914 /* Be more robust:
915 * We now know the domain and realm for sure - if they didn't
916 * put one on the command line, use this for the rest of the
917 * join */
918 cli_credentials_set_realm(ctx->cred, r->in.realm, CRED_GUESS_ENV);
919 cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
921 /* Now set these values into the smb.conf - we probably had
922 * empty or useless defaults here from whatever smb.conf we
923 * started with */
924 lpcfg_set_cmdline(s->lp_ctx, "realm", r->in.realm);
925 lpcfg_set_cmdline(s->lp_ctx, "workgroup", r->in.domain_name);
927 b.in.domain_dns_name = r->in.realm;
928 b.in.domain_netbios_name = r->in.domain_name;
929 b.in.domain_sid = r->in.domain_sid;
930 b.in.source_dsa_address = r->in.server;
931 b.in.dest_dsa_netbios_name = netbios_name;
933 b.in.callbacks.private_data = s;
934 b.in.callbacks.check_options = libnet_vampire_cb_check_options;
935 b.in.callbacks.prepare_db = libnet_vampire_cb_prepare_db;
936 b.in.callbacks.schema_chunk = libnet_vampire_cb_schema_chunk;
937 b.in.callbacks.config_chunk = libnet_vampire_cb_store_chunk;
938 b.in.callbacks.domain_chunk = libnet_vampire_cb_store_chunk;
940 b.in.rodc_join = lpcfg_parm_bool(s->lp_ctx, NULL, "repl", "RODC", false);
942 status = libnet_BecomeDC(ctx, s, &b);
943 if (!NT_STATUS_IS_OK(status)) {
944 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
945 talloc_free(s);
946 return status;
949 msg = ldb_msg_new(s);
950 if (!msg) {
951 printf("ldb_msg_new() failed\n");
952 talloc_free(s);
953 return NT_STATUS_NO_MEMORY;
955 msg->dn = ldb_dn_new(msg, s->ldb, "@ROOTDSE");
956 if (!msg->dn) {
957 printf("ldb_msg_new(@ROOTDSE) failed\n");
958 talloc_free(s);
959 return NT_STATUS_NO_MEMORY;
962 ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE");
963 if (ldb_ret != LDB_SUCCESS) {
964 printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret);
965 talloc_free(s);
966 return NT_STATUS_NO_MEMORY;
969 for (i=0; i < msg->num_elements; i++) {
970 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
973 printf("mark ROOTDSE with isSynchronized=TRUE\n");
974 ldb_ret = ldb_modify(s->ldb, msg);
975 if (ldb_ret != LDB_SUCCESS) {
976 printf("ldb_modify() failed: %d : %s\n", ldb_ret, ldb_errstring(s->ldb));
977 talloc_free(s);
978 return NT_STATUS_INTERNAL_DB_ERROR;
980 /* during dcpromo the 2nd computer adds dNSHostName attribute to his Server object
981 * the attribute appears on the original DC after replication
983 status = update_dnshostname_for_server(s, s->ldb, s->server_dn_str, s->netbios_name, s->realm);
984 if (!NT_STATUS_IS_OK(status)) {
985 printf("Failed to update dNSHostName on Server object - %s\n", nt_errstr(status));
986 talloc_free(s);
987 return status;
989 /* prepare the transaction - this prepares to commit all the changes in
990 the ldb from the whole vampire. Note that this
991 triggers the writing of the linked attribute backlinks.
993 if (ldb_transaction_prepare_commit(s->ldb) != LDB_SUCCESS) {
994 printf("Failed to prepare_commit vampire transaction: %s\n", ldb_errstring(s->ldb));
995 return NT_STATUS_INTERNAL_DB_ERROR;
998 set_secrets = talloc(s, struct provision_store_self_join_settings);
999 if (!set_secrets) {
1000 r->out.error_string = NULL;
1001 talloc_free(s);
1002 return NT_STATUS_NO_MEMORY;
1005 ZERO_STRUCTP(set_secrets);
1006 set_secrets->domain_name = r->in.domain_name;
1007 set_secrets->realm = r->in.realm;
1008 set_secrets->netbios_name = netbios_name;
1009 set_secrets->secure_channel_type = SEC_CHAN_BDC;
1010 set_secrets->machine_password = r->in.join_password;
1011 set_secrets->key_version_number = r->in.kvno;
1012 set_secrets->domain_sid = r->in.domain_sid;
1014 status = provision_store_self_join(ctx, s->lp_ctx, ctx->event_ctx, set_secrets, &error_string);
1015 if (!NT_STATUS_IS_OK(status)) {
1016 r->out.error_string = talloc_steal(mem_ctx, error_string);
1017 talloc_free(s);
1018 return status;
1021 /* commit the transaction now we know the secrets were written
1022 * out properly
1024 if (ldb_transaction_commit(s->ldb) != LDB_SUCCESS) {
1025 printf("Failed to commit vampire transaction\n");
1026 return NT_STATUS_INTERNAL_DB_ERROR;
1029 talloc_free(s);
1031 return NT_STATUS_OK;