r20380: verify the incoming schema info and oid mappings
[gd/samba-autobuild/.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
31 #define TORTURE_NETBIOS_NAME "smbtorturedc"
32
33 struct test_become_dc_state {
34         struct libnet_context *ctx;
35         struct test_join *tj;
36         struct cli_credentials *machine_account;
37         struct dsdb_schema *schema;
38 };
39
40 static NTSTATUS test_become_dc_check_options(void *private_data,
41                                              const struct libnet_BecomeDC_CheckOptions *o)
42 {
43         DEBUG(0,("Become DC of Domain[%s]/[%s]\n",
44                 o->domain->netbios_name, o->domain->dns_name));
45
46         DEBUG(0,("Promotion Partner is Server[%s] from Site[%s]\n",
47                 o->source_dsa->dns_name, o->source_dsa->site_name));
48
49         DEBUG(0,("Options:crossRef behavior_version[%u]\n"
50                        "\tschema object_version[%u]\n"
51                        "\tdomain behavior_version[%u]\n"
52                        "\tdomain w2k3_update_revision[%u]\n", 
53                 o->forest->crossref_behavior_version,
54                 o->forest->schema_object_version,
55                 o->domain->behavior_version,
56                 o->domain->w2k3_update_revision));
57
58         return NT_STATUS_OK;
59 }
60
61 static NTSTATUS test_become_dc_prepare_db(void *private_data,
62                                           const struct libnet_BecomeDC_PrepareDB *p)
63 {
64         struct test_become_dc_state *s = talloc_get_type(private_data, struct test_become_dc_state);
65
66         DEBUG(0,("New Server[%s] in Site[%s]\n",
67                 p->dest_dsa->dns_name, p->dest_dsa->site_name));
68
69         DEBUG(0,("DSA Instance [%s]\n"
70                 "\tobjectGUID[%s]\n"
71                 "\tinvocationId[%s]\n",
72                 p->dest_dsa->ntds_dn_str,
73                 GUID_string(s, &p->dest_dsa->ntds_guid),
74                 GUID_string(s, &p->dest_dsa->invocation_id)));
75
76         DEBUG(0,("Schema Partition[%s]\n",
77                 p->forest->schema_dn_str));
78
79         DEBUG(0,("Config Partition[%s]\n",
80                 p->forest->config_dn_str));
81
82         DEBUG(0,("Domain Partition[%s]\n",
83                 p->domain->dn_str));
84
85         return NT_STATUS_OK;
86 }
87
88 static NTSTATUS test_become_dc_schema_chunk(void *private_data,
89                                             const struct libnet_BecomeDC_StoreChunk *c)
90 {
91         struct test_become_dc_state *s = talloc_get_type(private_data, struct test_become_dc_state);
92         WERROR status;
93         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
94         uint32_t total_object_count;
95         uint32_t object_count;
96         struct drsuapi_DsReplicaObjectListItemEx *first_object;
97         struct drsuapi_DsReplicaObjectListItemEx *cur;
98
99         switch (c->ctr_level) {
100         case 1:
101                 mapping_ctr             = &c->ctr1->mapping_ctr;
102                 total_object_count      = c->ctr1->total_object_count;
103                 object_count            = c->ctr1->object_count;
104                 first_object            = c->ctr1->first_object;
105                 break;
106         case 6:
107                 mapping_ctr             = &c->ctr6->mapping_ctr;
108                 total_object_count      = c->ctr6->total_object_count;
109                 object_count            = c->ctr6->object_count;
110                 first_object            = c->ctr6->first_object;
111                 break;
112         default:
113                 return NT_STATUS_INVALID_PARAMETER;
114         }
115
116         if (total_object_count) {
117                 DEBUG(0,("Schema-DN[%s] objects[%u/%u]\n",
118                         c->partition->nc.dn, object_count, total_object_count));
119         } else {
120                 DEBUG(0,("Schema-DN[%s] objects[%u]\n",
121                 c->partition->nc.dn, object_count));
122         }
123
124         if (!s->schema) {
125                 s->schema = talloc_zero(s, struct dsdb_schema);
126                 NT_STATUS_HAVE_NO_MEMORY(s->schema);
127
128                 status = dsdb_load_oid_mappings(s->schema, mapping_ctr);
129                 if (!W_ERROR_IS_OK(status)) {
130                         return werror_to_ntstatus(status);
131                 }
132         } else {
133                 status = dsdb_verify_oid_mappings(s->schema, mapping_ctr);
134                 if (!W_ERROR_IS_OK(status)) {
135                         return werror_to_ntstatus(status);
136                 }
137         }
138
139         for (cur = first_object; cur; cur = cur->next_object) {
140                 uint32_t i;
141                 bool dn_printed = false;
142                 bool is_attr = false;
143                 bool is_class = false;
144
145                 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
146                         struct drsuapi_DsReplicaAttribute *a;
147                         uint32_t j;
148                         const char *oid = NULL;
149
150                         a = &cur->object.attribute_ctr.attributes[i];
151                         status = dsdb_map_int2oid(s->schema, a->attid, s, &oid);
152                         if (!W_ERROR_IS_OK(status)) {
153                                 if (!dn_printed) {
154                                         DEBUG(0,("%s:\n", cur->object.identifier->dn));
155                                         dn_printed = true;
156                                 }
157                                 DEBUG(0,("\tattr 0x%08X => %s\n", a->attid, win_errstr(status)));
158                         }
159
160                         switch (a->attid) {
161                         case DRSUAPI_ATTRIBUTE_objectClass:
162                         case DRSUAPI_ATTRIBUTE_attributeID:
163                         case DRSUAPI_ATTRIBUTE_attributeSyntax:
164                                 for (j=0; j < a->value_ctr.uint32.num_values; j++) {
165                                         uint32_t val = *a->value_ctr.uint32.values[j].value;
166
167                                         if (val == DRSUAPI_OBJECTCLASS_attributeSchema) {
168                                                 is_attr = true;
169                                         }
170                                         if (val == DRSUAPI_OBJECTCLASS_classSchema) {
171                                                 is_class = true;
172                                         }
173
174                                         status = dsdb_map_int2oid(s->schema, val, s, &oid);
175                                         if (!W_ERROR_IS_OK(status)) {
176                                                 if (!dn_printed) {
177                                                         DEBUG(0,("%s:\n", cur->object.identifier->dn));
178                                                         dn_printed = true;
179                                                 }
180                                                 DEBUG(0,("\tattr 0x%08X => %s value[%u] 0x%08X => %s\n",
181                                                          a->attid, oid, j, val, win_errstr(status)));
182                                         }
183                                 }
184                                 break;
185                         default:
186                                 break;
187                         }
188                 }
189
190                 if (is_attr) {
191                         struct dsdb_attribute sa;
192                         status = dsdb_attribute_from_drsuapi(s->schema, &cur->object, s, &sa);
193                         if (!W_ERROR_IS_OK(status)) {
194                                 return werror_to_ntstatus(status);
195                         }
196                 }
197
198                 if (is_class) {
199                         struct dsdb_class sc;
200                         status = dsdb_class_from_drsuapi(s->schema, &cur->object, s, &sc);
201                         if (!W_ERROR_IS_OK(status)) {
202                                 return werror_to_ntstatus(status);
203                         }
204                 }
205         }
206
207         return NT_STATUS_OK;
208 }
209
210 static NTSTATUS test_become_dc_store_chunk(void *private_data,
211                                            const struct libnet_BecomeDC_StoreChunk *c)
212 {
213         uint32_t total_object_count;
214         uint32_t object_count;
215
216         switch (c->ctr_level) {
217         case 1:
218                 total_object_count      = c->ctr1->total_object_count;
219                 object_count            = c->ctr1->object_count;
220                 break;
221         case 6:
222                 total_object_count      = c->ctr6->total_object_count;
223                 object_count            = c->ctr6->object_count;
224                 break;
225         default:
226                 return NT_STATUS_INVALID_PARAMETER;
227         }
228
229         if (total_object_count) {
230                 DEBUG(0,("Partition[%s] objects[%u/%u]\n",
231                         c->partition->nc.dn, object_count, total_object_count));
232         } else {
233                 DEBUG(0,("Partition[%s] objects[%u]\n",
234                 c->partition->nc.dn, object_count));
235         }
236
237         return NT_STATUS_OK;
238 }
239
240 BOOL torture_net_become_dc(struct torture_context *torture)
241 {
242         BOOL ret = True;
243         NTSTATUS status;
244         struct libnet_BecomeDC b;
245         struct libnet_UnbecomeDC u;
246         struct test_become_dc_state *s;
247
248         s = talloc_zero(torture, struct test_become_dc_state);
249         if (!s) return False;
250
251         /* Join domain as a member server. */
252         s->tj = torture_join_domain(TORTURE_NETBIOS_NAME,
253                                  ACB_WSTRUST,
254                                  &s->machine_account);
255         if (!s->tj) {
256                 DEBUG(0, ("%s failed to join domain as workstation\n",
257                           TORTURE_NETBIOS_NAME));
258                 return False;
259         }
260
261         s->ctx = libnet_context_init(event_context_init(s));
262         s->ctx->cred = cmdline_credentials;
263
264         ZERO_STRUCT(b);
265         b.in.domain_dns_name            = torture_join_dom_dns_name(s->tj);
266         b.in.domain_netbios_name        = torture_join_dom_netbios_name(s->tj);
267         b.in.domain_sid                 = torture_join_sid(s->tj);
268         b.in.source_dsa_address         = lp_parm_string(-1, "torture", "host");
269         b.in.dest_dsa_netbios_name      = TORTURE_NETBIOS_NAME;
270
271         b.in.callbacks.private_data     = s;
272         b.in.callbacks.check_options    = test_become_dc_check_options;
273         b.in.callbacks.prepare_db       = test_become_dc_prepare_db;
274         b.in.callbacks.schema_chunk     = test_become_dc_schema_chunk;
275         b.in.callbacks.config_chunk     = test_become_dc_store_chunk;
276         b.in.callbacks.domain_chunk     = test_become_dc_store_chunk;
277
278         status = libnet_BecomeDC(s->ctx, s, &b);
279         if (!NT_STATUS_IS_OK(status)) {
280                 printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
281                 ret = False;
282         }
283
284         ZERO_STRUCT(u);
285         u.in.domain_dns_name            = torture_join_dom_dns_name(s->tj);
286         u.in.domain_netbios_name        = torture_join_dom_netbios_name(s->tj);
287         u.in.source_dsa_address         = lp_parm_string(-1, "torture", "host");
288         u.in.dest_dsa_netbios_name      = TORTURE_NETBIOS_NAME;
289
290         status = libnet_UnbecomeDC(s->ctx, s, &u);
291         if (!NT_STATUS_IS_OK(status)) {
292                 printf("libnet_UnbecomeDC() failed - %s\n", nt_errstr(status));
293                 ret = False;
294         }
295
296         /* Leave domain. */                          
297         torture_leave_domain(s->tj);
298
299         talloc_free(s);
300         return ret;
301 }