6167493c359efa8f35481cc5aac4946b13ae541b
[gd/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 #undef DBGC_CLASS
46 #define DBGC_CLASS            DBGC_DRS_REPL
47
48 /* 
49 List of tasks vampire.py must perform:
50 - Domain Join
51  - but don't write the secrets.ldb
52  - results for this should be enough to handle the provision
53 - if vampire method is samsync 
54  - Provision using these results 
55   - do we still want to support this NT4 technology?
56 - Start samsync with libnet code
57  - provision in the callback 
58 - Write out the secrets database, using the code from libnet_Join
59
60 */
61 struct libnet_vampire_cb_state {
62         const char *netbios_name;
63         const char *domain_name;
64         const char *realm;
65         struct cli_credentials *machine_account;
66
67         /* Schema loaded from local LDIF files */
68         struct dsdb_schema *provision_schema;
69
70         /* 1st pass, with some OIDs/attribute names/class names not
71          * converted, because we may not know them yet */
72         struct dsdb_schema *self_made_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         unsigned total_links;
92         char *last_partition;
93         const char *server_dn_str;
94 };
95
96 /* initialise a state structure ready for replication of chunks */
97 void *libnet_vampire_replicate_init(TALLOC_CTX *mem_ctx,
98                                     struct ldb_context *samdb,
99                                     struct loadparm_context *lp_ctx)
100 {
101         struct libnet_vampire_cb_state *s = talloc_zero(mem_ctx, struct libnet_vampire_cb_state);
102         if (!s) {
103                 return NULL;
104         }
105
106         s->ldb              = samdb;
107         s->lp_ctx           = lp_ctx;
108         s->provision_schema = dsdb_get_schema(s->ldb, s);
109         s->schema           = s->provision_schema;
110         s->netbios_name     = lpcfg_netbios_name(lp_ctx);
111         s->domain_name      = lpcfg_workgroup(lp_ctx);
112         s->realm            = lpcfg_realm(lp_ctx);
113
114         return s;
115 }
116
117 /* Caller is expected to keep supplied pointers around for the lifetime of the structure */
118 void *libnet_vampire_cb_state_init(TALLOC_CTX *mem_ctx,
119                                    struct loadparm_context *lp_ctx, struct tevent_context *event_ctx,
120                                    const char *netbios_name, const char *domain_name, const char *realm,
121                                    const char *targetdir)
122 {
123         struct libnet_vampire_cb_state *s = talloc_zero(mem_ctx, struct libnet_vampire_cb_state);
124         if (!s) {
125                 return NULL;
126         }
127
128         s->lp_ctx = lp_ctx;
129         s->event_ctx = event_ctx;
130         s->netbios_name = netbios_name;
131         s->domain_name = domain_name;
132         s->realm = realm;
133         s->targetdir = targetdir;
134         return s;
135 }
136
137 struct ldb_context *libnet_vampire_cb_ldb(struct libnet_vampire_cb_state *state)
138 {
139         state = talloc_get_type_abort(state, struct libnet_vampire_cb_state);
140         return state->ldb;
141 }
142
143 struct loadparm_context *libnet_vampire_cb_lp_ctx(struct libnet_vampire_cb_state *state)
144 {
145         state = talloc_get_type_abort(state, struct libnet_vampire_cb_state);
146         return state->lp_ctx;
147 }
148
149 NTSTATUS libnet_vampire_cb_prepare_db(void *private_data,
150                                       const struct libnet_BecomeDC_PrepareDB *p)
151 {
152         struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
153         struct provision_settings settings;
154         struct provision_result result;
155         NTSTATUS status;
156
157         ZERO_STRUCT(settings);
158         settings.site_name = p->dest_dsa->site_name;
159         settings.root_dn_str = p->forest->root_dn_str;
160         settings.domain_dn_str = p->domain->dn_str;
161         settings.config_dn_str = p->forest->config_dn_str;
162         settings.schema_dn_str = p->forest->schema_dn_str;
163         settings.netbios_name = p->dest_dsa->netbios_name;
164         settings.realm = s->realm;
165         settings.domain = s->domain_name;
166         settings.server_dn_str = p->dest_dsa->server_dn_str;
167         settings.machine_password = generate_random_machine_password(s, 128, 255);
168         settings.targetdir = s->targetdir;
169         settings.use_ntvfs = true;
170         status = provision_bare(s, s->lp_ctx, &settings, &result);
171
172         if (!NT_STATUS_IS_OK(status)) {
173                 return status;
174         }
175
176         s->ldb = talloc_steal(s, result.samdb);
177         s->lp_ctx = talloc_reparent(talloc_parent(result.lp_ctx), s, result.lp_ctx);
178         s->provision_schema = dsdb_get_schema(s->ldb, s);
179         s->server_dn_str = talloc_steal(s, p->dest_dsa->server_dn_str);
180
181         /* wrap the entire vapire operation in a transaction.  This
182            isn't just cosmetic - we use this to ensure that linked
183            attribute back links are added at the end by relying on a
184            transaction commit hook in the linked attributes module. We
185            need to do this as the order of objects coming from the
186            server is not sufficiently deterministic to know that the
187            record that a backlink needs to be created in has itself
188            been created before the object containing the forward link
189            has come over the wire */
190         if (ldb_transaction_start(s->ldb) != LDB_SUCCESS) {
191                 return NT_STATUS_FOOBAR;
192         }
193
194         return NT_STATUS_OK;
195
196
197 }
198
199 NTSTATUS libnet_vampire_cb_check_options(void *private_data,
200                                          const struct libnet_BecomeDC_CheckOptions *o)
201 {
202         struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
203
204         DEBUG(0,("Become DC [%s] of Domain[%s]/[%s]\n",
205                 s->netbios_name,
206                 o->domain->netbios_name, o->domain->dns_name));
207
208         DEBUG(0,("Promotion Partner is Server[%s] from Site[%s]\n",
209                 o->source_dsa->dns_name, o->source_dsa->site_name));
210
211         DEBUG(0,("Options:crossRef behavior_version[%u]\n"
212                        "\tschema object_version[%u]\n"
213                        "\tdomain behavior_version[%u]\n"
214                        "\tdomain w2k3_update_revision[%u]\n", 
215                 o->forest->crossref_behavior_version,
216                 o->forest->schema_object_version,
217                 o->domain->behavior_version,
218                 o->domain->w2k3_update_revision));
219
220         return NT_STATUS_OK;
221 }
222
223 static WERROR libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s,
224                                              const struct libnet_BecomeDC_StoreChunk *c)
225 {
226         WERROR status;
227         struct dsdb_schema_prefixmap *pfm_remote;
228         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
229         struct dsdb_schema *provision_schema;
230         uint32_t object_count = 0;
231         struct drsuapi_DsReplicaObjectListItemEx *first_object;
232         uint32_t linked_attributes_count;
233         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
234         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
235         struct dsdb_extended_replicated_objects *schema_objs;
236         struct repsFromTo1 *s_dsa;
237         char *tmp_dns_name;
238         struct ldb_context *schema_ldb;
239         struct ldb_dn *partition_dn;
240         struct ldb_message *msg;
241         struct ldb_message_element *prefixMap_el;
242         uint32_t i;
243         int ret;
244         bool ok;
245         uint64_t seq_num = 0;
246         uint32_t cycle_before_switching;
247
248         DEBUG(0,("Analyze and apply schema objects\n"));
249
250         s_dsa                   = talloc_zero(s, struct repsFromTo1);
251         if (s_dsa == NULL) {
252                 return WERR_NOT_ENOUGH_MEMORY;
253         }
254         s_dsa->other_info       = talloc(s_dsa, struct repsFromTo1OtherInfo);
255         if (s_dsa->other_info == NULL) {
256                 return WERR_NOT_ENOUGH_MEMORY;
257         }
258
259         switch (c->ctr_level) {
260         case 1:
261                 mapping_ctr                     = &c->ctr1->mapping_ctr;
262                 object_count                    = s->schema_part.object_count;
263                 first_object                    = s->schema_part.first_object;
264                 linked_attributes_count         = 0;
265                 linked_attributes               = NULL;
266                 s_dsa->highwatermark            = c->ctr1->new_highwatermark;
267                 s_dsa->source_dsa_obj_guid      = c->ctr1->source_dsa_guid;
268                 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
269                 uptodateness_vector             = NULL; /* TODO: map it */
270                 break;
271         case 6:
272                 mapping_ctr                     = &c->ctr6->mapping_ctr;
273                 object_count                    = s->schema_part.object_count;
274                 first_object                    = s->schema_part.first_object;
275                 linked_attributes_count         = c->ctr6->linked_attributes_count;
276                 linked_attributes               = c->ctr6->linked_attributes;
277                 s_dsa->highwatermark            = c->ctr6->new_highwatermark;
278                 s_dsa->source_dsa_obj_guid      = c->ctr6->source_dsa_guid;
279                 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
280                 uptodateness_vector             = c->ctr6->uptodateness_vector;
281                 break;
282         default:
283                 return WERR_INVALID_PARAMETER;
284         }
285         /* We must set these up to ensure the replMetaData is written
286          * correctly, before our NTDS Settings entry is replicated */
287         ok = samdb_set_ntds_invocation_id(s->ldb, &c->dest_dsa->invocation_id);
288         if (!ok) {
289                 DEBUG(0,("Failed to set cached ntds invocationId\n"));
290                 return WERR_INTERNAL_ERROR;
291         }
292         ok = samdb_set_ntds_objectGUID(s->ldb, &c->dest_dsa->ntds_guid);
293         if (!ok) {
294                 DEBUG(0,("Failed to set cached ntds objectGUID\n"));
295                 return WERR_INTERNAL_ERROR;
296         }
297
298         status = dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr, true,
299                                                   s, &pfm_remote, NULL);
300         if (!W_ERROR_IS_OK(status)) {
301                 DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s",
302                          win_errstr(status)));
303                 return status;
304         }
305
306         s_dsa->replica_flags            = DRSUAPI_DRS_WRIT_REP
307                                         | DRSUAPI_DRS_INIT_SYNC
308                                         | DRSUAPI_DRS_PER_SYNC;
309         memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
310
311         tmp_dns_name    = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
312         if (tmp_dns_name == NULL) {
313                 return WERR_NOT_ENOUGH_MEMORY;
314         }
315         tmp_dns_name    = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
316         if (tmp_dns_name == NULL) {
317                 return WERR_NOT_ENOUGH_MEMORY;
318         }
319         s_dsa->other_info->dns_name = tmp_dns_name;
320
321         if (s->self_made_schema == NULL) {
322                 DEBUG(0,("libnet_vampire_cb_apply_schema: called with out self_made_schema\n"));
323                 return WERR_INTERNAL_ERROR;
324         }
325
326         schema_ldb = provision_get_schema(s, s->lp_ctx,
327                                           c->forest->schema_dn_str,
328                                           &s->prefixmap_blob);
329         if (!schema_ldb) {
330                 DEBUG(0,("Failed to re-load from local provision using remote prefixMap. "
331                          "Will continue with local prefixMap\n"));
332                 provision_schema = dsdb_get_schema(s->ldb, s);
333         } else {
334                 provision_schema = dsdb_get_schema(schema_ldb, s);
335                 ret = dsdb_reference_schema(s->ldb, provision_schema, SCHEMA_MEMORY_ONLY);
336                 if (ret != LDB_SUCCESS) {
337                         DEBUG(0,("Failed to attach schema from local provision using remote prefixMap."));
338                         return WERR_INTERNAL_ERROR;
339                 }
340                 talloc_free(schema_ldb);
341         }
342
343         cycle_before_switching = lpcfg_parm_long(s->lp_ctx, NULL,
344                                                  "become dc",
345                                                  "schema convert retrial", 1);
346
347         provision_schema->resolving_in_progress = true;
348         s->self_made_schema->resolving_in_progress = true;
349
350         status = dsdb_repl_resolve_working_schema(s->ldb,
351                                                   pfm_remote,
352                                                   cycle_before_switching,
353                                                   provision_schema,
354                                                   s->self_made_schema,
355                                                   object_count,
356                                                   first_object);
357         if (!W_ERROR_IS_OK(status)) {
358                 DEBUG(0, ("%s: dsdb_repl_resolve_working_schema() failed: %s",
359                           __location__, win_errstr(status)));
360                 return status;
361         }
362
363         /* free temp objects for 1st conversion phase */
364         talloc_unlink(s, provision_schema);
365
366         s->self_made_schema->resolving_in_progress = false;
367
368         /*
369          * attach the schema we just brought over DRS to the ldb,
370          * so we can use it in dsdb_convert_object_ex below
371          */
372         ret = dsdb_set_schema(s->ldb, s->self_made_schema, SCHEMA_WRITE);
373         if (ret != LDB_SUCCESS) {
374                 DEBUG(0,("Failed to attach working schema from DRS.\n"));
375                 return WERR_INTERNAL_ERROR;
376         }
377
378         /* we don't want to access the self made schema anymore */
379         s->schema = s->self_made_schema;
380         s->self_made_schema = NULL;
381
382         partition_dn = ldb_dn_new(s, s->ldb, c->partition->nc.dn);
383         if (partition_dn == NULL) {
384                 DEBUG(0,("Failed to parse partition DN from DRS.\n"));
385                 return WERR_INVALID_PARAMETER;
386         }
387
388         /* Now convert the schema elements again, using the schema we finalised, ready to actually import */
389         status = dsdb_replicated_objects_convert(s->ldb,
390                                                  s->schema,
391                                                  partition_dn,
392                                                  mapping_ctr,
393                                                  object_count,
394                                                  first_object,
395                                                  linked_attributes_count,
396                                                  linked_attributes,
397                                                  s_dsa,
398                                                  uptodateness_vector,
399                                                  c->gensec_skey,
400                                                  0,
401                                                  s, &schema_objs);
402         if (!W_ERROR_IS_OK(status)) {
403                 DEBUG(0,("Failed to convert objects when trying to import over DRS (2nd pass, to store remote schema): %s\n", win_errstr(status)));
404                 return status;
405         }
406
407         if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
408                 for (i=0; i < schema_objs->num_objects; i++) {
409                         struct ldb_ldif ldif;
410                         fprintf(stdout, "#\n");
411                         ldif.changetype = LDB_CHANGETYPE_NONE;
412                         ldif.msg = schema_objs->objects[i].msg;
413                         ldb_ldif_write_file(s->ldb, stdout, &ldif);
414                         NDR_PRINT_DEBUG(replPropertyMetaDataBlob, schema_objs->objects[i].meta_data);
415                 }
416         }
417
418         status = dsdb_replicated_objects_commit(s->ldb, NULL, schema_objs, &seq_num);
419         if (!W_ERROR_IS_OK(status)) {
420                 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
421                 return status;
422         }
423
424         msg = ldb_msg_new(schema_objs);
425         if (msg == NULL) {
426                 return WERR_NOT_ENOUGH_MEMORY;
427         }
428         msg->dn = schema_objs->partition_dn;
429
430         /* We must ensure a prefixMap has been written.  Unlike other
431          * attributes (including schemaInfo), it is not replicated in
432          * the normal replication stream.  We can use the one from
433          * s->prefixmap_blob because we operate with one, unchanging
434          * prefixMap for this entire operation.  */
435         ret = ldb_msg_add_value(msg, "prefixMap", &s->prefixmap_blob, &prefixMap_el);
436         if (ret != LDB_SUCCESS) {
437                 return WERR_NOT_ENOUGH_MEMORY;
438         }
439         /* We want to know if a prefixMap was written already, as it
440          * would mean that the above comment was not true, and we have
441          * somehow updated the prefixMap during this transaction */
442         prefixMap_el->flags = LDB_FLAG_MOD_ADD;
443
444         ret = dsdb_modify(s->ldb, msg, DSDB_FLAG_AS_SYSTEM);
445         if (ret != LDB_SUCCESS) {
446                 DEBUG(0,("Failed to add prefixMap: %s\n", ldb_errstring(s->ldb)));
447                 return WERR_INTERNAL_ERROR;
448         }
449
450         talloc_free(s_dsa);
451         talloc_free(schema_objs);
452
453         s->schema = dsdb_get_schema(s->ldb, s);
454         if (!s->schema) {
455                 DEBUG(0,("Failed to get loaded dsdb_schema\n"));
456                 return WERR_INTERNAL_ERROR;
457         }
458
459         return WERR_OK;
460 }
461
462 WERROR libnet_vampire_cb_schema_chunk(void *private_data,
463                                       const struct libnet_BecomeDC_StoreChunk *c)
464 {
465         struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
466         WERROR werr;
467         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
468         uint32_t nc_object_count;
469         uint32_t nc_total_received = 0;
470         uint32_t object_count;
471         struct drsuapi_DsReplicaObjectListItemEx *first_object;
472         struct drsuapi_DsReplicaObjectListItemEx *cur;
473         uint32_t nc_linked_attributes_count;
474         uint32_t linked_attributes_count;
475
476         switch (c->ctr_level) {
477         case 1:
478                 mapping_ctr                     = &c->ctr1->mapping_ctr;
479                 nc_object_count                 = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
480                 object_count                    = c->ctr1->object_count;
481                 first_object                    = c->ctr1->first_object;
482                 nc_linked_attributes_count      = 0;
483                 linked_attributes_count         = 0;
484                 break;
485         case 6:
486                 mapping_ctr                     = &c->ctr6->mapping_ctr;
487                 nc_object_count                 = c->ctr6->nc_object_count;
488                 object_count                    = c->ctr6->object_count;
489                 first_object                    = c->ctr6->first_object;
490                 nc_linked_attributes_count      = c->ctr6->nc_linked_attributes_count;
491                 linked_attributes_count         = c->ctr6->linked_attributes_count;
492                 break;
493         default:
494                 return WERR_INVALID_PARAMETER;
495         }
496
497         if (!s->schema_part.first_object) {
498                 nc_total_received = object_count;
499         } else {
500                 nc_total_received = s->schema_part.object_count + object_count;
501         }
502         if (nc_object_count) {
503                 DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n",
504                         c->partition->nc.dn, nc_total_received, nc_object_count,
505                         linked_attributes_count, nc_linked_attributes_count));
506         } else {
507                 DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u]\n",
508                 c->partition->nc.dn, nc_total_received, linked_attributes_count));
509         }
510
511         if (!s->self_made_schema) {
512                 struct drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr_without_schema_info;
513                 /* Put the DRS prefixmap aside for the schema we are
514                  * about to load in the provision, and into the one we
515                  * are making with the help of DRS */
516
517                 mapping_ctr_without_schema_info = *mapping_ctr;
518
519                 /* This strips off the 0xFF schema info from the end,
520                  * because we don't want it in the blob */
521                 if (mapping_ctr_without_schema_info.num_mappings > 0) {
522                         mapping_ctr_without_schema_info.num_mappings--;
523                 }
524                 werr = dsdb_get_drsuapi_prefixmap_as_blob(&mapping_ctr_without_schema_info, s, &s->prefixmap_blob);
525                 if (!W_ERROR_IS_OK(werr)) {
526                         return werr;
527                 }
528
529                 /* Set up two manually-constructed schema - the local
530                  * schema from the provision will be used to build
531                  * one, which will then in turn be used to build the
532                  * other. */
533                 s->self_made_schema = dsdb_new_schema(s);
534                 if (s->self_made_schema == NULL) {
535                         return WERR_NOT_ENOUGH_MEMORY;
536                 }
537
538                 werr = dsdb_load_prefixmap_from_drsuapi(s->self_made_schema, mapping_ctr);
539                 if (!W_ERROR_IS_OK(werr)) {
540                         return werr;
541                 }
542         } else {
543                 werr = dsdb_schema_pfm_contains_drsuapi_pfm(s->self_made_schema->prefixmap, mapping_ctr);
544                 if (!W_ERROR_IS_OK(werr)) {
545                         return werr;
546                 }
547         }
548
549         if (!s->schema_part.first_object) {
550                 s->schema_part.object_count = object_count;
551                 s->schema_part.first_object = talloc_steal(s, first_object);
552         } else {
553                 s->schema_part.object_count             += object_count;
554                 s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
555                                                                        first_object);
556         }
557         for (cur = first_object; cur->next_object; cur = cur->next_object) {}
558         s->schema_part.last_object = cur;
559
560         if (!c->partition->more_data) {
561                 return libnet_vampire_cb_apply_schema(s, c);
562         }
563
564         return WERR_OK;
565 }
566
567 WERROR libnet_vampire_cb_store_chunk(void *private_data,
568                                      const struct libnet_BecomeDC_StoreChunk *c)
569 {
570         struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
571         WERROR status;
572         struct dsdb_schema *schema;
573         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
574         uint32_t nc_object_count;
575         uint32_t object_count;
576         struct drsuapi_DsReplicaObjectListItemEx *first_object;
577         uint32_t nc_linked_attributes_count;
578         uint32_t linked_attributes_count;
579         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
580         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
581         struct dsdb_extended_replicated_objects *objs;
582         uint32_t req_replica_flags;
583         uint32_t dsdb_repl_flags = 0;
584         struct repsFromTo1 *s_dsa;
585         char *tmp_dns_name;
586         uint32_t i;
587         uint64_t seq_num;
588         bool is_exop = false;
589         struct ldb_dn *partition_dn = NULL;
590         struct ldb_dn *nc_root = NULL;
591
592         s_dsa                   = talloc_zero(s, struct repsFromTo1);
593         if (s_dsa == NULL) {
594                 return WERR_NOT_ENOUGH_MEMORY;
595         }
596         s_dsa->other_info       = talloc(s_dsa, struct repsFromTo1OtherInfo);
597         if (s_dsa->other_info == NULL) {
598                 return WERR_NOT_ENOUGH_MEMORY;
599         }
600
601         switch (c->ctr_level) {
602         case 1:
603                 mapping_ctr                     = &c->ctr1->mapping_ctr;
604                 nc_object_count                 = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
605                 object_count                    = c->ctr1->object_count;
606                 first_object                    = c->ctr1->first_object;
607                 nc_linked_attributes_count      = 0;
608                 linked_attributes_count         = 0;
609                 linked_attributes               = NULL;
610                 s_dsa->highwatermark            = c->ctr1->new_highwatermark;
611                 s_dsa->source_dsa_obj_guid      = c->ctr1->source_dsa_guid;
612                 s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
613                 uptodateness_vector             = NULL; /* TODO: map it */
614                 break;
615         case 6:
616                 mapping_ctr                     = &c->ctr6->mapping_ctr;
617                 nc_object_count                 = c->ctr6->nc_object_count;
618                 object_count                    = c->ctr6->object_count;
619                 first_object                    = c->ctr6->first_object;
620                 nc_linked_attributes_count      = c->ctr6->nc_linked_attributes_count;
621                 linked_attributes_count         = c->ctr6->linked_attributes_count;
622                 linked_attributes               = c->ctr6->linked_attributes;
623                 s_dsa->highwatermark            = c->ctr6->new_highwatermark;
624                 s_dsa->source_dsa_obj_guid      = c->ctr6->source_dsa_guid;
625                 s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
626                 uptodateness_vector             = c->ctr6->uptodateness_vector;
627                 break;
628         default:
629                 return WERR_INVALID_PARAMETER;
630         }
631
632         switch (c->req_level) {
633         case 0:
634                 /* none */
635                 req_replica_flags = 0;
636                 break;
637         case 5:
638                 if (c->req5->extended_op != DRSUAPI_EXOP_NONE) {
639                         is_exop = true;
640                 }
641                 req_replica_flags = c->req5->replica_flags;
642                 break;
643         case 8:
644                 if (c->req8->extended_op != DRSUAPI_EXOP_NONE) {
645                         is_exop = true;
646                 }
647                 req_replica_flags = c->req8->replica_flags;
648                 break;
649         case 10:
650                 if (c->req10->extended_op != DRSUAPI_EXOP_NONE) {
651                         is_exop = true;
652                 }
653                 req_replica_flags = c->req10->replica_flags;
654
655                 if (c->req10->more_flags & DRSUAPI_DRS_GET_TGT) {
656                         dsdb_repl_flags |= DSDB_REPL_FLAG_TARGETS_UPTODATE;
657                 }
658                 break;
659         default:
660                 return WERR_INVALID_PARAMETER;
661         }
662
663         if (req_replica_flags & DRSUAPI_DRS_CRITICAL_ONLY || is_exop) {
664                 /*
665                  * If we only replicate the critical objects, or this
666                  * is an exop we should not remember what we already
667                  * got, as it is incomplete.
668                  */
669                 ZERO_STRUCT(s_dsa->highwatermark);
670                 uptodateness_vector = NULL;
671                 dsdb_repl_flags |= DSDB_REPL_FLAG_OBJECT_SUBSET;
672         }
673
674         /* TODO: avoid hardcoded flags */
675         s_dsa->replica_flags            = DRSUAPI_DRS_WRIT_REP
676                                         | DRSUAPI_DRS_INIT_SYNC
677                                         | DRSUAPI_DRS_PER_SYNC;
678         memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
679
680         tmp_dns_name    = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
681         if (tmp_dns_name == NULL) {
682                 return WERR_NOT_ENOUGH_MEMORY;
683         }
684         tmp_dns_name    = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
685         if (tmp_dns_name == NULL) {
686                 return WERR_NOT_ENOUGH_MEMORY;
687         }
688         s_dsa->other_info->dns_name = tmp_dns_name;
689
690         /* we want to show a count per partition */
691         if (!s->last_partition || strcmp(s->last_partition, c->partition->nc.dn) != 0) {
692                 s->total_objects = 0;
693                 s->total_links = 0;
694                 talloc_free(s->last_partition);
695                 s->last_partition = talloc_strdup(s, c->partition->nc.dn);
696         }
697         s->total_objects += object_count;
698         s->total_links += linked_attributes_count;
699
700         partition_dn = ldb_dn_new(s_dsa, s->ldb, c->partition->nc.dn);
701         if (partition_dn == NULL) {
702                 DEBUG(0,("Failed to parse partition DN from DRS.\n"));
703                 return WERR_INVALID_PARAMETER;
704         }
705
706         if (is_exop) {
707                 int ret;
708                 if (nc_object_count) {
709                         DEBUG(0,("Exop on[%s] objects[%u/%u] linked_values[%u/%u]\n",
710                                 c->partition->nc.dn, s->total_objects, nc_object_count,
711                                 s->total_links, nc_linked_attributes_count));
712                 } else {
713                         DEBUG(0,("Exop on[%s] objects[%u] linked_values[%u]\n",
714                         c->partition->nc.dn, s->total_objects, linked_attributes_count));
715                 }
716                 ret = dsdb_find_nc_root(s->ldb, s_dsa,
717                                         partition_dn, &nc_root);
718                 if (ret != LDB_SUCCESS) {
719                         DEBUG(0,(__location__ ": Failed to find nc_root for %s\n",
720                                  ldb_dn_get_linearized(partition_dn)));
721                         return WERR_INTERNAL_ERROR;
722                 }
723         } else {
724                 if (nc_object_count) {
725                         DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n",
726                                 c->partition->nc.dn, s->total_objects, nc_object_count,
727                                 s->total_links, nc_linked_attributes_count));
728                 } else {
729                         DEBUG(0,("Partition[%s] objects[%u] linked_values[%u]\n",
730                         c->partition->nc.dn, s->total_objects, s->total_links));
731                 }
732                 nc_root = partition_dn;
733         }
734
735
736         schema = dsdb_get_schema(s->ldb, NULL);
737         if (!schema) {
738                 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
739                 return WERR_INTERNAL_ERROR;
740         }
741
742         if (req_replica_flags & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
743                 dsdb_repl_flags |= DSDB_REPL_FLAG_PRIORITISE_INCOMING;
744         }
745
746         if (req_replica_flags & DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) {
747                 dsdb_repl_flags |= DSDB_REPL_FLAG_EXPECT_NO_SECRETS;
748         }
749
750         status = dsdb_replicated_objects_convert(s->ldb,
751                                                  schema,
752                                                  nc_root,
753                                                  mapping_ctr,
754                                                  object_count,
755                                                  first_object,
756                                                  linked_attributes_count,
757                                                  linked_attributes,
758                                                  s_dsa,
759                                                  uptodateness_vector,
760                                                  c->gensec_skey,
761                                                  dsdb_repl_flags,
762                                                  s, &objs);
763         if (!W_ERROR_IS_OK(status)) {
764                 DEBUG(0,("Failed to convert objects: %s\n", win_errstr(status)));
765                 return status;
766         }
767
768         if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
769                 for (i=0; i < objs->num_objects; i++) {
770                         struct ldb_ldif ldif;
771                         fprintf(stdout, "#\n");
772                         ldif.changetype = LDB_CHANGETYPE_NONE;
773                         ldif.msg = objs->objects[i].msg;
774                         ldb_ldif_write_file(s->ldb, stdout, &ldif);
775                         NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
776                 }
777         }
778         status = dsdb_replicated_objects_commit(s->ldb, NULL, objs, &seq_num);
779         if (!W_ERROR_IS_OK(status)) {
780                 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
781                 return status;
782         }
783
784         /* reset debug counters once we've finished replicating the partition */
785         if (!c->partition->more_data) {
786                 s->total_objects = 0;
787                 s->total_links = 0;
788         }
789
790         talloc_free(s_dsa);
791         talloc_free(objs);
792
793         for (i=0; i < linked_attributes_count; i++) {
794                 const struct dsdb_attribute *sa;
795
796                 if (!linked_attributes[i].identifier) {
797                         DEBUG(0, ("No linked attribute identifier\n"));
798                         return WERR_INTERNAL_ERROR;
799                 }
800
801                 if (!linked_attributes[i].value.blob) {
802                         DEBUG(0, ("No linked attribute value\n"));
803                         return WERR_INTERNAL_ERROR;
804                 }
805
806                 sa = dsdb_attribute_by_attributeID_id(s->schema,
807                                                       linked_attributes[i].attid);
808                 if (!sa) {
809                         DEBUG(0, ("Unable to find attribute via attribute id %d\n", linked_attributes[i].attid));
810                         return WERR_INTERNAL_ERROR;
811                 }
812
813                 if (lpcfg_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
814                         DEBUG(0,("# %s\n", sa->lDAPDisplayName));
815                         NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, &linked_attributes[i]);
816                         dump_data(0,
817                                 linked_attributes[i].value.blob->data,
818                                 linked_attributes[i].value.blob->length);
819                 }
820         }
821
822         return WERR_OK;
823 }
824