s4-rodc: s->schema need initialisation
[sfrench/samba-autobuild/.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 "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 #include "dsdb/common/util.h"
44
45 /* 
46 List of tasks vampire.py must perform:
47 - Domain Join
48  - but don't write the secrets.ldb
49  - results for this should be enough to handle the provision
50 - if vampire method is samsync 
51  - Provision using these results 
52   - do we still want to support this NT4 technology?
53 - Start samsync with libnet code
54  - provision in the callback 
55 - Write out the secrets database, using the code from libnet_Join
56
57 */
58 struct libnet_vampire_cb_state {
59         const char *netbios_name;
60         const char *domain_name;
61         const char *realm;
62         struct cli_credentials *machine_account;
63
64         /* Schema loaded from local LDIF files */
65         struct dsdb_schema *provision_schema;
66
67         /* 1st pass, with some OIDs/attribute names/class names not
68          * converted, because we may not know them yet */
69         struct dsdb_schema *self_made_schema;
70
71         /* 2nd pass, with full ID->OID->name table */
72         struct dsdb_schema *self_corrected_schema;
73
74         /* prefixMap in LDB format, from the remote DRS server */
75         DATA_BLOB prefixmap_blob;
76         const struct dsdb_schema *schema;
77
78         struct ldb_context *ldb;
79
80         struct {
81                 uint32_t object_count;
82                 struct drsuapi_DsReplicaObjectListItemEx *first_object;
83                 struct drsuapi_DsReplicaObjectListItemEx *last_object;
84         } schema_part;
85
86         const char *targetdir;
87
88         struct loadparm_context *lp_ctx;
89         struct tevent_context *event_ctx;
90         unsigned total_objects;
91         char *last_partition;
92         const char *server_dn_str;
93 };
94
95 /* initialise a state structure ready for replication of chunks */
96 void *libnet_vampire_replicate_init(TALLOC_CTX *mem_ctx,
97                                     struct ldb_context *samdb,
98                                     struct loadparm_context *lp_ctx)
99 {
100         struct libnet_vampire_cb_state *s = talloc_zero(mem_ctx, struct libnet_vampire_cb_state);
101         if (!s) {
102                 return NULL;
103         }
104
105         s->ldb              = samdb;
106         s->lp_ctx           = lp_ctx;
107         s->provision_schema = dsdb_get_schema(s->ldb, s);
108         s->schema           = s->provision_schema;
109
110         return s;
111 }
112
113 /* Caller is expected to keep supplied pointers around for the lifetime of the structure */
114 void *libnet_vampire_cb_state_init(TALLOC_CTX *mem_ctx,
115                                    struct loadparm_context *lp_ctx, struct tevent_context *event_ctx,
116                                    const char *netbios_name, const char *domain_name, const char *realm,
117                                    const char *targetdir)
118 {
119         struct libnet_vampire_cb_state *s = talloc_zero(mem_ctx, struct libnet_vampire_cb_state);
120         if (!s) {
121                 return NULL;
122         }
123
124         s->lp_ctx = lp_ctx;
125         s->event_ctx = event_ctx;
126         s->netbios_name = netbios_name;
127         s->domain_name = domain_name;
128         s->realm = realm;
129         s->targetdir = targetdir;
130         return s;
131 }
132
133 struct ldb_context *libnet_vampire_cb_ldb(struct libnet_vampire_cb_state *state)
134 {
135         state = talloc_get_type_abort(state, struct libnet_vampire_cb_state);
136         return state->ldb;
137 }
138
139 struct loadparm_context *libnet_vampire_cb_lp_ctx(struct libnet_vampire_cb_state *state)
140 {
141         state = talloc_get_type_abort(state, struct libnet_vampire_cb_state);
142         return state->lp_ctx;
143 }
144
145 NTSTATUS libnet_vampire_cb_prepare_db(void *private_data,
146                                       const struct libnet_BecomeDC_PrepareDB *p)
147 {
148         struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
149         struct provision_settings settings;
150         struct provision_result result;
151         NTSTATUS status;
152
153         ZERO_STRUCT(settings);
154         settings.site_name = p->dest_dsa->site_name;
155         settings.root_dn_str = p->forest->root_dn_str;
156         settings.domain_dn_str = p->domain->dn_str;
157         settings.config_dn_str = p->forest->config_dn_str;
158         settings.schema_dn_str = p->forest->schema_dn_str;
159         settings.netbios_name = p->dest_dsa->netbios_name;
160         settings.realm = s->realm;
161         settings.domain = s->domain_name;
162         settings.server_dn_str = p->dest_dsa->server_dn_str;
163         settings.machine_password = generate_random_password(s, 16, 255);
164         settings.targetdir = s->targetdir;
165
166         status = provision_bare(s, s->lp_ctx, &settings, &result);
167
168         if (!NT_STATUS_IS_OK(status)) {
169                 return status;
170         }
171
172         s->ldb = talloc_steal(s, result.samdb);
173         s->lp_ctx = talloc_steal(s, result.lp_ctx);
174         s->provision_schema = dsdb_get_schema(s->ldb, s);
175         s->server_dn_str = talloc_steal(s, p->dest_dsa->server_dn_str);
176
177         /* wrap the entire vapire operation in a transaction.  This
178            isn't just cosmetic - we use this to ensure that linked
179            attribute back links are added at the end by relying on a
180            transaction commit hook in the linked attributes module. We
181            need to do this as the order of objects coming from the
182            server is not sufficiently deterministic to know that the
183            record that a backlink needs to be created in has itself
184            been created before the object containing the forward link
185            has come over the wire */
186         if (ldb_transaction_start(s->ldb) != LDB_SUCCESS) {
187                 return NT_STATUS_FOOBAR;
188         }
189
190         return NT_STATUS_OK;
191
192
193 }
194
195 NTSTATUS libnet_vampire_cb_check_options(void *private_data,
196                                          const struct libnet_BecomeDC_CheckOptions *o)
197 {
198         struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
199
200         DEBUG(0,("Become DC [%s] of Domain[%s]/[%s]\n",
201                 s->netbios_name,
202                 o->domain->netbios_name, o->domain->dns_name));
203
204         DEBUG(0,("Promotion Partner is Server[%s] from Site[%s]\n",
205                 o->source_dsa->dns_name, o->source_dsa->site_name));
206
207         DEBUG(0,("Options:crossRef behavior_version[%u]\n"
208                        "\tschema object_version[%u]\n"
209                        "\tdomain behavior_version[%u]\n"
210                        "\tdomain w2k3_update_revision[%u]\n", 
211                 o->forest->crossref_behavior_version,
212                 o->forest->schema_object_version,
213                 o->domain->behavior_version,
214                 o->domain->w2k3_update_revision));
215
216         return NT_STATUS_OK;
217 }
218
219 static NTSTATUS libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s,
220                                                const struct libnet_BecomeDC_StoreChunk *c)
221 {
222         WERROR status;
223         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
224         uint32_t object_count;
225         struct drsuapi_DsReplicaObjectListItemEx *first_object;
226         const struct drsuapi_DsReplicaObjectListItemEx *cur;
227         uint32_t linked_attributes_count;
228         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
229         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
230         struct dsdb_extended_replicated_objects *schema_objs;
231         struct repsFromTo1 *s_dsa;
232         char *tmp_dns_name;
233         struct ldb_context *schema_ldb;
234         struct ldb_message *msg;
235         struct ldb_message_element *prefixMap_el;
236         uint32_t i;
237         int ret;
238         bool ok;
239         uint64_t seq_num;
240
241         DEBUG(0,("Analyze and apply schema objects\n"));
242
243         s_dsa                   = talloc_zero(s, struct repsFromTo1);
244         NT_STATUS_HAVE_NO_MEMORY(s_dsa);
245         s_dsa->other_info       = talloc(s_dsa, struct repsFromTo1OtherInfo);
246         NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
247
248         switch (c->ctr_level) {
249         case 1:
250                 mapping_ctr                     = &c->ctr1->mapping_ctr;
251                 object_count                    = s->schema_part.object_count;
252                 first_object                    = s->schema_part.first_object;
253                 linked_attributes_count         = 0;
254                 linked_attributes               = NULL;
255                 s_dsa->highwatermark            = c->ctr1->new_highwatermark;
256                 s_dsa->source_dsa_obj_guid      = c->ctr1->source_dsa_guid;
257                 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
258                 uptodateness_vector             = NULL; /* TODO: map it */
259                 break;
260         case 6:
261                 mapping_ctr                     = &c->ctr6->mapping_ctr;
262                 object_count                    = s->schema_part.object_count;
263                 first_object                    = s->schema_part.first_object;
264                 linked_attributes_count         = c->ctr6->linked_attributes_count;
265                 linked_attributes               = c->ctr6->linked_attributes;
266                 s_dsa->highwatermark            = c->ctr6->new_highwatermark;
267                 s_dsa->source_dsa_obj_guid      = c->ctr6->source_dsa_guid;
268                 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
269                 uptodateness_vector             = c->ctr6->uptodateness_vector;
270                 break;
271         default:
272                 return NT_STATUS_INVALID_PARAMETER;
273         }
274
275         s_dsa->replica_flags            = DRSUAPI_DRS_WRIT_REP
276                                         | DRSUAPI_DRS_INIT_SYNC
277                                         | DRSUAPI_DRS_PER_SYNC;
278         memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
279
280         tmp_dns_name    = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
281         NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
282         tmp_dns_name    = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
283         NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
284         s_dsa->other_info->dns_name = tmp_dns_name;
285
286         schema_ldb = provision_get_schema(s, s->lp_ctx, &s->prefixmap_blob);
287         if (!schema_ldb) {
288                 DEBUG(0,("Failed to re-load from local provision using remote prefixMap.  Will continue with local prefixMap\n"));
289                 s->provision_schema = dsdb_get_schema(s->ldb, s);
290         } else {
291                 s->provision_schema = dsdb_get_schema(schema_ldb, s);
292                 ret = dsdb_reference_schema(s->ldb, s->provision_schema, false);
293                 if (ret != LDB_SUCCESS) {
294                         DEBUG(0,("Failed to attach schema from local provision using remote prefixMap."));
295                         return NT_STATUS_UNSUCCESSFUL;
296                 }
297                 talloc_free(schema_ldb);
298         }
299
300         s->provision_schema->relax_OID_conversions = true;
301
302         /* Now convert the schema elements, using the schema we loaded locally */
303         for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
304                 struct dsdb_extended_replicated_object object;
305                 TALLOC_CTX *tmp_ctx = talloc_new(s);
306                 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
307
308                 /* Convert the objects into LDB messages using the
309                  * provision schema, and either the provision or DRS
310                  * prefix map - it should not matter, as these are
311                  * just schema objects, so the critical parts.  At
312                  * most we would mix up the mayContain etc for new
313                  * schema classes */
314                 status = dsdb_convert_object_ex(s->ldb, s->provision_schema,
315                                                 cur, c->gensec_skey,
316                                                 tmp_ctx, &object);
317                 if (!W_ERROR_IS_OK(status)) {
318                         DEBUG(1,("Warning: Failed to convert schema object %s into ldb msg\n", cur->object.identifier->dn));
319                 } else {
320                         /* Convert the schema from ldb_message format
321                          * (OIDs as OID strings) into schema, using
322                          * the remote prefixMap */
323                         status = dsdb_schema_set_el_from_ldb_msg(s->ldb, s->self_made_schema, object.msg);
324                         if (!W_ERROR_IS_OK(status)) {
325                                 DEBUG(1,("Warning: failed to convert object %s into a schema element: %s\n",
326                                          ldb_dn_get_linearized(object.msg->dn),
327                                          win_errstr(status)));
328                         }
329                 }
330                 talloc_free(tmp_ctx);
331         }
332
333         /* attach the schema we just brought over DRS to the ldb, so we can use it in dsdb_convert_object_ex below */
334         ret = dsdb_set_schema(s->ldb, s->self_made_schema);
335         if (ret != LDB_SUCCESS) {
336                 DEBUG(0,("Failed to attach 1st pass schema from DRS.\n"));
337                 return NT_STATUS_FOOBAR;
338         }
339
340         /* Now convert the schema elements again, using the schema we loaded over DRS */
341         for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
342                 struct dsdb_extended_replicated_object object;
343                 TALLOC_CTX *tmp_ctx = talloc_new(s);
344                 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
345
346                 /* Convert the objects into LDB messages using the
347                  * self_made_schema, and the DRS prefix map.  We now
348                  * know the full schema int->OID->name mapping, so we
349                  * can get it right this time */
350                 status = dsdb_convert_object_ex(s->ldb, s->self_made_schema,
351                                                 cur, c->gensec_skey,
352                                                 tmp_ctx, &object);
353                 if (!W_ERROR_IS_OK(status)) {
354                         DEBUG(0,("ERROR: Failed to convert schema object %s into ldb msg\n", cur->object.identifier->dn));
355                 } else {
356                         /* Convert the schema from ldb_message format
357                          * (OIDs as OID strings) into schema, using
358                          * the remote prefixMap, now that we know
359                          * names for all the schema elements (from the
360                          * first conversion) */
361                         status = dsdb_schema_set_el_from_ldb_msg(s->ldb, s->self_corrected_schema, object.msg);
362                         if (!W_ERROR_IS_OK(status)) {
363                                 DEBUG(0,("ERROR: failed to convert object %s into a schema element: %s\n",
364                                          ldb_dn_get_linearized(object.msg->dn),
365                                          win_errstr(status)));
366                         }
367                 }
368                 talloc_free(tmp_ctx);
369         }
370
371         /* We don't want to use the s->self_made_schema any more */
372         s->self_made_schema = NULL;
373
374         /* attach the schema we just brought over DRS to the ldb */
375         ret = dsdb_set_schema(s->ldb, s->self_corrected_schema);
376         if (ret != LDB_SUCCESS) {
377                 DEBUG(0,("Failed to attach 2nd pass (corrected) schema from DRS.\n"));
378                 return NT_STATUS_FOOBAR;
379         }
380
381         /* we don't want to access the self made schema anymore */
382         s->schema = s->self_corrected_schema;
383         s->self_corrected_schema = NULL;
384
385         /* Now convert the schema elements again, using the schema we finalised, ready to actually import */
386         status = dsdb_extended_replicated_objects_convert(s->ldb,
387                                                           c->partition->nc.dn,
388                                                           mapping_ctr,
389                                                           object_count,
390                                                           first_object,
391                                                           linked_attributes_count,
392                                                           linked_attributes,
393                                                           s_dsa,
394                                                           uptodateness_vector,
395                                                           c->gensec_skey,
396                                                           s, &schema_objs);
397         if (!W_ERROR_IS_OK(status)) {
398                 DEBUG(0,("Failed to convert objects when trying to import over DRS (2nd pass, to store remote schema): %s\n", win_errstr(status)));
399                 return werror_to_ntstatus(status);
400         }
401
402         if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
403                 for (i=0; i < schema_objs->num_objects; i++) {
404                         struct ldb_ldif ldif;
405                         fprintf(stdout, "#\n");
406                         ldif.changetype = LDB_CHANGETYPE_NONE;
407                         ldif.msg = schema_objs->objects[i].msg;
408                         ldb_ldif_write_file(s->ldb, stdout, &ldif);
409                         NDR_PRINT_DEBUG(replPropertyMetaDataBlob, schema_objs->objects[i].meta_data);
410                 }
411         }
412
413         status = dsdb_extended_replicated_objects_commit(s->ldb, schema_objs, &seq_num);
414         if (!W_ERROR_IS_OK(status)) {
415                 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
416                 return werror_to_ntstatus(status);
417         }
418
419         msg = ldb_msg_new(schema_objs);
420         NT_STATUS_HAVE_NO_MEMORY(msg);
421         msg->dn = schema_objs->partition_dn;
422
423         /* We must ensure a prefixMap has been written.  Unlike other
424          * attributes (including schemaInfo), it is not replicated in
425          * the normal replication stream.  We can use the one from
426          * s->prefixmap_blob because we operate with one, unchanging
427          * prefixMap for this entire operation.  */
428         ret = ldb_msg_add_value(msg, "prefixMap", &s->prefixmap_blob, &prefixMap_el);
429         if (ret != LDB_SUCCESS) {
430                 return NT_STATUS_FOOBAR;
431         }
432         /* We want to know if a prefixMap was written already, as it
433          * would mean that the above comment was not true, and we have
434          * somehow updated the prefixMap during this transaction */
435         prefixMap_el->flags = LDB_FLAG_MOD_ADD;
436
437         ret = ldb_modify(s->ldb, msg);
438         if (ret != LDB_SUCCESS) {
439                 DEBUG(0,("Failed to add prefixMap: %s\n", ldb_errstring(s->ldb)));
440                 return NT_STATUS_FOOBAR;
441         }
442
443         talloc_free(s_dsa);
444         talloc_free(schema_objs);
445
446         /* We must set these up to ensure the replMetaData is written
447          * correctly, before our NTDS Settings entry is replicated */
448         ok = samdb_set_ntds_invocation_id(s->ldb, &c->dest_dsa->invocation_id);
449         if (!ok) {
450                 DEBUG(0,("Failed to set cached ntds invocationId\n"));
451                 return NT_STATUS_FOOBAR;
452         }
453         ok = samdb_set_ntds_objectGUID(s->ldb, &c->dest_dsa->ntds_guid);
454         if (!ok) {
455                 DEBUG(0,("Failed to set cached ntds objectGUID\n"));
456                 return NT_STATUS_FOOBAR;
457         }
458
459         s->schema = dsdb_get_schema(s->ldb, s);
460         if (!s->schema) {
461                 DEBUG(0,("Failed to get loaded dsdb_schema\n"));
462                 return NT_STATUS_FOOBAR;
463         }
464
465         return NT_STATUS_OK;
466 }
467
468 NTSTATUS libnet_vampire_cb_schema_chunk(void *private_data,
469                                         const struct libnet_BecomeDC_StoreChunk *c)
470 {
471         struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
472         WERROR status;
473         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
474         uint32_t nc_object_count;
475         uint32_t object_count;
476         struct drsuapi_DsReplicaObjectListItemEx *first_object;
477         struct drsuapi_DsReplicaObjectListItemEx *cur;
478         uint32_t nc_linked_attributes_count;
479         uint32_t linked_attributes_count;
480         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
481
482         switch (c->ctr_level) {
483         case 1:
484                 mapping_ctr                     = &c->ctr1->mapping_ctr;
485                 nc_object_count                 = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
486                 object_count                    = c->ctr1->object_count;
487                 first_object                    = c->ctr1->first_object;
488                 nc_linked_attributes_count      = 0;
489                 linked_attributes_count         = 0;
490                 linked_attributes               = NULL;
491                 break;
492         case 6:
493                 mapping_ctr                     = &c->ctr6->mapping_ctr;
494                 nc_object_count                 = c->ctr6->nc_object_count;
495                 object_count                    = c->ctr6->object_count;
496                 first_object                    = c->ctr6->first_object;
497                 nc_linked_attributes_count      = c->ctr6->nc_linked_attributes_count;
498                 linked_attributes_count         = c->ctr6->linked_attributes_count;
499                 linked_attributes               = c->ctr6->linked_attributes;
500                 break;
501         default:
502                 return NT_STATUS_INVALID_PARAMETER;
503         }
504
505         if (nc_object_count) {
506                 DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n",
507                         c->partition->nc.dn, object_count, nc_object_count,
508                         linked_attributes_count, nc_linked_attributes_count));
509         } else {
510                 DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u]\n",
511                 c->partition->nc.dn, object_count, linked_attributes_count));
512         }
513
514         if (!s->self_made_schema) {
515                 WERROR werr;
516                 struct drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr_without_schema_info;
517                 /* Put the DRS prefixmap aside for the schema we are
518                  * about to load in the provision, and into the one we
519                  * are making with the help of DRS */
520
521                 mapping_ctr_without_schema_info = *mapping_ctr;
522
523                 /* This strips off the 0xFF schema info from the end,
524                  * because we don't want it in the blob */
525                 if (mapping_ctr_without_schema_info.num_mappings > 0) {
526                         mapping_ctr_without_schema_info.num_mappings--;
527                 }
528                 werr = dsdb_get_drsuapi_prefixmap_as_blob(&mapping_ctr_without_schema_info, s, &s->prefixmap_blob);
529                 if (!W_ERROR_IS_OK(werr)) {
530                         return werror_to_ntstatus(werr);
531                 }
532
533                 /* Set up two manually-constructed schema - the local
534                  * schema from the provision will be used to build
535                  * one, which will then in turn be used to build the
536                  * other. */
537                 s->self_made_schema = dsdb_new_schema(s);
538                 NT_STATUS_HAVE_NO_MEMORY(s->self_made_schema);
539                 s->self_corrected_schema = dsdb_new_schema(s);
540                 NT_STATUS_HAVE_NO_MEMORY(s->self_corrected_schema);
541
542                 status = dsdb_load_prefixmap_from_drsuapi(s->self_made_schema, mapping_ctr);
543                 if (!W_ERROR_IS_OK(status)) {
544                         return werror_to_ntstatus(status);
545                 }
546
547                 status = dsdb_load_prefixmap_from_drsuapi(s->self_corrected_schema, mapping_ctr);
548                 if (!W_ERROR_IS_OK(status)) {
549                         return werror_to_ntstatus(status);
550                 }
551         } else {
552                 status = dsdb_schema_pfm_contains_drsuapi_pfm(s->self_made_schema->prefixmap, mapping_ctr);
553                 if (!W_ERROR_IS_OK(status)) {
554                         return werror_to_ntstatus(status);
555                 }
556         }
557
558         if (!s->schema_part.first_object) {
559                 s->schema_part.object_count = object_count;
560                 s->schema_part.first_object = talloc_steal(s, first_object);
561         } else {
562                 s->schema_part.object_count             += object_count;
563                 s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
564                                                                        first_object);
565         }
566         for (cur = first_object; cur->next_object; cur = cur->next_object) {}
567         s->schema_part.last_object = cur;
568
569         if (!c->partition->more_data) {
570                 return libnet_vampire_cb_apply_schema(s, c);
571         }
572
573         return NT_STATUS_OK;
574 }
575
576 NTSTATUS libnet_vampire_cb_store_chunk(void *private_data,
577                              const struct libnet_BecomeDC_StoreChunk *c)
578 {
579         struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
580         WERROR status;
581         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
582         uint32_t nc_object_count;
583         uint32_t object_count;
584         struct drsuapi_DsReplicaObjectListItemEx *first_object;
585         uint32_t nc_linked_attributes_count;
586         uint32_t linked_attributes_count;
587         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
588         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
589         struct dsdb_extended_replicated_objects *objs;
590         struct repsFromTo1 *s_dsa;
591         char *tmp_dns_name;
592         uint32_t i;
593         uint64_t seq_num;
594
595         s_dsa                   = talloc_zero(s, struct repsFromTo1);
596         NT_STATUS_HAVE_NO_MEMORY(s_dsa);
597         s_dsa->other_info       = talloc(s_dsa, struct repsFromTo1OtherInfo);
598         NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
599
600         switch (c->ctr_level) {
601         case 1:
602                 mapping_ctr                     = &c->ctr1->mapping_ctr;
603                 nc_object_count                 = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
604                 object_count                    = c->ctr1->object_count;
605                 first_object                    = c->ctr1->first_object;
606                 nc_linked_attributes_count      = 0;
607                 linked_attributes_count         = 0;
608                 linked_attributes               = NULL;
609                 s_dsa->highwatermark            = c->ctr1->new_highwatermark;
610                 s_dsa->source_dsa_obj_guid      = c->ctr1->source_dsa_guid;
611                 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
612                 uptodateness_vector             = NULL; /* TODO: map it */
613                 break;
614         case 6:
615                 mapping_ctr                     = &c->ctr6->mapping_ctr;
616                 nc_object_count                 = c->ctr6->nc_object_count;
617                 object_count                    = c->ctr6->object_count;
618                 first_object                    = c->ctr6->first_object;
619                 nc_linked_attributes_count      = c->ctr6->nc_linked_attributes_count;
620                 linked_attributes_count         = c->ctr6->linked_attributes_count;
621                 linked_attributes               = c->ctr6->linked_attributes;
622                 s_dsa->highwatermark            = c->ctr6->new_highwatermark;
623                 s_dsa->source_dsa_obj_guid      = c->ctr6->source_dsa_guid;
624                 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
625                 uptodateness_vector             = c->ctr6->uptodateness_vector;
626                 break;
627         default:
628                 return NT_STATUS_INVALID_PARAMETER;
629         }
630
631         s_dsa->replica_flags            = DRSUAPI_DRS_WRIT_REP
632                                         | DRSUAPI_DRS_INIT_SYNC
633                                         | DRSUAPI_DRS_PER_SYNC;
634         memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
635
636         tmp_dns_name    = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
637         NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
638         tmp_dns_name    = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
639         NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
640         s_dsa->other_info->dns_name = tmp_dns_name;
641
642         /* we want to show a count per partition */
643         if (!s->last_partition || strcmp(s->last_partition, c->partition->nc.dn) != 0) {
644                 s->total_objects = 0;
645                 talloc_free(s->last_partition);
646                 s->last_partition = talloc_strdup(s, c->partition->nc.dn);
647         }
648         s->total_objects += object_count;
649
650         if (nc_object_count) {
651                 DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n",
652                         c->partition->nc.dn, s->total_objects, nc_object_count,
653                         linked_attributes_count, nc_linked_attributes_count));
654         } else {
655                 DEBUG(0,("Partition[%s] objects[%u] linked_values[%u]\n",
656                 c->partition->nc.dn, s->total_objects, linked_attributes_count));
657         }
658
659
660         status = dsdb_extended_replicated_objects_convert(s->ldb,
661                                                           c->partition->nc.dn,
662                                                           mapping_ctr,
663                                                           object_count,
664                                                           first_object,
665                                                           linked_attributes_count,
666                                                           linked_attributes,
667                                                           s_dsa,
668                                                           uptodateness_vector,
669                                                           c->gensec_skey,
670                                                           s, &objs);
671         if (!W_ERROR_IS_OK(status)) {
672                 DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status)));
673                 return werror_to_ntstatus(status);
674         }
675
676         if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
677                 for (i=0; i < objs->num_objects; i++) {
678                         struct ldb_ldif ldif;
679                         fprintf(stdout, "#\n");
680                         ldif.changetype = LDB_CHANGETYPE_NONE;
681                         ldif.msg = objs->objects[i].msg;
682                         ldb_ldif_write_file(s->ldb, stdout, &ldif);
683                         NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
684                 }
685         }
686         status = dsdb_extended_replicated_objects_commit(s->ldb,
687                                                          objs, &seq_num);
688         if (!W_ERROR_IS_OK(status)) {
689                 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
690                 return werror_to_ntstatus(status);
691         }
692
693         talloc_free(s_dsa);
694         talloc_free(objs);
695
696         for (i=0; i < linked_attributes_count; i++) {
697                 const struct dsdb_attribute *sa;
698
699                 if (!linked_attributes[i].identifier) {
700                         return NT_STATUS_FOOBAR;                
701                 }
702
703                 if (!linked_attributes[i].value.blob) {
704                         return NT_STATUS_FOOBAR;                
705                 }
706
707                 sa = dsdb_attribute_by_attributeID_id(s->schema,
708                                                       linked_attributes[i].attid);
709                 if (!sa) {
710                         return NT_STATUS_FOOBAR;
711                 }
712
713                 if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
714                         DEBUG(0,("# %s\n", sa->lDAPDisplayName));
715                         NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, &linked_attributes[i]);
716                         dump_data(0,
717                                 linked_attributes[i].value.blob->data,
718                                 linked_attributes[i].value.blob->length);
719                 }
720         }
721
722         return NT_STATUS_OK;
723 }
724
725 static NTSTATUS update_dnshostname_for_server(TALLOC_CTX *mem_ctx,
726                                               struct ldb_context *ldb,
727                                               const char *server_dn_str,
728                                               const char *netbios_name,
729                                               const char *realm)
730 {
731         int ret;
732         struct ldb_message *msg;
733         struct ldb_message_element *el;
734         struct ldb_dn *server_dn;
735         const char *dNSHostName = strlower_talloc(mem_ctx,
736                                                   talloc_asprintf(mem_ctx,
737                                                                   "%s.%s",
738                                                                   netbios_name,
739                                                                   realm));
740         msg = ldb_msg_new(mem_ctx);
741         if (msg == NULL) {
742                 return NT_STATUS_NO_MEMORY;
743         }
744
745         server_dn = ldb_dn_new(mem_ctx, ldb, server_dn_str);
746         if (!server_dn) {
747                 return NT_STATUS_INTERNAL_ERROR;
748         }
749
750         msg->dn = server_dn;
751         ret = ldb_msg_add_empty(msg, "dNSHostName", LDB_FLAG_MOD_ADD, &el);
752         if (ret != LDB_SUCCESS) {
753                 return NT_STATUS_INTERNAL_ERROR;
754         }
755
756         ret = ldb_msg_add_steal_string(msg,
757                                        "dNSHostName",
758                                        talloc_asprintf(el->values, "%s", dNSHostName));
759         if (ret != LDB_SUCCESS) {
760                 return NT_STATUS_INTERNAL_ERROR;
761         }
762
763         ret = dsdb_modify(ldb, msg, DSDB_MODIFY_PERMISSIVE);
764         if (ret != LDB_SUCCESS) {
765                 DEBUG(0,(__location__ ": Failed to add dnsHostName to the Server object: %s\n",
766                          ldb_errstring(ldb)));
767                 return NT_STATUS_INTERNAL_ERROR;
768         }
769
770         return NT_STATUS_OK;
771 }
772
773
774 NTSTATUS libnet_Vampire(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, 
775                         struct libnet_Vampire *r)
776 {
777         struct libnet_JoinDomain *join;
778         struct libnet_Replicate rep;
779         NTSTATUS status;
780
781         const char *account_name;
782         const char *netbios_name;
783         
784         r->out.error_string = NULL;
785
786         join = talloc_zero(mem_ctx, struct libnet_JoinDomain);
787         if (!join) {
788                 return NT_STATUS_NO_MEMORY;
789         }
790                 
791         if (r->in.netbios_name != NULL) {
792                 netbios_name = r->in.netbios_name;
793         } else {
794                 netbios_name = talloc_reference(join, lpcfg_netbios_name(ctx->lp_ctx));
795                 if (!netbios_name) {
796                         talloc_free(join);
797                         r->out.error_string = NULL;
798                         return NT_STATUS_NO_MEMORY;
799                 }
800         }
801
802         account_name = talloc_asprintf(join, "%s$", netbios_name);
803         if (!account_name) {
804                 talloc_free(join);
805                 r->out.error_string = NULL;
806                 return NT_STATUS_NO_MEMORY;
807         }
808         
809         /* Re-use the domain we are joining as the domain for the user
810          * to be authenticated with, unless they specified
811          * otherwise */
812         cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
813
814         join->in.domain_name    = r->in.domain_name;
815         join->in.account_name   = account_name;
816         join->in.netbios_name   = netbios_name;
817         join->in.level          = LIBNET_JOINDOMAIN_AUTOMATIC;
818         join->in.acct_type      = ACB_WSTRUST;
819         join->in.recreate_account = false;
820         status = libnet_JoinDomain(ctx, join, join);
821         if (!NT_STATUS_IS_OK(status)) {
822                 r->out.error_string = talloc_steal(mem_ctx, join->out.error_string);
823                 talloc_free(join);
824                 return status;
825         }
826
827         rep.in.domain_name   = join->out.domain_name;
828         rep.in.netbios_name  = netbios_name;
829         rep.in.targetdir     = r->in.targetdir;
830         rep.in.domain_sid    = join->out.domain_sid;
831         rep.in.realm         = join->out.realm;
832         rep.in.server        = join->out.samr_binding->host;
833         rep.in.join_password = join->out.join_password;
834         rep.in.kvno          = join->out.kvno;
835
836         status = libnet_Replicate(ctx, mem_ctx, &rep);
837
838         r->out.domain_sid   = join->out.domain_sid;
839         r->out.domain_name  = join->out.domain_name;
840         r->out.error_string = rep.out.error_string;
841
842         return status;
843 }
844
845
846
847 NTSTATUS libnet_Replicate(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
848                           struct libnet_Replicate *r)
849 {
850         struct provision_store_self_join_settings *set_secrets;
851         struct libnet_BecomeDC b;
852         struct libnet_vampire_cb_state *s;
853         struct ldb_message *msg;
854         const char *error_string;
855         int ldb_ret;
856         uint32_t i;
857         NTSTATUS status;
858         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
859         const char *account_name;
860         const char *netbios_name;
861
862         r->out.error_string = NULL;
863
864         netbios_name = r->in.netbios_name;
865         account_name = talloc_asprintf(tmp_ctx, "%s$", netbios_name);
866         if (!account_name) {
867                 talloc_free(tmp_ctx);
868                 r->out.error_string = NULL;
869                 return NT_STATUS_NO_MEMORY;
870         }
871         
872         /* Re-use the domain we are joining as the domain for the user
873          * to be authenticated with, unless they specified
874          * otherwise */
875         cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
876
877         s = libnet_vampire_cb_state_init(mem_ctx, ctx->lp_ctx, ctx->event_ctx,
878                                          netbios_name, r->in.domain_name, r->in.realm,
879                                          r->in.targetdir);
880         if (!s) {
881                 return NT_STATUS_NO_MEMORY;
882         }
883         talloc_steal(s, tmp_ctx);
884
885         ZERO_STRUCT(b);
886
887         /* Be more robust:
888          * We now know the domain and realm for sure - if they didn't
889          * put one on the command line, use this for the rest of the
890          * join */
891         cli_credentials_set_realm(ctx->cred, r->in.realm, CRED_GUESS_ENV);
892         cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
893
894         /* Now set these values into the smb.conf - we probably had
895          * empty or useless defaults here from whatever smb.conf we
896          * started with */
897         lpcfg_set_cmdline(s->lp_ctx, "realm", r->in.realm);
898         lpcfg_set_cmdline(s->lp_ctx, "workgroup", r->in.domain_name);
899
900         b.in.domain_dns_name            = r->in.realm;
901         b.in.domain_netbios_name        = r->in.domain_name;
902         b.in.domain_sid                 = r->in.domain_sid;
903         b.in.source_dsa_address         = r->in.server;
904         b.in.dest_dsa_netbios_name      = netbios_name;
905
906         b.in.callbacks.private_data     = s;
907         b.in.callbacks.check_options    = libnet_vampire_cb_check_options;
908         b.in.callbacks.prepare_db       = libnet_vampire_cb_prepare_db;
909         b.in.callbacks.schema_chunk     = libnet_vampire_cb_schema_chunk;
910         b.in.callbacks.config_chunk     = libnet_vampire_cb_store_chunk;
911         b.in.callbacks.domain_chunk     = libnet_vampire_cb_store_chunk;
912
913         b.in.rodc_join = lpcfg_parm_bool(s->lp_ctx, NULL, "repl", "RODC", false);
914
915         status = libnet_BecomeDC(ctx, s, &b);
916         if (!NT_STATUS_IS_OK(status)) {
917                 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
918                 talloc_free(s);
919                 return status;
920         }
921
922         msg = ldb_msg_new(s);
923         if (!msg) {
924                 printf("ldb_msg_new() failed\n");
925                 talloc_free(s);
926                 return NT_STATUS_NO_MEMORY;
927         }
928         msg->dn = ldb_dn_new(msg, s->ldb, "@ROOTDSE");
929         if (!msg->dn) {
930                 printf("ldb_msg_new(@ROOTDSE) failed\n");
931                 talloc_free(s);
932                 return NT_STATUS_NO_MEMORY;
933         }
934
935         ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE");
936         if (ldb_ret != LDB_SUCCESS) {
937                 printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret);
938                 talloc_free(s);
939                 return NT_STATUS_NO_MEMORY;
940         }
941
942         for (i=0; i < msg->num_elements; i++) {
943                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
944         }
945
946         printf("mark ROOTDSE with isSynchronized=TRUE\n");
947         ldb_ret = ldb_modify(s->ldb, msg);
948         if (ldb_ret != LDB_SUCCESS) {
949                 printf("ldb_modify() failed: %d : %s\n", ldb_ret, ldb_errstring(s->ldb));
950                 talloc_free(s);
951                 return NT_STATUS_INTERNAL_DB_ERROR;
952         }
953         /* during dcpromo the 2nd computer adds dNSHostName attribute to his Server object
954          * the attribute appears on the original DC after replication
955          */
956         status = update_dnshostname_for_server(s, s->ldb, s->server_dn_str, s->netbios_name, s->realm);
957         if (!NT_STATUS_IS_OK(status)) {
958                 printf("Failed to update dNSHostName on Server object - %s\n", nt_errstr(status));
959                 talloc_free(s);
960                 return status;
961         }
962         /* prepare the transaction - this prepares to commit all the changes in
963            the ldb from the whole vampire.  Note that this 
964            triggers the writing of the linked attribute backlinks.
965         */
966         if (ldb_transaction_prepare_commit(s->ldb) != LDB_SUCCESS) {
967                 printf("Failed to prepare_commit vampire transaction: %s\n", ldb_errstring(s->ldb));
968                 return NT_STATUS_INTERNAL_DB_ERROR;
969         }
970
971         set_secrets = talloc(s, struct provision_store_self_join_settings);
972         if (!set_secrets) {
973                 r->out.error_string = NULL;
974                 talloc_free(s);
975                 return NT_STATUS_NO_MEMORY;
976         }
977         
978         ZERO_STRUCTP(set_secrets);
979         set_secrets->domain_name = r->in.domain_name;
980         set_secrets->realm = r->in.realm;
981         set_secrets->netbios_name = netbios_name;
982         set_secrets->secure_channel_type = SEC_CHAN_BDC;
983         set_secrets->machine_password = r->in.join_password;
984         set_secrets->key_version_number = r->in.kvno;
985         set_secrets->domain_sid = r->in.domain_sid;
986         
987         status = provision_store_self_join(ctx, s->lp_ctx, ctx->event_ctx, set_secrets, &error_string);
988         if (!NT_STATUS_IS_OK(status)) {
989                 r->out.error_string = talloc_steal(mem_ctx, error_string);
990                 talloc_free(s);
991                 return status;
992         }
993
994         /* commit the transaction now we know the secrets were written
995          * out properly
996         */
997         if (ldb_transaction_commit(s->ldb) != LDB_SUCCESS) {
998                 printf("Failed to commit vampire transaction\n");
999                 return NT_STATUS_INTERNAL_DB_ERROR;
1000         }
1001
1002         talloc_free(s);
1003
1004         return NT_STATUS_OK;
1005 }