r20575: apply records to the test_samdb.ldb (my birthday present to myself...:-)
[jra/samba/.git] / source4 / 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\",should only handle originating changes...\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 = \"objectguid\";\n"
193                 "subobj.CONFIGDN_MOD = \"objectguid\";\n"
194                 "subobj.SCHEMADN_MOD = \"objectguid\";\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         int ret;
269
270         if (!obj->object.identifier) {
271                 return WERR_FOOBAR;
272         }
273
274         if (!obj->object.identifier->dn || !obj->object.identifier->dn[0]) {
275                 return WERR_FOOBAR;
276         }
277
278         msg = ldb_msg_new(mem_ctx);
279         W_ERROR_HAVE_NO_MEMORY(msg);
280
281         msg->dn                 = ldb_dn_new(msg, s->ldb, obj->object.identifier->dn);
282         W_ERROR_HAVE_NO_MEMORY(msg->dn);
283
284         rdn_name        = ldb_dn_get_rdn_name(msg->dn);
285         rdn_attr        = dsdb_attribute_by_lDAPDisplayName(s->schema, rdn_name);
286         if (!rdn_attr) {
287                 return WERR_FOOBAR;
288         }
289         rdn_attid       = rdn_attr->attributeID_id;
290         rdn_value       = ldb_dn_get_rdn_val(msg->dn);
291
292         msg->num_elements       = obj->object.attribute_ctr.num_attributes;
293         msg->elements           = talloc_array(msg, struct ldb_message_element,
294                                                msg->num_elements);
295         W_ERROR_HAVE_NO_MEMORY(msg->elements);
296
297         for (i=0; i < msg->num_elements; i++) {
298                 status = dsdb_attribute_drsuapi_to_ldb(s->schema,
299                                                        &obj->object.attribute_ctr.attributes[i],
300                                                        msg->elements, &msg->elements[i]);
301                 W_ERROR_NOT_OK_RETURN(status);
302         }
303
304         if (obj->object.attribute_ctr.num_attributes != 0 && !obj->meta_data_ctr) {
305                 return WERR_FOOBAR;
306         }
307
308         if (obj->object.attribute_ctr.num_attributes != obj->meta_data_ctr->count) {
309                 return WERR_FOOBAR;
310         }
311
312         md.version              = 1;
313         md.reserved             = 0;
314         md.ctr.ctr1.count       = obj->meta_data_ctr->count;
315         md.ctr.ctr1.reserved    = 0;
316         md.ctr.ctr1.array       = talloc_array(mem_ctx,
317                                                struct replPropertyMetaData1,
318                                                md.ctr.ctr1.count + 1);
319         W_ERROR_HAVE_NO_MEMORY(md.ctr.ctr1.array);
320
321         mdc.count       = obj->meta_data_ctr->count;
322         mdc.reserved    = 0;
323         mdc.array       = talloc_array(mem_ctx,
324                                        struct drsuapi_DsReplicaObjMetaData,
325                                        mdc.count + 1);
326         W_ERROR_HAVE_NO_MEMORY(mdc.array);
327
328         for (i=0; i < obj->meta_data_ctr->count; i++) {
329                 struct drsuapi_DsReplicaAttribute *a;
330                 struct drsuapi_DsReplicaMetaData *d;
331                 struct replPropertyMetaData1 *m;
332                 struct drsuapi_DsReplicaObjMetaData *mc;
333
334                 a = &obj->object.attribute_ctr.attributes[i];
335                 d = &obj->meta_data_ctr->meta_data[i];
336                 m = &md.ctr.ctr1.array[i];
337                 mc = &mdc.array[i];
338
339                 m->attid                        = a->attid;
340                 m->version                      = d->version;
341                 m->orginating_time              = d->orginating_time;
342                 m->orginating_invocation_id     = d->orginating_invocation_id;
343                 m->orginating_usn               = d->orginating_usn;
344                 m->local_usn                    = 0;
345
346                 mc->attribute_name              = dsdb_lDAPDisplayName_by_id(s->schema, a->attid);
347                 mc->version                     = d->version;
348                 mc->originating_last_changed    = d->orginating_time;
349                 mc->originating_dsa_invocation_id= d->orginating_invocation_id;
350                 mc->originating_usn             = d->orginating_usn;
351                 mc->local_usn                   = 0;
352
353                 if (d->orginating_time > whenChanged) {
354                         whenChanged = d->orginating_time;
355                 }
356
357                 if (a->attid == DRSUAPI_ATTRIBUTE_name) {
358                         name_a = a;
359                         name_d = d;
360                         rdn_m = &md.ctr.ctr1.array[md.ctr.ctr1.count];
361                         rdn_mc = &mdc.array[mdc.count];
362                 }
363         }
364
365         if (!name_d) {
366                 return WERR_FOOBAR;
367         }
368
369         ret = ldb_msg_add_value(msg, rdn_attr->lDAPDisplayName, rdn_value, NULL);
370         if (ret != LDB_SUCCESS) {
371                 return WERR_FOOBAR;
372         }
373
374         nt_status = ndr_push_struct_blob(&guid_value, msg, &obj->object.identifier->guid,
375                                          (ndr_push_flags_fn_t)ndr_push_GUID);
376         if (!NT_STATUS_IS_OK(nt_status)) {
377                 return ntstatus_to_werror(nt_status);
378         }
379         ret = ldb_msg_add_value(msg, "objectGUID", &guid_value, NULL);
380         if (ret != LDB_SUCCESS) {
381                 return WERR_FOOBAR;
382         }
383
384         whenChanged_t = nt_time_to_unix(whenChanged);
385         whenChanged_s = ldb_timestring(msg, whenChanged_t);
386         W_ERROR_HAVE_NO_MEMORY(whenChanged_s);
387         ret = ldb_msg_add_string(msg, "whenChanged", whenChanged_s);
388         if (ret != LDB_SUCCESS) {
389                 return WERR_FOOBAR;
390         }
391
392         rdn_m->attid                            = rdn_attid;
393         rdn_m->version                          = name_d->version;
394         rdn_m->orginating_time                  = name_d->orginating_time;
395         rdn_m->orginating_invocation_id         = name_d->orginating_invocation_id;
396         rdn_m->orginating_usn                   = name_d->orginating_usn;
397         rdn_m->local_usn                        = 0;
398         md.ctr.ctr1.count++;
399
400         rdn_mc->attribute_name                  = rdn_attr->lDAPDisplayName;
401         rdn_mc->version                         = name_d->version;
402         rdn_mc->originating_last_changed        = name_d->orginating_time;
403         rdn_mc->originating_dsa_invocation_id   = name_d->orginating_invocation_id;
404         rdn_mc->originating_usn                 = name_d->orginating_usn;
405         rdn_mc->local_usn                       = 0;
406         mdc.count++;
407
408         nt_status = ndr_push_struct_blob(&md_value, msg, &md,
409                                          (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
410         if (!NT_STATUS_IS_OK(nt_status)) {
411                 return ntstatus_to_werror(nt_status);
412         }
413         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
414         if (ret != LDB_SUCCESS) {
415                 return WERR_FOOBAR;
416         }
417
418         if (lp_parm_bool(-1, "become dc", "dump objects", False)) {
419                 struct ldb_ldif ldif;
420                 fprintf(stdout, "#\n");
421                 ldif.changetype = LDB_CHANGETYPE_NONE;
422                 ldif.msg = msg;
423                 ldb_ldif_write_file(s->ldb, stdout, &ldif);
424                 NDR_PRINT_DEBUG(drsuapi_DsReplicaObjMetaDataCtr, &mdc);
425         }
426
427         ret = ldb_add(s->ldb, msg);
428         if (ret != LDB_SUCCESS) {
429                 if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
430                         DEBUG(0,("record exists (ignored): %s: %d\n",
431                                 obj->object.identifier->dn, ret));
432                 } else {
433                         DEBUG(0,("Failed to add record: %s: %d\n",
434                                 obj->object.identifier->dn, ret));
435                         return WERR_FOOBAR;
436                 }
437         }
438
439         *_msg = msg;
440         return WERR_OK;
441 }
442
443 static NTSTATUS test_apply_schema(struct test_become_dc_state *s,
444                                   const struct libnet_BecomeDC_StoreChunk *c)
445 {
446         WERROR status;
447         struct drsuapi_DsReplicaObjectListItemEx *cur;
448         int ret;
449
450         for (cur = s->schema_part.first_object; cur; cur = cur->next_object) {
451                 uint32_t i;
452                 bool is_attr = false;
453                 bool is_class = false;
454
455                 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
456                         struct drsuapi_DsReplicaAttribute *a;
457                         uint32_t j;
458                         const char *oid = NULL;
459
460                         a = &cur->object.attribute_ctr.attributes[i];
461                         status = dsdb_map_int2oid(s->schema, a->attid, s, &oid);
462                         if (!W_ERROR_IS_OK(status)) {
463                                 return werror_to_ntstatus(status);
464                         }
465
466                         switch (a->attid) {
467                         case DRSUAPI_ATTRIBUTE_objectClass:
468                                 for (j=0; j < a->value_ctr.num_values; j++) {
469                                         uint32_t val = 0xFFFFFFFF;
470
471                                         if (a->value_ctr.values[i].blob
472                                             && a->value_ctr.values[i].blob->length == 4) {
473                                                 val = IVAL(a->value_ctr.values[i].blob->data,0);
474                                         }
475
476                                         if (val == DRSUAPI_OBJECTCLASS_attributeSchema) {
477                                                 is_attr = true;
478                                         }
479                                         if (val == DRSUAPI_OBJECTCLASS_classSchema) {
480                                                 is_class = true;
481                                         }
482                                 }
483
484                                 break;
485                         default:
486                                 break;
487                         }
488                 }
489
490                 if (is_attr) {
491                         struct dsdb_attribute *sa;
492
493                         sa = talloc_zero(s->schema, struct dsdb_attribute);
494                         NT_STATUS_HAVE_NO_MEMORY(sa);
495
496                         status = dsdb_attribute_from_drsuapi(s->schema, &cur->object, s, sa);
497                         if (!W_ERROR_IS_OK(status)) {
498                                 return werror_to_ntstatus(status);
499                         }
500
501                         DLIST_ADD_END(s->schema->attributes, sa, struct dsdb_attribute *);
502                 }
503
504                 if (is_class) {
505                         struct dsdb_class *sc;
506
507                         sc = talloc_zero(s->schema, struct dsdb_class);
508                         NT_STATUS_HAVE_NO_MEMORY(sc);
509
510                         status = dsdb_class_from_drsuapi(s->schema, &cur->object, s, sc);
511                         if (!W_ERROR_IS_OK(status)) {
512                                 return werror_to_ntstatus(status);
513                         }
514
515                         DLIST_ADD_END(s->schema->classes, sc, struct dsdb_class *);
516                 }
517         }
518
519         for (cur = s->schema_part.first_object; cur; cur = cur->next_object) {
520                 struct ldb_message *msg;
521                 status = test_object_to_ldb(s, c, cur, s, &msg);
522                 if (!W_ERROR_IS_OK(status)) {
523                         return werror_to_ntstatus(status);
524                 }
525         }
526
527         ret = ldb_transaction_commit(s->ldb);
528         if (ret != LDB_SUCCESS) {
529                 DEBUG(0,("Failed to commit the schema changes: %d\n", ret));
530                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
531         }
532
533         ret = ldb_transaction_start(s->ldb);
534         if (ret != LDB_SUCCESS) {
535                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
536         }
537
538         return NT_STATUS_OK;
539 }
540
541 static NTSTATUS test_become_dc_schema_chunk(void *private_data,
542                                             const struct libnet_BecomeDC_StoreChunk *c)
543 {
544         struct test_become_dc_state *s = talloc_get_type(private_data, struct test_become_dc_state);
545         WERROR status;
546         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
547         uint32_t total_object_count;
548         uint32_t object_count;
549         struct drsuapi_DsReplicaObjectListItemEx *first_object;
550         struct drsuapi_DsReplicaObjectListItemEx *cur;
551
552         switch (c->ctr_level) {
553         case 1:
554                 mapping_ctr             = &c->ctr1->mapping_ctr;
555                 total_object_count      = c->ctr1->total_object_count;
556                 object_count            = c->ctr1->object_count;
557                 first_object            = c->ctr1->first_object;
558                 break;
559         case 6:
560                 mapping_ctr             = &c->ctr6->mapping_ctr;
561                 total_object_count      = c->ctr6->total_object_count;
562                 object_count            = c->ctr6->object_count;
563                 first_object            = c->ctr6->first_object;
564                 break;
565         default:
566                 return NT_STATUS_INVALID_PARAMETER;
567         }
568
569         if (total_object_count) {
570                 DEBUG(0,("Schema-DN[%s] objects[%u/%u]\n",
571                         c->partition->nc.dn, object_count, total_object_count));
572         } else {
573                 DEBUG(0,("Schema-DN[%s] objects[%u]\n",
574                 c->partition->nc.dn, object_count));
575         }
576
577         if (!s->schema) {
578                 s->schema = talloc_zero(s, struct dsdb_schema);
579                 NT_STATUS_HAVE_NO_MEMORY(s->schema);
580
581                 status = dsdb_load_oid_mappings(s->schema, mapping_ctr);
582                 if (!W_ERROR_IS_OK(status)) {
583                         return werror_to_ntstatus(status);
584                 }
585         } else {
586                 status = dsdb_verify_oid_mappings(s->schema, mapping_ctr);
587                 if (!W_ERROR_IS_OK(status)) {
588                         return werror_to_ntstatus(status);
589                 }
590         }
591
592         if (!s->schema_part.first_object) {
593                 s->schema_part.first_object = talloc_steal(s, first_object);
594         } else {
595                 s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
596                                                                        first_object);
597         }
598         for (cur = first_object; cur->next_object; cur = cur->next_object) {}
599         s->schema_part.last_object = cur;
600
601         if (c->partition->highwatermark.tmp_highest_usn == c->partition->highwatermark.highest_usn) {
602                 return test_apply_schema(s, c);
603         }
604
605         return NT_STATUS_OK;
606 }
607
608 static NTSTATUS test_become_dc_store_chunk(void *private_data,
609                                            const struct libnet_BecomeDC_StoreChunk *c)
610 {
611         struct test_become_dc_state *s = talloc_get_type(private_data, struct test_become_dc_state);
612         WERROR status;
613         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
614         uint32_t total_object_count;
615         uint32_t object_count;
616         struct drsuapi_DsReplicaObjectListItemEx *first_object;
617         struct drsuapi_DsReplicaObjectListItemEx *cur;
618         uint32_t linked_attributes_count;
619         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
620         uint32_t i;
621         int ret;
622
623         switch (c->ctr_level) {
624         case 1:
625                 mapping_ctr             = &c->ctr1->mapping_ctr;
626                 total_object_count      = c->ctr1->total_object_count;
627                 object_count            = c->ctr1->object_count;
628                 first_object            = c->ctr1->first_object;
629                 linked_attributes_count = 0;
630                 linked_attributes       = NULL;
631                 break;
632         case 6:
633                 mapping_ctr             = &c->ctr6->mapping_ctr;
634                 total_object_count      = c->ctr6->total_object_count;
635                 object_count            = c->ctr6->object_count;
636                 first_object            = c->ctr6->first_object;
637                 linked_attributes_count = c->ctr6->linked_attributes_count;
638                 linked_attributes       = c->ctr6->linked_attributes;
639                 break;
640         default:
641                 return NT_STATUS_INVALID_PARAMETER;
642         }
643
644         if (total_object_count) {
645                 DEBUG(0,("Partition[%s] objects[%u/%u]\n",
646                         c->partition->nc.dn, object_count, total_object_count));
647         } else {
648                 DEBUG(0,("Partition[%s] objects[%u]\n",
649                 c->partition->nc.dn, object_count));
650         }
651
652         status = dsdb_verify_oid_mappings(s->schema, mapping_ctr);
653         if (!W_ERROR_IS_OK(status)) {
654                 return werror_to_ntstatus(status);
655         }
656
657         for (cur = first_object; cur; cur = cur->next_object) {
658                 struct ldb_message *msg;
659                 status = test_object_to_ldb(s, c, cur, s, &msg);
660                 if (!W_ERROR_IS_OK(status)) {
661                         return werror_to_ntstatus(status);
662                 }
663         }
664
665         for (i=0; i < linked_attributes_count; i++) {
666                 const struct dsdb_attribute *sa;
667
668                 if (!linked_attributes[i].identifier) {
669                         return NT_STATUS_FOOBAR;                
670                 }
671
672                 if (!linked_attributes[i].value.blob) {
673                         return NT_STATUS_FOOBAR;                
674                 }
675
676                 sa = dsdb_attribute_by_attributeID_id(s->schema,
677                                                       linked_attributes[i].attid);
678                 if (!sa) {
679                         return NT_STATUS_FOOBAR;
680                 }
681
682                 if (lp_parm_bool(-1, "become dc", "dump objects", False)) {
683                         DEBUG(0,("# %s\n", sa->lDAPDisplayName));
684                         NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, &linked_attributes[i]);
685                         dump_data(0,
686                                 linked_attributes[i].value.blob->data,
687                                 linked_attributes[i].value.blob->length);
688                 }
689         }
690
691         ret = ldb_transaction_commit(s->ldb);
692         if (ret != LDB_SUCCESS) {
693                 DEBUG(0,("Failed to commit the changes: %d\n", ret));
694                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
695         }
696
697         ret = ldb_transaction_start(s->ldb);
698         if (ret != LDB_SUCCESS) {
699                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
700         }
701
702         return NT_STATUS_OK;
703 }
704
705 BOOL torture_net_become_dc(struct torture_context *torture)
706 {
707         BOOL ret = True;
708         NTSTATUS status;
709         struct libnet_BecomeDC b;
710         struct libnet_UnbecomeDC u;
711         struct test_become_dc_state *s;
712
713         s = talloc_zero(torture, struct test_become_dc_state);
714         if (!s) return False;
715
716         /* Join domain as a member server. */
717         s->tj = torture_join_domain(TORTURE_NETBIOS_NAME,
718                                  ACB_WSTRUST,
719                                  &s->machine_account);
720         if (!s->tj) {
721                 DEBUG(0, ("%s failed to join domain as workstation\n",
722                           TORTURE_NETBIOS_NAME));
723                 return False;
724         }
725
726         s->ctx = libnet_context_init(event_context_init(s));
727         s->ctx->cred = cmdline_credentials;
728
729         s->ldb = ldb_init(s);
730
731         ZERO_STRUCT(b);
732         b.in.domain_dns_name            = torture_join_dom_dns_name(s->tj);
733         b.in.domain_netbios_name        = torture_join_dom_netbios_name(s->tj);
734         b.in.domain_sid                 = torture_join_sid(s->tj);
735         b.in.source_dsa_address         = lp_parm_string(-1, "torture", "host");
736         b.in.dest_dsa_netbios_name      = TORTURE_NETBIOS_NAME;
737
738         b.in.callbacks.private_data     = s;
739         b.in.callbacks.check_options    = test_become_dc_check_options;
740         b.in.callbacks.prepare_db       = test_become_dc_prepare_db;
741         b.in.callbacks.schema_chunk     = test_become_dc_schema_chunk;
742         b.in.callbacks.config_chunk     = test_become_dc_store_chunk;
743         b.in.callbacks.domain_chunk     = test_become_dc_store_chunk;
744
745         status = libnet_BecomeDC(s->ctx, s, &b);
746         if (!NT_STATUS_IS_OK(status)) {
747                 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
748                 ret = False;
749         }
750
751         ZERO_STRUCT(u);
752         u.in.domain_dns_name            = torture_join_dom_dns_name(s->tj);
753         u.in.domain_netbios_name        = torture_join_dom_netbios_name(s->tj);
754         u.in.source_dsa_address         = lp_parm_string(-1, "torture", "host");
755         u.in.dest_dsa_netbios_name      = TORTURE_NETBIOS_NAME;
756
757         status = libnet_UnbecomeDC(s->ctx, s, &u);
758         if (!NT_STATUS_IS_OK(status)) {
759                 printf("libnet_UnbecomeDC() failed - %s\n", nt_errstr(status));
760                 ret = False;
761         }
762
763         /* Leave domain. */                          
764         torture_leave_domain(s->tj);
765
766         talloc_free(s);
767         return ret;
768 }