s4/libnet: Vampire should join us as a Domain Controller
[kamenim/samba.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_password(s, 16, 255);
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_DRS_WRIT_REP
209                                         | DRSUAPI_DRS_INIT_SYNC
210                                         | DRSUAPI_DRS_PER_SYNC;
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->ldb, s->self_made_schema, &cur->object, s, sc);
280                         if (!W_ERROR_IS_OK(status)) {
281                                 return werror_to_ntstatus(status);
282                         }
283                         DLIST_ADD_END(s->self_made_schema->classes, sc, struct dsdb_class *);
284                 }
285         }
286
287         /* attach the schema to the ldb */
288         ret = dsdb_set_schema(s->ldb, s->self_made_schema);
289         if (ret != LDB_SUCCESS) {
290                 return NT_STATUS_FOOBAR;
291         }
292         /* we don't want to access the self made schema anymore */
293         s->schema = s->self_made_schema;
294         s->self_made_schema = NULL;
295
296         /* Now convert the schema elements again, using the schema we just imported */
297         status = dsdb_extended_replicated_objects_convert(s->ldb, 
298                                                           c->partition->nc.dn,
299                                                           mapping_ctr,
300                                                           object_count,
301                                                           first_object,
302                                                           linked_attributes_count,
303                                                           linked_attributes,
304                                                           s_dsa,
305                                                           uptodateness_vector,
306                                                           c->gensec_skey,
307                                                           s, &objs);
308         if (!W_ERROR_IS_OK(status)) {
309                 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
310                 return werror_to_ntstatus(status);
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         status = dsdb_extended_replicated_objects_commit(s->ldb, objs, &seq_num);
325         if (!W_ERROR_IS_OK(status)) {
326                 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
327                 return werror_to_ntstatus(status);
328         }
329
330         msg = ldb_msg_new(objs);
331         NT_STATUS_HAVE_NO_MEMORY(msg);
332         msg->dn = objs->partition_dn;
333
334         status = dsdb_get_oid_mappings_ldb(s->schema, msg, &prefixMap_val, &schemaInfo_val);
335         if (!W_ERROR_IS_OK(status)) {
336                 DEBUG(0,("Failed dsdb_get_oid_mappings_ldb(%s)\n", win_errstr(status)));
337                 return werror_to_ntstatus(status);
338         }
339
340         /* we only add prefixMap here, because schemaInfo is a replicated attribute and already applied */
341         ret = ldb_msg_add_value(msg, "prefixMap", &prefixMap_val, &prefixMap_el);
342         if (ret != LDB_SUCCESS) {
343                 return NT_STATUS_FOOBAR;
344         }
345         prefixMap_el->flags = LDB_FLAG_MOD_REPLACE;
346
347         ret = ldb_modify(s->ldb, msg);
348         if (ret != LDB_SUCCESS) {
349                 DEBUG(0,("Failed to add prefixMap and schemaInfo %s\n", ldb_strerror(ret)));
350                 return NT_STATUS_FOOBAR;
351         }
352
353         talloc_free(s_dsa);
354         talloc_free(objs);
355
356         /* We must set these up to ensure the replMetaData is written
357          * correctly, before our NTDS Settings entry is replicated */
358         ok = samdb_set_ntds_invocation_id(s->ldb, &c->dest_dsa->invocation_id);
359         if (!ok) {
360                 DEBUG(0,("Failed to set cached ntds invocationId\n"));
361                 return NT_STATUS_FOOBAR;
362         }
363         ok = samdb_set_ntds_objectGUID(s->ldb, &c->dest_dsa->ntds_guid);
364         if (!ok) {
365                 DEBUG(0,("Failed to set cached ntds objectGUID\n"));
366                 return NT_STATUS_FOOBAR;
367         }
368
369         s->schema = dsdb_get_schema(s->ldb, s);
370         if (!s->schema) {
371                 DEBUG(0,("Failed to get loaded dsdb_schema\n"));
372                 return NT_STATUS_FOOBAR;
373         }
374
375         return NT_STATUS_OK;
376 }
377
378 static NTSTATUS vampire_schema_chunk(void *private_data,
379                                             const struct libnet_BecomeDC_StoreChunk *c)
380 {
381         struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
382         WERROR status;
383         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
384         uint32_t nc_object_count;
385         uint32_t object_count;
386         struct drsuapi_DsReplicaObjectListItemEx *first_object;
387         struct drsuapi_DsReplicaObjectListItemEx *cur;
388         uint32_t nc_linked_attributes_count;
389         uint32_t linked_attributes_count;
390         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
391
392         switch (c->ctr_level) {
393         case 1:
394                 mapping_ctr                     = &c->ctr1->mapping_ctr;
395                 nc_object_count                 = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
396                 object_count                    = c->ctr1->object_count;
397                 first_object                    = c->ctr1->first_object;
398                 nc_linked_attributes_count      = 0;
399                 linked_attributes_count         = 0;
400                 linked_attributes               = NULL;
401                 break;
402         case 6:
403                 mapping_ctr                     = &c->ctr6->mapping_ctr;
404                 nc_object_count                 = c->ctr6->nc_object_count;
405                 object_count                    = c->ctr6->object_count;
406                 first_object                    = c->ctr6->first_object;
407                 nc_linked_attributes_count      = c->ctr6->nc_linked_attributes_count;
408                 linked_attributes_count         = c->ctr6->linked_attributes_count;
409                 linked_attributes               = c->ctr6->linked_attributes;
410                 break;
411         default:
412                 return NT_STATUS_INVALID_PARAMETER;
413         }
414
415         if (nc_object_count) {
416                 DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n",
417                         c->partition->nc.dn, object_count, nc_object_count,
418                         linked_attributes_count, nc_linked_attributes_count));
419         } else {
420                 DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u]\n",
421                 c->partition->nc.dn, object_count, linked_attributes_count));
422         }
423
424         if (!s->schema) {
425                 s->self_made_schema = dsdb_new_schema(s, lp_iconv_convenience(s->lp_ctx));
426
427                 NT_STATUS_HAVE_NO_MEMORY(s->self_made_schema);
428
429                 status = dsdb_load_prefixmap_from_drsuapi(s->self_made_schema, mapping_ctr);
430                 if (!W_ERROR_IS_OK(status)) {
431                         return werror_to_ntstatus(status);
432                 }
433
434                 s->schema = s->self_made_schema;
435         } else {
436                 status = dsdb_schema_pfm_contains_drsuapi_pfm(s->schema->prefixmap, mapping_ctr);
437                 if (!W_ERROR_IS_OK(status)) {
438                         return werror_to_ntstatus(status);
439                 }
440         }
441
442         if (!s->schema_part.first_object) {
443                 s->schema_part.object_count = object_count;
444                 s->schema_part.first_object = talloc_steal(s, first_object);
445         } else {
446                 s->schema_part.object_count             += object_count;
447                 s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
448                                                                        first_object);
449         }
450         for (cur = first_object; cur->next_object; cur = cur->next_object) {}
451         s->schema_part.last_object = cur;
452
453         if (!c->partition->more_data) {
454                 return vampire_apply_schema(s, c);
455         }
456
457         return NT_STATUS_OK;
458 }
459
460 static NTSTATUS vampire_store_chunk(void *private_data,
461                                            const struct libnet_BecomeDC_StoreChunk *c)
462 {
463         struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
464         WERROR status;
465         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
466         uint32_t nc_object_count;
467         uint32_t object_count;
468         struct drsuapi_DsReplicaObjectListItemEx *first_object;
469         uint32_t nc_linked_attributes_count;
470         uint32_t linked_attributes_count;
471         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
472         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
473         struct dsdb_extended_replicated_objects *objs;
474         struct repsFromTo1 *s_dsa;
475         char *tmp_dns_name;
476         uint32_t i;
477         uint64_t seq_num;
478
479         s_dsa                   = talloc_zero(s, struct repsFromTo1);
480         NT_STATUS_HAVE_NO_MEMORY(s_dsa);
481         s_dsa->other_info       = talloc(s_dsa, struct repsFromTo1OtherInfo);
482         NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
483
484         switch (c->ctr_level) {
485         case 1:
486                 mapping_ctr                     = &c->ctr1->mapping_ctr;
487                 nc_object_count                 = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
488                 object_count                    = c->ctr1->object_count;
489                 first_object                    = c->ctr1->first_object;
490                 nc_linked_attributes_count      = 0;
491                 linked_attributes_count         = 0;
492                 linked_attributes               = NULL;
493                 s_dsa->highwatermark            = c->ctr1->new_highwatermark;
494                 s_dsa->source_dsa_obj_guid      = c->ctr1->source_dsa_guid;
495                 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
496                 uptodateness_vector             = NULL; /* TODO: map it */
497                 break;
498         case 6:
499                 mapping_ctr                     = &c->ctr6->mapping_ctr;
500                 nc_object_count                 = c->ctr6->nc_object_count;
501                 object_count                    = c->ctr6->object_count;
502                 first_object                    = c->ctr6->first_object;
503                 nc_linked_attributes_count      = c->ctr6->nc_linked_attributes_count;
504                 linked_attributes_count         = c->ctr6->linked_attributes_count;
505                 linked_attributes               = c->ctr6->linked_attributes;
506                 s_dsa->highwatermark            = c->ctr6->new_highwatermark;
507                 s_dsa->source_dsa_obj_guid      = c->ctr6->source_dsa_guid;
508                 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
509                 uptodateness_vector             = c->ctr6->uptodateness_vector;
510                 break;
511         default:
512                 return NT_STATUS_INVALID_PARAMETER;
513         }
514
515         s_dsa->replica_flags            = DRSUAPI_DRS_WRIT_REP
516                                         | DRSUAPI_DRS_INIT_SYNC
517                                         | DRSUAPI_DRS_PER_SYNC;
518         memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
519
520         tmp_dns_name    = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
521         NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
522         tmp_dns_name    = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
523         NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
524         s_dsa->other_info->dns_name = tmp_dns_name;
525
526         /* we want to show a count per partition */
527         if (!s->last_partition || strcmp(s->last_partition, c->partition->nc.dn) != 0) {
528                 s->total_objects = 0;
529                 talloc_free(s->last_partition);
530                 s->last_partition = talloc_strdup(s, c->partition->nc.dn);
531         }
532         s->total_objects += object_count;
533
534         if (nc_object_count) {
535                 DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n",
536                         c->partition->nc.dn, s->total_objects, nc_object_count,
537                         linked_attributes_count, nc_linked_attributes_count));
538         } else {
539                 DEBUG(0,("Partition[%s] objects[%u] linked_values[%u]\n",
540                 c->partition->nc.dn, s->total_objects, linked_attributes_count));
541         }
542
543
544         status = dsdb_extended_replicated_objects_convert(s->ldb,
545                                                           c->partition->nc.dn,
546                                                           mapping_ctr,
547                                                           object_count,
548                                                           first_object,
549                                                           linked_attributes_count,
550                                                           linked_attributes,
551                                                           s_dsa,
552                                                           uptodateness_vector,
553                                                           c->gensec_skey,
554                                                           s, &objs);
555         if (!W_ERROR_IS_OK(status)) {
556                 DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status)));
557                 return werror_to_ntstatus(status);
558         }
559
560         if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
561                 for (i=0; i < objs->num_objects; i++) {
562                         struct ldb_ldif ldif;
563                         fprintf(stdout, "#\n");
564                         ldif.changetype = LDB_CHANGETYPE_NONE;
565                         ldif.msg = objs->objects[i].msg;
566                         ldb_ldif_write_file(s->ldb, stdout, &ldif);
567                         NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
568                 }
569         }
570         status = dsdb_extended_replicated_objects_commit(s->ldb,
571                                                          objs, &seq_num);
572         if (!W_ERROR_IS_OK(status)) {
573                 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
574                 return werror_to_ntstatus(status);
575         }
576
577         talloc_free(s_dsa);
578         talloc_free(objs);
579
580         for (i=0; i < linked_attributes_count; i++) {
581                 const struct dsdb_attribute *sa;
582
583                 if (!linked_attributes[i].identifier) {
584                         return NT_STATUS_FOOBAR;                
585                 }
586
587                 if (!linked_attributes[i].value.blob) {
588                         return NT_STATUS_FOOBAR;                
589                 }
590
591                 sa = dsdb_attribute_by_attributeID_id(s->schema,
592                                                       linked_attributes[i].attid);
593                 if (!sa) {
594                         return NT_STATUS_FOOBAR;
595                 }
596
597                 if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
598                         DEBUG(0,("# %s\n", sa->lDAPDisplayName));
599                         NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, &linked_attributes[i]);
600                         dump_data(0,
601                                 linked_attributes[i].value.blob->data,
602                                 linked_attributes[i].value.blob->length);
603                 }
604         }
605
606         return NT_STATUS_OK;
607 }
608
609 NTSTATUS libnet_Vampire(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, 
610                         struct libnet_Vampire *r)
611 {
612         struct libnet_JoinDomain *join;
613         struct provision_store_self_join_settings *set_secrets;
614         struct libnet_BecomeDC b;
615         struct vampire_state *s;
616         struct ldb_message *msg;
617         const char *error_string;
618         int ldb_ret;
619         uint32_t i;
620         NTSTATUS status;
621
622         const char *account_name;
623         const char *netbios_name;
624         
625         r->out.error_string = NULL;
626
627         s = talloc_zero(mem_ctx, struct vampire_state);
628         if (!s) {
629                 return NT_STATUS_NO_MEMORY;
630         }
631
632         s->lp_ctx = ctx->lp_ctx;
633         s->event_ctx = ctx->event_ctx;
634
635         join = talloc_zero(s, struct libnet_JoinDomain);
636         if (!join) {
637                 return NT_STATUS_NO_MEMORY;
638         }
639                 
640         if (r->in.netbios_name != NULL) {
641                 netbios_name = r->in.netbios_name;
642         } else {
643                 netbios_name = talloc_reference(join, lp_netbios_name(ctx->lp_ctx));
644                 if (!netbios_name) {
645                         r->out.error_string = NULL;
646                         talloc_free(s);
647                         return NT_STATUS_NO_MEMORY;
648                 }
649         }
650
651         account_name = talloc_asprintf(join, "%s$", netbios_name);
652         if (!account_name) {
653                 r->out.error_string = NULL;
654                 talloc_free(s);
655                 return NT_STATUS_NO_MEMORY;
656         }
657         
658         join->in.domain_name    = r->in.domain_name;
659         join->in.account_name   = account_name;
660         join->in.netbios_name   = netbios_name;
661         join->in.level          = LIBNET_JOINDOMAIN_AUTOMATIC;
662         join->in.acct_type      = ACB_SVRTRUST;
663         join->in.recreate_account = false;
664         status = libnet_JoinDomain(ctx, join, join);
665         if (!NT_STATUS_IS_OK(status)) {
666                 r->out.error_string = talloc_steal(mem_ctx, join->out.error_string);
667                 talloc_free(s);
668                 return status;
669         }
670         
671         s->join = join;
672
673         s->targetdir = r->in.targetdir;
674
675         ZERO_STRUCT(b);
676         b.in.domain_dns_name            = join->out.realm;
677         b.in.domain_netbios_name        = join->out.domain_name;
678         b.in.domain_sid                 = join->out.domain_sid;
679         b.in.source_dsa_address         = join->out.samr_binding->host;
680         b.in.dest_dsa_netbios_name      = netbios_name;
681
682         b.in.callbacks.private_data     = s;
683         b.in.callbacks.check_options    = vampire_check_options;
684         b.in.callbacks.prepare_db       = vampire_prepare_db;
685         b.in.callbacks.schema_chunk     = vampire_schema_chunk;
686         b.in.callbacks.config_chunk     = vampire_store_chunk;
687         b.in.callbacks.domain_chunk     = vampire_store_chunk;
688
689         b.in.rodc_join = lp_parm_bool(s->lp_ctx, NULL, "repl", "RODC", false);
690
691         status = libnet_BecomeDC(ctx, s, &b);
692         if (!NT_STATUS_IS_OK(status)) {
693                 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
694                 talloc_free(s);
695                 return status;
696         }
697
698         msg = ldb_msg_new(s);
699         if (!msg) {
700                 printf("ldb_msg_new() failed\n");
701                 talloc_free(s);
702                 return NT_STATUS_NO_MEMORY;
703         }
704         msg->dn = ldb_dn_new(msg, s->ldb, "@ROOTDSE");
705         if (!msg->dn) {
706                 printf("ldb_msg_new(@ROOTDSE) failed\n");
707                 talloc_free(s);
708                 return NT_STATUS_NO_MEMORY;
709         }
710
711         ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE");
712         if (ldb_ret != LDB_SUCCESS) {
713                 printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret);
714                 talloc_free(s);
715                 return NT_STATUS_NO_MEMORY;
716         }
717
718         for (i=0; i < msg->num_elements; i++) {
719                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
720         }
721
722         printf("mark ROOTDSE with isSynchronized=TRUE\n");
723         ldb_ret = ldb_modify(s->ldb, msg);
724         if (ldb_ret != LDB_SUCCESS) {
725                 printf("ldb_modify() failed: %d : %s\n", ldb_ret, ldb_errstring(s->ldb));
726                 talloc_free(s);
727                 return NT_STATUS_INTERNAL_DB_ERROR;
728         }
729
730         /* prepare the transaction - this prepares to commit all the changes in
731            the ldb from the whole vampire.  Note that this 
732            triggers the writing of the linked attribute backlinks.
733         */
734         if (ldb_transaction_prepare_commit(s->ldb) != LDB_SUCCESS) {
735                 printf("Failed to prepare_commit vampire transaction: %s\n", ldb_errstring(s->ldb));
736                 return NT_STATUS_INTERNAL_DB_ERROR;
737         }
738
739         set_secrets = talloc(s, struct provision_store_self_join_settings);
740         if (!set_secrets) {
741                 r->out.error_string = NULL;
742                 talloc_free(s);
743                 return NT_STATUS_NO_MEMORY;
744         }
745         
746         ZERO_STRUCTP(set_secrets);
747         set_secrets->domain_name = join->out.domain_name;
748         set_secrets->realm = join->out.realm;
749         set_secrets->account_name = account_name;
750         set_secrets->netbios_name = netbios_name;
751         set_secrets->secure_channel_type = SEC_CHAN_BDC;
752         set_secrets->machine_password = join->out.join_password;
753         set_secrets->key_version_number = join->out.kvno;
754         set_secrets->domain_sid = join->out.domain_sid;
755         
756         status = provision_store_self_join(ctx, ctx->lp_ctx, ctx->event_ctx, set_secrets, &error_string);
757         if (!NT_STATUS_IS_OK(status)) {
758                 r->out.error_string = talloc_steal(mem_ctx, error_string);
759                 talloc_free(s);
760                 return status;
761         }
762
763         r->out.domain_name = talloc_steal(mem_ctx, join->out.domain_name);
764         r->out.domain_sid = dom_sid_dup(mem_ctx, join->out.domain_sid);
765         
766         /* commit the transaction now we know the secrets were written
767          * out properly
768         */
769         if (ldb_transaction_commit(s->ldb) != LDB_SUCCESS) {
770                 printf("Failed to commit vampire transaction\n");
771                 return NT_STATUS_INTERNAL_DB_ERROR;
772         }
773
774         talloc_free(s);
775
776         return NT_STATUS_OK;
777
778 }