s4-libnet_vampire: Ignore some attributes when building working schema cache
[kamenim/samba.git] / source4 / libnet / libnet_vampire.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    Extract the user/system database from a remote server
5
6    Copyright (C) Stefan Metzmacher      2004-2006
7    Copyright (C) Brad Henry 2005
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2008
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24
25 #include "includes.h"
26 #include "libnet/libnet.h"
27 #include "lib/events/events.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "../lib/util/dlinklist.h"
30 #include <ldb.h>
31 #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/security.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         /* prefixMap in LDB format, from the remote DRS server */
72         DATA_BLOB prefixmap_blob;
73         const struct dsdb_schema *schema;
74
75         struct ldb_context *ldb;
76
77         struct {
78                 uint32_t object_count;
79                 struct drsuapi_DsReplicaObjectListItemEx *first_object;
80                 struct drsuapi_DsReplicaObjectListItemEx *last_object;
81         } schema_part;
82
83         const char *targetdir;
84
85         struct loadparm_context *lp_ctx;
86         struct tevent_context *event_ctx;
87         unsigned total_objects;
88         char *last_partition;
89         const char *server_dn_str;
90 };
91
92 /* initialise a state structure ready for replication of chunks */
93 void *libnet_vampire_replicate_init(TALLOC_CTX *mem_ctx,
94                                     struct ldb_context *samdb,
95                                     struct loadparm_context *lp_ctx)
96 {
97         struct libnet_vampire_cb_state *s = talloc_zero(mem_ctx, struct libnet_vampire_cb_state);
98         if (!s) {
99                 return NULL;
100         }
101
102         s->ldb              = samdb;
103         s->lp_ctx           = lp_ctx;
104         s->provision_schema = dsdb_get_schema(s->ldb, s);
105         s->schema           = s->provision_schema;
106         s->netbios_name     = lpcfg_netbios_name(lp_ctx);
107         s->domain_name      = lpcfg_workgroup(lp_ctx);
108         s->realm            = lpcfg_realm(lp_ctx);
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_reparent(talloc_parent(result.lp_ctx), 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         struct schema_list {
223                 struct schema_list *next, *prev;
224                 const struct drsuapi_DsReplicaObjectListItemEx *obj;
225         };
226
227         WERROR status;
228         struct dsdb_schema_prefixmap *pfm_remote;
229         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
230         struct schema_list *schema_list = NULL, *schema_list_item, *schema_list_next_item;
231         struct dsdb_schema *working_schema;
232         struct dsdb_schema *provision_schema;
233         uint32_t object_count = 0;
234         struct drsuapi_DsReplicaObjectListItemEx *first_object;
235         const struct drsuapi_DsReplicaObjectListItemEx *cur;
236         uint32_t linked_attributes_count;
237         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
238         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
239         struct dsdb_extended_replicated_objects *schema_objs;
240         struct repsFromTo1 *s_dsa;
241         char *tmp_dns_name;
242         struct ldb_context *schema_ldb;
243         struct ldb_message *msg;
244         struct ldb_message_element *prefixMap_el;
245         uint32_t i;
246         int ret, pass_no;
247         bool ok;
248         uint64_t seq_num;
249         uint32_t ignore_attids[] = {
250                         DRSUAPI_ATTID_auxiliaryClass,
251                         DRSUAPI_ATTID_mayContain,
252                         DRSUAPI_ATTID_mustContain,
253                         DRSUAPI_ATTID_possSuperiors,
254                         DRSUAPI_ATTID_systemPossSuperiors,
255                         DRSUAPI_ATTID_INVALID
256         };
257
258         DEBUG(0,("Analyze and apply schema objects\n"));
259
260         s_dsa                   = talloc_zero(s, struct repsFromTo1);
261         NT_STATUS_HAVE_NO_MEMORY(s_dsa);
262         s_dsa->other_info       = talloc(s_dsa, struct repsFromTo1OtherInfo);
263         NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
264
265         switch (c->ctr_level) {
266         case 1:
267                 mapping_ctr                     = &c->ctr1->mapping_ctr;
268                 object_count                    = s->schema_part.object_count;
269                 first_object                    = s->schema_part.first_object;
270                 linked_attributes_count         = 0;
271                 linked_attributes               = NULL;
272                 s_dsa->highwatermark            = c->ctr1->new_highwatermark;
273                 s_dsa->source_dsa_obj_guid      = c->ctr1->source_dsa_guid;
274                 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
275                 uptodateness_vector             = NULL; /* TODO: map it */
276                 break;
277         case 6:
278                 mapping_ctr                     = &c->ctr6->mapping_ctr;
279                 object_count                    = s->schema_part.object_count;
280                 first_object                    = s->schema_part.first_object;
281                 linked_attributes_count         = c->ctr6->linked_attributes_count;
282                 linked_attributes               = c->ctr6->linked_attributes;
283                 s_dsa->highwatermark            = c->ctr6->new_highwatermark;
284                 s_dsa->source_dsa_obj_guid      = c->ctr6->source_dsa_guid;
285                 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
286                 uptodateness_vector             = c->ctr6->uptodateness_vector;
287                 break;
288         default:
289                 return NT_STATUS_INVALID_PARAMETER;
290         }
291
292         status = dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr, true,
293                                                   s, &pfm_remote, NULL);
294         if (!W_ERROR_IS_OK(status)) {
295                 DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s",
296                          win_errstr(status)));
297                 return werror_to_ntstatus(status);
298         }
299
300         s_dsa->replica_flags            = DRSUAPI_DRS_WRIT_REP
301                                         | DRSUAPI_DRS_INIT_SYNC
302                                         | DRSUAPI_DRS_PER_SYNC;
303         memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
304
305         tmp_dns_name    = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
306         NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
307         tmp_dns_name    = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
308         NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
309         s_dsa->other_info->dns_name = tmp_dns_name;
310
311         schema_ldb = provision_get_schema(s, s->lp_ctx, &s->prefixmap_blob);
312         if (!schema_ldb) {
313                 DEBUG(0,("Failed to re-load from local provision using remote prefixMap. "
314                          "Will continue with local prefixMap\n"));
315                 provision_schema = dsdb_get_schema(s->ldb, s);
316         } else {
317                 provision_schema = dsdb_get_schema(schema_ldb, s);
318                 ret = dsdb_reference_schema(s->ldb, provision_schema, false);
319                 if (ret != LDB_SUCCESS) {
320                         DEBUG(0,("Failed to attach schema from local provision using remote prefixMap."));
321                         return NT_STATUS_UNSUCCESSFUL;
322                 }
323                 talloc_free(schema_ldb);
324         }
325
326         /* create a list of objects yet to be converted */
327         for (cur = first_object; cur; cur = cur->next_object) {
328                 schema_list_item = talloc(s, struct schema_list);
329                 schema_list_item->obj = cur;
330                 DLIST_ADD_END(schema_list, schema_list_item, struct schema_list);
331         }
332
333         /* resolve objects until all are resolved and in local schema */
334         pass_no = 1;
335         working_schema = provision_schema;
336
337         while (schema_list) {
338                 uint32_t converted_obj_count = 0;
339                 uint32_t failed_obj_count = 0;
340                 TALLOC_CTX *tmp_ctx = talloc_new(s);
341                 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
342
343                 for (schema_list_item = schema_list; schema_list_item; schema_list_item=schema_list_next_item) {
344                         struct dsdb_extended_replicated_object object;
345
346                         cur = schema_list_item->obj;
347
348                         /* Save the next item, now we have saved out
349                          * the current one, so we can DLIST_REMOVE it
350                          * safely */
351                         schema_list_next_item = schema_list_item->next;
352
353                         /*
354                          * Convert the objects into LDB messages using the
355                          * schema we have so far. It's ok if we fail to convert
356                          * an object. We should convert more objects on next pass.
357                          */
358                         status = dsdb_convert_object_ex(s->ldb, working_schema, pfm_remote,
359                                                         cur, c->gensec_skey,
360                                                         ignore_attids,
361                                                         tmp_ctx, &object);
362                         if (!W_ERROR_IS_OK(status)) {
363                                 DEBUG(1,("Warning: Failed to convert schema object %s into ldb msg\n",
364                                          cur->object.identifier->dn));
365
366                                 failed_obj_count++;
367                         } else {
368                                 /*
369                                  * Convert the schema from ldb_message format
370                                  * (OIDs as OID strings) into schema, using
371                                  * the remote prefixMap
372                                  */
373                                 status = dsdb_schema_set_el_from_ldb_msg(s->ldb,
374                                                                          s->self_made_schema,
375                                                                          object.msg);
376                                 if (!W_ERROR_IS_OK(status)) {
377                                         DEBUG(1,("Warning: failed to convert object %s into a schema element: %s\n",
378                                                  ldb_dn_get_linearized(object.msg->dn),
379                                                  win_errstr(status)));
380                                         failed_obj_count++;
381                                 } else {
382                                         DLIST_REMOVE(schema_list, schema_list_item);
383                                         converted_obj_count++;
384                                 }
385                         }
386                 }
387                 talloc_free(tmp_ctx);
388
389                 DEBUG(4,("Schema load pass %d: %d/%d of %d objects left to be converted.\n",
390                          pass_no, failed_obj_count, converted_obj_count, object_count));
391                 pass_no++;
392
393                 /* check if we converted any objects in this pass */
394                 if (converted_obj_count == 0) {
395                         DEBUG(0,("Can't continue Schema load: didn't manage to convert any objects: all %d remaining of %d objects failed to convert\n", failed_obj_count, object_count));
396                         return NT_STATUS_INTERNAL_ERROR;
397                 }
398
399                 if (schema_list) {
400                         /* prepare for another cycle */
401                         working_schema = s->self_made_schema;
402
403                         ret = dsdb_setup_sorted_accessors(s->ldb, working_schema);
404                         if (LDB_SUCCESS != ret) {
405                                 DEBUG(0,("Failed to create schema-cache indexes!\n"));
406                                 return NT_STATUS_INTERNAL_ERROR;
407                         }
408                 }
409         };
410
411         /* free temp objects for 1st conversion phase */
412         talloc_unlink(s, provision_schema);
413         TALLOC_FREE(schema_list);
414
415         /*
416          * attach the schema we just brought over DRS to the ldb,
417          * so we can use it in dsdb_convert_object_ex below
418          */
419         ret = dsdb_set_schema(s->ldb, s->self_made_schema);
420         if (ret != LDB_SUCCESS) {
421                 DEBUG(0,("Failed to attach working schema from DRS.\n"));
422                 return NT_STATUS_FOOBAR;
423         }
424
425         /* we don't want to access the self made schema anymore */
426         s->schema = s->self_made_schema;
427         s->self_made_schema = NULL;
428
429         /* Now convert the schema elements again, using the schema we finalised, ready to actually import */
430         status = dsdb_replicated_objects_convert(s->ldb,
431                                                  s->schema,
432                                                  c->partition->nc.dn,
433                                                  mapping_ctr,
434                                                  object_count,
435                                                  first_object,
436                                                  linked_attributes_count,
437                                                  linked_attributes,
438                                                  s_dsa,
439                                                  uptodateness_vector,
440                                                  c->gensec_skey,
441                                                  s, &schema_objs);
442         if (!W_ERROR_IS_OK(status)) {
443                 DEBUG(0,("Failed to convert objects when trying to import over DRS (2nd pass, to store remote schema): %s\n", win_errstr(status)));
444                 return werror_to_ntstatus(status);
445         }
446
447         if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
448                 for (i=0; i < schema_objs->num_objects; i++) {
449                         struct ldb_ldif ldif;
450                         fprintf(stdout, "#\n");
451                         ldif.changetype = LDB_CHANGETYPE_NONE;
452                         ldif.msg = schema_objs->objects[i].msg;
453                         ldb_ldif_write_file(s->ldb, stdout, &ldif);
454                         NDR_PRINT_DEBUG(replPropertyMetaDataBlob, schema_objs->objects[i].meta_data);
455                 }
456         }
457
458         status = dsdb_replicated_objects_commit(s->ldb, NULL, schema_objs, &seq_num);
459         if (!W_ERROR_IS_OK(status)) {
460                 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
461                 return werror_to_ntstatus(status);
462         }
463
464         msg = ldb_msg_new(schema_objs);
465         NT_STATUS_HAVE_NO_MEMORY(msg);
466         msg->dn = schema_objs->partition_dn;
467
468         /* We must ensure a prefixMap has been written.  Unlike other
469          * attributes (including schemaInfo), it is not replicated in
470          * the normal replication stream.  We can use the one from
471          * s->prefixmap_blob because we operate with one, unchanging
472          * prefixMap for this entire operation.  */
473         ret = ldb_msg_add_value(msg, "prefixMap", &s->prefixmap_blob, &prefixMap_el);
474         if (ret != LDB_SUCCESS) {
475                 return NT_STATUS_FOOBAR;
476         }
477         /* We want to know if a prefixMap was written already, as it
478          * would mean that the above comment was not true, and we have
479          * somehow updated the prefixMap during this transaction */
480         prefixMap_el->flags = LDB_FLAG_MOD_ADD;
481
482         ret = ldb_modify(s->ldb, msg);
483         if (ret != LDB_SUCCESS) {
484                 DEBUG(0,("Failed to add prefixMap: %s\n", ldb_errstring(s->ldb)));
485                 return NT_STATUS_FOOBAR;
486         }
487
488         talloc_free(s_dsa);
489         talloc_free(schema_objs);
490
491         /* We must set these up to ensure the replMetaData is written
492          * correctly, before our NTDS Settings entry is replicated */
493         ok = samdb_set_ntds_invocation_id(s->ldb, &c->dest_dsa->invocation_id);
494         if (!ok) {
495                 DEBUG(0,("Failed to set cached ntds invocationId\n"));
496                 return NT_STATUS_FOOBAR;
497         }
498         ok = samdb_set_ntds_objectGUID(s->ldb, &c->dest_dsa->ntds_guid);
499         if (!ok) {
500                 DEBUG(0,("Failed to set cached ntds objectGUID\n"));
501                 return NT_STATUS_FOOBAR;
502         }
503
504         s->schema = dsdb_get_schema(s->ldb, s);
505         if (!s->schema) {
506                 DEBUG(0,("Failed to get loaded dsdb_schema\n"));
507                 return NT_STATUS_FOOBAR;
508         }
509
510         return NT_STATUS_OK;
511 }
512
513 NTSTATUS libnet_vampire_cb_schema_chunk(void *private_data,
514                                         const struct libnet_BecomeDC_StoreChunk *c)
515 {
516         struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
517         WERROR status;
518         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
519         uint32_t nc_object_count;
520         uint32_t object_count;
521         struct drsuapi_DsReplicaObjectListItemEx *first_object;
522         struct drsuapi_DsReplicaObjectListItemEx *cur;
523         uint32_t nc_linked_attributes_count;
524         uint32_t linked_attributes_count;
525         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
526
527         switch (c->ctr_level) {
528         case 1:
529                 mapping_ctr                     = &c->ctr1->mapping_ctr;
530                 nc_object_count                 = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
531                 object_count                    = c->ctr1->object_count;
532                 first_object                    = c->ctr1->first_object;
533                 nc_linked_attributes_count      = 0;
534                 linked_attributes_count         = 0;
535                 linked_attributes               = NULL;
536                 break;
537         case 6:
538                 mapping_ctr                     = &c->ctr6->mapping_ctr;
539                 nc_object_count                 = c->ctr6->nc_object_count;
540                 object_count                    = c->ctr6->object_count;
541                 first_object                    = c->ctr6->first_object;
542                 nc_linked_attributes_count      = c->ctr6->nc_linked_attributes_count;
543                 linked_attributes_count         = c->ctr6->linked_attributes_count;
544                 linked_attributes               = c->ctr6->linked_attributes;
545                 break;
546         default:
547                 return NT_STATUS_INVALID_PARAMETER;
548         }
549
550         if (nc_object_count) {
551                 DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n",
552                         c->partition->nc.dn, object_count, nc_object_count,
553                         linked_attributes_count, nc_linked_attributes_count));
554         } else {
555                 DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u]\n",
556                 c->partition->nc.dn, object_count, linked_attributes_count));
557         }
558
559         if (!s->self_made_schema) {
560                 WERROR werr;
561                 struct drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr_without_schema_info;
562                 /* Put the DRS prefixmap aside for the schema we are
563                  * about to load in the provision, and into the one we
564                  * are making with the help of DRS */
565
566                 mapping_ctr_without_schema_info = *mapping_ctr;
567
568                 /* This strips off the 0xFF schema info from the end,
569                  * because we don't want it in the blob */
570                 if (mapping_ctr_without_schema_info.num_mappings > 0) {
571                         mapping_ctr_without_schema_info.num_mappings--;
572                 }
573                 werr = dsdb_get_drsuapi_prefixmap_as_blob(&mapping_ctr_without_schema_info, s, &s->prefixmap_blob);
574                 if (!W_ERROR_IS_OK(werr)) {
575                         return werror_to_ntstatus(werr);
576                 }
577
578                 /* Set up two manually-constructed schema - the local
579                  * schema from the provision will be used to build
580                  * one, which will then in turn be used to build the
581                  * other. */
582                 s->self_made_schema = dsdb_new_schema(s);
583                 NT_STATUS_HAVE_NO_MEMORY(s->self_made_schema);
584
585                 status = dsdb_load_prefixmap_from_drsuapi(s->self_made_schema, mapping_ctr);
586                 if (!W_ERROR_IS_OK(status)) {
587                         return werror_to_ntstatus(status);
588                 }
589         } else {
590                 status = dsdb_schema_pfm_contains_drsuapi_pfm(s->self_made_schema->prefixmap, mapping_ctr);
591                 if (!W_ERROR_IS_OK(status)) {
592                         return werror_to_ntstatus(status);
593                 }
594         }
595
596         if (!s->schema_part.first_object) {
597                 s->schema_part.object_count = object_count;
598                 s->schema_part.first_object = talloc_steal(s, first_object);
599         } else {
600                 s->schema_part.object_count             += object_count;
601                 s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
602                                                                        first_object);
603         }
604         for (cur = first_object; cur->next_object; cur = cur->next_object) {}
605         s->schema_part.last_object = cur;
606
607         if (!c->partition->more_data) {
608                 return libnet_vampire_cb_apply_schema(s, c);
609         }
610
611         return NT_STATUS_OK;
612 }
613
614 NTSTATUS libnet_vampire_cb_store_chunk(void *private_data,
615                              const struct libnet_BecomeDC_StoreChunk *c)
616 {
617         struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
618         WERROR status;
619         struct dsdb_schema *schema;
620         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
621         uint32_t nc_object_count;
622         uint32_t object_count;
623         struct drsuapi_DsReplicaObjectListItemEx *first_object;
624         uint32_t nc_linked_attributes_count;
625         uint32_t linked_attributes_count;
626         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
627         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
628         struct dsdb_extended_replicated_objects *objs;
629         struct repsFromTo1 *s_dsa;
630         char *tmp_dns_name;
631         uint32_t i;
632         uint64_t seq_num;
633
634         s_dsa                   = talloc_zero(s, struct repsFromTo1);
635         NT_STATUS_HAVE_NO_MEMORY(s_dsa);
636         s_dsa->other_info       = talloc(s_dsa, struct repsFromTo1OtherInfo);
637         NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
638
639         switch (c->ctr_level) {
640         case 1:
641                 mapping_ctr                     = &c->ctr1->mapping_ctr;
642                 nc_object_count                 = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
643                 object_count                    = c->ctr1->object_count;
644                 first_object                    = c->ctr1->first_object;
645                 nc_linked_attributes_count      = 0;
646                 linked_attributes_count         = 0;
647                 linked_attributes               = NULL;
648                 s_dsa->highwatermark            = c->ctr1->new_highwatermark;
649                 s_dsa->source_dsa_obj_guid      = c->ctr1->source_dsa_guid;
650                 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
651                 uptodateness_vector             = NULL; /* TODO: map it */
652                 break;
653         case 6:
654                 mapping_ctr                     = &c->ctr6->mapping_ctr;
655                 nc_object_count                 = c->ctr6->nc_object_count;
656                 object_count                    = c->ctr6->object_count;
657                 first_object                    = c->ctr6->first_object;
658                 nc_linked_attributes_count      = c->ctr6->nc_linked_attributes_count;
659                 linked_attributes_count         = c->ctr6->linked_attributes_count;
660                 linked_attributes               = c->ctr6->linked_attributes;
661                 s_dsa->highwatermark            = c->ctr6->new_highwatermark;
662                 s_dsa->source_dsa_obj_guid      = c->ctr6->source_dsa_guid;
663                 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
664                 uptodateness_vector             = c->ctr6->uptodateness_vector;
665                 break;
666         default:
667                 return NT_STATUS_INVALID_PARAMETER;
668         }
669
670         s_dsa->replica_flags            = DRSUAPI_DRS_WRIT_REP
671                                         | DRSUAPI_DRS_INIT_SYNC
672                                         | DRSUAPI_DRS_PER_SYNC;
673         memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
674
675         tmp_dns_name    = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
676         NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
677         tmp_dns_name    = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
678         NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
679         s_dsa->other_info->dns_name = tmp_dns_name;
680
681         /* we want to show a count per partition */
682         if (!s->last_partition || strcmp(s->last_partition, c->partition->nc.dn) != 0) {
683                 s->total_objects = 0;
684                 talloc_free(s->last_partition);
685                 s->last_partition = talloc_strdup(s, c->partition->nc.dn);
686         }
687         s->total_objects += object_count;
688
689         if (nc_object_count) {
690                 DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n",
691                         c->partition->nc.dn, s->total_objects, nc_object_count,
692                         linked_attributes_count, nc_linked_attributes_count));
693         } else {
694                 DEBUG(0,("Partition[%s] objects[%u] linked_values[%u]\n",
695                 c->partition->nc.dn, s->total_objects, linked_attributes_count));
696         }
697
698
699         schema = dsdb_get_schema(s->ldb, NULL);
700         if (!schema) {
701                 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
702                 return NT_STATUS_INTERNAL_ERROR;
703         }
704
705         status = dsdb_replicated_objects_convert(s->ldb,
706                                                  schema,
707                                                  c->partition->nc.dn,
708                                                  mapping_ctr,
709                                                  object_count,
710                                                  first_object,
711                                                  linked_attributes_count,
712                                                  linked_attributes,
713                                                  s_dsa,
714                                                  uptodateness_vector,
715                                                  c->gensec_skey,
716                                                  s, &objs);
717         if (!W_ERROR_IS_OK(status)) {
718                 DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status)));
719                 return werror_to_ntstatus(status);
720         }
721
722         if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
723                 for (i=0; i < objs->num_objects; i++) {
724                         struct ldb_ldif ldif;
725                         fprintf(stdout, "#\n");
726                         ldif.changetype = LDB_CHANGETYPE_NONE;
727                         ldif.msg = objs->objects[i].msg;
728                         ldb_ldif_write_file(s->ldb, stdout, &ldif);
729                         NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
730                 }
731         }
732         status = dsdb_replicated_objects_commit(s->ldb, NULL, objs, &seq_num);
733         if (!W_ERROR_IS_OK(status)) {
734                 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
735                 return werror_to_ntstatus(status);
736         }
737
738         talloc_free(s_dsa);
739         talloc_free(objs);
740
741         for (i=0; i < linked_attributes_count; i++) {
742                 const struct dsdb_attribute *sa;
743
744                 if (!linked_attributes[i].identifier) {
745                         return NT_STATUS_FOOBAR;                
746                 }
747
748                 if (!linked_attributes[i].value.blob) {
749                         return NT_STATUS_FOOBAR;                
750                 }
751
752                 sa = dsdb_attribute_by_attributeID_id(s->schema,
753                                                       linked_attributes[i].attid);
754                 if (!sa) {
755                         return NT_STATUS_FOOBAR;
756                 }
757
758                 if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
759                         DEBUG(0,("# %s\n", sa->lDAPDisplayName));
760                         NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, &linked_attributes[i]);
761                         dump_data(0,
762                                 linked_attributes[i].value.blob->data,
763                                 linked_attributes[i].value.blob->length);
764                 }
765         }
766
767         return NT_STATUS_OK;
768 }
769
770 static NTSTATUS update_dnshostname_for_server(TALLOC_CTX *mem_ctx,
771                                               struct ldb_context *ldb,
772                                               const char *server_dn_str,
773                                               const char *netbios_name,
774                                               const char *realm)
775 {
776         int ret;
777         struct ldb_message *msg;
778         struct ldb_message_element *el;
779         struct ldb_dn *server_dn;
780         const char *dNSHostName = strlower_talloc(mem_ctx,
781                                                   talloc_asprintf(mem_ctx,
782                                                                   "%s.%s",
783                                                                   netbios_name,
784                                                                   realm));
785         msg = ldb_msg_new(mem_ctx);
786         if (msg == NULL) {
787                 return NT_STATUS_NO_MEMORY;
788         }
789
790         server_dn = ldb_dn_new(mem_ctx, ldb, server_dn_str);
791         if (!server_dn) {
792                 return NT_STATUS_INTERNAL_ERROR;
793         }
794
795         msg->dn = server_dn;
796         ret = ldb_msg_add_empty(msg, "dNSHostName", LDB_FLAG_MOD_ADD, &el);
797         if (ret != LDB_SUCCESS) {
798                 return NT_STATUS_INTERNAL_ERROR;
799         }
800
801         ret = ldb_msg_add_steal_string(msg,
802                                        "dNSHostName",
803                                        talloc_asprintf(el->values, "%s", dNSHostName));
804         if (ret != LDB_SUCCESS) {
805                 return NT_STATUS_INTERNAL_ERROR;
806         }
807
808         ret = dsdb_modify(ldb, msg, DSDB_MODIFY_PERMISSIVE);
809         if (ret != LDB_SUCCESS) {
810                 DEBUG(0,(__location__ ": Failed to add dnsHostName to the Server object: %s\n",
811                          ldb_errstring(ldb)));
812                 return NT_STATUS_INTERNAL_ERROR;
813         }
814
815         return NT_STATUS_OK;
816 }
817
818
819 NTSTATUS libnet_Vampire(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, 
820                         struct libnet_Vampire *r)
821 {
822         struct libnet_JoinDomain *join;
823         struct libnet_Replicate rep;
824         NTSTATUS status;
825
826         const char *account_name;
827         const char *netbios_name;
828         
829         r->out.error_string = NULL;
830
831         join = talloc_zero(mem_ctx, struct libnet_JoinDomain);
832         if (!join) {
833                 return NT_STATUS_NO_MEMORY;
834         }
835                 
836         if (r->in.netbios_name != NULL) {
837                 netbios_name = r->in.netbios_name;
838         } else {
839                 netbios_name = talloc_reference(join, lpcfg_netbios_name(ctx->lp_ctx));
840                 if (!netbios_name) {
841                         talloc_free(join);
842                         r->out.error_string = NULL;
843                         return NT_STATUS_NO_MEMORY;
844                 }
845         }
846
847         account_name = talloc_asprintf(join, "%s$", netbios_name);
848         if (!account_name) {
849                 talloc_free(join);
850                 r->out.error_string = NULL;
851                 return NT_STATUS_NO_MEMORY;
852         }
853         
854         /* Re-use the domain we are joining as the domain for the user
855          * to be authenticated with, unless they specified
856          * otherwise */
857         cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
858
859         join->in.domain_name    = r->in.domain_name;
860         join->in.account_name   = account_name;
861         join->in.netbios_name   = netbios_name;
862         join->in.level          = LIBNET_JOINDOMAIN_AUTOMATIC;
863         join->in.acct_type      = ACB_WSTRUST;
864         join->in.recreate_account = false;
865         status = libnet_JoinDomain(ctx, join, join);
866         if (!NT_STATUS_IS_OK(status)) {
867                 r->out.error_string = talloc_steal(mem_ctx, join->out.error_string);
868                 talloc_free(join);
869                 return status;
870         }
871
872         rep.in.domain_name   = join->out.domain_name;
873         rep.in.netbios_name  = netbios_name;
874         rep.in.targetdir     = r->in.targetdir;
875         rep.in.domain_sid    = join->out.domain_sid;
876         rep.in.realm         = join->out.realm;
877         rep.in.server        = join->out.samr_binding->host;
878         rep.in.join_password = join->out.join_password;
879         rep.in.kvno          = join->out.kvno;
880
881         status = libnet_Replicate(ctx, mem_ctx, &rep);
882
883         r->out.domain_sid   = join->out.domain_sid;
884         r->out.domain_name  = join->out.domain_name;
885         r->out.error_string = rep.out.error_string;
886
887         return status;
888 }
889
890
891
892 NTSTATUS libnet_Replicate(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
893                           struct libnet_Replicate *r)
894 {
895         struct provision_store_self_join_settings *set_secrets;
896         struct libnet_BecomeDC b;
897         struct libnet_vampire_cb_state *s;
898         struct ldb_message *msg;
899         const char *error_string;
900         int ldb_ret;
901         uint32_t i;
902         NTSTATUS status;
903         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
904         const char *account_name;
905         const char *netbios_name;
906
907         r->out.error_string = NULL;
908
909         netbios_name = r->in.netbios_name;
910         account_name = talloc_asprintf(tmp_ctx, "%s$", netbios_name);
911         if (!account_name) {
912                 talloc_free(tmp_ctx);
913                 r->out.error_string = NULL;
914                 return NT_STATUS_NO_MEMORY;
915         }
916         
917         /* Re-use the domain we are joining as the domain for the user
918          * to be authenticated with, unless they specified
919          * otherwise */
920         cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
921
922         s = libnet_vampire_cb_state_init(mem_ctx, ctx->lp_ctx, ctx->event_ctx,
923                                          netbios_name, r->in.domain_name, r->in.realm,
924                                          r->in.targetdir);
925         if (!s) {
926                 return NT_STATUS_NO_MEMORY;
927         }
928         talloc_steal(s, tmp_ctx);
929
930         ZERO_STRUCT(b);
931
932         /* Be more robust:
933          * We now know the domain and realm for sure - if they didn't
934          * put one on the command line, use this for the rest of the
935          * join */
936         cli_credentials_set_realm(ctx->cred, r->in.realm, CRED_GUESS_ENV);
937         cli_credentials_set_domain(ctx->cred, r->in.domain_name, CRED_GUESS_ENV);
938
939         /* Now set these values into the smb.conf - we probably had
940          * empty or useless defaults here from whatever smb.conf we
941          * started with */
942         lpcfg_set_cmdline(s->lp_ctx, "realm", r->in.realm);
943         lpcfg_set_cmdline(s->lp_ctx, "workgroup", r->in.domain_name);
944
945         b.in.domain_dns_name            = r->in.realm;
946         b.in.domain_netbios_name        = r->in.domain_name;
947         b.in.domain_sid                 = r->in.domain_sid;
948         b.in.source_dsa_address         = r->in.server;
949         b.in.dest_dsa_netbios_name      = netbios_name;
950
951         b.in.callbacks.private_data     = s;
952         b.in.callbacks.check_options    = libnet_vampire_cb_check_options;
953         b.in.callbacks.prepare_db       = libnet_vampire_cb_prepare_db;
954         b.in.callbacks.schema_chunk     = libnet_vampire_cb_schema_chunk;
955         b.in.callbacks.config_chunk     = libnet_vampire_cb_store_chunk;
956         b.in.callbacks.domain_chunk     = libnet_vampire_cb_store_chunk;
957
958         b.in.rodc_join = lpcfg_parm_bool(s->lp_ctx, NULL, "repl", "RODC", false);
959
960         status = libnet_BecomeDC(ctx, s, &b);
961         if (!NT_STATUS_IS_OK(status)) {
962                 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
963                 talloc_free(s);
964                 return status;
965         }
966
967         msg = ldb_msg_new(s);
968         if (!msg) {
969                 printf("ldb_msg_new() failed\n");
970                 talloc_free(s);
971                 return NT_STATUS_NO_MEMORY;
972         }
973         msg->dn = ldb_dn_new(msg, s->ldb, "@ROOTDSE");
974         if (!msg->dn) {
975                 printf("ldb_msg_new(@ROOTDSE) failed\n");
976                 talloc_free(s);
977                 return NT_STATUS_NO_MEMORY;
978         }
979
980         ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE");
981         if (ldb_ret != LDB_SUCCESS) {
982                 printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret);
983                 talloc_free(s);
984                 return NT_STATUS_NO_MEMORY;
985         }
986
987         for (i=0; i < msg->num_elements; i++) {
988                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
989         }
990
991         printf("mark ROOTDSE with isSynchronized=TRUE\n");
992         ldb_ret = ldb_modify(s->ldb, msg);
993         if (ldb_ret != LDB_SUCCESS) {
994                 printf("ldb_modify() failed: %d : %s\n", ldb_ret, ldb_errstring(s->ldb));
995                 talloc_free(s);
996                 return NT_STATUS_INTERNAL_DB_ERROR;
997         }
998         /* during dcpromo the 2nd computer adds dNSHostName attribute to his Server object
999          * the attribute appears on the original DC after replication
1000          */
1001         status = update_dnshostname_for_server(s, s->ldb, s->server_dn_str, s->netbios_name, s->realm);
1002         if (!NT_STATUS_IS_OK(status)) {
1003                 printf("Failed to update dNSHostName on Server object - %s\n", nt_errstr(status));
1004                 talloc_free(s);
1005                 return status;
1006         }
1007         /* prepare the transaction - this prepares to commit all the changes in
1008            the ldb from the whole vampire.  Note that this 
1009            triggers the writing of the linked attribute backlinks.
1010         */
1011         if (ldb_transaction_prepare_commit(s->ldb) != LDB_SUCCESS) {
1012                 printf("Failed to prepare_commit vampire transaction: %s\n", ldb_errstring(s->ldb));
1013                 return NT_STATUS_INTERNAL_DB_ERROR;
1014         }
1015
1016         set_secrets = talloc(s, struct provision_store_self_join_settings);
1017         if (!set_secrets) {
1018                 r->out.error_string = NULL;
1019                 talloc_free(s);
1020                 return NT_STATUS_NO_MEMORY;
1021         }
1022         
1023         ZERO_STRUCTP(set_secrets);
1024         set_secrets->domain_name = r->in.domain_name;
1025         set_secrets->realm = r->in.realm;
1026         set_secrets->netbios_name = netbios_name;
1027         set_secrets->secure_channel_type = SEC_CHAN_BDC;
1028         set_secrets->machine_password = r->in.join_password;
1029         set_secrets->key_version_number = r->in.kvno;
1030         set_secrets->domain_sid = r->in.domain_sid;
1031         
1032         status = provision_store_self_join(ctx, s->lp_ctx, ctx->event_ctx, set_secrets, &error_string);
1033         if (!NT_STATUS_IS_OK(status)) {
1034                 r->out.error_string = talloc_steal(mem_ctx, error_string);
1035                 talloc_free(s);
1036                 return status;
1037         }
1038
1039         /* commit the transaction now we know the secrets were written
1040          * out properly
1041         */
1042         if (ldb_transaction_commit(s->ldb) != LDB_SUCCESS) {
1043                 printf("Failed to commit vampire transaction\n");
1044                 return NT_STATUS_INTERNAL_DB_ERROR;
1045         }
1046
1047         talloc_free(s);
1048
1049         return NT_STATUS_OK;
1050 }