s3-waf: Build libwbclient as dynamic library
[Samba/gebeck_regimport.git] / source4 / libnet / libnet_vampire.c
blob1b6a8dd24407896a383fbeb353cb025bcfe1f13e
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 "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/dom_sid.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 /* 2nd pass, with full ID->OID->name table */
72 struct dsdb_schema *self_corrected_schema;
74 /* prefixMap in LDB format, from the remote DRS server */
75 DATA_BLOB prefixmap_blob;
76 const struct dsdb_schema *schema;
78 struct ldb_context *ldb;
80 struct {
81 uint32_t object_count;
82 struct drsuapi_DsReplicaObjectListItemEx *first_object;
83 struct drsuapi_DsReplicaObjectListItemEx *last_object;
84 } schema_part;
86 const char *targetdir;
88 struct loadparm_context *lp_ctx;
89 struct tevent_context *event_ctx;
90 unsigned total_objects;
91 char *last_partition;
92 const char *server_dn_str;
95 /* initialise a state structure ready for replication of chunks */
96 void *libnet_vampire_replicate_init(TALLOC_CTX *mem_ctx,
97 struct ldb_context *samdb,
98 struct loadparm_context *lp_ctx)
100 struct libnet_vampire_cb_state *s = talloc_zero(mem_ctx, struct libnet_vampire_cb_state);
101 if (!s) {
102 return NULL;
105 s->ldb = samdb;
106 s->lp_ctx = lp_ctx;
107 s->provision_schema = dsdb_get_schema(s->ldb, s);
108 s->schema = s->provision_schema;
109 s->netbios_name = lpcfg_netbios_name(lp_ctx);
110 s->domain_name = lpcfg_workgroup(lp_ctx);
111 s->realm = lpcfg_realm(lp_ctx);
113 return s;
116 /* Caller is expected to keep supplied pointers around for the lifetime of the structure */
117 void *libnet_vampire_cb_state_init(TALLOC_CTX *mem_ctx,
118 struct loadparm_context *lp_ctx, struct tevent_context *event_ctx,
119 const char *netbios_name, const char *domain_name, const char *realm,
120 const char *targetdir)
122 struct libnet_vampire_cb_state *s = talloc_zero(mem_ctx, struct libnet_vampire_cb_state);
123 if (!s) {
124 return NULL;
127 s->lp_ctx = lp_ctx;
128 s->event_ctx = event_ctx;
129 s->netbios_name = netbios_name;
130 s->domain_name = domain_name;
131 s->realm = realm;
132 s->targetdir = targetdir;
133 return s;
136 struct ldb_context *libnet_vampire_cb_ldb(struct libnet_vampire_cb_state *state)
138 state = talloc_get_type_abort(state, struct libnet_vampire_cb_state);
139 return state->ldb;
142 struct loadparm_context *libnet_vampire_cb_lp_ctx(struct libnet_vampire_cb_state *state)
144 state = talloc_get_type_abort(state, struct libnet_vampire_cb_state);
145 return state->lp_ctx;
148 NTSTATUS libnet_vampire_cb_prepare_db(void *private_data,
149 const struct libnet_BecomeDC_PrepareDB *p)
151 struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
152 struct provision_settings settings;
153 struct provision_result result;
154 NTSTATUS status;
156 ZERO_STRUCT(settings);
157 settings.site_name = p->dest_dsa->site_name;
158 settings.root_dn_str = p->forest->root_dn_str;
159 settings.domain_dn_str = p->domain->dn_str;
160 settings.config_dn_str = p->forest->config_dn_str;
161 settings.schema_dn_str = p->forest->schema_dn_str;
162 settings.netbios_name = p->dest_dsa->netbios_name;
163 settings.realm = s->realm;
164 settings.domain = s->domain_name;
165 settings.server_dn_str = p->dest_dsa->server_dn_str;
166 settings.machine_password = generate_random_password(s, 16, 255);
167 settings.targetdir = s->targetdir;
169 status = provision_bare(s, s->lp_ctx, &settings, &result);
171 if (!NT_STATUS_IS_OK(status)) {
172 return status;
175 s->ldb = talloc_steal(s, result.samdb);
176 s->lp_ctx = talloc_steal(s, result.lp_ctx);
177 s->provision_schema = dsdb_get_schema(s->ldb, s);
178 s->server_dn_str = talloc_steal(s, p->dest_dsa->server_dn_str);
180 /* wrap the entire vapire operation in a transaction. This
181 isn't just cosmetic - we use this to ensure that linked
182 attribute back links are added at the end by relying on a
183 transaction commit hook in the linked attributes module. We
184 need to do this as the order of objects coming from the
185 server is not sufficiently deterministic to know that the
186 record that a backlink needs to be created in has itself
187 been created before the object containing the forward link
188 has come over the wire */
189 if (ldb_transaction_start(s->ldb) != LDB_SUCCESS) {
190 return NT_STATUS_FOOBAR;
193 return NT_STATUS_OK;
198 NTSTATUS libnet_vampire_cb_check_options(void *private_data,
199 const struct libnet_BecomeDC_CheckOptions *o)
201 struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
203 DEBUG(0,("Become DC [%s] of Domain[%s]/[%s]\n",
204 s->netbios_name,
205 o->domain->netbios_name, o->domain->dns_name));
207 DEBUG(0,("Promotion Partner is Server[%s] from Site[%s]\n",
208 o->source_dsa->dns_name, o->source_dsa->site_name));
210 DEBUG(0,("Options:crossRef behavior_version[%u]\n"
211 "\tschema object_version[%u]\n"
212 "\tdomain behavior_version[%u]\n"
213 "\tdomain w2k3_update_revision[%u]\n",
214 o->forest->crossref_behavior_version,
215 o->forest->schema_object_version,
216 o->domain->behavior_version,
217 o->domain->w2k3_update_revision));
219 return NT_STATUS_OK;
222 static NTSTATUS libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s,
223 const struct libnet_BecomeDC_StoreChunk *c)
225 WERROR status;
226 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
227 uint32_t object_count;
228 struct drsuapi_DsReplicaObjectListItemEx *first_object;
229 const struct drsuapi_DsReplicaObjectListItemEx *cur;
230 uint32_t linked_attributes_count;
231 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
232 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
233 struct dsdb_extended_replicated_objects *schema_objs;
234 struct repsFromTo1 *s_dsa;
235 char *tmp_dns_name;
236 struct ldb_context *schema_ldb;
237 struct ldb_message *msg;
238 struct ldb_message_element *prefixMap_el;
239 uint32_t i;
240 int ret;
241 bool ok;
242 uint64_t seq_num;
244 DEBUG(0,("Analyze and apply schema objects\n"));
246 s_dsa = talloc_zero(s, struct repsFromTo1);
247 NT_STATUS_HAVE_NO_MEMORY(s_dsa);
248 s_dsa->other_info = talloc(s_dsa, struct repsFromTo1OtherInfo);
249 NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
251 switch (c->ctr_level) {
252 case 1:
253 mapping_ctr = &c->ctr1->mapping_ctr;
254 object_count = s->schema_part.object_count;
255 first_object = s->schema_part.first_object;
256 linked_attributes_count = 0;
257 linked_attributes = NULL;
258 s_dsa->highwatermark = c->ctr1->new_highwatermark;
259 s_dsa->source_dsa_obj_guid = c->ctr1->source_dsa_guid;
260 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
261 uptodateness_vector = NULL; /* TODO: map it */
262 break;
263 case 6:
264 mapping_ctr = &c->ctr6->mapping_ctr;
265 object_count = s->schema_part.object_count;
266 first_object = s->schema_part.first_object;
267 linked_attributes_count = c->ctr6->linked_attributes_count;
268 linked_attributes = c->ctr6->linked_attributes;
269 s_dsa->highwatermark = c->ctr6->new_highwatermark;
270 s_dsa->source_dsa_obj_guid = c->ctr6->source_dsa_guid;
271 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
272 uptodateness_vector = c->ctr6->uptodateness_vector;
273 break;
274 default:
275 return NT_STATUS_INVALID_PARAMETER;
278 s_dsa->replica_flags = DRSUAPI_DRS_WRIT_REP
279 | DRSUAPI_DRS_INIT_SYNC
280 | DRSUAPI_DRS_PER_SYNC;
281 memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
283 tmp_dns_name = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
284 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
285 tmp_dns_name = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
286 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
287 s_dsa->other_info->dns_name = tmp_dns_name;
289 schema_ldb = provision_get_schema(s, s->lp_ctx, &s->prefixmap_blob);
290 if (!schema_ldb) {
291 DEBUG(0,("Failed to re-load from local provision using remote prefixMap. Will continue with local prefixMap\n"));
292 s->provision_schema = dsdb_get_schema(s->ldb, s);
293 } else {
294 s->provision_schema = dsdb_get_schema(schema_ldb, s);
295 ret = dsdb_reference_schema(s->ldb, s->provision_schema, false);
296 if (ret != LDB_SUCCESS) {
297 DEBUG(0,("Failed to attach schema from local provision using remote prefixMap."));
298 return NT_STATUS_UNSUCCESSFUL;
300 talloc_free(schema_ldb);
303 s->provision_schema->relax_OID_conversions = true;
305 /* Now convert the schema elements, using the schema we loaded locally */
306 for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
307 struct dsdb_extended_replicated_object object;
308 TALLOC_CTX *tmp_ctx = talloc_new(s);
309 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
311 /* Convert the objects into LDB messages using the
312 * provision schema, and either the provision or DRS
313 * prefix map - it should not matter, as these are
314 * just schema objects, so the critical parts. At
315 * most we would mix up the mayContain etc for new
316 * schema classes */
317 status = dsdb_convert_object_ex(s->ldb, s->provision_schema,
318 cur, c->gensec_skey,
319 tmp_ctx, &object);
320 if (!W_ERROR_IS_OK(status)) {
321 DEBUG(1,("Warning: Failed to convert schema object %s into ldb msg\n", cur->object.identifier->dn));
322 } else {
323 /* Convert the schema from ldb_message format
324 * (OIDs as OID strings) into schema, using
325 * the remote prefixMap */
326 status = dsdb_schema_set_el_from_ldb_msg(s->ldb, s->self_made_schema, object.msg);
327 if (!W_ERROR_IS_OK(status)) {
328 DEBUG(1,("Warning: failed to convert object %s into a schema element: %s\n",
329 ldb_dn_get_linearized(object.msg->dn),
330 win_errstr(status)));
333 talloc_free(tmp_ctx);
336 /* attach the schema we just brought over DRS to the ldb, so we can use it in dsdb_convert_object_ex below */
337 ret = dsdb_set_schema(s->ldb, s->self_made_schema);
338 if (ret != LDB_SUCCESS) {
339 DEBUG(0,("Failed to attach 1st pass schema from DRS.\n"));
340 return NT_STATUS_FOOBAR;
343 /* Now convert the schema elements again, using the schema we loaded over DRS */
344 for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
345 struct dsdb_extended_replicated_object object;
346 TALLOC_CTX *tmp_ctx = talloc_new(s);
347 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
349 /* Convert the objects into LDB messages using the
350 * self_made_schema, and the DRS prefix map. We now
351 * know the full schema int->OID->name mapping, so we
352 * can get it right this time */
353 status = dsdb_convert_object_ex(s->ldb, s->self_made_schema,
354 cur, c->gensec_skey,
355 tmp_ctx, &object);
356 if (!W_ERROR_IS_OK(status)) {
357 DEBUG(0,("ERROR: Failed to convert schema object %s into ldb msg\n", cur->object.identifier->dn));
358 } else {
359 /* Convert the schema from ldb_message format
360 * (OIDs as OID strings) into schema, using
361 * the remote prefixMap, now that we know
362 * names for all the schema elements (from the
363 * first conversion) */
364 status = dsdb_schema_set_el_from_ldb_msg(s->ldb, s->self_corrected_schema, object.msg);
365 if (!W_ERROR_IS_OK(status)) {
366 DEBUG(0,("ERROR: failed to convert object %s into a schema element: %s\n",
367 ldb_dn_get_linearized(object.msg->dn),
368 win_errstr(status)));
371 talloc_free(tmp_ctx);
374 /* We don't want to use the s->self_made_schema any more */
375 s->self_made_schema = NULL;
377 /* attach the schema we just brought over DRS to the ldb */
378 ret = dsdb_set_schema(s->ldb, s->self_corrected_schema);
379 if (ret != LDB_SUCCESS) {
380 DEBUG(0,("Failed to attach 2nd pass (corrected) schema from DRS.\n"));
381 return NT_STATUS_FOOBAR;
384 /* we don't want to access the self made schema anymore */
385 s->schema = s->self_corrected_schema;
386 s->self_corrected_schema = NULL;
388 /* Now convert the schema elements again, using the schema we finalised, ready to actually import */
389 status = dsdb_extended_replicated_objects_convert(s->ldb,
390 c->partition->nc.dn,
391 mapping_ctr,
392 object_count,
393 first_object,
394 linked_attributes_count,
395 linked_attributes,
396 s_dsa,
397 uptodateness_vector,
398 c->gensec_skey,
399 s, &schema_objs);
400 if (!W_ERROR_IS_OK(status)) {
401 DEBUG(0,("Failed to convert objects when trying to import over DRS (2nd pass, to store remote schema): %s\n", win_errstr(status)));
402 return werror_to_ntstatus(status);
405 if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
406 for (i=0; i < schema_objs->num_objects; i++) {
407 struct ldb_ldif ldif;
408 fprintf(stdout, "#\n");
409 ldif.changetype = LDB_CHANGETYPE_NONE;
410 ldif.msg = schema_objs->objects[i].msg;
411 ldb_ldif_write_file(s->ldb, stdout, &ldif);
412 NDR_PRINT_DEBUG(replPropertyMetaDataBlob, schema_objs->objects[i].meta_data);
416 status = dsdb_extended_replicated_objects_commit(s->ldb, schema_objs, &seq_num);
417 if (!W_ERROR_IS_OK(status)) {
418 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
419 return werror_to_ntstatus(status);
422 msg = ldb_msg_new(schema_objs);
423 NT_STATUS_HAVE_NO_MEMORY(msg);
424 msg->dn = schema_objs->partition_dn;
426 /* We must ensure a prefixMap has been written. Unlike other
427 * attributes (including schemaInfo), it is not replicated in
428 * the normal replication stream. We can use the one from
429 * s->prefixmap_blob because we operate with one, unchanging
430 * prefixMap for this entire operation. */
431 ret = ldb_msg_add_value(msg, "prefixMap", &s->prefixmap_blob, &prefixMap_el);
432 if (ret != LDB_SUCCESS) {
433 return NT_STATUS_FOOBAR;
435 /* We want to know if a prefixMap was written already, as it
436 * would mean that the above comment was not true, and we have
437 * somehow updated the prefixMap during this transaction */
438 prefixMap_el->flags = LDB_FLAG_MOD_ADD;
440 ret = ldb_modify(s->ldb, msg);
441 if (ret != LDB_SUCCESS) {
442 DEBUG(0,("Failed to add prefixMap: %s\n", ldb_errstring(s->ldb)));
443 return NT_STATUS_FOOBAR;
446 talloc_free(s_dsa);
447 talloc_free(schema_objs);
449 /* We must set these up to ensure the replMetaData is written
450 * correctly, before our NTDS Settings entry is replicated */
451 ok = samdb_set_ntds_invocation_id(s->ldb, &c->dest_dsa->invocation_id);
452 if (!ok) {
453 DEBUG(0,("Failed to set cached ntds invocationId\n"));
454 return NT_STATUS_FOOBAR;
456 ok = samdb_set_ntds_objectGUID(s->ldb, &c->dest_dsa->ntds_guid);
457 if (!ok) {
458 DEBUG(0,("Failed to set cached ntds objectGUID\n"));
459 return NT_STATUS_FOOBAR;
462 s->schema = dsdb_get_schema(s->ldb, s);
463 if (!s->schema) {
464 DEBUG(0,("Failed to get loaded dsdb_schema\n"));
465 return NT_STATUS_FOOBAR;
468 return NT_STATUS_OK;
471 NTSTATUS libnet_vampire_cb_schema_chunk(void *private_data,
472 const struct libnet_BecomeDC_StoreChunk *c)
474 struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
475 WERROR status;
476 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
477 uint32_t nc_object_count;
478 uint32_t object_count;
479 struct drsuapi_DsReplicaObjectListItemEx *first_object;
480 struct drsuapi_DsReplicaObjectListItemEx *cur;
481 uint32_t nc_linked_attributes_count;
482 uint32_t linked_attributes_count;
483 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
485 switch (c->ctr_level) {
486 case 1:
487 mapping_ctr = &c->ctr1->mapping_ctr;
488 nc_object_count = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
489 object_count = c->ctr1->object_count;
490 first_object = c->ctr1->first_object;
491 nc_linked_attributes_count = 0;
492 linked_attributes_count = 0;
493 linked_attributes = NULL;
494 break;
495 case 6:
496 mapping_ctr = &c->ctr6->mapping_ctr;
497 nc_object_count = c->ctr6->nc_object_count;
498 object_count = c->ctr6->object_count;
499 first_object = c->ctr6->first_object;
500 nc_linked_attributes_count = c->ctr6->nc_linked_attributes_count;
501 linked_attributes_count = c->ctr6->linked_attributes_count;
502 linked_attributes = c->ctr6->linked_attributes;
503 break;
504 default:
505 return NT_STATUS_INVALID_PARAMETER;
508 if (nc_object_count) {
509 DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n",
510 c->partition->nc.dn, object_count, nc_object_count,
511 linked_attributes_count, nc_linked_attributes_count));
512 } else {
513 DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u]\n",
514 c->partition->nc.dn, object_count, linked_attributes_count));
517 if (!s->self_made_schema) {
518 WERROR werr;
519 struct drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr_without_schema_info;
520 /* Put the DRS prefixmap aside for the schema we are
521 * about to load in the provision, and into the one we
522 * are making with the help of DRS */
524 mapping_ctr_without_schema_info = *mapping_ctr;
526 /* This strips off the 0xFF schema info from the end,
527 * because we don't want it in the blob */
528 if (mapping_ctr_without_schema_info.num_mappings > 0) {
529 mapping_ctr_without_schema_info.num_mappings--;
531 werr = dsdb_get_drsuapi_prefixmap_as_blob(&mapping_ctr_without_schema_info, s, &s->prefixmap_blob);
532 if (!W_ERROR_IS_OK(werr)) {
533 return werror_to_ntstatus(werr);
536 /* Set up two manually-constructed schema - the local
537 * schema from the provision will be used to build
538 * one, which will then in turn be used to build the
539 * other. */
540 s->self_made_schema = dsdb_new_schema(s);
541 NT_STATUS_HAVE_NO_MEMORY(s->self_made_schema);
542 s->self_corrected_schema = dsdb_new_schema(s);
543 NT_STATUS_HAVE_NO_MEMORY(s->self_corrected_schema);
545 status = dsdb_load_prefixmap_from_drsuapi(s->self_made_schema, mapping_ctr);
546 if (!W_ERROR_IS_OK(status)) {
547 return werror_to_ntstatus(status);
550 status = dsdb_load_prefixmap_from_drsuapi(s->self_corrected_schema, mapping_ctr);
551 if (!W_ERROR_IS_OK(status)) {
552 return werror_to_ntstatus(status);
554 } else {
555 status = dsdb_schema_pfm_contains_drsuapi_pfm(s->self_made_schema->prefixmap, mapping_ctr);
556 if (!W_ERROR_IS_OK(status)) {
557 return werror_to_ntstatus(status);
561 if (!s->schema_part.first_object) {
562 s->schema_part.object_count = object_count;
563 s->schema_part.first_object = talloc_steal(s, first_object);
564 } else {
565 s->schema_part.object_count += object_count;
566 s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
567 first_object);
569 for (cur = first_object; cur->next_object; cur = cur->next_object) {}
570 s->schema_part.last_object = cur;
572 if (!c->partition->more_data) {
573 return libnet_vampire_cb_apply_schema(s, c);
576 return NT_STATUS_OK;
579 NTSTATUS libnet_vampire_cb_store_chunk(void *private_data,
580 const struct libnet_BecomeDC_StoreChunk *c)
582 struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
583 WERROR status;
584 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
585 uint32_t nc_object_count;
586 uint32_t object_count;
587 struct drsuapi_DsReplicaObjectListItemEx *first_object;
588 uint32_t nc_linked_attributes_count;
589 uint32_t linked_attributes_count;
590 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
591 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
592 struct dsdb_extended_replicated_objects *objs;
593 struct repsFromTo1 *s_dsa;
594 char *tmp_dns_name;
595 uint32_t i;
596 uint64_t seq_num;
598 s_dsa = talloc_zero(s, struct repsFromTo1);
599 NT_STATUS_HAVE_NO_MEMORY(s_dsa);
600 s_dsa->other_info = talloc(s_dsa, struct repsFromTo1OtherInfo);
601 NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
603 switch (c->ctr_level) {
604 case 1:
605 mapping_ctr = &c->ctr1->mapping_ctr;
606 nc_object_count = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
607 object_count = c->ctr1->object_count;
608 first_object = c->ctr1->first_object;
609 nc_linked_attributes_count = 0;
610 linked_attributes_count = 0;
611 linked_attributes = NULL;
612 s_dsa->highwatermark = c->ctr1->new_highwatermark;
613 s_dsa->source_dsa_obj_guid = c->ctr1->source_dsa_guid;
614 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
615 uptodateness_vector = NULL; /* TODO: map it */
616 break;
617 case 6:
618 mapping_ctr = &c->ctr6->mapping_ctr;
619 nc_object_count = c->ctr6->nc_object_count;
620 object_count = c->ctr6->object_count;
621 first_object = c->ctr6->first_object;
622 nc_linked_attributes_count = c->ctr6->nc_linked_attributes_count;
623 linked_attributes_count = c->ctr6->linked_attributes_count;
624 linked_attributes = c->ctr6->linked_attributes;
625 s_dsa->highwatermark = c->ctr6->new_highwatermark;
626 s_dsa->source_dsa_obj_guid = c->ctr6->source_dsa_guid;
627 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
628 uptodateness_vector = c->ctr6->uptodateness_vector;
629 break;
630 default:
631 return NT_STATUS_INVALID_PARAMETER;
634 s_dsa->replica_flags = DRSUAPI_DRS_WRIT_REP
635 | DRSUAPI_DRS_INIT_SYNC
636 | DRSUAPI_DRS_PER_SYNC;
637 memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
639 tmp_dns_name = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
640 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
641 tmp_dns_name = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
642 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
643 s_dsa->other_info->dns_name = tmp_dns_name;
645 /* we want to show a count per partition */
646 if (!s->last_partition || strcmp(s->last_partition, c->partition->nc.dn) != 0) {
647 s->total_objects = 0;
648 talloc_free(s->last_partition);
649 s->last_partition = talloc_strdup(s, c->partition->nc.dn);
651 s->total_objects += object_count;
653 if (nc_object_count) {
654 DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n",
655 c->partition->nc.dn, s->total_objects, nc_object_count,
656 linked_attributes_count, nc_linked_attributes_count));
657 } else {
658 DEBUG(0,("Partition[%s] objects[%u] linked_values[%u]\n",
659 c->partition->nc.dn, s->total_objects, linked_attributes_count));
663 status = dsdb_extended_replicated_objects_convert(s->ldb,
664 c->partition->nc.dn,
665 mapping_ctr,
666 object_count,
667 first_object,
668 linked_attributes_count,
669 linked_attributes,
670 s_dsa,
671 uptodateness_vector,
672 c->gensec_skey,
673 s, &objs);
674 if (!W_ERROR_IS_OK(status)) {
675 DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status)));
676 return werror_to_ntstatus(status);
679 if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
680 for (i=0; i < objs->num_objects; i++) {
681 struct ldb_ldif ldif;
682 fprintf(stdout, "#\n");
683 ldif.changetype = LDB_CHANGETYPE_NONE;
684 ldif.msg = objs->objects[i].msg;
685 ldb_ldif_write_file(s->ldb, stdout, &ldif);
686 NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
689 status = dsdb_extended_replicated_objects_commit(s->ldb,
690 objs, &seq_num);
691 if (!W_ERROR_IS_OK(status)) {
692 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
693 return werror_to_ntstatus(status);
696 talloc_free(s_dsa);
697 talloc_free(objs);
699 for (i=0; i < linked_attributes_count; i++) {
700 const struct dsdb_attribute *sa;
702 if (!linked_attributes[i].identifier) {
703 return NT_STATUS_FOOBAR;
706 if (!linked_attributes[i].value.blob) {
707 return NT_STATUS_FOOBAR;
710 sa = dsdb_attribute_by_attributeID_id(s->schema,
711 linked_attributes[i].attid);
712 if (!sa) {
713 return NT_STATUS_FOOBAR;
716 if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
717 DEBUG(0,("# %s\n", sa->lDAPDisplayName));
718 NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, &linked_attributes[i]);
719 dump_data(0,
720 linked_attributes[i].value.blob->data,
721 linked_attributes[i].value.blob->length);
725 return NT_STATUS_OK;
728 static NTSTATUS update_dnshostname_for_server(TALLOC_CTX *mem_ctx,
729 struct ldb_context *ldb,
730 const char *server_dn_str,
731 const char *netbios_name,
732 const char *realm)
734 int ret;
735 struct ldb_message *msg;
736 struct ldb_message_element *el;
737 struct ldb_dn *server_dn;
738 const char *dNSHostName = strlower_talloc(mem_ctx,
739 talloc_asprintf(mem_ctx,
740 "%s.%s",
741 netbios_name,
742 realm));
743 msg = ldb_msg_new(mem_ctx);
744 if (msg == NULL) {
745 return NT_STATUS_NO_MEMORY;
748 server_dn = ldb_dn_new(mem_ctx, ldb, server_dn_str);
749 if (!server_dn) {
750 return NT_STATUS_INTERNAL_ERROR;
753 msg->dn = server_dn;
754 ret = ldb_msg_add_empty(msg, "dNSHostName", LDB_FLAG_MOD_ADD, &el);
755 if (ret != LDB_SUCCESS) {
756 return NT_STATUS_INTERNAL_ERROR;
759 ret = ldb_msg_add_steal_string(msg,
760 "dNSHostName",
761 talloc_asprintf(el->values, "%s", dNSHostName));
762 if (ret != LDB_SUCCESS) {
763 return NT_STATUS_INTERNAL_ERROR;
766 ret = dsdb_modify(ldb, msg, DSDB_MODIFY_PERMISSIVE);
767 if (ret != LDB_SUCCESS) {
768 DEBUG(0,(__location__ ": Failed to add dnsHostName to the Server object: %s\n",
769 ldb_errstring(ldb)));
770 return NT_STATUS_INTERNAL_ERROR;
773 return NT_STATUS_OK;
777 NTSTATUS libnet_Vampire(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
778 struct libnet_Vampire *r)
780 struct libnet_JoinDomain *join;
781 struct libnet_Replicate rep;
782 NTSTATUS status;
784 const char *account_name;
785 const char *netbios_name;
787 r->out.error_string = NULL;
789 join = talloc_zero(mem_ctx, struct libnet_JoinDomain);
790 if (!join) {
791 return NT_STATUS_NO_MEMORY;
794 if (r->in.netbios_name != NULL) {
795 netbios_name = r->in.netbios_name;
796 } else {
797 netbios_name = talloc_reference(join, lpcfg_netbios_name(ctx->lp_ctx));
798 if (!netbios_name) {
799 talloc_free(join);
800 r->out.error_string = NULL;
801 return NT_STATUS_NO_MEMORY;
805 account_name = talloc_asprintf(join, "%s$", netbios_name);
806 if (!account_name) {
807 talloc_free(join);
808 r->out.error_string = NULL;
809 return NT_STATUS_NO_MEMORY;
812 /* Re-use the domain we are joining as the domain for the user
813 * to be authenticated with, unless they specified
814 * otherwise */
815 cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
817 join->in.domain_name = r->in.domain_name;
818 join->in.account_name = account_name;
819 join->in.netbios_name = netbios_name;
820 join->in.level = LIBNET_JOINDOMAIN_AUTOMATIC;
821 join->in.acct_type = ACB_WSTRUST;
822 join->in.recreate_account = false;
823 status = libnet_JoinDomain(ctx, join, join);
824 if (!NT_STATUS_IS_OK(status)) {
825 r->out.error_string = talloc_steal(mem_ctx, join->out.error_string);
826 talloc_free(join);
827 return status;
830 rep.in.domain_name = join->out.domain_name;
831 rep.in.netbios_name = netbios_name;
832 rep.in.targetdir = r->in.targetdir;
833 rep.in.domain_sid = join->out.domain_sid;
834 rep.in.realm = join->out.realm;
835 rep.in.server = join->out.samr_binding->host;
836 rep.in.join_password = join->out.join_password;
837 rep.in.kvno = join->out.kvno;
839 status = libnet_Replicate(ctx, mem_ctx, &rep);
841 r->out.domain_sid = join->out.domain_sid;
842 r->out.domain_name = join->out.domain_name;
843 r->out.error_string = rep.out.error_string;
845 return status;
850 NTSTATUS libnet_Replicate(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
851 struct libnet_Replicate *r)
853 struct provision_store_self_join_settings *set_secrets;
854 struct libnet_BecomeDC b;
855 struct libnet_vampire_cb_state *s;
856 struct ldb_message *msg;
857 const char *error_string;
858 int ldb_ret;
859 uint32_t i;
860 NTSTATUS status;
861 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
862 const char *account_name;
863 const char *netbios_name;
865 r->out.error_string = NULL;
867 netbios_name = r->in.netbios_name;
868 account_name = talloc_asprintf(tmp_ctx, "%s$", netbios_name);
869 if (!account_name) {
870 talloc_free(tmp_ctx);
871 r->out.error_string = NULL;
872 return NT_STATUS_NO_MEMORY;
875 /* Re-use the domain we are joining as the domain for the user
876 * to be authenticated with, unless they specified
877 * otherwise */
878 cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
880 s = libnet_vampire_cb_state_init(mem_ctx, ctx->lp_ctx, ctx->event_ctx,
881 netbios_name, r->in.domain_name, r->in.realm,
882 r->in.targetdir);
883 if (!s) {
884 return NT_STATUS_NO_MEMORY;
886 talloc_steal(s, tmp_ctx);
888 ZERO_STRUCT(b);
890 /* Be more robust:
891 * We now know the domain and realm for sure - if they didn't
892 * put one on the command line, use this for the rest of the
893 * join */
894 cli_credentials_set_realm(ctx->cred, r->in.realm, CRED_GUESS_ENV);
895 cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
897 /* Now set these values into the smb.conf - we probably had
898 * empty or useless defaults here from whatever smb.conf we
899 * started with */
900 lpcfg_set_cmdline(s->lp_ctx, "realm", r->in.realm);
901 lpcfg_set_cmdline(s->lp_ctx, "workgroup", r->in.domain_name);
903 b.in.domain_dns_name = r->in.realm;
904 b.in.domain_netbios_name = r->in.domain_name;
905 b.in.domain_sid = r->in.domain_sid;
906 b.in.source_dsa_address = r->in.server;
907 b.in.dest_dsa_netbios_name = netbios_name;
909 b.in.callbacks.private_data = s;
910 b.in.callbacks.check_options = libnet_vampire_cb_check_options;
911 b.in.callbacks.prepare_db = libnet_vampire_cb_prepare_db;
912 b.in.callbacks.schema_chunk = libnet_vampire_cb_schema_chunk;
913 b.in.callbacks.config_chunk = libnet_vampire_cb_store_chunk;
914 b.in.callbacks.domain_chunk = libnet_vampire_cb_store_chunk;
916 b.in.rodc_join = lpcfg_parm_bool(s->lp_ctx, NULL, "repl", "RODC", false);
918 status = libnet_BecomeDC(ctx, s, &b);
919 if (!NT_STATUS_IS_OK(status)) {
920 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
921 talloc_free(s);
922 return status;
925 msg = ldb_msg_new(s);
926 if (!msg) {
927 printf("ldb_msg_new() failed\n");
928 talloc_free(s);
929 return NT_STATUS_NO_MEMORY;
931 msg->dn = ldb_dn_new(msg, s->ldb, "@ROOTDSE");
932 if (!msg->dn) {
933 printf("ldb_msg_new(@ROOTDSE) failed\n");
934 talloc_free(s);
935 return NT_STATUS_NO_MEMORY;
938 ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE");
939 if (ldb_ret != LDB_SUCCESS) {
940 printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret);
941 talloc_free(s);
942 return NT_STATUS_NO_MEMORY;
945 for (i=0; i < msg->num_elements; i++) {
946 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
949 printf("mark ROOTDSE with isSynchronized=TRUE\n");
950 ldb_ret = ldb_modify(s->ldb, msg);
951 if (ldb_ret != LDB_SUCCESS) {
952 printf("ldb_modify() failed: %d : %s\n", ldb_ret, ldb_errstring(s->ldb));
953 talloc_free(s);
954 return NT_STATUS_INTERNAL_DB_ERROR;
956 /* during dcpromo the 2nd computer adds dNSHostName attribute to his Server object
957 * the attribute appears on the original DC after replication
959 status = update_dnshostname_for_server(s, s->ldb, s->server_dn_str, s->netbios_name, s->realm);
960 if (!NT_STATUS_IS_OK(status)) {
961 printf("Failed to update dNSHostName on Server object - %s\n", nt_errstr(status));
962 talloc_free(s);
963 return status;
965 /* prepare the transaction - this prepares to commit all the changes in
966 the ldb from the whole vampire. Note that this
967 triggers the writing of the linked attribute backlinks.
969 if (ldb_transaction_prepare_commit(s->ldb) != LDB_SUCCESS) {
970 printf("Failed to prepare_commit vampire transaction: %s\n", ldb_errstring(s->ldb));
971 return NT_STATUS_INTERNAL_DB_ERROR;
974 set_secrets = talloc(s, struct provision_store_self_join_settings);
975 if (!set_secrets) {
976 r->out.error_string = NULL;
977 talloc_free(s);
978 return NT_STATUS_NO_MEMORY;
981 ZERO_STRUCTP(set_secrets);
982 set_secrets->domain_name = r->in.domain_name;
983 set_secrets->realm = r->in.realm;
984 set_secrets->netbios_name = netbios_name;
985 set_secrets->secure_channel_type = SEC_CHAN_BDC;
986 set_secrets->machine_password = r->in.join_password;
987 set_secrets->key_version_number = r->in.kvno;
988 set_secrets->domain_sid = r->in.domain_sid;
990 status = provision_store_self_join(ctx, s->lp_ctx, ctx->event_ctx, set_secrets, &error_string);
991 if (!NT_STATUS_IS_OK(status)) {
992 r->out.error_string = talloc_steal(mem_ctx, error_string);
993 talloc_free(s);
994 return status;
997 /* commit the transaction now we know the secrets were written
998 * out properly
1000 if (ldb_transaction_commit(s->ldb) != LDB_SUCCESS) {
1001 printf("Failed to commit vampire transaction\n");
1002 return NT_STATUS_INTERNAL_DB_ERROR;
1005 talloc_free(s);
1007 return NT_STATUS_OK;