d89256b02a80d3ac7fe0d0c769f16b8312a95c13
[nivanova/samba-autobuild/.git] / source4 / libnet / libnet_vampire.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    Extract the user/system database from a remote server
5
6    Copyright (C) Stefan Metzmacher      2004-2006
7    Copyright (C) Brad Henry 2005
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2008
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24
25 #include "includes.h"
26 #include "libnet/libnet.h"
27 #include "lib/events/events.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "../lib/util/dlinklist.h"
30 #include <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_machine_password(s, 128, 255);
164         settings.targetdir = s->targetdir;
165         settings.use_ntvfs = true;
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 WERROR libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s,
220                                              const struct libnet_BecomeDC_StoreChunk *c)
221 {
222         WERROR status;
223         struct dsdb_schema_prefixmap *pfm_remote;
224         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
225         struct dsdb_schema *provision_schema;
226         uint32_t object_count = 0;
227         struct drsuapi_DsReplicaObjectListItemEx *first_object;
228         uint32_t linked_attributes_count;
229         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
230         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
231         struct dsdb_extended_replicated_objects *schema_objs;
232         struct repsFromTo1 *s_dsa;
233         char *tmp_dns_name;
234         struct ldb_context *schema_ldb;
235         struct ldb_dn *partition_dn;
236         struct ldb_message *msg;
237         struct ldb_message_element *prefixMap_el;
238         uint32_t i;
239         int ret;
240         bool ok;
241         uint64_t seq_num = 0;
242         uint32_t cycle_before_switching;
243
244         DEBUG(0,("Analyze and apply schema objects\n"));
245
246         s_dsa                   = talloc_zero(s, struct repsFromTo1);
247         if (s_dsa == NULL) {
248                 return WERR_NOT_ENOUGH_MEMORY;
249         }
250         s_dsa->other_info       = talloc(s_dsa, struct repsFromTo1OtherInfo);
251         if (s_dsa->other_info == NULL) {
252                 return WERR_NOT_ENOUGH_MEMORY;
253         }
254
255         switch (c->ctr_level) {
256         case 1:
257                 mapping_ctr                     = &c->ctr1->mapping_ctr;
258                 object_count                    = s->schema_part.object_count;
259                 first_object                    = s->schema_part.first_object;
260                 linked_attributes_count         = 0;
261                 linked_attributes               = NULL;
262                 s_dsa->highwatermark            = c->ctr1->new_highwatermark;
263                 s_dsa->source_dsa_obj_guid      = c->ctr1->source_dsa_guid;
264                 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
265                 uptodateness_vector             = NULL; /* TODO: map it */
266                 break;
267         case 6:
268                 mapping_ctr                     = &c->ctr6->mapping_ctr;
269                 object_count                    = s->schema_part.object_count;
270                 first_object                    = s->schema_part.first_object;
271                 linked_attributes_count         = c->ctr6->linked_attributes_count;
272                 linked_attributes               = c->ctr6->linked_attributes;
273                 s_dsa->highwatermark            = c->ctr6->new_highwatermark;
274                 s_dsa->source_dsa_obj_guid      = c->ctr6->source_dsa_guid;
275                 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
276                 uptodateness_vector             = c->ctr6->uptodateness_vector;
277                 break;
278         default:
279                 return WERR_INVALID_PARAMETER;
280         }
281         /* We must set these up to ensure the replMetaData is written
282          * correctly, before our NTDS Settings entry is replicated */
283         ok = samdb_set_ntds_invocation_id(s->ldb, &c->dest_dsa->invocation_id);
284         if (!ok) {
285                 DEBUG(0,("Failed to set cached ntds invocationId\n"));
286                 return WERR_INTERNAL_ERROR;
287         }
288         ok = samdb_set_ntds_objectGUID(s->ldb, &c->dest_dsa->ntds_guid);
289         if (!ok) {
290                 DEBUG(0,("Failed to set cached ntds objectGUID\n"));
291                 return WERR_INTERNAL_ERROR;
292         }
293
294         status = dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr, true,
295                                                   s, &pfm_remote, NULL);
296         if (!W_ERROR_IS_OK(status)) {
297                 DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s",
298                          win_errstr(status)));
299                 return status;
300         }
301
302         s_dsa->replica_flags            = DRSUAPI_DRS_WRIT_REP
303                                         | DRSUAPI_DRS_INIT_SYNC
304                                         | DRSUAPI_DRS_PER_SYNC;
305         memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
306
307         tmp_dns_name    = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
308         if (tmp_dns_name == NULL) {
309                 return WERR_NOT_ENOUGH_MEMORY;
310         }
311         tmp_dns_name    = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
312         if (tmp_dns_name == NULL) {
313                 return WERR_NOT_ENOUGH_MEMORY;
314         }
315         s_dsa->other_info->dns_name = tmp_dns_name;
316
317         if (s->self_made_schema == NULL) {
318                 DEBUG(0,("libnet_vampire_cb_apply_schema: called with out self_made_schema\n"));
319                 return WERR_INTERNAL_ERROR;
320         }
321
322         schema_ldb = provision_get_schema(s, s->lp_ctx,
323                                           c->forest->schema_dn_str,
324                                           &s->prefixmap_blob);
325         if (!schema_ldb) {
326                 DEBUG(0,("Failed to re-load from local provision using remote prefixMap. "
327                          "Will continue with local prefixMap\n"));
328                 provision_schema = dsdb_get_schema(s->ldb, s);
329         } else {
330                 provision_schema = dsdb_get_schema(schema_ldb, s);
331                 ret = dsdb_reference_schema(s->ldb, provision_schema, false);
332                 if (ret != LDB_SUCCESS) {
333                         DEBUG(0,("Failed to attach schema from local provision using remote prefixMap."));
334                         return WERR_INTERNAL_ERROR;
335                 }
336                 talloc_free(schema_ldb);
337         }
338
339         cycle_before_switching = lpcfg_parm_long(s->lp_ctx, NULL,
340                                                  "become dc",
341                                                  "schema convert retrial", 1);
342
343         provision_schema->resolving_in_progress = true;
344         s->self_made_schema->resolving_in_progress = true;
345
346         status = dsdb_repl_resolve_working_schema(s->ldb,
347                                                   pfm_remote,
348                                                   cycle_before_switching,
349                                                   provision_schema,
350                                                   s->self_made_schema,
351                                                   object_count,
352                                                   first_object);
353         if (!W_ERROR_IS_OK(status)) {
354                 DEBUG(0, ("%s: dsdb_repl_resolve_working_schema() failed: %s",
355                           __location__, win_errstr(status)));
356                 return status;
357         }
358
359         /* free temp objects for 1st conversion phase */
360         talloc_unlink(s, provision_schema);
361
362         s->self_made_schema->resolving_in_progress = false;
363
364         /*
365          * attach the schema we just brought over DRS to the ldb,
366          * so we can use it in dsdb_convert_object_ex below
367          */
368         ret = dsdb_set_schema(s->ldb, s->self_made_schema, true);
369         if (ret != LDB_SUCCESS) {
370                 DEBUG(0,("Failed to attach working schema from DRS.\n"));
371                 return WERR_INTERNAL_ERROR;
372         }
373
374         /* we don't want to access the self made schema anymore */
375         s->schema = s->self_made_schema;
376         s->self_made_schema = NULL;
377
378         partition_dn = ldb_dn_new(s, s->ldb, c->partition->nc.dn);
379         if (partition_dn == NULL) {
380                 DEBUG(0,("Failed to parse partition DN from DRS.\n"));
381                 return WERR_INVALID_PARAMETER;
382         }
383
384         /* Now convert the schema elements again, using the schema we finalised, ready to actually import */
385         status = dsdb_replicated_objects_convert(s->ldb,
386                                                  s->schema,
387                                                  partition_dn,
388                                                  mapping_ctr,
389                                                  object_count,
390                                                  first_object,
391                                                  linked_attributes_count,
392                                                  linked_attributes,
393                                                  s_dsa,
394                                                  uptodateness_vector,
395                                                  c->gensec_skey,
396                                                  0,
397                                                  s, &schema_objs);
398         if (!W_ERROR_IS_OK(status)) {
399                 DEBUG(0,("Failed to convert objects when trying to import over DRS (2nd pass, to store remote schema): %s\n", win_errstr(status)));
400                 return status;
401         }
402
403         if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
404                 for (i=0; i < schema_objs->num_objects; i++) {
405                         struct ldb_ldif ldif;
406                         fprintf(stdout, "#\n");
407                         ldif.changetype = LDB_CHANGETYPE_NONE;
408                         ldif.msg = schema_objs->objects[i].msg;
409                         ldb_ldif_write_file(s->ldb, stdout, &ldif);
410                         NDR_PRINT_DEBUG(replPropertyMetaDataBlob, schema_objs->objects[i].meta_data);
411                 }
412         }
413
414         status = dsdb_replicated_objects_commit(s->ldb, NULL, schema_objs, &seq_num);
415         if (!W_ERROR_IS_OK(status)) {
416                 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
417                 return status;
418         }
419
420         msg = ldb_msg_new(schema_objs);
421         if (msg == NULL) {
422                 return WERR_NOT_ENOUGH_MEMORY;
423         }
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 WERR_NOT_ENOUGH_MEMORY;
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 = dsdb_modify(s->ldb, msg, DSDB_FLAG_AS_SYSTEM);
441         if (ret != LDB_SUCCESS) {
442                 DEBUG(0,("Failed to add prefixMap: %s\n", ldb_errstring(s->ldb)));
443                 return WERR_INTERNAL_ERROR;
444         }
445
446         talloc_free(s_dsa);
447         talloc_free(schema_objs);
448
449         s->schema = dsdb_get_schema(s->ldb, s);
450         if (!s->schema) {
451                 DEBUG(0,("Failed to get loaded dsdb_schema\n"));
452                 return WERR_INTERNAL_ERROR;
453         }
454
455         return WERR_OK;
456 }
457
458 WERROR libnet_vampire_cb_schema_chunk(void *private_data,
459                                       const struct libnet_BecomeDC_StoreChunk *c)
460 {
461         struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
462         WERROR werr;
463         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
464         uint32_t nc_object_count;
465         uint32_t nc_total_received = 0;
466         uint32_t object_count;
467         struct drsuapi_DsReplicaObjectListItemEx *first_object;
468         struct drsuapi_DsReplicaObjectListItemEx *cur;
469         uint32_t nc_linked_attributes_count;
470         uint32_t linked_attributes_count;
471
472         switch (c->ctr_level) {
473         case 1:
474                 mapping_ctr                     = &c->ctr1->mapping_ctr;
475                 nc_object_count                 = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
476                 object_count                    = c->ctr1->object_count;
477                 first_object                    = c->ctr1->first_object;
478                 nc_linked_attributes_count      = 0;
479                 linked_attributes_count         = 0;
480                 break;
481         case 6:
482                 mapping_ctr                     = &c->ctr6->mapping_ctr;
483                 nc_object_count                 = c->ctr6->nc_object_count;
484                 object_count                    = c->ctr6->object_count;
485                 first_object                    = c->ctr6->first_object;
486                 nc_linked_attributes_count      = c->ctr6->nc_linked_attributes_count;
487                 linked_attributes_count         = c->ctr6->linked_attributes_count;
488                 break;
489         default:
490                 return WERR_INVALID_PARAMETER;
491         }
492
493         if (!s->schema_part.first_object) {
494                 nc_total_received = object_count;
495         } else {
496                 nc_total_received = s->schema_part.object_count + object_count;
497         }
498         if (nc_object_count) {
499                 DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n",
500                         c->partition->nc.dn, nc_total_received, nc_object_count,
501                         linked_attributes_count, nc_linked_attributes_count));
502         } else {
503                 DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u]\n",
504                 c->partition->nc.dn, nc_total_received, linked_attributes_count));
505         }
506
507         if (!s->self_made_schema) {
508                 struct drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr_without_schema_info;
509                 /* Put the DRS prefixmap aside for the schema we are
510                  * about to load in the provision, and into the one we
511                  * are making with the help of DRS */
512
513                 mapping_ctr_without_schema_info = *mapping_ctr;
514
515                 /* This strips off the 0xFF schema info from the end,
516                  * because we don't want it in the blob */
517                 if (mapping_ctr_without_schema_info.num_mappings > 0) {
518                         mapping_ctr_without_schema_info.num_mappings--;
519                 }
520                 werr = dsdb_get_drsuapi_prefixmap_as_blob(&mapping_ctr_without_schema_info, s, &s->prefixmap_blob);
521                 if (!W_ERROR_IS_OK(werr)) {
522                         return werr;
523                 }
524
525                 /* Set up two manually-constructed schema - the local
526                  * schema from the provision will be used to build
527                  * one, which will then in turn be used to build the
528                  * other. */
529                 s->self_made_schema = dsdb_new_schema(s);
530                 if (s->self_made_schema == NULL) {
531                         return WERR_NOT_ENOUGH_MEMORY;
532                 }
533
534                 werr = dsdb_load_prefixmap_from_drsuapi(s->self_made_schema, mapping_ctr);
535                 if (!W_ERROR_IS_OK(werr)) {
536                         return werr;
537                 }
538         } else {
539                 werr = dsdb_schema_pfm_contains_drsuapi_pfm(s->self_made_schema->prefixmap, mapping_ctr);
540                 if (!W_ERROR_IS_OK(werr)) {
541                         return werr;
542                 }
543         }
544
545         if (!s->schema_part.first_object) {
546                 s->schema_part.object_count = object_count;
547                 s->schema_part.first_object = talloc_steal(s, first_object);
548         } else {
549                 s->schema_part.object_count             += object_count;
550                 s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
551                                                                        first_object);
552         }
553         for (cur = first_object; cur->next_object; cur = cur->next_object) {}
554         s->schema_part.last_object = cur;
555
556         if (!c->partition->more_data) {
557                 return libnet_vampire_cb_apply_schema(s, c);
558         }
559
560         return WERR_OK;
561 }
562
563 WERROR libnet_vampire_cb_store_chunk(void *private_data,
564                                      const struct libnet_BecomeDC_StoreChunk *c)
565 {
566         struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
567         WERROR status;
568         struct dsdb_schema *schema;
569         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
570         uint32_t nc_object_count;
571         uint32_t object_count;
572         struct drsuapi_DsReplicaObjectListItemEx *first_object;
573         uint32_t nc_linked_attributes_count;
574         uint32_t linked_attributes_count;
575         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
576         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
577         struct dsdb_extended_replicated_objects *objs;
578         uint32_t req_replica_flags;
579         uint32_t dsdb_repl_flags = 0;
580         struct repsFromTo1 *s_dsa;
581         char *tmp_dns_name;
582         uint32_t i;
583         uint64_t seq_num;
584         bool is_exop = false;
585         struct ldb_dn *partition_dn = NULL;
586         struct ldb_dn *nc_root = NULL;
587
588         s_dsa                   = talloc_zero(s, struct repsFromTo1);
589         if (s_dsa == NULL) {
590                 return WERR_NOT_ENOUGH_MEMORY;
591         }
592         s_dsa->other_info       = talloc(s_dsa, struct repsFromTo1OtherInfo);
593         if (s_dsa->other_info == NULL) {
594                 return WERR_NOT_ENOUGH_MEMORY;
595         }
596
597         switch (c->ctr_level) {
598         case 1:
599                 mapping_ctr                     = &c->ctr1->mapping_ctr;
600                 nc_object_count                 = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
601                 object_count                    = c->ctr1->object_count;
602                 first_object                    = c->ctr1->first_object;
603                 nc_linked_attributes_count      = 0;
604                 linked_attributes_count         = 0;
605                 linked_attributes               = NULL;
606                 s_dsa->highwatermark            = c->ctr1->new_highwatermark;
607                 s_dsa->source_dsa_obj_guid      = c->ctr1->source_dsa_guid;
608                 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
609                 uptodateness_vector             = NULL; /* TODO: map it */
610                 break;
611         case 6:
612                 mapping_ctr                     = &c->ctr6->mapping_ctr;
613                 nc_object_count                 = c->ctr6->nc_object_count;
614                 object_count                    = c->ctr6->object_count;
615                 first_object                    = c->ctr6->first_object;
616                 nc_linked_attributes_count      = c->ctr6->nc_linked_attributes_count;
617                 linked_attributes_count         = c->ctr6->linked_attributes_count;
618                 linked_attributes               = c->ctr6->linked_attributes;
619                 s_dsa->highwatermark            = c->ctr6->new_highwatermark;
620                 s_dsa->source_dsa_obj_guid      = c->ctr6->source_dsa_guid;
621                 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
622                 uptodateness_vector             = c->ctr6->uptodateness_vector;
623                 break;
624         default:
625                 return WERR_INVALID_PARAMETER;
626         }
627
628         switch (c->req_level) {
629         case 0:
630                 /* none */
631                 req_replica_flags = 0;
632                 break;
633         case 5:
634                 if (c->req5->extended_op != DRSUAPI_EXOP_NONE) {
635                         is_exop = true;
636                 }
637                 req_replica_flags = c->req5->replica_flags;
638                 break;
639         case 8:
640                 if (c->req8->extended_op != DRSUAPI_EXOP_NONE) {
641                         is_exop = true;
642                 }
643                 req_replica_flags = c->req8->replica_flags;
644                 break;
645         case 10:
646                 if (c->req10->extended_op != DRSUAPI_EXOP_NONE) {
647                         is_exop = true;
648                 }
649                 req_replica_flags = c->req10->replica_flags;
650                 break;
651         default:
652                 return WERR_INVALID_PARAMETER;
653         }
654
655         if (req_replica_flags & DRSUAPI_DRS_CRITICAL_ONLY || is_exop) {
656                 /*
657                  * If we only replicate the critical objects, or this
658                  * is an exop we should not remember what we already
659                  * got, as it is incomplete.
660                  */
661                 ZERO_STRUCT(s_dsa->highwatermark);
662                 uptodateness_vector = NULL;
663                 dsdb_repl_flags |= DSDB_REPL_FLAG_OBJECT_SUBSET;
664         }
665
666         /* TODO: avoid hardcoded flags */
667         s_dsa->replica_flags            = DRSUAPI_DRS_WRIT_REP
668                                         | DRSUAPI_DRS_INIT_SYNC
669                                         | DRSUAPI_DRS_PER_SYNC;
670         memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
671
672         tmp_dns_name    = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
673         if (tmp_dns_name == NULL) {
674                 return WERR_NOT_ENOUGH_MEMORY;
675         }
676         tmp_dns_name    = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
677         if (tmp_dns_name == NULL) {
678                 return WERR_NOT_ENOUGH_MEMORY;
679         }
680         s_dsa->other_info->dns_name = tmp_dns_name;
681
682         /* we want to show a count per partition */
683         if (!s->last_partition || strcmp(s->last_partition, c->partition->nc.dn) != 0) {
684                 s->total_objects = 0;
685                 talloc_free(s->last_partition);
686                 s->last_partition = talloc_strdup(s, c->partition->nc.dn);
687         }
688         s->total_objects += object_count;
689
690         partition_dn = ldb_dn_new(s, s->ldb, c->partition->nc.dn);
691         if (partition_dn == NULL) {
692                 DEBUG(0,("Failed to parse partition DN from DRS.\n"));
693                 return WERR_INVALID_PARAMETER;
694         }
695
696         if (is_exop) {
697                 int ret;
698                 if (nc_object_count) {
699                         DEBUG(0,("Exop on[%s] objects[%u/%u] linked_values[%u/%u]\n",
700                                 c->partition->nc.dn, s->total_objects, nc_object_count,
701                                 linked_attributes_count, nc_linked_attributes_count));
702                 } else {
703                         DEBUG(0,("Exop on[%s] objects[%u] linked_values[%u]\n",
704                         c->partition->nc.dn, s->total_objects, linked_attributes_count));
705                 }
706                 ret = dsdb_find_nc_root(s->ldb, s,
707                                         partition_dn, &nc_root);
708                 if (ret != LDB_SUCCESS) {
709                         DEBUG(0,(__location__ ": Failed to find nc_root for %s\n",
710                                  ldb_dn_get_linearized(partition_dn)));
711                         return WERR_INTERNAL_ERROR;
712                 }
713         } else {
714                 if (nc_object_count) {
715                         DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n",
716                                 c->partition->nc.dn, s->total_objects, nc_object_count,
717                                 linked_attributes_count, nc_linked_attributes_count));
718                 } else {
719                         DEBUG(0,("Partition[%s] objects[%u] linked_values[%u]\n",
720                         c->partition->nc.dn, s->total_objects, linked_attributes_count));
721                 }
722                 nc_root = partition_dn;
723         }
724
725
726         schema = dsdb_get_schema(s->ldb, NULL);
727         if (!schema) {
728                 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
729                 return WERR_INTERNAL_ERROR;
730         }
731
732         if (req_replica_flags & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
733                 dsdb_repl_flags |= DSDB_REPL_FLAG_PRIORITISE_INCOMING;
734         }
735
736         if (req_replica_flags & DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) {
737                 dsdb_repl_flags |= DSDB_REPL_FLAG_EXPECT_NO_SECRETS;
738         }
739
740         status = dsdb_replicated_objects_convert(s->ldb,
741                                                  schema,
742                                                  nc_root,
743                                                  mapping_ctr,
744                                                  object_count,
745                                                  first_object,
746                                                  linked_attributes_count,
747                                                  linked_attributes,
748                                                  s_dsa,
749                                                  uptodateness_vector,
750                                                  c->gensec_skey,
751                                                  dsdb_repl_flags,
752                                                  s, &objs);
753         if (!W_ERROR_IS_OK(status)) {
754                 DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status)));
755                 return status;
756         }
757
758         if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
759                 for (i=0; i < objs->num_objects; i++) {
760                         struct ldb_ldif ldif;
761                         fprintf(stdout, "#\n");
762                         ldif.changetype = LDB_CHANGETYPE_NONE;
763                         ldif.msg = objs->objects[i].msg;
764                         ldb_ldif_write_file(s->ldb, stdout, &ldif);
765                         NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
766                 }
767         }
768         status = dsdb_replicated_objects_commit(s->ldb, NULL, objs, &seq_num);
769         if (!W_ERROR_IS_OK(status)) {
770                 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
771                 return status;
772         }
773
774         talloc_free(s_dsa);
775         talloc_free(objs);
776
777         for (i=0; i < linked_attributes_count; i++) {
778                 const struct dsdb_attribute *sa;
779
780                 if (!linked_attributes[i].identifier) {
781                         DEBUG(0, ("No linked attribute identifier\n"));
782                         return WERR_INTERNAL_ERROR;
783                 }
784
785                 if (!linked_attributes[i].value.blob) {
786                         DEBUG(0, ("No linked attribute value\n"));
787                         return WERR_INTERNAL_ERROR;
788                 }
789
790                 sa = dsdb_attribute_by_attributeID_id(s->schema,
791                                                       linked_attributes[i].attid);
792                 if (!sa) {
793                         DEBUG(0, ("Unable to find attribute via attribute id %d\n", linked_attributes[i].attid));
794                         return WERR_INTERNAL_ERROR;
795                 }
796
797                 if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
798                         DEBUG(0,("# %s\n", sa->lDAPDisplayName));
799                         NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, &linked_attributes[i]);
800                         dump_data(0,
801                                 linked_attributes[i].value.blob->data,
802                                 linked_attributes[i].value.blob->length);
803                 }
804         }
805
806         return WERR_OK;
807 }
808