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