r20483: Sorry Volker:-)
[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
32 #define TORTURE_NETBIOS_NAME "smbtorturedc"
33
34 struct test_become_dc_state {
35         struct libnet_context *ctx;
36         struct test_join *tj;
37         struct cli_credentials *machine_account;
38         struct dsdb_schema *schema;
39
40         struct ldb_context *ldb;
41
42         struct {
43                 struct drsuapi_DsReplicaObjectListItemEx *first_object;
44                 struct drsuapi_DsReplicaObjectListItemEx *last_object;
45         } schema_part;
46 };
47
48 static NTSTATUS test_become_dc_check_options(void *private_data,
49                                              const struct libnet_BecomeDC_CheckOptions *o)
50 {
51         DEBUG(0,("Become DC of Domain[%s]/[%s]\n",
52                 o->domain->netbios_name, o->domain->dns_name));
53
54         DEBUG(0,("Promotion Partner is Server[%s] from Site[%s]\n",
55                 o->source_dsa->dns_name, o->source_dsa->site_name));
56
57         DEBUG(0,("Options:crossRef behavior_version[%u]\n"
58                        "\tschema object_version[%u]\n"
59                        "\tdomain behavior_version[%u]\n"
60                        "\tdomain w2k3_update_revision[%u]\n", 
61                 o->forest->crossref_behavior_version,
62                 o->forest->schema_object_version,
63                 o->domain->behavior_version,
64                 o->domain->w2k3_update_revision));
65
66         return NT_STATUS_OK;
67 }
68
69 static NTSTATUS test_become_dc_prepare_db(void *private_data,
70                                           const struct libnet_BecomeDC_PrepareDB *p)
71 {
72         struct test_become_dc_state *s = talloc_get_type(private_data, struct test_become_dc_state);
73
74         DEBUG(0,("New Server[%s] in Site[%s]\n",
75                 p->dest_dsa->dns_name, p->dest_dsa->site_name));
76
77         DEBUG(0,("DSA Instance [%s]\n"
78                 "\tobjectGUID[%s]\n"
79                 "\tinvocationId[%s]\n",
80                 p->dest_dsa->ntds_dn_str,
81                 GUID_string(s, &p->dest_dsa->ntds_guid),
82                 GUID_string(s, &p->dest_dsa->invocation_id)));
83
84         DEBUG(0,("Schema Partition[%s]\n",
85                 p->forest->schema_dn_str));
86
87         DEBUG(0,("Config Partition[%s]\n",
88                 p->forest->config_dn_str));
89
90         DEBUG(0,("Domain Partition[%s]\n",
91                 p->domain->dn_str));
92
93         return NT_STATUS_OK;
94 }
95
96 static WERROR test_object_to_ldb(struct test_become_dc_state *s,
97                                  const struct libnet_BecomeDC_StoreChunk *c,
98                                  struct drsuapi_DsReplicaObjectListItemEx *obj,
99                                  TALLOC_CTX *mem_ctx,
100                                  struct ldb_message **_msg)
101 {
102         WERROR status;
103         uint32_t i;
104         struct ldb_message *msg;
105
106         msg = ldb_msg_new(mem_ctx);
107         W_ERROR_HAVE_NO_MEMORY(msg);
108
109         msg->dn                 = ldb_dn_new(msg, s->ldb, obj->object.identifier->dn);
110         W_ERROR_HAVE_NO_MEMORY(msg->dn);
111
112         msg->num_elements       = obj->object.attribute_ctr.num_attributes;
113         msg->elements           = talloc_array(msg, struct ldb_message_element,
114                                                msg->num_elements);
115         W_ERROR_HAVE_NO_MEMORY(msg->elements);
116
117         for (i=0; i < msg->num_elements; i++) {
118                 status = dsdb_attribute_drsuapi_to_ldb(s->schema,
119                                                        &obj->object.attribute_ctr.attributes[i],
120                                                        msg->elements, &msg->elements[i]);
121                 W_ERROR_NOT_OK_RETURN(status);
122         }
123
124         if (lp_parm_bool(-1, "become dc", "dump objects", False)) {
125                 struct ldb_ldif ldif;
126                 fprintf(stdout, "#\n");
127                 ldif.changetype = LDB_CHANGETYPE_NONE;
128                 ldif.msg = msg;
129                 ldb_ldif_write_file(s->ldb, stdout, &ldif);
130         }
131
132         *_msg = msg;
133         return WERR_OK;
134 }
135
136 static NTSTATUS test_apply_schema(struct test_become_dc_state *s,
137                                   const struct libnet_BecomeDC_StoreChunk *c)
138 {
139         WERROR status;
140         struct drsuapi_DsReplicaObjectListItemEx *cur;
141
142         for (cur = s->schema_part.first_object; cur; cur = cur->next_object) {
143                 uint32_t i;
144                 bool is_attr = false;
145                 bool is_class = false;
146
147                 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
148                         struct drsuapi_DsReplicaAttribute *a;
149                         uint32_t j;
150                         const char *oid = NULL;
151
152                         a = &cur->object.attribute_ctr.attributes[i];
153                         status = dsdb_map_int2oid(s->schema, a->attid, s, &oid);
154                         if (!W_ERROR_IS_OK(status)) {
155                                 return werror_to_ntstatus(status);
156                         }
157
158                         switch (a->attid) {
159                         case DRSUAPI_ATTRIBUTE_objectClass:
160                                 for (j=0; j < a->value_ctr.data_blob.num_values; j++) {
161                                         uint32_t val = 0xFFFFFFFF;
162
163                                         if (a->value_ctr.data_blob.values[i].data
164                                             && a->value_ctr.data_blob.values[i].data->length == 4) {
165                                                 val = IVAL(a->value_ctr.data_blob.values[i].data->data,0);
166                                         }
167
168                                         if (val == DRSUAPI_OBJECTCLASS_attributeSchema) {
169                                                 is_attr = true;
170                                         }
171                                         if (val == DRSUAPI_OBJECTCLASS_classSchema) {
172                                                 is_class = true;
173                                         }
174                                 }
175
176                                 break;
177                         default:
178                                 break;
179                         }
180                 }
181
182                 if (is_attr) {
183                         struct dsdb_attribute *sa;
184
185                         sa = talloc_zero(s->schema, struct dsdb_attribute);
186                         NT_STATUS_HAVE_NO_MEMORY(sa);
187
188                         status = dsdb_attribute_from_drsuapi(s->schema, &cur->object, s, sa);
189                         if (!W_ERROR_IS_OK(status)) {
190                                 return werror_to_ntstatus(status);
191                         }
192
193                         DLIST_ADD_END(s->schema->attributes, sa, struct dsdb_attribute *);
194                 }
195
196                 if (is_class) {
197                         struct dsdb_class *sc;
198
199                         sc = talloc_zero(s->schema, struct dsdb_class);
200                         NT_STATUS_HAVE_NO_MEMORY(sc);
201
202                         status = dsdb_class_from_drsuapi(s->schema, &cur->object, s, sc);
203                         if (!W_ERROR_IS_OK(status)) {
204                                 return werror_to_ntstatus(status);
205                         }
206
207                         DLIST_ADD_END(s->schema->classes, sc, struct dsdb_class *);
208                 }
209         }
210
211         for (cur = s->schema_part.first_object; cur; cur = cur->next_object) {
212                 struct ldb_message *msg;
213                 status = test_object_to_ldb(s, c, cur, s, &msg);
214                 if (!W_ERROR_IS_OK(status)) {
215                         return werror_to_ntstatus(status);
216                 }
217         }
218
219         return NT_STATUS_OK;
220 }
221
222 static NTSTATUS test_become_dc_schema_chunk(void *private_data,
223                                             const struct libnet_BecomeDC_StoreChunk *c)
224 {
225         struct test_become_dc_state *s = talloc_get_type(private_data, struct test_become_dc_state);
226         WERROR status;
227         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
228         uint32_t total_object_count;
229         uint32_t object_count;
230         struct drsuapi_DsReplicaObjectListItemEx *first_object;
231         struct drsuapi_DsReplicaObjectListItemEx *cur;
232
233         switch (c->ctr_level) {
234         case 1:
235                 mapping_ctr             = &c->ctr1->mapping_ctr;
236                 total_object_count      = c->ctr1->total_object_count;
237                 object_count            = c->ctr1->object_count;
238                 first_object            = c->ctr1->first_object;
239                 break;
240         case 6:
241                 mapping_ctr             = &c->ctr6->mapping_ctr;
242                 total_object_count      = c->ctr6->total_object_count;
243                 object_count            = c->ctr6->object_count;
244                 first_object            = c->ctr6->first_object;
245                 break;
246         default:
247                 return NT_STATUS_INVALID_PARAMETER;
248         }
249
250         if (total_object_count) {
251                 DEBUG(0,("Schema-DN[%s] objects[%u/%u]\n",
252                         c->partition->nc.dn, object_count, total_object_count));
253         } else {
254                 DEBUG(0,("Schema-DN[%s] objects[%u]\n",
255                 c->partition->nc.dn, object_count));
256         }
257
258         if (!s->schema) {
259                 s->schema = talloc_zero(s, struct dsdb_schema);
260                 NT_STATUS_HAVE_NO_MEMORY(s->schema);
261
262                 status = dsdb_load_oid_mappings(s->schema, mapping_ctr);
263                 if (!W_ERROR_IS_OK(status)) {
264                         return werror_to_ntstatus(status);
265                 }
266         } else {
267                 status = dsdb_verify_oid_mappings(s->schema, mapping_ctr);
268                 if (!W_ERROR_IS_OK(status)) {
269                         return werror_to_ntstatus(status);
270                 }
271         }
272
273         if (!s->schema_part.first_object) {
274                 s->schema_part.first_object = talloc_steal(s, first_object);
275         } else {
276                 s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
277                                                                        first_object);
278         }
279         for (cur = first_object; cur->next_object; cur = cur->next_object) {}
280         s->schema_part.last_object = cur;
281
282         if (c->partition->highwatermark.tmp_highest_usn == c->partition->highwatermark.highest_usn) {
283                 return test_apply_schema(s, c);
284         }
285
286         return NT_STATUS_OK;
287 }
288
289 static NTSTATUS test_become_dc_store_chunk(void *private_data,
290                                            const struct libnet_BecomeDC_StoreChunk *c)
291 {
292         struct test_become_dc_state *s = talloc_get_type(private_data, struct test_become_dc_state);
293         WERROR status;
294         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
295         uint32_t total_object_count;
296         uint32_t object_count;
297         struct drsuapi_DsReplicaObjectListItemEx *first_object;
298         struct drsuapi_DsReplicaObjectListItemEx *cur;
299
300         switch (c->ctr_level) {
301         case 1:
302                 mapping_ctr             = &c->ctr1->mapping_ctr;
303                 total_object_count      = c->ctr1->total_object_count;
304                 object_count            = c->ctr1->object_count;
305                 first_object            = c->ctr1->first_object;
306                 break;
307         case 6:
308                 mapping_ctr             = &c->ctr6->mapping_ctr;
309                 total_object_count      = c->ctr6->total_object_count;
310                 object_count            = c->ctr6->object_count;
311                 first_object            = c->ctr6->first_object;
312                 break;
313         default:
314                 return NT_STATUS_INVALID_PARAMETER;
315         }
316
317         if (total_object_count) {
318                 DEBUG(0,("Partition[%s] objects[%u/%u]\n",
319                         c->partition->nc.dn, object_count, total_object_count));
320         } else {
321                 DEBUG(0,("Partition[%s] objects[%u]\n",
322                 c->partition->nc.dn, object_count));
323         }
324
325         status = dsdb_verify_oid_mappings(s->schema, mapping_ctr);
326         if (!W_ERROR_IS_OK(status)) {
327                 return werror_to_ntstatus(status);
328         }
329
330         for (cur = first_object; cur; cur = cur->next_object) {
331                 struct ldb_message *msg;
332                 status = test_object_to_ldb(s, c, cur, s, &msg);
333                 if (!W_ERROR_IS_OK(status)) {
334                         return werror_to_ntstatus(status);
335                 }
336         }
337
338         return NT_STATUS_OK;
339 }
340
341 BOOL torture_net_become_dc(struct torture_context *torture)
342 {
343         BOOL ret = True;
344         NTSTATUS status;
345         struct libnet_BecomeDC b;
346         struct libnet_UnbecomeDC u;
347         struct test_become_dc_state *s;
348
349         s = talloc_zero(torture, struct test_become_dc_state);
350         if (!s) return False;
351
352         /* Join domain as a member server. */
353         s->tj = torture_join_domain(TORTURE_NETBIOS_NAME,
354                                  ACB_WSTRUST,
355                                  &s->machine_account);
356         if (!s->tj) {
357                 DEBUG(0, ("%s failed to join domain as workstation\n",
358                           TORTURE_NETBIOS_NAME));
359                 return False;
360         }
361
362         s->ctx = libnet_context_init(event_context_init(s));
363         s->ctx->cred = cmdline_credentials;
364
365         s->ldb = ldb_init(s);
366
367         ZERO_STRUCT(b);
368         b.in.domain_dns_name            = torture_join_dom_dns_name(s->tj);
369         b.in.domain_netbios_name        = torture_join_dom_netbios_name(s->tj);
370         b.in.domain_sid                 = torture_join_sid(s->tj);
371         b.in.source_dsa_address         = lp_parm_string(-1, "torture", "host");
372         b.in.dest_dsa_netbios_name      = TORTURE_NETBIOS_NAME;
373
374         b.in.callbacks.private_data     = s;
375         b.in.callbacks.check_options    = test_become_dc_check_options;
376         b.in.callbacks.prepare_db       = test_become_dc_prepare_db;
377         b.in.callbacks.schema_chunk     = test_become_dc_schema_chunk;
378         b.in.callbacks.config_chunk     = test_become_dc_store_chunk;
379         b.in.callbacks.domain_chunk     = test_become_dc_store_chunk;
380
381         status = libnet_BecomeDC(s->ctx, s, &b);
382         if (!NT_STATUS_IS_OK(status)) {
383                 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
384                 ret = False;
385         }
386
387         ZERO_STRUCT(u);
388         u.in.domain_dns_name            = torture_join_dom_dns_name(s->tj);
389         u.in.domain_netbios_name        = torture_join_dom_netbios_name(s->tj);
390         u.in.source_dsa_address         = lp_parm_string(-1, "torture", "host");
391         u.in.dest_dsa_netbios_name      = TORTURE_NETBIOS_NAME;
392
393         status = libnet_UnbecomeDC(s->ctx, s, &u);
394         if (!NT_STATUS_IS_OK(status)) {
395                 printf("libnet_UnbecomeDC() failed - %s\n", nt_errstr(status));
396                 ret = False;
397         }
398
399         /* Leave domain. */                          
400         torture_leave_domain(s->tj);
401
402         talloc_free(s);
403         return ret;
404 }