s4:dsdb Allow the setting an override on the schema
[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         struct dsdb_schema *provision_schema;
64         const struct dsdb_schema *schema;
65
66         struct ldb_context *ldb;
67
68         struct {
69                 uint32_t object_count;
70                 struct drsuapi_DsReplicaObjectListItemEx *first_object;
71                 struct drsuapi_DsReplicaObjectListItemEx *last_object;
72         } schema_part;
73
74         const char *targetdir;
75
76         struct loadparm_context *lp_ctx;
77         struct tevent_context *event_ctx;
78         unsigned total_objects;
79         char *last_partition;
80 };
81
82 /* Caller is expected to keep supplied pointers around for the lifetime of the structure */
83 void *libnet_vampire_cb_state_init(TALLOC_CTX *mem_ctx,
84                                    struct loadparm_context *lp_ctx, struct tevent_context *event_ctx,
85                                    const char *netbios_name, const char *domain_name, const char *realm,
86                                    const char *targetdir)
87 {
88         struct libnet_vampire_cb_state *s = talloc_zero(mem_ctx, struct libnet_vampire_cb_state);
89         if (!s) {
90                 return NULL;
91         }
92
93         s->lp_ctx = lp_ctx;
94         s->event_ctx = event_ctx;
95         s->netbios_name = netbios_name;
96         s->domain_name = domain_name;
97         s->realm = realm;
98         s->targetdir = targetdir;
99         return s;
100 }
101
102 struct ldb_context *libnet_vampire_cb_ldb(struct libnet_vampire_cb_state *state)
103 {
104         state = talloc_get_type_abort(state, struct libnet_vampire_cb_state);
105         return state->ldb;
106 }
107
108 struct loadparm_context *libnet_vampire_cb_lp_ctx(struct libnet_vampire_cb_state *state)
109 {
110         state = talloc_get_type_abort(state, struct libnet_vampire_cb_state);
111         return state->lp_ctx;
112 }
113
114 NTSTATUS libnet_vampire_cb_prepare_db(void *private_data,
115                                       const struct libnet_BecomeDC_PrepareDB *p)
116 {
117         struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
118         struct provision_settings settings;
119         struct provision_result result;
120         NTSTATUS status;
121
122         ZERO_STRUCT(settings);
123         settings.site_name = p->dest_dsa->site_name;
124         settings.root_dn_str = p->forest->root_dn_str;
125         settings.domain_dn_str = p->domain->dn_str;
126         settings.config_dn_str = p->forest->config_dn_str;
127         settings.schema_dn_str = p->forest->schema_dn_str;
128         settings.netbios_name = p->dest_dsa->netbios_name;
129         settings.realm = s->realm;
130         settings.domain = s->domain_name;
131         settings.server_dn_str = p->dest_dsa->server_dn_str;
132         settings.machine_password = generate_random_password(s, 16, 255);
133         settings.targetdir = s->targetdir;
134
135         status = provision_bare(s, s->lp_ctx, &settings, &result);
136
137         if (!NT_STATUS_IS_OK(status)) {
138                 return status;
139         }
140
141         s->ldb = talloc_steal(s, result.samdb);
142         s->lp_ctx = talloc_steal(s, result.lp_ctx);
143         s->provision_schema = dsdb_get_schema(s->ldb, s);
144
145         /* wrap the entire vapire operation in a transaction.  This
146            isn't just cosmetic - we use this to ensure that linked
147            attribute back links are added at the end by relying on a
148            transaction commit hook in the linked attributes module. We
149            need to do this as the order of objects coming from the
150            server is not sufficiently deterministic to know that the
151            record that a backlink needs to be created in has itself
152            been created before the object containing the forward link
153            has come over the wire */
154         if (ldb_transaction_start(s->ldb) != LDB_SUCCESS) {
155                 return NT_STATUS_FOOBAR;
156         }
157
158         return NT_STATUS_OK;
159
160
161 }
162
163 NTSTATUS libnet_vampire_cb_check_options(void *private_data,
164                                          const struct libnet_BecomeDC_CheckOptions *o)
165 {
166         struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
167
168         DEBUG(0,("Become DC [%s] of Domain[%s]/[%s]\n",
169                 s->netbios_name,
170                 o->domain->netbios_name, o->domain->dns_name));
171
172         DEBUG(0,("Promotion Partner is Server[%s] from Site[%s]\n",
173                 o->source_dsa->dns_name, o->source_dsa->site_name));
174
175         DEBUG(0,("Options:crossRef behavior_version[%u]\n"
176                        "\tschema object_version[%u]\n"
177                        "\tdomain behavior_version[%u]\n"
178                        "\tdomain w2k3_update_revision[%u]\n", 
179                 o->forest->crossref_behavior_version,
180                 o->forest->schema_object_version,
181                 o->domain->behavior_version,
182                 o->domain->w2k3_update_revision));
183
184         return NT_STATUS_OK;
185 }
186
187 static NTSTATUS libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s,
188                                                const struct libnet_BecomeDC_StoreChunk *c)
189 {
190         WERROR status;
191         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
192         uint32_t object_count;
193         struct drsuapi_DsReplicaObjectListItemEx *first_object;
194         uint32_t linked_attributes_count;
195         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
196         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
197         struct dsdb_extended_replicated_objects *schema_objs_1, *schema_objs_2;
198         struct repsFromTo1 *s_dsa;
199         char *tmp_dns_name;
200         struct ldb_message *msg;
201         struct ldb_val prefixMap_val;
202         struct ldb_message_element *prefixMap_el;
203         struct ldb_val schemaInfo_val;
204         uint32_t i;
205         int ret;
206         bool ok;
207         uint64_t seq_num;
208
209         DEBUG(0,("Analyze and apply schema objects\n"));
210
211         s_dsa                   = talloc_zero(s, struct repsFromTo1);
212         NT_STATUS_HAVE_NO_MEMORY(s_dsa);
213         s_dsa->other_info       = talloc(s_dsa, struct repsFromTo1OtherInfo);
214         NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
215
216         switch (c->ctr_level) {
217         case 1:
218                 mapping_ctr                     = &c->ctr1->mapping_ctr;
219                 object_count                    = s->schema_part.object_count;
220                 first_object                    = s->schema_part.first_object;
221                 linked_attributes_count         = 0;
222                 linked_attributes               = NULL;
223                 s_dsa->highwatermark            = c->ctr1->new_highwatermark;
224                 s_dsa->source_dsa_obj_guid      = c->ctr1->source_dsa_guid;
225                 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
226                 uptodateness_vector             = NULL; /* TODO: map it */
227                 break;
228         case 6:
229                 mapping_ctr                     = &c->ctr6->mapping_ctr;
230                 object_count                    = s->schema_part.object_count;
231                 first_object                    = s->schema_part.first_object;
232                 linked_attributes_count         = c->ctr6->linked_attributes_count;
233                 linked_attributes               = c->ctr6->linked_attributes;
234                 s_dsa->highwatermark            = c->ctr6->new_highwatermark;
235                 s_dsa->source_dsa_obj_guid      = c->ctr6->source_dsa_guid;
236                 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
237                 uptodateness_vector             = c->ctr6->uptodateness_vector;
238                 break;
239         default:
240                 return NT_STATUS_INVALID_PARAMETER;
241         }
242
243         s_dsa->replica_flags            = DRSUAPI_DRS_WRIT_REP
244                                         | DRSUAPI_DRS_INIT_SYNC
245                                         | DRSUAPI_DRS_PER_SYNC;
246         memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
247
248         tmp_dns_name    = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
249         NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
250         tmp_dns_name    = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
251         NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
252         s_dsa->other_info->dns_name = tmp_dns_name;
253
254         s->provision_schema->relax_OID_conversions = true;
255
256         /* Now convert the schema elements again, using the schema we just imported */
257         status = dsdb_extended_replicated_objects_convert(s->ldb,
258                                                           c->partition->nc.dn,
259                                                           mapping_ctr,
260                                                           object_count,
261                                                           first_object,
262                                                           linked_attributes_count,
263                                                           linked_attributes,
264                                                           s_dsa,
265                                                           uptodateness_vector,
266                                                           c->gensec_skey,
267                                                           s, &schema_objs_1);
268         if (!W_ERROR_IS_OK(status)) {
269                 DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status)));
270                 return werror_to_ntstatus(status);
271         }
272
273         for (i=0; i < schema_objs_1->num_objects; i++) {
274                 status = dsdb_schema_set_el_from_ldb_msg(s->ldb, s->self_made_schema, schema_objs_1->objects[i].msg);
275                 if (!W_ERROR_IS_OK(status)) {
276                         DEBUG(0,("Failed to convert object %s into a schema element: %s\n",
277                                  ldb_dn_get_linearized(schema_objs_1->objects[i].msg->dn),
278                                  win_errstr(status)));
279                         return werror_to_ntstatus(status);
280                 }
281         }
282         /* We don't need the first conversion of the schema any more */
283         talloc_free(schema_objs_1);
284
285         /* attach the schema we just brought over DRS to the ldb */
286         ret = dsdb_set_schema(s->ldb, s->self_made_schema);
287         if (ret != LDB_SUCCESS) {
288                 DEBUG(0,("Failed to attach schema from DRS.\n"));
289                 return NT_STATUS_FOOBAR;
290         }
291
292         /* we don't want to access the self made schema anymore */
293         s->schema = s->self_made_schema;
294         s->self_made_schema = NULL;
295
296         /* Now convert the schema elements again, using the schema we just imported - we do this
297            'just in case' the schema in our LDIF was wrong, but correct enough to read a valid schema */
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, &schema_objs_2);
309         if (!W_ERROR_IS_OK(status)) {
310                 DEBUG(0,("Failed to convert 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 < schema_objs_2->num_objects; i++) {
316                         struct ldb_ldif ldif;
317                         fprintf(stdout, "#\n");
318                         ldif.changetype = LDB_CHANGETYPE_NONE;
319                         ldif.msg = schema_objs_2->objects[i].msg;
320                         ldb_ldif_write_file(s->ldb, stdout, &ldif);
321                         NDR_PRINT_DEBUG(replPropertyMetaDataBlob, schema_objs_2->objects[i].meta_data);
322                 }
323         }
324
325         status = dsdb_extended_replicated_objects_commit(s->ldb, schema_objs_2, &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(schema_objs_2);
332         NT_STATUS_HAVE_NO_MEMORY(msg);
333         msg->dn = schema_objs_2->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: %s\n", ldb_strerror(ret)));
351                 return NT_STATUS_FOOBAR;
352         }
353
354         talloc_free(s_dsa);
355         talloc_free(schema_objs_2);
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 NTSTATUS libnet_vampire_cb_schema_chunk(void *private_data,
380                                         const struct libnet_BecomeDC_StoreChunk *c)
381 {
382         struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_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 libnet_vampire_cb_apply_schema(s, c);
456         }
457
458         return NT_STATUS_OK;
459 }
460
461 NTSTATUS libnet_vampire_cb_store_chunk(void *private_data,
462                              const struct libnet_BecomeDC_StoreChunk *c)
463 {
464         struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_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 libnet_vampire_cb_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         join = talloc_zero(mem_ctx, struct libnet_JoinDomain);
629         if (!join) {
630                 return NT_STATUS_NO_MEMORY;
631         }
632                 
633         if (r->in.netbios_name != NULL) {
634                 netbios_name = r->in.netbios_name;
635         } else {
636                 netbios_name = talloc_reference(join, lp_netbios_name(ctx->lp_ctx));
637                 if (!netbios_name) {
638                         talloc_free(join);
639                         r->out.error_string = NULL;
640                         return NT_STATUS_NO_MEMORY;
641                 }
642         }
643
644         account_name = talloc_asprintf(join, "%s$", netbios_name);
645         if (!account_name) {
646                 talloc_free(join);
647                 r->out.error_string = NULL;
648                 return NT_STATUS_NO_MEMORY;
649         }
650         
651         /* Re-use the domain we are joining as the domain for the user
652          * to be authenticated with, unless they specified
653          * otherwise */
654         cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
655
656         join->in.domain_name    = r->in.domain_name;
657         join->in.account_name   = account_name;
658         join->in.netbios_name   = netbios_name;
659         join->in.level          = LIBNET_JOINDOMAIN_AUTOMATIC;
660         join->in.acct_type      = ACB_WSTRUST;
661         join->in.recreate_account = false;
662         status = libnet_JoinDomain(ctx, join, join);
663         if (!NT_STATUS_IS_OK(status)) {
664                 r->out.error_string = talloc_steal(mem_ctx, join->out.error_string);
665                 talloc_free(join);
666                 return status;
667         }
668         
669         s = libnet_vampire_cb_state_init(mem_ctx, ctx->lp_ctx, ctx->event_ctx,
670                                          netbios_name, join->out.domain_name, join->out.realm,
671                                          r->in.targetdir);
672         if (!s) {
673                 return NT_STATUS_NO_MEMORY;
674         }
675         talloc_steal(s, join);
676
677         ZERO_STRUCT(b);
678
679         /* Be more robust:
680          * We now know the domain and realm for sure - if they didn't
681          * put one on the command line, use this for the rest of the
682          * join */
683         cli_credentials_set_realm(ctx->cred, join->out.realm, CRED_GUESS_ENV);
684         cli_credentials_set_domain(ctx->cred, join->out.domain_name, CRED_GUESS_ENV);
685
686         /* Now set these values into the smb.conf - we probably had
687          * empty or useless defaults here from whatever smb.conf we
688          * started with */
689         lp_set_cmdline(s->lp_ctx, "realm", join->out.realm);
690         lp_set_cmdline(s->lp_ctx, "workgroup", join->out.domain_name);
691
692         b.in.domain_dns_name            = join->out.realm;
693         b.in.domain_netbios_name        = join->out.domain_name;
694         b.in.domain_sid                 = join->out.domain_sid;
695         b.in.source_dsa_address         = join->out.samr_binding->host;
696         b.in.dest_dsa_netbios_name      = netbios_name;
697
698         b.in.callbacks.private_data     = s;
699         b.in.callbacks.check_options    = libnet_vampire_cb_check_options;
700         b.in.callbacks.prepare_db       = libnet_vampire_cb_prepare_db;
701         b.in.callbacks.schema_chunk     = libnet_vampire_cb_schema_chunk;
702         b.in.callbacks.config_chunk     = libnet_vampire_cb_store_chunk;
703         b.in.callbacks.domain_chunk     = libnet_vampire_cb_store_chunk;
704
705         b.in.rodc_join = lp_parm_bool(s->lp_ctx, NULL, "repl", "RODC", false);
706
707         status = libnet_BecomeDC(ctx, s, &b);
708         if (!NT_STATUS_IS_OK(status)) {
709                 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
710                 talloc_free(s);
711                 return status;
712         }
713
714         msg = ldb_msg_new(s);
715         if (!msg) {
716                 printf("ldb_msg_new() failed\n");
717                 talloc_free(s);
718                 return NT_STATUS_NO_MEMORY;
719         }
720         msg->dn = ldb_dn_new(msg, s->ldb, "@ROOTDSE");
721         if (!msg->dn) {
722                 printf("ldb_msg_new(@ROOTDSE) failed\n");
723                 talloc_free(s);
724                 return NT_STATUS_NO_MEMORY;
725         }
726
727         ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE");
728         if (ldb_ret != LDB_SUCCESS) {
729                 printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret);
730                 talloc_free(s);
731                 return NT_STATUS_NO_MEMORY;
732         }
733
734         for (i=0; i < msg->num_elements; i++) {
735                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
736         }
737
738         printf("mark ROOTDSE with isSynchronized=TRUE\n");
739         ldb_ret = ldb_modify(s->ldb, msg);
740         if (ldb_ret != LDB_SUCCESS) {
741                 printf("ldb_modify() failed: %d : %s\n", ldb_ret, ldb_errstring(s->ldb));
742                 talloc_free(s);
743                 return NT_STATUS_INTERNAL_DB_ERROR;
744         }
745
746         /* prepare the transaction - this prepares to commit all the changes in
747            the ldb from the whole vampire.  Note that this 
748            triggers the writing of the linked attribute backlinks.
749         */
750         if (ldb_transaction_prepare_commit(s->ldb) != LDB_SUCCESS) {
751                 printf("Failed to prepare_commit vampire transaction: %s\n", ldb_errstring(s->ldb));
752                 return NT_STATUS_INTERNAL_DB_ERROR;
753         }
754
755         set_secrets = talloc(s, struct provision_store_self_join_settings);
756         if (!set_secrets) {
757                 r->out.error_string = NULL;
758                 talloc_free(s);
759                 return NT_STATUS_NO_MEMORY;
760         }
761         
762         ZERO_STRUCTP(set_secrets);
763         set_secrets->domain_name = join->out.domain_name;
764         set_secrets->realm = join->out.realm;
765         set_secrets->netbios_name = netbios_name;
766         set_secrets->secure_channel_type = SEC_CHAN_BDC;
767         set_secrets->machine_password = join->out.join_password;
768         set_secrets->key_version_number = join->out.kvno;
769         set_secrets->domain_sid = join->out.domain_sid;
770         
771         status = provision_store_self_join(ctx, s->lp_ctx, ctx->event_ctx, set_secrets, &error_string);
772         if (!NT_STATUS_IS_OK(status)) {
773                 r->out.error_string = talloc_steal(mem_ctx, error_string);
774                 talloc_free(s);
775                 return status;
776         }
777
778         r->out.domain_name = talloc_steal(mem_ctx, join->out.domain_name);
779         r->out.domain_sid = dom_sid_dup(mem_ctx, join->out.domain_sid);
780         
781         /* commit the transaction now we know the secrets were written
782          * out properly
783         */
784         if (ldb_transaction_commit(s->ldb) != LDB_SUCCESS) {
785                 printf("Failed to commit vampire transaction\n");
786                 return NT_STATUS_INTERNAL_DB_ERROR;
787         }
788
789         talloc_free(s);
790
791         return NT_STATUS_OK;
792
793 }