f7131c1d02253540dec46a529c03b2bbd56b9cb2
[abartlet/samba.git/.git] / source4 / libnet / libnet_vampire.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    Extract the user/system database from a remote server
5
6    Copyright (C) Stefan Metzmacher      2004-2006
7    Copyright (C) Brad Henry 2005
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2008
9    
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.
14    
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.
19    
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/>.
22 */
23
24
25 #include "includes.h"
26 #include "libnet/libnet.h"
27 #include "lib/events/events.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "../lib/util/dlinklist.h"
30 #include "lib/ldb/include/ldb.h"
31 #include "lib/ldb/include/ldb_errors.h"
32 #include "librpc/ndr/libndr.h"
33 #include "librpc/gen_ndr/ndr_drsuapi.h"
34 #include "librpc/gen_ndr/ndr_drsblobs.h"
35 #include "librpc/gen_ndr/ndr_misc.h"
36 #include "system/time.h"
37 #include "lib/ldb_wrap.h"
38 #include "auth/auth.h"
39 #include "param/param.h"
40 #include "param/provision.h"
41 #include "libcli/security/dom_sid.h"
42
43 /* 
44 List of tasks vampire.py must perform:
45 - Domain Join
46  - but don't write the secrets.ldb
47  - results for this should be enough to handle the provision
48 - if vampire method is samsync 
49  - Provision using these results 
50   - do we still want to support this NT4 technology?
51 - Start samsync with libnet code
52  - provision in the callback 
53 - Write out the secrets database, using the code from libnet_Join
54
55 */
56 struct vampire_state {
57         const char *netbios_name;
58         struct libnet_JoinDomain *join;
59         struct cli_credentials *machine_account;
60         struct dsdb_schema *self_made_schema;
61         const struct dsdb_schema *schema;
62
63         struct ldb_context *ldb;
64
65         struct {
66                 uint32_t object_count;
67                 struct drsuapi_DsReplicaObjectListItemEx *first_object;
68                 struct drsuapi_DsReplicaObjectListItemEx *last_object;
69         } schema_part;
70
71         const char *targetdir;
72
73         struct loadparm_context *lp_ctx;
74         struct tevent_context *event_ctx;
75         unsigned total_objects;
76         char *last_partition;
77 };
78
79 static NTSTATUS vampire_prepare_db(void *private_data,
80                                               const struct libnet_BecomeDC_PrepareDB *p)
81 {
82         struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
83         struct provision_settings settings;
84         struct provision_result result;
85         NTSTATUS status;
86
87         ZERO_STRUCT(settings);
88         settings.site_name = p->dest_dsa->site_name;
89         settings.root_dn_str = p->forest->root_dn_str;
90         settings.domain_dn_str = p->domain->dn_str;
91         settings.config_dn_str = p->forest->config_dn_str;
92         settings.schema_dn_str = p->forest->schema_dn_str;
93         settings.netbios_name = p->dest_dsa->netbios_name;
94         settings.realm = s->join->out.realm;
95         settings.domain = s->join->out.domain_name;
96         settings.server_dn_str = p->dest_dsa->server_dn_str;
97         settings.machine_password = generate_random_str(s, 16);
98         settings.targetdir = s->targetdir;
99
100         status = provision_bare(s, s->lp_ctx, &settings, &result);
101
102         if (!NT_STATUS_IS_OK(status)) {
103                 return status;
104         }
105
106         s->ldb = result.samdb;
107         s->lp_ctx = result.lp_ctx;
108
109         /* wrap the entire vapire operation in a transaction.  This
110            isn't just cosmetic - we use this to ensure that linked
111            attribute back links are added at the end by relying on a
112            transaction commit hook in the linked attributes module. We
113            need to do this as the order of objects coming from the
114            server is not sufficiently deterministic to know that the
115            record that a backlink needs to be created in has itself
116            been created before the object containing the forward link
117            has come over the wire */
118         if (ldb_transaction_start(s->ldb) != LDB_SUCCESS) {
119                 return NT_STATUS_FOOBAR;
120         }
121
122         return NT_STATUS_OK;
123
124
125 }
126
127 static NTSTATUS vampire_check_options(void *private_data,
128                                              const struct libnet_BecomeDC_CheckOptions *o)
129 {
130         struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
131
132         DEBUG(0,("Become DC [%s] of Domain[%s]/[%s]\n",
133                 s->netbios_name,
134                 o->domain->netbios_name, o->domain->dns_name));
135
136         DEBUG(0,("Promotion Partner is Server[%s] from Site[%s]\n",
137                 o->source_dsa->dns_name, o->source_dsa->site_name));
138
139         DEBUG(0,("Options:crossRef behavior_version[%u]\n"
140                        "\tschema object_version[%u]\n"
141                        "\tdomain behavior_version[%u]\n"
142                        "\tdomain w2k3_update_revision[%u]\n", 
143                 o->forest->crossref_behavior_version,
144                 o->forest->schema_object_version,
145                 o->domain->behavior_version,
146                 o->domain->w2k3_update_revision));
147
148         return NT_STATUS_OK;
149 }
150
151 static NTSTATUS vampire_apply_schema(struct vampire_state *s,
152                                   const struct libnet_BecomeDC_StoreChunk *c)
153 {
154         WERROR status;
155         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
156         uint32_t object_count;
157         struct drsuapi_DsReplicaObjectListItemEx *first_object;
158         struct drsuapi_DsReplicaObjectListItemEx *cur;
159         uint32_t linked_attributes_count;
160         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
161         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
162         struct dsdb_extended_replicated_objects *objs;
163         struct repsFromTo1 *s_dsa;
164         char *tmp_dns_name;
165         struct ldb_message *msg;
166         struct ldb_val prefixMap_val;
167         struct ldb_message_element *prefixMap_el;
168         struct ldb_val schemaInfo_val;
169         uint32_t i;
170         int ret;
171         bool ok;
172         uint64_t seq_num;
173
174         DEBUG(0,("Analyze and apply schema objects\n"));
175
176         s_dsa                   = talloc_zero(s, struct repsFromTo1);
177         NT_STATUS_HAVE_NO_MEMORY(s_dsa);
178         s_dsa->other_info       = talloc(s_dsa, struct repsFromTo1OtherInfo);
179         NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
180
181         switch (c->ctr_level) {
182         case 1:
183                 mapping_ctr                     = &c->ctr1->mapping_ctr;
184                 object_count                    = s->schema_part.object_count;
185                 first_object                    = s->schema_part.first_object;
186                 linked_attributes_count         = 0;
187                 linked_attributes               = NULL;
188                 s_dsa->highwatermark            = c->ctr1->new_highwatermark;
189                 s_dsa->source_dsa_obj_guid      = c->ctr1->source_dsa_guid;
190                 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
191                 uptodateness_vector             = NULL; /* TODO: map it */
192                 break;
193         case 6:
194                 mapping_ctr                     = &c->ctr6->mapping_ctr;
195                 object_count                    = s->schema_part.object_count;
196                 first_object                    = s->schema_part.first_object;
197                 linked_attributes_count         = c->ctr6->linked_attributes_count;
198                 linked_attributes               = c->ctr6->linked_attributes;
199                 s_dsa->highwatermark            = c->ctr6->new_highwatermark;
200                 s_dsa->source_dsa_obj_guid      = c->ctr6->source_dsa_guid;
201                 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
202                 uptodateness_vector             = c->ctr6->uptodateness_vector;
203                 break;
204         default:
205                 return NT_STATUS_INVALID_PARAMETER;
206         }
207
208         s_dsa->replica_flags            = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
209                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
210                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS;
211         memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
212
213         tmp_dns_name    = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
214         NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
215         tmp_dns_name    = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
216         NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
217         s_dsa->other_info->dns_name = tmp_dns_name;
218
219         for (cur = first_object; cur; cur = cur->next_object) {
220                 bool is_attr = false;
221                 bool is_class = false;
222
223                 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
224                         struct drsuapi_DsReplicaAttribute *a;
225                         uint32_t j;
226                         const char *oid = NULL;
227
228                         a = &cur->object.attribute_ctr.attributes[i];
229                         status = dsdb_schema_pfm_oid_from_attid(s->self_made_schema->prefixmap,
230                                                                 a->attid, s, &oid);
231                         if (!W_ERROR_IS_OK(status)) {
232                                 return werror_to_ntstatus(status);
233                         }
234
235                         switch (a->attid) {
236                         case DRSUAPI_ATTRIBUTE_objectClass:
237                                 for (j=0; j < a->value_ctr.num_values; j++) {
238                                         uint32_t val = 0xFFFFFFFF;
239
240                                         if (a->value_ctr.values[j].blob
241                                             && a->value_ctr.values[j].blob->length == 4) {
242                                                 val = IVAL(a->value_ctr.values[j].blob->data,0);
243                                         }
244
245                                         if (val == DRSUAPI_OBJECTCLASS_attributeSchema) {
246                                                 is_attr = true;
247                                         }
248                                         if (val == DRSUAPI_OBJECTCLASS_classSchema) {
249                                                 is_class = true;
250                                         }
251                                 }
252
253                                 break;
254                         default:
255                                 break;
256                         }
257                 }
258
259                 if (is_attr) {
260                         struct dsdb_attribute *sa;
261
262                         sa = talloc_zero(s->self_made_schema, struct dsdb_attribute);
263                         NT_STATUS_HAVE_NO_MEMORY(sa);
264
265                         status = dsdb_attribute_from_drsuapi(s->ldb, s->self_made_schema, &cur->object, s, sa);
266                         if (!W_ERROR_IS_OK(status)) {
267                                 return werror_to_ntstatus(status);
268                         }
269
270                         DLIST_ADD_END(s->self_made_schema->attributes, sa, struct dsdb_attribute *);
271                 }
272
273                 if (is_class) {
274                         struct dsdb_class *sc;
275
276                         sc = talloc_zero(s->self_made_schema, struct dsdb_class);
277                         NT_STATUS_HAVE_NO_MEMORY(sc);
278
279                         status = dsdb_class_from_drsuapi(s->self_made_schema, &cur->object, s, sc);
280                         if (!W_ERROR_IS_OK(status)) {
281                                 return werror_to_ntstatus(status);
282                         }
283
284                         DLIST_ADD_END(s->self_made_schema->classes, sc, struct dsdb_class *);
285                 }
286         }
287
288         /* attach the schema to the ldb */
289         ret = dsdb_set_schema(s->ldb, s->self_made_schema);
290         if (ret != LDB_SUCCESS) {
291                 return NT_STATUS_FOOBAR;
292         }
293         /* we don't want to access the self made schema anymore */
294         s->self_made_schema = NULL;
295         s->schema = dsdb_get_schema(s->ldb);
296
297         status = dsdb_extended_replicated_objects_commit(s->ldb,
298                                                          c->partition->nc.dn,
299                                                          mapping_ctr,
300                                                          object_count,
301                                                          first_object,
302                                                          linked_attributes_count,
303                                                          linked_attributes,
304                                                          s_dsa,
305                                                          uptodateness_vector,
306                                                          c->gensec_skey,
307                                                          s, &objs, &seq_num);
308         if (!W_ERROR_IS_OK(status)) {
309                 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
310                 return werror_to_ntstatus(status);
311         }
312
313         if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
314                 for (i=0; i < objs->num_objects; i++) {
315                         struct ldb_ldif ldif;
316                         fprintf(stdout, "#\n");
317                         ldif.changetype = LDB_CHANGETYPE_NONE;
318                         ldif.msg = objs->objects[i].msg;
319                         ldb_ldif_write_file(s->ldb, stdout, &ldif);
320                         NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
321                 }
322         }
323
324         msg = ldb_msg_new(objs);
325         NT_STATUS_HAVE_NO_MEMORY(msg);
326         msg->dn = objs->partition_dn;
327
328         status = dsdb_get_oid_mappings_ldb(s->schema, msg, &prefixMap_val, &schemaInfo_val);
329         if (!W_ERROR_IS_OK(status)) {
330                 DEBUG(0,("Failed dsdb_get_oid_mappings_ldb(%s)\n", win_errstr(status)));
331                 return werror_to_ntstatus(status);
332         }
333
334         /* we only add prefixMap here, because schemaInfo is a replicated attribute and already applied */
335         ret = ldb_msg_add_value(msg, "prefixMap", &prefixMap_val, &prefixMap_el);
336         if (ret != LDB_SUCCESS) {
337                 return NT_STATUS_FOOBAR;
338         }
339         prefixMap_el->flags = LDB_FLAG_MOD_REPLACE;
340
341         ret = ldb_modify(s->ldb, msg);
342         if (ret != LDB_SUCCESS) {
343                 DEBUG(0,("Failed to add prefixMap and schemaInfo %s\n", ldb_strerror(ret)));
344                 return NT_STATUS_FOOBAR;
345         }
346
347         talloc_free(s_dsa);
348         talloc_free(objs);
349
350         /* We must set these up to ensure the replMetaData is written
351          * correctly, before our NTDS Settings entry is replicated */
352         ok = samdb_set_ntds_invocation_id(s->ldb, &c->dest_dsa->invocation_id);
353         if (!ok) {
354                 DEBUG(0,("Failed to set cached ntds invocationId\n"));
355                 return NT_STATUS_FOOBAR;
356         }
357         ok = samdb_set_ntds_objectGUID(s->ldb, &c->dest_dsa->ntds_guid);
358         if (!ok) {
359                 DEBUG(0,("Failed to set cached ntds objectGUID\n"));
360                 return NT_STATUS_FOOBAR;
361         }
362
363         s->schema = dsdb_get_schema(s->ldb);
364         if (!s->schema) {
365                 DEBUG(0,("Failed to get loaded dsdb_schema\n"));
366                 return NT_STATUS_FOOBAR;
367         }
368
369         return NT_STATUS_OK;
370 }
371
372 static NTSTATUS vampire_schema_chunk(void *private_data,
373                                             const struct libnet_BecomeDC_StoreChunk *c)
374 {
375         struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
376         WERROR status;
377         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
378         uint32_t nc_object_count;
379         uint32_t object_count;
380         struct drsuapi_DsReplicaObjectListItemEx *first_object;
381         struct drsuapi_DsReplicaObjectListItemEx *cur;
382         uint32_t nc_linked_attributes_count;
383         uint32_t linked_attributes_count;
384         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
385
386         switch (c->ctr_level) {
387         case 1:
388                 mapping_ctr                     = &c->ctr1->mapping_ctr;
389                 nc_object_count                 = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
390                 object_count                    = c->ctr1->object_count;
391                 first_object                    = c->ctr1->first_object;
392                 nc_linked_attributes_count      = 0;
393                 linked_attributes_count         = 0;
394                 linked_attributes               = NULL;
395                 break;
396         case 6:
397                 mapping_ctr                     = &c->ctr6->mapping_ctr;
398                 nc_object_count                 = c->ctr6->nc_object_count;
399                 object_count                    = c->ctr6->object_count;
400                 first_object                    = c->ctr6->first_object;
401                 nc_linked_attributes_count      = c->ctr6->nc_linked_attributes_count;
402                 linked_attributes_count         = c->ctr6->linked_attributes_count;
403                 linked_attributes               = c->ctr6->linked_attributes;
404                 break;
405         default:
406                 return NT_STATUS_INVALID_PARAMETER;
407         }
408
409         if (nc_object_count) {
410                 DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n",
411                         c->partition->nc.dn, object_count, nc_object_count,
412                         linked_attributes_count, nc_linked_attributes_count));
413         } else {
414                 DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u]\n",
415                 c->partition->nc.dn, object_count, linked_attributes_count));
416         }
417
418         if (!s->schema) {
419                 s->self_made_schema = dsdb_new_schema(s, lp_iconv_convenience(s->lp_ctx));
420
421                 NT_STATUS_HAVE_NO_MEMORY(s->self_made_schema);
422
423                 status = dsdb_load_prefixmap_from_drsuapi(s->self_made_schema, mapping_ctr);
424                 if (!W_ERROR_IS_OK(status)) {
425                         return werror_to_ntstatus(status);
426                 }
427
428                 s->schema = s->self_made_schema;
429         } else {
430                 status = dsdb_schema_pfm_contains_drsuapi_pfm(s->schema->prefixmap, mapping_ctr);
431                 if (!W_ERROR_IS_OK(status)) {
432                         return werror_to_ntstatus(status);
433                 }
434         }
435
436         if (!s->schema_part.first_object) {
437                 s->schema_part.object_count = object_count;
438                 s->schema_part.first_object = talloc_steal(s, first_object);
439         } else {
440                 s->schema_part.object_count             += object_count;
441                 s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
442                                                                        first_object);
443         }
444         for (cur = first_object; cur->next_object; cur = cur->next_object) {}
445         s->schema_part.last_object = cur;
446
447         if (!c->partition->more_data) {
448                 return vampire_apply_schema(s, c);
449         }
450
451         return NT_STATUS_OK;
452 }
453
454 static NTSTATUS vampire_store_chunk(void *private_data,
455                                            const struct libnet_BecomeDC_StoreChunk *c)
456 {
457         struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
458         WERROR status;
459         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
460         uint32_t nc_object_count;
461         uint32_t object_count;
462         struct drsuapi_DsReplicaObjectListItemEx *first_object;
463         uint32_t nc_linked_attributes_count;
464         uint32_t linked_attributes_count;
465         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
466         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
467         struct dsdb_extended_replicated_objects *objs;
468         struct repsFromTo1 *s_dsa;
469         char *tmp_dns_name;
470         uint32_t i;
471         uint64_t seq_num;
472
473         s_dsa                   = talloc_zero(s, struct repsFromTo1);
474         NT_STATUS_HAVE_NO_MEMORY(s_dsa);
475         s_dsa->other_info       = talloc(s_dsa, struct repsFromTo1OtherInfo);
476         NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
477
478         switch (c->ctr_level) {
479         case 1:
480                 mapping_ctr                     = &c->ctr1->mapping_ctr;
481                 nc_object_count                 = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
482                 object_count                    = c->ctr1->object_count;
483                 first_object                    = c->ctr1->first_object;
484                 nc_linked_attributes_count      = 0;
485                 linked_attributes_count         = 0;
486                 linked_attributes               = NULL;
487                 s_dsa->highwatermark            = c->ctr1->new_highwatermark;
488                 s_dsa->source_dsa_obj_guid      = c->ctr1->source_dsa_guid;
489                 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
490                 uptodateness_vector             = NULL; /* TODO: map it */
491                 break;
492         case 6:
493                 mapping_ctr                     = &c->ctr6->mapping_ctr;
494                 nc_object_count                 = c->ctr6->nc_object_count;
495                 object_count                    = c->ctr6->object_count;
496                 first_object                    = c->ctr6->first_object;
497                 nc_linked_attributes_count      = c->ctr6->nc_linked_attributes_count;
498                 linked_attributes_count         = c->ctr6->linked_attributes_count;
499                 linked_attributes               = c->ctr6->linked_attributes;
500                 s_dsa->highwatermark            = c->ctr6->new_highwatermark;
501                 s_dsa->source_dsa_obj_guid      = c->ctr6->source_dsa_guid;
502                 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
503                 uptodateness_vector             = c->ctr6->uptodateness_vector;
504                 break;
505         default:
506                 return NT_STATUS_INVALID_PARAMETER;
507         }
508
509         s_dsa->replica_flags            = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
510                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
511                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS;
512         memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
513
514         tmp_dns_name    = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
515         NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
516         tmp_dns_name    = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
517         NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
518         s_dsa->other_info->dns_name = tmp_dns_name;
519
520         /* we want to show a count per partition */
521         if (!s->last_partition || strcmp(s->last_partition, c->partition->nc.dn) != 0) {
522                 s->total_objects = 0;
523                 talloc_free(s->last_partition);
524                 s->last_partition = talloc_strdup(s, c->partition->nc.dn);
525         }
526         s->total_objects += object_count;
527
528         if (nc_object_count) {
529                 DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n",
530                         c->partition->nc.dn, s->total_objects, nc_object_count,
531                         linked_attributes_count, nc_linked_attributes_count));
532         } else {
533                 DEBUG(0,("Partition[%s] objects[%u] linked_values[%u]\n",
534                 c->partition->nc.dn, s->total_objects, linked_attributes_count));
535         }
536
537
538         status = dsdb_extended_replicated_objects_commit(s->ldb,
539                                                          c->partition->nc.dn,
540                                                          mapping_ctr,
541                                                          object_count,
542                                                          first_object,
543                                                          linked_attributes_count,
544                                                          linked_attributes,
545                                                          s_dsa,
546                                                          uptodateness_vector,
547                                                          c->gensec_skey,
548                                                          s, &objs, &seq_num);
549         if (!W_ERROR_IS_OK(status)) {
550                 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
551                 return werror_to_ntstatus(status);
552         }
553
554         if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
555                 for (i=0; i < objs->num_objects; i++) {
556                         struct ldb_ldif ldif;
557                         fprintf(stdout, "#\n");
558                         ldif.changetype = LDB_CHANGETYPE_NONE;
559                         ldif.msg = objs->objects[i].msg;
560                         ldb_ldif_write_file(s->ldb, stdout, &ldif);
561                         NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
562                 }
563         }
564         talloc_free(s_dsa);
565         talloc_free(objs);
566
567         for (i=0; i < linked_attributes_count; i++) {
568                 const struct dsdb_attribute *sa;
569
570                 if (!linked_attributes[i].identifier) {
571                         return NT_STATUS_FOOBAR;                
572                 }
573
574                 if (!linked_attributes[i].value.blob) {
575                         return NT_STATUS_FOOBAR;                
576                 }
577
578                 sa = dsdb_attribute_by_attributeID_id(s->schema,
579                                                       linked_attributes[i].attid);
580                 if (!sa) {
581                         return NT_STATUS_FOOBAR;
582                 }
583
584                 if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
585                         DEBUG(0,("# %s\n", sa->lDAPDisplayName));
586                         NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, &linked_attributes[i]);
587                         dump_data(0,
588                                 linked_attributes[i].value.blob->data,
589                                 linked_attributes[i].value.blob->length);
590                 }
591         }
592
593         return NT_STATUS_OK;
594 }
595
596 NTSTATUS libnet_Vampire(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, 
597                         struct libnet_Vampire *r)
598 {
599         struct libnet_JoinDomain *join;
600         struct provision_store_self_join_settings *set_secrets;
601         struct libnet_BecomeDC b;
602         struct vampire_state *s;
603         struct ldb_message *msg;
604         const char *error_string;
605         int ldb_ret;
606         uint32_t i;
607         NTSTATUS status;
608
609         const char *account_name;
610         const char *netbios_name;
611         
612         r->out.error_string = NULL;
613
614         s = talloc_zero(mem_ctx, struct vampire_state);
615         if (!s) {
616                 return NT_STATUS_NO_MEMORY;
617         }
618
619         s->lp_ctx = ctx->lp_ctx;
620         s->event_ctx = ctx->event_ctx;
621
622         join = talloc_zero(s, struct libnet_JoinDomain);
623         if (!join) {
624                 return NT_STATUS_NO_MEMORY;
625         }
626                 
627         if (r->in.netbios_name != NULL) {
628                 netbios_name = r->in.netbios_name;
629         } else {
630                 netbios_name = talloc_reference(join, lp_netbios_name(ctx->lp_ctx));
631                 if (!netbios_name) {
632                         r->out.error_string = NULL;
633                         talloc_free(s);
634                         return NT_STATUS_NO_MEMORY;
635                 }
636         }
637
638         account_name = talloc_asprintf(join, "%s$", netbios_name);
639         if (!account_name) {
640                 r->out.error_string = NULL;
641                 talloc_free(s);
642                 return NT_STATUS_NO_MEMORY;
643         }
644         
645         join->in.domain_name    = r->in.domain_name;
646         join->in.account_name   = account_name;
647         join->in.netbios_name   = netbios_name;
648         join->in.level          = LIBNET_JOINDOMAIN_AUTOMATIC;
649         join->in.acct_type      = ACB_WSTRUST;
650         join->in.recreate_account = false;
651         status = libnet_JoinDomain(ctx, join, join);
652         if (!NT_STATUS_IS_OK(status)) {
653                 r->out.error_string = talloc_steal(mem_ctx, join->out.error_string);
654                 talloc_free(s);
655                 return status;
656         }
657         
658         s->join = join;
659
660         s->targetdir = r->in.targetdir;
661
662         ZERO_STRUCT(b);
663         b.in.domain_dns_name            = join->out.realm;
664         b.in.domain_netbios_name        = join->out.domain_name;
665         b.in.domain_sid                 = join->out.domain_sid;
666         b.in.source_dsa_address         = join->out.samr_binding->host;
667         b.in.dest_dsa_netbios_name      = netbios_name;
668
669         b.in.callbacks.private_data     = s;
670         b.in.callbacks.check_options    = vampire_check_options;
671         b.in.callbacks.prepare_db       = vampire_prepare_db;
672         b.in.callbacks.schema_chunk     = vampire_schema_chunk;
673         b.in.callbacks.config_chunk     = vampire_store_chunk;
674         b.in.callbacks.domain_chunk     = vampire_store_chunk;
675
676         status = libnet_BecomeDC(ctx, s, &b);
677         if (!NT_STATUS_IS_OK(status)) {
678                 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
679                 talloc_free(s);
680                 return status;
681         }
682
683         msg = ldb_msg_new(s);
684         if (!msg) {
685                 printf("ldb_msg_new() failed\n");
686                 talloc_free(s);
687                 return NT_STATUS_NO_MEMORY;
688         }
689         msg->dn = ldb_dn_new(msg, s->ldb, "@ROOTDSE");
690         if (!msg->dn) {
691                 printf("ldb_msg_new(@ROOTDSE) failed\n");
692                 talloc_free(s);
693                 return NT_STATUS_NO_MEMORY;
694         }
695
696         ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE");
697         if (ldb_ret != LDB_SUCCESS) {
698                 printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret);
699                 talloc_free(s);
700                 return NT_STATUS_NO_MEMORY;
701         }
702
703         for (i=0; i < msg->num_elements; i++) {
704                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
705         }
706
707         printf("mark ROOTDSE with isSynchronized=TRUE\n");
708         ldb_ret = ldb_modify(s->ldb, msg);
709         if (ldb_ret != LDB_SUCCESS) {
710                 printf("ldb_modify() failed: %d\n", ldb_ret);
711                 talloc_free(s);
712                 return NT_STATUS_INTERNAL_DB_ERROR;
713         }
714
715         /* prepare the transaction - this prepares to commit all the changes in
716            the ldb from the whole vampire.  Note that this 
717            triggers the writing of the linked attribute backlinks.
718         */
719         if (ldb_transaction_prepare_commit(s->ldb) != LDB_SUCCESS) {
720                 printf("Failed to prepare_commit vampire transaction\n");
721                 return NT_STATUS_INTERNAL_DB_ERROR;
722         }
723
724         set_secrets = talloc(s, struct provision_store_self_join_settings);
725         if (!set_secrets) {
726                 r->out.error_string = NULL;
727                 talloc_free(s);
728                 return NT_STATUS_NO_MEMORY;
729         }
730         
731         ZERO_STRUCTP(set_secrets);
732         set_secrets->domain_name = join->out.domain_name;
733         set_secrets->realm = join->out.realm;
734         set_secrets->account_name = account_name;
735         set_secrets->netbios_name = netbios_name;
736         set_secrets->secure_channel_type = SEC_CHAN_BDC;
737         set_secrets->machine_password = join->out.join_password;
738         set_secrets->key_version_number = join->out.kvno;
739         set_secrets->domain_sid = join->out.domain_sid;
740         
741         status = provision_store_self_join(ctx, ctx->lp_ctx, ctx->event_ctx, set_secrets, &error_string);
742         if (!NT_STATUS_IS_OK(status)) {
743                 r->out.error_string = talloc_steal(mem_ctx, error_string);
744                 talloc_free(s);
745                 return status;
746         }
747
748         r->out.domain_name = talloc_steal(r, join->out.domain_name);
749         r->out.domain_sid = dom_sid_dup(r, join->out.domain_sid);
750         
751         /* commit the transaction now we know the secrets were written
752          * out properly
753         */
754         if (ldb_transaction_commit(s->ldb) != LDB_SUCCESS) {
755                 printf("Failed to commit vampire transaction\n");
756                 return NT_STATUS_INTERNAL_DB_ERROR;
757         }
758
759         talloc_free(s);
760
761         return NT_STATUS_OK;
762
763 }