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