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