r20580: pass the DSDB_CONTROL_REPLICATED_OBJECT_OID with the ldb_add request
[jelmer/samba4-debian.git] / source / torture / libnet / libnet_BecomeDC.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    libnet_BecomeDC() tests
5
6    Copyright (C) Stefan (metze) Metzmacher 2006
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "lib/cmdline/popt_common.h"
25 #include "torture/torture.h"
26 #include "torture/rpc/rpc.h"
27 #include "libnet/libnet.h"
28 #include "lib/events/events.h"
29 #include "dsdb/samdb/samdb.h"
30 #include "lib/util/dlinklist.h"
31 #include "lib/ldb/include/ldb.h"
32 #include "lib/ldb/include/ldb_errors.h"
33 #include "librpc/ndr/libndr.h"
34 #include "librpc/gen_ndr/ndr_drsuapi.h"
35 #include "librpc/gen_ndr/ndr_drsblobs.h"
36 #include "librpc/gen_ndr/ndr_misc.h"
37 #include "system/time.h"
38 #include "auth/auth.h"
39 #include "lib/db_wrap.h"
40 #include "lib/appweb/ejs/ejs.h"
41 #include "lib/appweb/ejs/ejsInternal.h"
42 #include "scripting/ejs/smbcalls.h"
43
44 static EjsId eid;
45 static int ejs_error;
46
47 static void test_ejs_exception(const char *reason)
48 {
49         Ejs *ep = ejsPtr(eid);
50         ejsSetErrorMsg(eid, "%s", reason);
51         fprintf(stderr, "%s", ep->error);
52         ejs_error = 127;
53 }
54
55 static int test_run_ejs(char *script)
56 {
57         EjsHandle handle = 0;
58         MprVar result;
59         char *emsg;
60         TALLOC_CTX *mem_ctx = talloc_new(NULL);
61         struct MprVar *return_var;
62
63         mprSetCtx(mem_ctx);
64
65         if (ejsOpen(NULL, NULL, NULL) != 0) {
66                 d_printf("ejsOpen(): unable to initialise EJS subsystem\n");
67                 ejs_error = 127;
68                 goto failed;
69         }
70
71         smb_setup_ejs_functions(test_ejs_exception);
72
73         if ((eid = ejsOpenEngine(handle, 0)) == (EjsId)-1) {
74                 d_printf("smbscript: ejsOpenEngine(): unable to initialise an EJS engine\n");
75                 ejs_error = 127;
76                 goto failed;
77         }
78
79         mprSetVar(ejsGetGlobalObject(eid), "ARGV", mprList("ARGV", NULL));
80
81         /* run the script */
82         if (ejsEvalScript(eid, script, &result, &emsg) == -1) {
83                 d_printf("smbscript: ejsEvalScript(): %s\n", emsg);
84                 if (ejs_error == 0) ejs_error = 127;
85                 goto failed;
86         }
87
88         return_var = ejsGetReturnValue(eid);
89         ejs_error = mprVarToNumber(return_var);
90
91 failed:
92         ejsClose();
93         talloc_free(mem_ctx);
94         return ejs_error;
95 }
96
97 #define TORTURE_NETBIOS_NAME "smbtorturedc"
98 #define TORTURE_SAMDB_LDB "test_samdb.ldb"
99
100 struct test_become_dc_state {
101         struct libnet_context *ctx;
102         struct test_join *tj;
103         struct cli_credentials *machine_account;
104         struct dsdb_schema *schema;
105
106         struct ldb_context *ldb;
107
108         struct {
109                 struct drsuapi_DsReplicaObjectListItemEx *first_object;
110                 struct drsuapi_DsReplicaObjectListItemEx *last_object;
111         } schema_part;
112 };
113
114 static NTSTATUS test_become_dc_check_options(void *private_data,
115                                              const struct libnet_BecomeDC_CheckOptions *o)
116 {
117         DEBUG(0,("Become DC of Domain[%s]/[%s]\n",
118                 o->domain->netbios_name, o->domain->dns_name));
119
120         DEBUG(0,("Promotion Partner is Server[%s] from Site[%s]\n",
121                 o->source_dsa->dns_name, o->source_dsa->site_name));
122
123         DEBUG(0,("Options:crossRef behavior_version[%u]\n"
124                        "\tschema object_version[%u]\n"
125                        "\tdomain behavior_version[%u]\n"
126                        "\tdomain w2k3_update_revision[%u]\n", 
127                 o->forest->crossref_behavior_version,
128                 o->forest->schema_object_version,
129                 o->domain->behavior_version,
130                 o->domain->w2k3_update_revision));
131
132         return NT_STATUS_OK;
133 }
134
135 static NTSTATUS test_become_dc_prepare_db(void *private_data,
136                                           const struct libnet_BecomeDC_PrepareDB *p)
137 {
138         struct test_become_dc_state *s = talloc_get_type(private_data, struct test_become_dc_state);
139         char *ejs;
140         int ret;
141
142         DEBUG(0,("New Server[%s] in Site[%s]\n",
143                 p->dest_dsa->dns_name, p->dest_dsa->site_name));
144
145         DEBUG(0,("DSA Instance [%s]\n"
146                 "\tobjectGUID[%s]\n"
147                 "\tinvocationId[%s]\n",
148                 p->dest_dsa->ntds_dn_str,
149                 GUID_string(s, &p->dest_dsa->ntds_guid),
150                 GUID_string(s, &p->dest_dsa->invocation_id)));
151
152         DEBUG(0,("Schema Partition[%s]\n",
153                 p->forest->schema_dn_str));
154
155         DEBUG(0,("Config Partition[%s]\n",
156                 p->forest->config_dn_str));
157
158         DEBUG(0,("Domain Partition[%s]\n",
159                 p->domain->dn_str));
160
161         ejs = talloc_asprintf(s,
162                 "libinclude(\"base.js\");\n"
163                 "libinclude(\"provision.js\");\n"
164                 "\n"
165                 "function message() { print(vsprintf(arguments)); }\n"
166                 "\n"
167                 "var subobj = provision_guess();\n"
168                 "subobj.ROOTDN       = \"%s\";\n"
169                 "subobj.DOMAINDN     = \"%s\";\n"
170                 "subobj.DOMAINDN_LDB = \"test_domain.ldb\";\n"
171                 "subobj.CONFIGDN     = \"%s\";\n"
172                 "subobj.CONFIGDN_LDB = \"test_config.ldb\";\n"
173                 "subobj.SCHEMADN     = \"%s\";\n"
174                 "subobj.SCHEMADN_LDB = \"test_schema.ldb\";\n"
175                 "subobj.HOSTNAME     = \"%s\";\n"
176                 "subobj.DNSNAME      = \"%s\";\n"
177                 "subobj.DEFAULTSITE  = \"%s\";\n"
178                 "\n"
179                 "modules_list        = new Array(\"rootdse\",\n"
180                 "                                \"kludge_acl\",\n"
181                 "                                \"paged_results\",\n"
182                 "                                \"server_sort\",\n"
183                 "                                \"extended_dn\",\n"
184                 "                                \"asq\",\n"
185                 "                                \"samldb\",\n"
186                 "                                \"password_hash\",\n"
187                 "                                \"operational\",\n"
188                 "                                \"objectclass\",\n"
189                 "                                \"rdn_name\",\n"
190                 "                                \"partition\");\n"
191                 "subobj.MODULES_LIST = join(\",\", modules_list);\n"
192                 "subobj.DOMAINDN_MOD = \"repl_meta_data\";\n"
193                 "subobj.CONFIGDN_MOD = \"repl_meta_data\";\n"
194                 "subobj.SCHEMADN_MOD = \"repl_meta_data\";\n"
195                 "\n"
196                 "var paths = provision_default_paths(subobj);\n"
197                 "paths.samdb = \"%s\";\n"
198                 "\n"
199                 "var system_session = system_session();\n"
200                 "\n"
201                 "var ok = provision_become_dc(subobj, message, paths, system_session);\n"
202                 "assert(ok);\n"
203                 "\n"
204                 "return 0;\n",
205                 p->forest->root_dn_str,
206                 p->domain->dn_str,
207                 p->forest->config_dn_str,
208                 p->forest->schema_dn_str,
209                 p->dest_dsa->netbios_name,
210                 p->dest_dsa->dns_name,
211                 p->dest_dsa->site_name,
212                 TORTURE_SAMDB_LDB);
213         NT_STATUS_HAVE_NO_MEMORY(ejs);
214
215         ret = test_run_ejs(ejs);
216         if (ret != 0) {
217                 DEBUG(0,("Failed to run ejs script: %d:\n%s",
218                         ret, ejs));
219                 talloc_free(ejs);
220                 return NT_STATUS_FOOBAR;
221         }
222         talloc_free(ejs);
223
224         talloc_free(s->ldb);
225
226         s->ldb = ldb_wrap_connect(s, TORTURE_SAMDB_LDB,
227                                   system_session(s),
228                                   NULL, 0, NULL);
229         if (!s->ldb) {
230                 DEBUG(0,("Failed to open '%s'\n",
231                         TORTURE_SAMDB_LDB));
232                 return NT_STATUS_INTERNAL_DB_ERROR;
233         }
234
235         ret = ldb_transaction_start(s->ldb);
236         if (ret != LDB_SUCCESS) {
237                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
238         }
239
240         return NT_STATUS_OK;
241 }
242
243 static WERROR test_object_to_ldb(struct test_become_dc_state *s,
244                                  const struct libnet_BecomeDC_StoreChunk *c,
245                                  struct drsuapi_DsReplicaObjectListItemEx *obj,
246                                  TALLOC_CTX *mem_ctx,
247                                  struct ldb_message **_msg)
248 {
249         NTSTATUS nt_status;
250         WERROR status;
251         uint32_t i;
252         struct ldb_message *msg;
253         struct replPropertyMetaDataBlob md;
254         struct ldb_val md_value;
255         struct drsuapi_DsReplicaObjMetaDataCtr mdc;
256         struct ldb_val guid_value;
257         NTTIME whenChanged = 0;
258         time_t whenChanged_t;
259         const char *whenChanged_s;
260         const char *rdn_name;
261         const struct ldb_val *rdn_value;
262         const struct dsdb_attribute *rdn_attr;
263         uint32_t rdn_attid;
264         struct drsuapi_DsReplicaAttribute *name_a;
265         struct drsuapi_DsReplicaMetaData *name_d;
266         struct replPropertyMetaData1 *rdn_m;
267         struct drsuapi_DsReplicaObjMetaData *rdn_mc;
268         struct ldb_request *req;
269         struct ldb_control **ctrls;
270         struct dsdb_control_replicated_object *ctrl;
271         int ret;
272
273         if (!obj->object.identifier) {
274                 return WERR_FOOBAR;
275         }
276
277         if (!obj->object.identifier->dn || !obj->object.identifier->dn[0]) {
278                 return WERR_FOOBAR;
279         }
280
281         msg = ldb_msg_new(mem_ctx);
282         W_ERROR_HAVE_NO_MEMORY(msg);
283
284         msg->dn                 = ldb_dn_new(msg, s->ldb, obj->object.identifier->dn);
285         W_ERROR_HAVE_NO_MEMORY(msg->dn);
286
287         rdn_name        = ldb_dn_get_rdn_name(msg->dn);
288         rdn_attr        = dsdb_attribute_by_lDAPDisplayName(s->schema, rdn_name);
289         if (!rdn_attr) {
290                 return WERR_FOOBAR;
291         }
292         rdn_attid       = rdn_attr->attributeID_id;
293         rdn_value       = ldb_dn_get_rdn_val(msg->dn);
294
295         msg->num_elements       = obj->object.attribute_ctr.num_attributes;
296         msg->elements           = talloc_array(msg, struct ldb_message_element,
297                                                msg->num_elements);
298         W_ERROR_HAVE_NO_MEMORY(msg->elements);
299
300         for (i=0; i < msg->num_elements; i++) {
301                 status = dsdb_attribute_drsuapi_to_ldb(s->schema,
302                                                        &obj->object.attribute_ctr.attributes[i],
303                                                        msg->elements, &msg->elements[i]);
304                 W_ERROR_NOT_OK_RETURN(status);
305         }
306
307         if (obj->object.attribute_ctr.num_attributes != 0 && !obj->meta_data_ctr) {
308                 return WERR_FOOBAR;
309         }
310
311         if (obj->object.attribute_ctr.num_attributes != obj->meta_data_ctr->count) {
312                 return WERR_FOOBAR;
313         }
314
315         md.version              = 1;
316         md.reserved             = 0;
317         md.ctr.ctr1.count       = obj->meta_data_ctr->count;
318         md.ctr.ctr1.reserved    = 0;
319         md.ctr.ctr1.array       = talloc_array(mem_ctx,
320                                                struct replPropertyMetaData1,
321                                                md.ctr.ctr1.count + 1);
322         W_ERROR_HAVE_NO_MEMORY(md.ctr.ctr1.array);
323
324         mdc.count       = obj->meta_data_ctr->count;
325         mdc.reserved    = 0;
326         mdc.array       = talloc_array(mem_ctx,
327                                        struct drsuapi_DsReplicaObjMetaData,
328                                        mdc.count + 1);
329         W_ERROR_HAVE_NO_MEMORY(mdc.array);
330
331         for (i=0; i < obj->meta_data_ctr->count; i++) {
332                 struct drsuapi_DsReplicaAttribute *a;
333                 struct drsuapi_DsReplicaMetaData *d;
334                 struct replPropertyMetaData1 *m;
335                 struct drsuapi_DsReplicaObjMetaData *mc;
336
337                 a = &obj->object.attribute_ctr.attributes[i];
338                 d = &obj->meta_data_ctr->meta_data[i];
339                 m = &md.ctr.ctr1.array[i];
340                 mc = &mdc.array[i];
341
342                 m->attid                        = a->attid;
343                 m->version                      = d->version;
344                 m->orginating_time              = d->orginating_time;
345                 m->orginating_invocation_id     = d->orginating_invocation_id;
346                 m->orginating_usn               = d->orginating_usn;
347                 m->local_usn                    = 0;
348
349                 mc->attribute_name              = dsdb_lDAPDisplayName_by_id(s->schema, a->attid);
350                 mc->version                     = d->version;
351                 mc->originating_last_changed    = d->orginating_time;
352                 mc->originating_dsa_invocation_id= d->orginating_invocation_id;
353                 mc->originating_usn             = d->orginating_usn;
354                 mc->local_usn                   = 0;
355
356                 if (d->orginating_time > whenChanged) {
357                         whenChanged = d->orginating_time;
358                 }
359
360                 if (a->attid == DRSUAPI_ATTRIBUTE_name) {
361                         name_a = a;
362                         name_d = d;
363                         rdn_m = &md.ctr.ctr1.array[md.ctr.ctr1.count];
364                         rdn_mc = &mdc.array[mdc.count];
365                 }
366         }
367
368         if (!name_d) {
369                 return WERR_FOOBAR;
370         }
371
372         ret = ldb_msg_add_value(msg, rdn_attr->lDAPDisplayName, rdn_value, NULL);
373         if (ret != LDB_SUCCESS) {
374                 return WERR_FOOBAR;
375         }
376
377         nt_status = ndr_push_struct_blob(&guid_value, msg, &obj->object.identifier->guid,
378                                          (ndr_push_flags_fn_t)ndr_push_GUID);
379         if (!NT_STATUS_IS_OK(nt_status)) {
380                 return ntstatus_to_werror(nt_status);
381         }
382         ret = ldb_msg_add_value(msg, "objectGUID", &guid_value, NULL);
383         if (ret != LDB_SUCCESS) {
384                 return WERR_FOOBAR;
385         }
386
387         whenChanged_t = nt_time_to_unix(whenChanged);
388         whenChanged_s = ldb_timestring(msg, whenChanged_t);
389         W_ERROR_HAVE_NO_MEMORY(whenChanged_s);
390         ret = ldb_msg_add_string(msg, "whenChanged", whenChanged_s);
391         if (ret != LDB_SUCCESS) {
392                 return WERR_FOOBAR;
393         }
394
395         rdn_m->attid                            = rdn_attid;
396         rdn_m->version                          = name_d->version;
397         rdn_m->orginating_time                  = name_d->orginating_time;
398         rdn_m->orginating_invocation_id         = name_d->orginating_invocation_id;
399         rdn_m->orginating_usn                   = name_d->orginating_usn;
400         rdn_m->local_usn                        = 0;
401         md.ctr.ctr1.count++;
402
403         rdn_mc->attribute_name                  = rdn_attr->lDAPDisplayName;
404         rdn_mc->version                         = name_d->version;
405         rdn_mc->originating_last_changed        = name_d->orginating_time;
406         rdn_mc->originating_dsa_invocation_id   = name_d->orginating_invocation_id;
407         rdn_mc->originating_usn                 = name_d->orginating_usn;
408         rdn_mc->local_usn                       = 0;
409         mdc.count++;
410
411         nt_status = ndr_push_struct_blob(&md_value, msg, &md,
412                                          (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
413         if (!NT_STATUS_IS_OK(nt_status)) {
414                 return ntstatus_to_werror(nt_status);
415         }
416         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
417         if (ret != LDB_SUCCESS) {
418                 return WERR_FOOBAR;
419         }
420
421         if (lp_parm_bool(-1, "become dc", "dump objects", False)) {
422                 struct ldb_ldif ldif;
423                 fprintf(stdout, "#\n");
424                 ldif.changetype = LDB_CHANGETYPE_NONE;
425                 ldif.msg = msg;
426                 ldb_ldif_write_file(s->ldb, stdout, &ldif);
427                 NDR_PRINT_DEBUG(drsuapi_DsReplicaObjMetaDataCtr, &mdc);
428         }
429
430         /*
431          * apply the record to the ldb
432          * using an ldb_control so indicate
433          * that it's a replicated change
434          */
435         ret = ldb_msg_sanity_check(s->ldb, msg);
436         if (ret != LDB_SUCCESS) {
437                 return WERR_FOOBAR;
438         }
439         ctrls = talloc_array(msg, struct ldb_control *, 2);
440         W_ERROR_HAVE_NO_MEMORY(ctrls);
441         ctrls[0] = talloc(ctrls, struct ldb_control);
442         W_ERROR_HAVE_NO_MEMORY(ctrls[0]);
443         ctrls[1] = NULL;
444
445         ctrl = talloc(ctrls, struct dsdb_control_replicated_object);
446         W_ERROR_HAVE_NO_MEMORY(ctrl);
447         ctrls[0]->oid           = DSDB_CONTROL_REPLICATED_OBJECT_OID;
448         ctrls[0]->critical      = True;
449         ctrls[0]->data          = ctrl;
450
451         ret = ldb_build_add_req(&req, s->ldb, msg, msg, ctrls, NULL, NULL);
452         if (ret != LDB_SUCCESS) {
453                 return WERR_FOOBAR;
454         }
455         ldb_set_timeout(s->ldb, req, 0); /* use default timeout */
456         ret = ldb_request(s->ldb, req);
457         if (ret == LDB_SUCCESS) {
458                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
459         }
460         talloc_free(req);
461         if (ret != LDB_SUCCESS) {
462                 if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
463                         DEBUG(0,("record exists (ignored): %s: %d\n",
464                                 obj->object.identifier->dn, ret));
465                 } else {
466                         DEBUG(0,("Failed to add record: %s: %d\n",
467                                 obj->object.identifier->dn, ret));
468                         return WERR_FOOBAR;
469                 }
470         }
471
472         *_msg = msg;
473         return WERR_OK;
474 }
475
476 static NTSTATUS test_apply_schema(struct test_become_dc_state *s,
477                                   const struct libnet_BecomeDC_StoreChunk *c)
478 {
479         WERROR status;
480         struct drsuapi_DsReplicaObjectListItemEx *cur;
481         int ret;
482
483         for (cur = s->schema_part.first_object; cur; cur = cur->next_object) {
484                 uint32_t i;
485                 bool is_attr = false;
486                 bool is_class = false;
487
488                 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
489                         struct drsuapi_DsReplicaAttribute *a;
490                         uint32_t j;
491                         const char *oid = NULL;
492
493                         a = &cur->object.attribute_ctr.attributes[i];
494                         status = dsdb_map_int2oid(s->schema, a->attid, s, &oid);
495                         if (!W_ERROR_IS_OK(status)) {
496                                 return werror_to_ntstatus(status);
497                         }
498
499                         switch (a->attid) {
500                         case DRSUAPI_ATTRIBUTE_objectClass:
501                                 for (j=0; j < a->value_ctr.num_values; j++) {
502                                         uint32_t val = 0xFFFFFFFF;
503
504                                         if (a->value_ctr.values[i].blob
505                                             && a->value_ctr.values[i].blob->length == 4) {
506                                                 val = IVAL(a->value_ctr.values[i].blob->data,0);
507                                         }
508
509                                         if (val == DRSUAPI_OBJECTCLASS_attributeSchema) {
510                                                 is_attr = true;
511                                         }
512                                         if (val == DRSUAPI_OBJECTCLASS_classSchema) {
513                                                 is_class = true;
514                                         }
515                                 }
516
517                                 break;
518                         default:
519                                 break;
520                         }
521                 }
522
523                 if (is_attr) {
524                         struct dsdb_attribute *sa;
525
526                         sa = talloc_zero(s->schema, struct dsdb_attribute);
527                         NT_STATUS_HAVE_NO_MEMORY(sa);
528
529                         status = dsdb_attribute_from_drsuapi(s->schema, &cur->object, s, sa);
530                         if (!W_ERROR_IS_OK(status)) {
531                                 return werror_to_ntstatus(status);
532                         }
533
534                         DLIST_ADD_END(s->schema->attributes, sa, struct dsdb_attribute *);
535                 }
536
537                 if (is_class) {
538                         struct dsdb_class *sc;
539
540                         sc = talloc_zero(s->schema, struct dsdb_class);
541                         NT_STATUS_HAVE_NO_MEMORY(sc);
542
543                         status = dsdb_class_from_drsuapi(s->schema, &cur->object, s, sc);
544                         if (!W_ERROR_IS_OK(status)) {
545                                 return werror_to_ntstatus(status);
546                         }
547
548                         DLIST_ADD_END(s->schema->classes, sc, struct dsdb_class *);
549                 }
550         }
551
552         for (cur = s->schema_part.first_object; cur; cur = cur->next_object) {
553                 struct ldb_message *msg;
554                 status = test_object_to_ldb(s, c, cur, s, &msg);
555                 if (!W_ERROR_IS_OK(status)) {
556                         return werror_to_ntstatus(status);
557                 }
558         }
559
560         ret = ldb_transaction_commit(s->ldb);
561         if (ret != LDB_SUCCESS) {
562                 DEBUG(0,("Failed to commit the schema changes: %d\n", ret));
563                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
564         }
565
566         ret = ldb_transaction_start(s->ldb);
567         if (ret != LDB_SUCCESS) {
568                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
569         }
570
571         return NT_STATUS_OK;
572 }
573
574 static NTSTATUS test_become_dc_schema_chunk(void *private_data,
575                                             const struct libnet_BecomeDC_StoreChunk *c)
576 {
577         struct test_become_dc_state *s = talloc_get_type(private_data, struct test_become_dc_state);
578         WERROR status;
579         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
580         uint32_t total_object_count;
581         uint32_t object_count;
582         struct drsuapi_DsReplicaObjectListItemEx *first_object;
583         struct drsuapi_DsReplicaObjectListItemEx *cur;
584
585         switch (c->ctr_level) {
586         case 1:
587                 mapping_ctr             = &c->ctr1->mapping_ctr;
588                 total_object_count      = c->ctr1->total_object_count;
589                 object_count            = c->ctr1->object_count;
590                 first_object            = c->ctr1->first_object;
591                 break;
592         case 6:
593                 mapping_ctr             = &c->ctr6->mapping_ctr;
594                 total_object_count      = c->ctr6->total_object_count;
595                 object_count            = c->ctr6->object_count;
596                 first_object            = c->ctr6->first_object;
597                 break;
598         default:
599                 return NT_STATUS_INVALID_PARAMETER;
600         }
601
602         if (total_object_count) {
603                 DEBUG(0,("Schema-DN[%s] objects[%u/%u]\n",
604                         c->partition->nc.dn, object_count, total_object_count));
605         } else {
606                 DEBUG(0,("Schema-DN[%s] objects[%u]\n",
607                 c->partition->nc.dn, object_count));
608         }
609
610         if (!s->schema) {
611                 s->schema = talloc_zero(s, struct dsdb_schema);
612                 NT_STATUS_HAVE_NO_MEMORY(s->schema);
613
614                 status = dsdb_load_oid_mappings(s->schema, mapping_ctr);
615                 if (!W_ERROR_IS_OK(status)) {
616                         return werror_to_ntstatus(status);
617                 }
618         } else {
619                 status = dsdb_verify_oid_mappings(s->schema, mapping_ctr);
620                 if (!W_ERROR_IS_OK(status)) {
621                         return werror_to_ntstatus(status);
622                 }
623         }
624
625         if (!s->schema_part.first_object) {
626                 s->schema_part.first_object = talloc_steal(s, first_object);
627         } else {
628                 s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
629                                                                        first_object);
630         }
631         for (cur = first_object; cur->next_object; cur = cur->next_object) {}
632         s->schema_part.last_object = cur;
633
634         if (c->partition->highwatermark.tmp_highest_usn == c->partition->highwatermark.highest_usn) {
635                 return test_apply_schema(s, c);
636         }
637
638         return NT_STATUS_OK;
639 }
640
641 static NTSTATUS test_become_dc_store_chunk(void *private_data,
642                                            const struct libnet_BecomeDC_StoreChunk *c)
643 {
644         struct test_become_dc_state *s = talloc_get_type(private_data, struct test_become_dc_state);
645         WERROR status;
646         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
647         uint32_t total_object_count;
648         uint32_t object_count;
649         struct drsuapi_DsReplicaObjectListItemEx *first_object;
650         struct drsuapi_DsReplicaObjectListItemEx *cur;
651         uint32_t linked_attributes_count;
652         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
653         uint32_t i;
654         int ret;
655
656         switch (c->ctr_level) {
657         case 1:
658                 mapping_ctr             = &c->ctr1->mapping_ctr;
659                 total_object_count      = c->ctr1->total_object_count;
660                 object_count            = c->ctr1->object_count;
661                 first_object            = c->ctr1->first_object;
662                 linked_attributes_count = 0;
663                 linked_attributes       = NULL;
664                 break;
665         case 6:
666                 mapping_ctr             = &c->ctr6->mapping_ctr;
667                 total_object_count      = c->ctr6->total_object_count;
668                 object_count            = c->ctr6->object_count;
669                 first_object            = c->ctr6->first_object;
670                 linked_attributes_count = c->ctr6->linked_attributes_count;
671                 linked_attributes       = c->ctr6->linked_attributes;
672                 break;
673         default:
674                 return NT_STATUS_INVALID_PARAMETER;
675         }
676
677         if (total_object_count) {
678                 DEBUG(0,("Partition[%s] objects[%u/%u]\n",
679                         c->partition->nc.dn, object_count, total_object_count));
680         } else {
681                 DEBUG(0,("Partition[%s] objects[%u]\n",
682                 c->partition->nc.dn, object_count));
683         }
684
685         status = dsdb_verify_oid_mappings(s->schema, mapping_ctr);
686         if (!W_ERROR_IS_OK(status)) {
687                 return werror_to_ntstatus(status);
688         }
689
690         for (cur = first_object; cur; cur = cur->next_object) {
691                 struct ldb_message *msg;
692                 status = test_object_to_ldb(s, c, cur, s, &msg);
693                 if (!W_ERROR_IS_OK(status)) {
694                         return werror_to_ntstatus(status);
695                 }
696         }
697
698         for (i=0; i < linked_attributes_count; i++) {
699                 const struct dsdb_attribute *sa;
700
701                 if (!linked_attributes[i].identifier) {
702                         return NT_STATUS_FOOBAR;                
703                 }
704
705                 if (!linked_attributes[i].value.blob) {
706                         return NT_STATUS_FOOBAR;                
707                 }
708
709                 sa = dsdb_attribute_by_attributeID_id(s->schema,
710                                                       linked_attributes[i].attid);
711                 if (!sa) {
712                         return NT_STATUS_FOOBAR;
713                 }
714
715                 if (lp_parm_bool(-1, "become dc", "dump objects", False)) {
716                         DEBUG(0,("# %s\n", sa->lDAPDisplayName));
717                         NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, &linked_attributes[i]);
718                         dump_data(0,
719                                 linked_attributes[i].value.blob->data,
720                                 linked_attributes[i].value.blob->length);
721                 }
722         }
723
724         ret = ldb_transaction_commit(s->ldb);
725         if (ret != LDB_SUCCESS) {
726                 DEBUG(0,("Failed to commit the changes: %d\n", ret));
727                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
728         }
729
730         ret = ldb_transaction_start(s->ldb);
731         if (ret != LDB_SUCCESS) {
732                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
733         }
734
735         return NT_STATUS_OK;
736 }
737
738 BOOL torture_net_become_dc(struct torture_context *torture)
739 {
740         BOOL ret = True;
741         NTSTATUS status;
742         struct libnet_BecomeDC b;
743         struct libnet_UnbecomeDC u;
744         struct test_become_dc_state *s;
745
746         s = talloc_zero(torture, struct test_become_dc_state);
747         if (!s) return False;
748
749         /* Join domain as a member server. */
750         s->tj = torture_join_domain(TORTURE_NETBIOS_NAME,
751                                  ACB_WSTRUST,
752                                  &s->machine_account);
753         if (!s->tj) {
754                 DEBUG(0, ("%s failed to join domain as workstation\n",
755                           TORTURE_NETBIOS_NAME));
756                 return False;
757         }
758
759         s->ctx = libnet_context_init(event_context_init(s));
760         s->ctx->cred = cmdline_credentials;
761
762         s->ldb = ldb_init(s);
763
764         ZERO_STRUCT(b);
765         b.in.domain_dns_name            = torture_join_dom_dns_name(s->tj);
766         b.in.domain_netbios_name        = torture_join_dom_netbios_name(s->tj);
767         b.in.domain_sid                 = torture_join_sid(s->tj);
768         b.in.source_dsa_address         = lp_parm_string(-1, "torture", "host");
769         b.in.dest_dsa_netbios_name      = TORTURE_NETBIOS_NAME;
770
771         b.in.callbacks.private_data     = s;
772         b.in.callbacks.check_options    = test_become_dc_check_options;
773         b.in.callbacks.prepare_db       = test_become_dc_prepare_db;
774         b.in.callbacks.schema_chunk     = test_become_dc_schema_chunk;
775         b.in.callbacks.config_chunk     = test_become_dc_store_chunk;
776         b.in.callbacks.domain_chunk     = test_become_dc_store_chunk;
777
778         status = libnet_BecomeDC(s->ctx, s, &b);
779         if (!NT_STATUS_IS_OK(status)) {
780                 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
781                 ret = False;
782         }
783
784         ZERO_STRUCT(u);
785         u.in.domain_dns_name            = torture_join_dom_dns_name(s->tj);
786         u.in.domain_netbios_name        = torture_join_dom_netbios_name(s->tj);
787         u.in.source_dsa_address         = lp_parm_string(-1, "torture", "host");
788         u.in.dest_dsa_netbios_name      = TORTURE_NETBIOS_NAME;
789
790         status = libnet_UnbecomeDC(s->ctx, s, &u);
791         if (!NT_STATUS_IS_OK(status)) {
792                 printf("libnet_UnbecomeDC() failed - %s\n", nt_errstr(status));
793                 ret = False;
794         }
795
796         /* Leave domain. */                          
797         torture_leave_domain(s->tj);
798
799         talloc_free(s);
800         return ret;
801 }