dsdb-acl: fix the order of special and system checks
[Samba/gebeck_regimport.git] / source4 / libnet / libnet_vampire.c
blob599119f81411d76d067b082bb0c120884e2a74be
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 struct schema_list {
223 struct schema_list *next, *prev;
224 const struct drsuapi_DsReplicaObjectListItemEx *obj;
227 WERROR status;
228 struct dsdb_schema_prefixmap *pfm_remote;
229 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
230 struct schema_list *schema_list = NULL, *schema_list_item, *schema_list_next_item;
231 struct dsdb_schema *working_schema;
232 struct dsdb_schema *provision_schema;
233 uint32_t object_count = 0;
234 struct drsuapi_DsReplicaObjectListItemEx *first_object;
235 const struct drsuapi_DsReplicaObjectListItemEx *cur;
236 uint32_t linked_attributes_count;
237 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
238 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
239 struct dsdb_extended_replicated_objects *schema_objs;
240 struct repsFromTo1 *s_dsa;
241 char *tmp_dns_name;
242 struct ldb_context *schema_ldb;
243 struct ldb_message *msg;
244 struct ldb_message_element *prefixMap_el;
245 uint32_t i;
246 int ret, pass_no;
247 bool ok;
248 uint64_t seq_num;
249 uint32_t ignore_attids[] = {
250 DRSUAPI_ATTID_auxiliaryClass,
251 DRSUAPI_ATTID_mayContain,
252 DRSUAPI_ATTID_mustContain,
253 DRSUAPI_ATTID_possSuperiors,
254 DRSUAPI_ATTID_systemPossSuperiors,
255 DRSUAPI_ATTID_INVALID
258 DEBUG(0,("Analyze and apply schema objects\n"));
260 s_dsa = talloc_zero(s, struct repsFromTo1);
261 NT_STATUS_HAVE_NO_MEMORY(s_dsa);
262 s_dsa->other_info = talloc(s_dsa, struct repsFromTo1OtherInfo);
263 NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
265 switch (c->ctr_level) {
266 case 1:
267 mapping_ctr = &c->ctr1->mapping_ctr;
268 object_count = s->schema_part.object_count;
269 first_object = s->schema_part.first_object;
270 linked_attributes_count = 0;
271 linked_attributes = NULL;
272 s_dsa->highwatermark = c->ctr1->new_highwatermark;
273 s_dsa->source_dsa_obj_guid = c->ctr1->source_dsa_guid;
274 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
275 uptodateness_vector = NULL; /* TODO: map it */
276 break;
277 case 6:
278 mapping_ctr = &c->ctr6->mapping_ctr;
279 object_count = s->schema_part.object_count;
280 first_object = s->schema_part.first_object;
281 linked_attributes_count = c->ctr6->linked_attributes_count;
282 linked_attributes = c->ctr6->linked_attributes;
283 s_dsa->highwatermark = c->ctr6->new_highwatermark;
284 s_dsa->source_dsa_obj_guid = c->ctr6->source_dsa_guid;
285 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
286 uptodateness_vector = c->ctr6->uptodateness_vector;
287 break;
288 default:
289 return NT_STATUS_INVALID_PARAMETER;
291 /* We must set these up to ensure the replMetaData is written
292 * correctly, before our NTDS Settings entry is replicated */
293 ok = samdb_set_ntds_invocation_id(s->ldb, &c->dest_dsa->invocation_id);
294 if (!ok) {
295 DEBUG(0,("Failed to set cached ntds invocationId\n"));
296 return NT_STATUS_FOOBAR;
298 ok = samdb_set_ntds_objectGUID(s->ldb, &c->dest_dsa->ntds_guid);
299 if (!ok) {
300 DEBUG(0,("Failed to set cached ntds objectGUID\n"));
301 return NT_STATUS_FOOBAR;
305 status = dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr, true,
306 s, &pfm_remote, NULL);
307 if (!W_ERROR_IS_OK(status)) {
308 DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s",
309 win_errstr(status)));
310 return werror_to_ntstatus(status);
313 s_dsa->replica_flags = DRSUAPI_DRS_WRIT_REP
314 | DRSUAPI_DRS_INIT_SYNC
315 | DRSUAPI_DRS_PER_SYNC;
316 memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
318 tmp_dns_name = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
319 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
320 tmp_dns_name = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
321 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
322 s_dsa->other_info->dns_name = tmp_dns_name;
324 schema_ldb = provision_get_schema(s, s->lp_ctx,
325 c->forest->schema_dn_str,
326 &s->prefixmap_blob);
327 if (!schema_ldb) {
328 DEBUG(0,("Failed to re-load from local provision using remote prefixMap. "
329 "Will continue with local prefixMap\n"));
330 provision_schema = dsdb_get_schema(s->ldb, s);
331 } else {
332 provision_schema = dsdb_get_schema(schema_ldb, s);
333 ret = dsdb_reference_schema(s->ldb, provision_schema, false);
334 if (ret != LDB_SUCCESS) {
335 DEBUG(0,("Failed to attach schema from local provision using remote prefixMap."));
336 return NT_STATUS_UNSUCCESSFUL;
338 talloc_free(schema_ldb);
341 /* create a list of objects yet to be converted */
342 for (cur = first_object; cur; cur = cur->next_object) {
343 schema_list_item = talloc(s, struct schema_list);
344 schema_list_item->obj = cur;
345 DLIST_ADD_END(schema_list, schema_list_item, struct schema_list);
348 /* resolve objects until all are resolved and in local schema */
349 pass_no = 1;
350 working_schema = provision_schema;
352 while (schema_list) {
353 uint32_t converted_obj_count = 0;
354 uint32_t failed_obj_count = 0;
355 TALLOC_CTX *tmp_ctx = talloc_new(s);
356 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
358 for (schema_list_item = schema_list; schema_list_item; schema_list_item=schema_list_next_item) {
359 struct dsdb_extended_replicated_object object;
361 cur = schema_list_item->obj;
363 /* Save the next item, now we have saved out
364 * the current one, so we can DLIST_REMOVE it
365 * safely */
366 schema_list_next_item = schema_list_item->next;
369 * Convert the objects into LDB messages using the
370 * schema we have so far. It's ok if we fail to convert
371 * an object. We should convert more objects on next pass.
373 status = dsdb_convert_object_ex(s->ldb, working_schema, pfm_remote,
374 cur, c->gensec_skey,
375 ignore_attids,
377 tmp_ctx, &object);
378 if (!W_ERROR_IS_OK(status)) {
379 DEBUG(1,("Warning: Failed to convert schema object %s into ldb msg\n",
380 cur->object.identifier->dn));
382 failed_obj_count++;
383 } else {
385 * Convert the schema from ldb_message format
386 * (OIDs as OID strings) into schema, using
387 * the remote prefixMap
389 status = dsdb_schema_set_el_from_ldb_msg(s->ldb,
390 s->self_made_schema,
391 object.msg);
392 if (!W_ERROR_IS_OK(status)) {
393 DEBUG(1,("Warning: failed to convert object %s into a schema element: %s\n",
394 ldb_dn_get_linearized(object.msg->dn),
395 win_errstr(status)));
396 failed_obj_count++;
397 } else {
398 DLIST_REMOVE(schema_list, schema_list_item);
399 converted_obj_count++;
403 talloc_free(tmp_ctx);
405 DEBUG(4,("Schema load pass %d: %d/%d of %d objects left to be converted.\n",
406 pass_no, failed_obj_count, converted_obj_count, object_count));
407 pass_no++;
409 /* check if we converted any objects in this pass */
410 if (converted_obj_count == 0) {
411 DEBUG(0,("Can't continue Schema load: didn't manage to convert any objects: all %d remaining of %d objects failed to convert\n", failed_obj_count, object_count));
412 return NT_STATUS_INTERNAL_ERROR;
415 if (schema_list) {
416 /* prepare for another cycle */
417 working_schema = s->self_made_schema;
419 ret = dsdb_setup_sorted_accessors(s->ldb, working_schema);
420 if (LDB_SUCCESS != ret) {
421 DEBUG(0,("Failed to create schema-cache indexes!\n"));
422 return NT_STATUS_INTERNAL_ERROR;
427 /* free temp objects for 1st conversion phase */
428 talloc_unlink(s, provision_schema);
429 TALLOC_FREE(schema_list);
432 * attach the schema we just brought over DRS to the ldb,
433 * so we can use it in dsdb_convert_object_ex below
435 ret = dsdb_set_schema(s->ldb, s->self_made_schema);
436 if (ret != LDB_SUCCESS) {
437 DEBUG(0,("Failed to attach working schema from DRS.\n"));
438 return NT_STATUS_FOOBAR;
441 /* we don't want to access the self made schema anymore */
442 s->schema = s->self_made_schema;
443 s->self_made_schema = NULL;
445 /* Now convert the schema elements again, using the schema we finalised, ready to actually import */
446 status = dsdb_replicated_objects_convert(s->ldb,
447 s->schema,
448 c->partition->nc.dn,
449 mapping_ctr,
450 object_count,
451 first_object,
452 linked_attributes_count,
453 linked_attributes,
454 s_dsa,
455 uptodateness_vector,
456 c->gensec_skey,
458 s, &schema_objs);
459 if (!W_ERROR_IS_OK(status)) {
460 DEBUG(0,("Failed to convert objects when trying to import over DRS (2nd pass, to store remote schema): %s\n", win_errstr(status)));
461 return werror_to_ntstatus(status);
464 if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
465 for (i=0; i < schema_objs->num_objects; i++) {
466 struct ldb_ldif ldif;
467 fprintf(stdout, "#\n");
468 ldif.changetype = LDB_CHANGETYPE_NONE;
469 ldif.msg = schema_objs->objects[i].msg;
470 ldb_ldif_write_file(s->ldb, stdout, &ldif);
471 NDR_PRINT_DEBUG(replPropertyMetaDataBlob, schema_objs->objects[i].meta_data);
475 status = dsdb_replicated_objects_commit(s->ldb, NULL, schema_objs, &seq_num);
476 if (!W_ERROR_IS_OK(status)) {
477 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
478 return werror_to_ntstatus(status);
481 msg = ldb_msg_new(schema_objs);
482 NT_STATUS_HAVE_NO_MEMORY(msg);
483 msg->dn = schema_objs->partition_dn;
485 /* We must ensure a prefixMap has been written. Unlike other
486 * attributes (including schemaInfo), it is not replicated in
487 * the normal replication stream. We can use the one from
488 * s->prefixmap_blob because we operate with one, unchanging
489 * prefixMap for this entire operation. */
490 ret = ldb_msg_add_value(msg, "prefixMap", &s->prefixmap_blob, &prefixMap_el);
491 if (ret != LDB_SUCCESS) {
492 return NT_STATUS_FOOBAR;
494 /* We want to know if a prefixMap was written already, as it
495 * would mean that the above comment was not true, and we have
496 * somehow updated the prefixMap during this transaction */
497 prefixMap_el->flags = LDB_FLAG_MOD_ADD;
499 ret = dsdb_modify(s->ldb, msg, DSDB_FLAG_AS_SYSTEM);
500 if (ret != LDB_SUCCESS) {
501 DEBUG(0,("Failed to add prefixMap: %s\n", ldb_errstring(s->ldb)));
502 return NT_STATUS_FOOBAR;
505 talloc_free(s_dsa);
506 talloc_free(schema_objs);
508 s->schema = dsdb_get_schema(s->ldb, s);
509 if (!s->schema) {
510 DEBUG(0,("Failed to get loaded dsdb_schema\n"));
511 return NT_STATUS_FOOBAR;
514 return NT_STATUS_OK;
517 NTSTATUS libnet_vampire_cb_schema_chunk(void *private_data,
518 const struct libnet_BecomeDC_StoreChunk *c)
520 struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
521 WERROR status;
522 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
523 uint32_t nc_object_count;
524 uint32_t nc_total_received = 0;
525 uint32_t object_count;
526 struct drsuapi_DsReplicaObjectListItemEx *first_object;
527 struct drsuapi_DsReplicaObjectListItemEx *cur;
528 uint32_t nc_linked_attributes_count;
529 uint32_t linked_attributes_count;
531 switch (c->ctr_level) {
532 case 1:
533 mapping_ctr = &c->ctr1->mapping_ctr;
534 nc_object_count = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
535 object_count = c->ctr1->object_count;
536 first_object = c->ctr1->first_object;
537 nc_linked_attributes_count = 0;
538 linked_attributes_count = 0;
539 break;
540 case 6:
541 mapping_ctr = &c->ctr6->mapping_ctr;
542 nc_object_count = c->ctr6->nc_object_count;
543 object_count = c->ctr6->object_count;
544 first_object = c->ctr6->first_object;
545 nc_linked_attributes_count = c->ctr6->nc_linked_attributes_count;
546 linked_attributes_count = c->ctr6->linked_attributes_count;
547 break;
548 default:
549 return NT_STATUS_INVALID_PARAMETER;
552 if (!s->schema_part.first_object) {
553 nc_total_received = object_count;
554 } else {
555 nc_total_received = s->schema_part.object_count + object_count;
557 if (nc_object_count) {
558 DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n",
559 c->partition->nc.dn, nc_total_received, nc_object_count,
560 linked_attributes_count, nc_linked_attributes_count));
561 } else {
562 DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u]\n",
563 c->partition->nc.dn, nc_total_received, linked_attributes_count));
566 if (!s->self_made_schema) {
567 WERROR werr;
568 struct drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr_without_schema_info;
569 /* Put the DRS prefixmap aside for the schema we are
570 * about to load in the provision, and into the one we
571 * are making with the help of DRS */
573 mapping_ctr_without_schema_info = *mapping_ctr;
575 /* This strips off the 0xFF schema info from the end,
576 * because we don't want it in the blob */
577 if (mapping_ctr_without_schema_info.num_mappings > 0) {
578 mapping_ctr_without_schema_info.num_mappings--;
580 werr = dsdb_get_drsuapi_prefixmap_as_blob(&mapping_ctr_without_schema_info, s, &s->prefixmap_blob);
581 if (!W_ERROR_IS_OK(werr)) {
582 return werror_to_ntstatus(werr);
585 /* Set up two manually-constructed schema - the local
586 * schema from the provision will be used to build
587 * one, which will then in turn be used to build the
588 * other. */
589 s->self_made_schema = dsdb_new_schema(s);
590 NT_STATUS_HAVE_NO_MEMORY(s->self_made_schema);
592 s->self_made_schema->base_dn = ldb_dn_new(s->self_made_schema,
593 s->ldb,
594 c->forest->schema_dn_str);
595 NT_STATUS_HAVE_NO_MEMORY(s->self_made_schema->base_dn);
597 status = dsdb_load_prefixmap_from_drsuapi(s->self_made_schema, mapping_ctr);
598 if (!W_ERROR_IS_OK(status)) {
599 return werror_to_ntstatus(status);
601 } else {
602 status = dsdb_schema_pfm_contains_drsuapi_pfm(s->self_made_schema->prefixmap, mapping_ctr);
603 if (!W_ERROR_IS_OK(status)) {
604 return werror_to_ntstatus(status);
608 if (!s->schema_part.first_object) {
609 s->schema_part.object_count = object_count;
610 s->schema_part.first_object = talloc_steal(s, first_object);
611 } else {
612 s->schema_part.object_count += object_count;
613 s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
614 first_object);
616 for (cur = first_object; cur->next_object; cur = cur->next_object) {}
617 s->schema_part.last_object = cur;
619 if (!c->partition->more_data) {
620 return libnet_vampire_cb_apply_schema(s, c);
623 return NT_STATUS_OK;
626 NTSTATUS libnet_vampire_cb_store_chunk(void *private_data,
627 const struct libnet_BecomeDC_StoreChunk *c)
629 struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
630 WERROR status;
631 struct dsdb_schema *schema;
632 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
633 uint32_t nc_object_count;
634 uint32_t object_count;
635 struct drsuapi_DsReplicaObjectListItemEx *first_object;
636 uint32_t nc_linked_attributes_count;
637 uint32_t linked_attributes_count;
638 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
639 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
640 struct dsdb_extended_replicated_objects *objs;
641 uint32_t req_replica_flags;
642 struct repsFromTo1 *s_dsa;
643 char *tmp_dns_name;
644 uint32_t i;
645 uint64_t seq_num;
646 bool is_exop = false;
648 s_dsa = talloc_zero(s, struct repsFromTo1);
649 NT_STATUS_HAVE_NO_MEMORY(s_dsa);
650 s_dsa->other_info = talloc(s_dsa, struct repsFromTo1OtherInfo);
651 NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
653 switch (c->ctr_level) {
654 case 1:
655 mapping_ctr = &c->ctr1->mapping_ctr;
656 nc_object_count = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
657 object_count = c->ctr1->object_count;
658 first_object = c->ctr1->first_object;
659 nc_linked_attributes_count = 0;
660 linked_attributes_count = 0;
661 linked_attributes = NULL;
662 s_dsa->highwatermark = c->ctr1->new_highwatermark;
663 s_dsa->source_dsa_obj_guid = c->ctr1->source_dsa_guid;
664 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
665 uptodateness_vector = NULL; /* TODO: map it */
666 break;
667 case 6:
668 mapping_ctr = &c->ctr6->mapping_ctr;
669 nc_object_count = c->ctr6->nc_object_count;
670 object_count = c->ctr6->object_count;
671 first_object = c->ctr6->first_object;
672 nc_linked_attributes_count = c->ctr6->nc_linked_attributes_count;
673 linked_attributes_count = c->ctr6->linked_attributes_count;
674 linked_attributes = c->ctr6->linked_attributes;
675 s_dsa->highwatermark = c->ctr6->new_highwatermark;
676 s_dsa->source_dsa_obj_guid = c->ctr6->source_dsa_guid;
677 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
678 uptodateness_vector = c->ctr6->uptodateness_vector;
679 break;
680 default:
681 return NT_STATUS_INVALID_PARAMETER;
684 switch (c->req_level) {
685 case 0:
686 /* none */
687 req_replica_flags = 0;
688 break;
689 case 5:
690 if (c->req5->extended_op != DRSUAPI_EXOP_NONE) {
691 is_exop = true;
693 req_replica_flags = c->req5->replica_flags;
694 break;
695 case 8:
696 if (c->req8->extended_op != DRSUAPI_EXOP_NONE) {
697 is_exop = true;
699 req_replica_flags = c->req8->replica_flags;
700 break;
701 case 10:
702 if (c->req10->extended_op != DRSUAPI_EXOP_NONE) {
703 is_exop = true;
705 req_replica_flags = c->req10->replica_flags;
706 break;
707 default:
708 return NT_STATUS_INVALID_PARAMETER;
711 if (req_replica_flags & DRSUAPI_DRS_CRITICAL_ONLY) {
713 * If we only replicate the critical objects
714 * we should not remember what we already
715 * got, as it is incomplete.
717 ZERO_STRUCT(s_dsa->highwatermark);
718 uptodateness_vector = NULL;
721 /* TODO: avoid hardcoded flags */
722 s_dsa->replica_flags = DRSUAPI_DRS_WRIT_REP
723 | DRSUAPI_DRS_INIT_SYNC
724 | DRSUAPI_DRS_PER_SYNC;
725 memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
727 tmp_dns_name = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
728 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
729 tmp_dns_name = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
730 NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
731 s_dsa->other_info->dns_name = tmp_dns_name;
733 /* we want to show a count per partition */
734 if (!s->last_partition || strcmp(s->last_partition, c->partition->nc.dn) != 0) {
735 s->total_objects = 0;
736 talloc_free(s->last_partition);
737 s->last_partition = talloc_strdup(s, c->partition->nc.dn);
739 s->total_objects += object_count;
741 if (is_exop) {
742 if (nc_object_count) {
743 DEBUG(0,("Exop on[%s] objects[%u/%u] linked_values[%u/%u]\n",
744 c->partition->nc.dn, s->total_objects, nc_object_count,
745 linked_attributes_count, nc_linked_attributes_count));
746 } else {
747 DEBUG(0,("Exop on[%s] objects[%u] linked_values[%u]\n",
748 c->partition->nc.dn, s->total_objects, linked_attributes_count));
750 } else {
751 if (nc_object_count) {
752 DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n",
753 c->partition->nc.dn, s->total_objects, nc_object_count,
754 linked_attributes_count, nc_linked_attributes_count));
755 } else {
756 DEBUG(0,("Partition[%s] objects[%u] linked_values[%u]\n",
757 c->partition->nc.dn, s->total_objects, linked_attributes_count));
762 schema = dsdb_get_schema(s->ldb, NULL);
763 if (!schema) {
764 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
765 return NT_STATUS_INTERNAL_ERROR;
768 status = dsdb_replicated_objects_convert(s->ldb,
769 schema,
770 c->partition->nc.dn,
771 mapping_ctr,
772 object_count,
773 first_object,
774 linked_attributes_count,
775 linked_attributes,
776 s_dsa,
777 uptodateness_vector,
778 c->gensec_skey,
780 s, &objs);
781 if (!W_ERROR_IS_OK(status)) {
782 DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status)));
783 return werror_to_ntstatus(status);
786 if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
787 for (i=0; i < objs->num_objects; i++) {
788 struct ldb_ldif ldif;
789 fprintf(stdout, "#\n");
790 ldif.changetype = LDB_CHANGETYPE_NONE;
791 ldif.msg = objs->objects[i].msg;
792 ldb_ldif_write_file(s->ldb, stdout, &ldif);
793 NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
796 status = dsdb_replicated_objects_commit(s->ldb, NULL, objs, &seq_num);
797 if (!W_ERROR_IS_OK(status)) {
798 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
799 return werror_to_ntstatus(status);
802 talloc_free(s_dsa);
803 talloc_free(objs);
805 for (i=0; i < linked_attributes_count; i++) {
806 const struct dsdb_attribute *sa;
808 if (!linked_attributes[i].identifier) {
809 DEBUG(0, ("No linked attribute identifier\n"));
810 return NT_STATUS_FOOBAR;
813 if (!linked_attributes[i].value.blob) {
814 DEBUG(0, ("No linked attribute value\n"));
815 return NT_STATUS_FOOBAR;
818 sa = dsdb_attribute_by_attributeID_id(s->schema,
819 linked_attributes[i].attid);
820 if (!sa) {
821 DEBUG(0, ("Unable to find attribute via attribute id %d\n", linked_attributes[i].attid));
822 return NT_STATUS_FOOBAR;
825 if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
826 DEBUG(0,("# %s\n", sa->lDAPDisplayName));
827 NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, &linked_attributes[i]);
828 dump_data(0,
829 linked_attributes[i].value.blob->data,
830 linked_attributes[i].value.blob->length);
834 return NT_STATUS_OK;
837 static NTSTATUS update_dnshostname_for_server(TALLOC_CTX *mem_ctx,
838 struct ldb_context *ldb,
839 const char *server_dn_str,
840 const char *netbios_name,
841 const char *realm)
843 int ret;
844 struct ldb_message *msg;
845 struct ldb_message_element *el;
846 struct ldb_dn *server_dn;
847 const char *dNSHostName = strlower_talloc(mem_ctx,
848 talloc_asprintf(mem_ctx,
849 "%s.%s",
850 netbios_name,
851 realm));
852 msg = ldb_msg_new(mem_ctx);
853 if (msg == NULL) {
854 return NT_STATUS_NO_MEMORY;
857 server_dn = ldb_dn_new(mem_ctx, ldb, server_dn_str);
858 if (!server_dn) {
859 return NT_STATUS_INTERNAL_ERROR;
862 msg->dn = server_dn;
863 ret = ldb_msg_add_empty(msg, "dNSHostName", LDB_FLAG_MOD_ADD, &el);
864 if (ret != LDB_SUCCESS) {
865 return NT_STATUS_INTERNAL_ERROR;
868 ret = ldb_msg_add_steal_string(msg,
869 "dNSHostName",
870 talloc_asprintf(el->values, "%s", dNSHostName));
871 if (ret != LDB_SUCCESS) {
872 return NT_STATUS_INTERNAL_ERROR;
875 ret = dsdb_modify(ldb, msg, DSDB_MODIFY_PERMISSIVE);
876 if (ret != LDB_SUCCESS) {
877 DEBUG(0,(__location__ ": Failed to add dnsHostName to the Server object: %s\n",
878 ldb_errstring(ldb)));
879 return NT_STATUS_INTERNAL_ERROR;
882 return NT_STATUS_OK;
886 NTSTATUS libnet_Vampire(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
887 struct libnet_Vampire *r)
889 struct libnet_JoinDomain *join;
890 struct libnet_Replicate rep;
891 NTSTATUS status;
893 const char *account_name;
894 const char *netbios_name;
896 r->out.error_string = NULL;
898 join = talloc_zero(mem_ctx, struct libnet_JoinDomain);
899 if (!join) {
900 return NT_STATUS_NO_MEMORY;
903 if (r->in.netbios_name != NULL) {
904 netbios_name = r->in.netbios_name;
905 } else {
906 netbios_name = talloc_reference(join, lpcfg_netbios_name(ctx->lp_ctx));
907 if (!netbios_name) {
908 talloc_free(join);
909 r->out.error_string = NULL;
910 return NT_STATUS_NO_MEMORY;
914 account_name = talloc_asprintf(join, "%s$", netbios_name);
915 if (!account_name) {
916 talloc_free(join);
917 r->out.error_string = NULL;
918 return NT_STATUS_NO_MEMORY;
921 /* Re-use the domain we are joining as the domain for the user
922 * to be authenticated with, unless they specified
923 * otherwise */
924 cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
926 join->in.domain_name = r->in.domain_name;
927 join->in.account_name = account_name;
928 join->in.netbios_name = netbios_name;
929 join->in.level = LIBNET_JOINDOMAIN_AUTOMATIC;
930 join->in.acct_type = ACB_WSTRUST;
931 join->in.recreate_account = false;
932 status = libnet_JoinDomain(ctx, join, join);
933 if (!NT_STATUS_IS_OK(status)) {
934 r->out.error_string = talloc_steal(mem_ctx, join->out.error_string);
935 talloc_free(join);
936 return status;
939 rep.in.domain_name = join->out.domain_name;
940 rep.in.netbios_name = netbios_name;
941 rep.in.targetdir = r->in.targetdir;
942 rep.in.domain_sid = join->out.domain_sid;
943 rep.in.realm = join->out.realm;
944 rep.in.server = join->out.samr_binding->host;
945 rep.in.join_password = join->out.join_password;
946 rep.in.kvno = join->out.kvno;
948 status = libnet_Replicate(ctx, mem_ctx, &rep);
950 r->out.domain_sid = join->out.domain_sid;
951 r->out.domain_name = join->out.domain_name;
952 r->out.error_string = rep.out.error_string;
954 return status;
959 NTSTATUS libnet_Replicate(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
960 struct libnet_Replicate *r)
962 struct provision_store_self_join_settings *set_secrets;
963 struct libnet_BecomeDC b;
964 struct libnet_vampire_cb_state *s;
965 struct ldb_message *msg;
966 const char *error_string;
967 int ldb_ret;
968 uint32_t i;
969 NTSTATUS status;
970 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
971 const char *account_name;
972 const char *netbios_name;
974 r->out.error_string = NULL;
976 netbios_name = r->in.netbios_name;
977 account_name = talloc_asprintf(tmp_ctx, "%s$", netbios_name);
978 if (!account_name) {
979 talloc_free(tmp_ctx);
980 r->out.error_string = NULL;
981 return NT_STATUS_NO_MEMORY;
984 /* Re-use the domain we are joining as the domain for the user
985 * to be authenticated with, unless they specified
986 * otherwise */
987 cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
989 s = libnet_vampire_cb_state_init(mem_ctx, ctx->lp_ctx, ctx->event_ctx,
990 netbios_name, r->in.domain_name, r->in.realm,
991 r->in.targetdir);
992 if (!s) {
993 return NT_STATUS_NO_MEMORY;
995 talloc_steal(s, tmp_ctx);
997 ZERO_STRUCT(b);
999 /* Be more robust:
1000 * We now know the domain and realm for sure - if they didn't
1001 * put one on the command line, use this for the rest of the
1002 * join */
1003 cli_credentials_set_realm(ctx->cred, r->in.realm, CRED_GUESS_ENV);
1004 cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
1006 /* Now set these values into the smb.conf - we probably had
1007 * empty or useless defaults here from whatever smb.conf we
1008 * started with */
1009 lpcfg_set_cmdline(s->lp_ctx, "realm", r->in.realm);
1010 lpcfg_set_cmdline(s->lp_ctx, "workgroup", r->in.domain_name);
1012 b.in.domain_dns_name = r->in.realm;
1013 b.in.domain_netbios_name = r->in.domain_name;
1014 b.in.domain_sid = r->in.domain_sid;
1015 b.in.source_dsa_address = r->in.server;
1016 b.in.dest_dsa_netbios_name = netbios_name;
1018 b.in.callbacks.private_data = s;
1019 b.in.callbacks.check_options = libnet_vampire_cb_check_options;
1020 b.in.callbacks.prepare_db = libnet_vampire_cb_prepare_db;
1021 b.in.callbacks.schema_chunk = libnet_vampire_cb_schema_chunk;
1022 b.in.callbacks.config_chunk = libnet_vampire_cb_store_chunk;
1023 b.in.callbacks.domain_chunk = libnet_vampire_cb_store_chunk;
1025 b.in.rodc_join = lpcfg_parm_bool(s->lp_ctx, NULL, "repl", "RODC", false);
1027 status = libnet_BecomeDC(ctx, s, &b);
1028 if (!NT_STATUS_IS_OK(status)) {
1029 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
1030 talloc_free(s);
1031 return status;
1034 msg = ldb_msg_new(s);
1035 if (!msg) {
1036 printf("ldb_msg_new() failed\n");
1037 talloc_free(s);
1038 return NT_STATUS_NO_MEMORY;
1040 msg->dn = ldb_dn_new(msg, s->ldb, "@ROOTDSE");
1041 if (!msg->dn) {
1042 printf("ldb_msg_new(@ROOTDSE) failed\n");
1043 talloc_free(s);
1044 return NT_STATUS_NO_MEMORY;
1047 ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE");
1048 if (ldb_ret != LDB_SUCCESS) {
1049 printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret);
1050 talloc_free(s);
1051 return NT_STATUS_NO_MEMORY;
1054 for (i=0; i < msg->num_elements; i++) {
1055 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1058 printf("mark ROOTDSE with isSynchronized=TRUE\n");
1059 ldb_ret = ldb_modify(s->ldb, msg);
1060 if (ldb_ret != LDB_SUCCESS) {
1061 printf("ldb_modify() failed: %d : %s\n", ldb_ret, ldb_errstring(s->ldb));
1062 talloc_free(s);
1063 return NT_STATUS_INTERNAL_DB_ERROR;
1065 /* during dcpromo the 2nd computer adds dNSHostName attribute to his Server object
1066 * the attribute appears on the original DC after replication
1068 status = update_dnshostname_for_server(s, s->ldb, s->server_dn_str, s->netbios_name, s->realm);
1069 if (!NT_STATUS_IS_OK(status)) {
1070 printf("Failed to update dNSHostName on Server object - %s\n", nt_errstr(status));
1071 talloc_free(s);
1072 return status;
1074 /* prepare the transaction - this prepares to commit all the changes in
1075 the ldb from the whole vampire. Note that this
1076 triggers the writing of the linked attribute backlinks.
1078 if (ldb_transaction_prepare_commit(s->ldb) != LDB_SUCCESS) {
1079 printf("Failed to prepare_commit vampire transaction: %s\n", ldb_errstring(s->ldb));
1080 return NT_STATUS_INTERNAL_DB_ERROR;
1083 set_secrets = talloc(s, struct provision_store_self_join_settings);
1084 if (!set_secrets) {
1085 r->out.error_string = NULL;
1086 talloc_free(s);
1087 return NT_STATUS_NO_MEMORY;
1090 ZERO_STRUCTP(set_secrets);
1091 set_secrets->domain_name = r->in.domain_name;
1092 set_secrets->realm = r->in.realm;
1093 set_secrets->netbios_name = netbios_name;
1094 set_secrets->secure_channel_type = SEC_CHAN_BDC;
1095 set_secrets->machine_password = r->in.join_password;
1096 set_secrets->key_version_number = r->in.kvno;
1097 set_secrets->domain_sid = r->in.domain_sid;
1099 status = provision_store_self_join(ctx, s->lp_ctx, ctx->event_ctx, set_secrets, &error_string);
1100 if (!NT_STATUS_IS_OK(status)) {
1101 r->out.error_string = talloc_steal(mem_ctx, error_string);
1102 talloc_free(s);
1103 return status;
1106 /* commit the transaction now we know the secrets were written
1107 * out properly
1109 if (ldb_transaction_commit(s->ldb) != LDB_SUCCESS) {
1110 printf("Failed to commit vampire transaction\n");
1111 return NT_STATUS_INTERNAL_DB_ERROR;
1114 talloc_free(s);
1116 return NT_STATUS_OK;