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