Merge branch 'selftest' of git://git.samba.org/jelmer/samba
[kai/samba.git] / source4 / torture / basic / aliases.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB trans2 alias scanner
4    Copyright (C) Andrew Tridgell 2003
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "../lib/util/dlinklist.h"
22 #include "libcli/raw/libcliraw.h"
23 #include "libcli/raw/raw_proto.h"
24 #include "torture/torture.h"
25 #include "libcli/libcli.h"
26 #include "torture/util.h"
27
28 int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname);
29
30 struct trans2_blobs {
31         struct trans2_blobs *next, *prev;
32         uint16_t level;
33         DATA_BLOB params, data;
34 };
35
36 /* look for aliases for a query */
37 static bool gen_aliases(struct torture_context *tctx, 
38                                                 struct smbcli_state *cli, struct smb_trans2 *t2, 
39                                                 int level_offset)
40 {
41         uint16_t level;
42         struct trans2_blobs *alias_blobs = NULL;
43         struct trans2_blobs *t2b, *t2b2;
44         int count=0, alias_count=0;
45
46         for (level=0;level<2000;level++) {
47                 NTSTATUS status;
48
49                 SSVAL(t2->in.params.data, level_offset, level);
50                 
51                 status = smb_raw_trans2(cli->tree, tctx, t2);
52                 if (!NT_STATUS_IS_OK(status)) continue;
53
54                 t2b = talloc(tctx, struct trans2_blobs);
55                 t2b->level = level;
56                 t2b->params = t2->out.params;
57                 t2b->data = t2->out.data;
58                 DLIST_ADD(alias_blobs, t2b);
59                 torture_comment(tctx, 
60                                                 "\tFound level %4u (0x%03x) of size %3d (0x%02x)\n", 
61                          level, level,
62                          (int)t2b->data.length, (int)t2b->data.length);
63                 count++;
64         }
65
66         torture_comment(tctx, "Found %d levels with success status\n", count);
67
68         for (t2b=alias_blobs; t2b; t2b=t2b->next) {
69                 for (t2b2=alias_blobs; t2b2; t2b2=t2b2->next) {
70                         if (t2b->level >= t2b2->level) continue;
71                         if (data_blob_cmp(&t2b->params, &t2b2->params) == 0 &&
72                             data_blob_cmp(&t2b->data, &t2b2->data) == 0) {
73                                 torture_comment(tctx, 
74                                 "\tLevel %u (0x%x) and level %u (0x%x) are possible aliases\n", 
75                                        t2b->level, t2b->level, t2b2->level, t2b2->level);
76                                 alias_count++;
77                         }
78                 }
79         }
80
81         torture_comment(tctx, "Found %d aliased levels\n", alias_count);
82
83         return true;
84 }
85
86 /* look for qfsinfo aliases */
87 static bool qfsinfo_aliases(struct torture_context *tctx, struct smbcli_state *cli)
88 {
89         struct smb_trans2 t2;
90         uint16_t setup = TRANSACT2_QFSINFO;
91
92         t2.in.max_param = 0;
93         t2.in.max_data = UINT16_MAX;
94         t2.in.max_setup = 0;
95         t2.in.flags = 0;
96         t2.in.timeout = 0;
97         t2.in.setup_count = 1;
98         t2.in.setup = &setup;
99         t2.in.params = data_blob_talloc_zero(tctx, 2);
100         t2.in.data = data_blob(NULL, 0);
101         ZERO_STRUCT(t2.out);
102
103         return gen_aliases(tctx, cli, &t2, 0);
104 }
105
106 /* look for qfileinfo aliases */
107 static bool qfileinfo_aliases(struct torture_context *tctx, struct smbcli_state *cli)
108 {
109         struct smb_trans2 t2;
110         uint16_t setup = TRANSACT2_QFILEINFO;
111         const char *fname = "\\qfileinfo_aliases.txt";
112         int fnum;
113
114         t2.in.max_param = 2;
115         t2.in.max_data = UINT16_MAX;
116         t2.in.max_setup = 0;
117         t2.in.flags = 0;
118         t2.in.timeout = 0;
119         t2.in.setup_count = 1;
120         t2.in.setup = &setup;
121         t2.in.params = data_blob_talloc_zero(tctx, 4);
122         t2.in.data = data_blob(NULL, 0);
123         ZERO_STRUCT(t2.out);
124
125         smbcli_unlink(cli->tree, fname);
126         fnum = create_complex_file(cli, cli, fname);
127         torture_assert(tctx, fnum != -1, talloc_asprintf(tctx, 
128                                         "open of %s failed (%s)", fname, 
129                                    smbcli_errstr(cli->tree)));
130
131         smbcli_write(cli->tree, fnum, 0, &t2, 0, sizeof(t2));
132
133         SSVAL(t2.in.params.data, 0, fnum);
134
135         if (!gen_aliases(tctx, cli, &t2, 2))
136                 return false;
137
138         smbcli_close(cli->tree, fnum);
139         smbcli_unlink(cli->tree, fname);
140
141         return true;
142 }
143
144
145 /* look for qpathinfo aliases */
146 static bool qpathinfo_aliases(struct torture_context *tctx, struct smbcli_state *cli)
147 {
148         struct smb_trans2 t2;
149         uint16_t setup = TRANSACT2_QPATHINFO;
150         const char *fname = "\\qpathinfo_aliases.txt";
151         int fnum;
152
153         t2.in.max_param = 2;
154         t2.in.max_data = UINT16_MAX;
155         t2.in.max_setup = 0;
156         t2.in.flags = 0;
157         t2.in.timeout = 0;
158         t2.in.setup_count = 1;
159         t2.in.setup = &setup;
160         t2.in.params = data_blob_talloc_zero(tctx, 6);
161         t2.in.data = data_blob(NULL, 0);
162         ZERO_STRUCT(t2.out);
163
164         smbcli_unlink(cli->tree, fname);
165         fnum = create_complex_file(cli, cli, fname);
166         torture_assert(tctx, fnum != -1, talloc_asprintf(tctx, 
167                                         "open of %s failed (%s)", fname, 
168                                    smbcli_errstr(cli->tree)));
169
170         smbcli_write(cli->tree, fnum, 0, &t2, 0, sizeof(t2));
171         smbcli_close(cli->tree, fnum);
172
173         SIVAL(t2.in.params.data, 2, 0);
174
175         smbcli_blob_append_string(cli->session, tctx, &t2.in.params, 
176                                fname, STR_TERMINATE);
177
178         if (!gen_aliases(tctx, cli, &t2, 0))
179                 return false;
180
181         smbcli_unlink(cli->tree, fname);
182
183         return true;
184 }
185
186
187 /* look for trans2 findfirst aliases */
188 static bool findfirst_aliases(struct torture_context *tctx, struct smbcli_state *cli)
189 {
190         struct smb_trans2 t2;
191         uint16_t setup = TRANSACT2_FINDFIRST;
192         const char *fname = "\\findfirst_aliases.txt";
193         int fnum;
194
195         t2.in.max_param = 16;
196         t2.in.max_data = UINT16_MAX;
197         t2.in.max_setup = 0;
198         t2.in.flags = 0;
199         t2.in.timeout = 0;
200         t2.in.setup_count = 1;
201         t2.in.setup = &setup;
202         t2.in.params = data_blob_talloc_zero(tctx, 12);
203         t2.in.data = data_blob(NULL, 0);
204         ZERO_STRUCT(t2.out);
205
206         smbcli_unlink(cli->tree, fname);
207         fnum = create_complex_file(cli, cli, fname);
208         torture_assert(tctx, fnum != -1, talloc_asprintf(tctx, 
209                                         "open of %s failed (%s)", fname, 
210                                    smbcli_errstr(cli->tree)));
211
212         smbcli_write(cli->tree, fnum, 0, &t2, 0, sizeof(t2));
213         smbcli_close(cli->tree, fnum);
214
215         SSVAL(t2.in.params.data, 0, 0);
216         SSVAL(t2.in.params.data, 2, 1);
217         SSVAL(t2.in.params.data, 4, FLAG_TRANS2_FIND_CLOSE);
218         SSVAL(t2.in.params.data, 6, 0);
219         SIVAL(t2.in.params.data, 8, 0);
220
221         smbcli_blob_append_string(cli->session, tctx, &t2.in.params, 
222                                fname, STR_TERMINATE);
223
224         if (!gen_aliases(tctx, cli, &t2, 6))
225                 return false;
226
227         smbcli_unlink(cli->tree, fname);
228
229         return true;
230 }
231
232
233
234 /* look for aliases for a set function */
235 static bool gen_set_aliases(struct torture_context *tctx, 
236                                                         struct smbcli_state *cli, 
237                                                         struct smb_trans2 *t2, int level_offset)
238 {
239         uint16_t level;
240         struct trans2_blobs *alias_blobs = NULL;
241         struct trans2_blobs *t2b;
242         int count=0, dsize;
243
244         for (level=1;level<1100;level++) {
245                 NTSTATUS status, status1;
246                 SSVAL(t2->in.params.data, level_offset, level);
247
248                 status1 = NT_STATUS_OK;
249
250                 for (dsize=2; dsize<1024; dsize += 2) {
251                         data_blob_free(&t2->in.data);
252                         t2->in.data = data_blob(NULL, dsize);
253                         data_blob_clear(&t2->in.data);
254                         status = smb_raw_trans2(cli->tree, tctx, t2);
255                         /* some error codes mean that this whole level doesn't exist */
256                         if (NT_STATUS_EQUAL(NT_STATUS_INVALID_LEVEL, status) ||
257                             NT_STATUS_EQUAL(NT_STATUS_INVALID_INFO_CLASS, status) ||
258                             NT_STATUS_EQUAL(NT_STATUS_NOT_SUPPORTED, status)) {
259                                 break;
260                         }
261                         if (NT_STATUS_IS_OK(status)) break;
262
263                         /* invalid parameter means that the level exists at this 
264                            size, but the contents are wrong (not surprising with
265                            all zeros!) */
266                         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) break;
267
268                         /* this is the usual code for 'wrong size' */
269                         if (NT_STATUS_EQUAL(status, NT_STATUS_INFO_LENGTH_MISMATCH)) {
270                                 continue;
271                         }
272
273                         if (!NT_STATUS_EQUAL(status, status1)) {
274                                 torture_comment(tctx, "level=%d size=%d %s\n", level, dsize, nt_errstr(status));
275                         }
276                         status1 = status;
277                 }
278
279                 if (!NT_STATUS_IS_OK(status) &&
280                     !NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) continue;
281
282                 t2b = talloc(tctx, struct trans2_blobs);
283                 t2b->level = level;
284                 t2b->params = t2->out.params;
285                 t2b->data = t2->out.data;
286                 DLIST_ADD(alias_blobs, t2b);
287                 torture_comment(tctx, 
288                                         "\tFound level %4u (0x%03x) of size %3d (0x%02x)\n", 
289                          level, level,
290                          (int)t2->in.data.length, (int)t2->in.data.length);
291                 count++;
292         }
293
294         torture_comment(tctx, "Found %d valid levels\n", count);
295
296         return true;
297 }
298
299
300
301 /* look for setfileinfo aliases */
302 static bool setfileinfo_aliases(struct torture_context *tctx, struct smbcli_state *cli)
303 {
304         struct smb_trans2 t2;
305         uint16_t setup = TRANSACT2_SETFILEINFO;
306         const char *fname = "\\setfileinfo_aliases.txt";
307         int fnum;
308
309         t2.in.max_param = 2;
310         t2.in.max_data = 0;
311         t2.in.max_setup = 0;
312         t2.in.flags = 0;
313         t2.in.timeout = 0;
314         t2.in.setup_count = 1;
315         t2.in.setup = &setup;
316         t2.in.params = data_blob_talloc_zero(tctx, 6);
317         t2.in.data = data_blob(NULL, 0);
318         ZERO_STRUCT(t2.out);
319
320         smbcli_unlink(cli->tree, fname);
321         fnum = create_complex_file(cli, cli, fname);
322         torture_assert(tctx, fnum != -1, talloc_asprintf(tctx, 
323                                    "open of %s failed (%s)", fname, 
324                                    smbcli_errstr(cli->tree)));
325
326         smbcli_write(cli->tree, fnum, 0, &t2, 0, sizeof(t2));
327
328         SSVAL(t2.in.params.data, 0, fnum);
329         SSVAL(t2.in.params.data, 4, 0);
330
331         gen_set_aliases(tctx, cli, &t2, 2);
332
333         smbcli_close(cli->tree, fnum);
334         smbcli_unlink(cli->tree, fname);
335
336         return true;
337 }
338
339 /* look for setpathinfo aliases */
340 static bool setpathinfo_aliases(struct torture_context *tctx, 
341                                                                 struct smbcli_state *cli)
342 {
343         struct smb_trans2 t2;
344         uint16_t setup = TRANSACT2_SETPATHINFO;
345         const char *fname = "\\setpathinfo_aliases.txt";
346         int fnum;
347
348         t2.in.max_param = 32;
349         t2.in.max_data = UINT16_MAX;
350         t2.in.max_setup = 0;
351         t2.in.flags = 0;
352         t2.in.timeout = 0;
353         t2.in.setup_count = 1;
354         t2.in.setup = &setup;
355         t2.in.params = data_blob_talloc_zero(tctx, 4);
356         t2.in.data = data_blob(NULL, 0);
357         ZERO_STRUCT(t2.out);
358
359         smbcli_unlink(cli->tree, fname);
360
361         fnum = create_complex_file(cli, cli, fname);
362         torture_assert(tctx, fnum != -1, talloc_asprintf(tctx, 
363                                         "open of %s failed (%s)", fname, 
364                                    smbcli_errstr(cli->tree)));
365
366         smbcli_write(cli->tree, fnum, 0, &t2, 0, sizeof(t2));
367         smbcli_close(cli->tree, fnum);
368
369         SSVAL(t2.in.params.data, 2, 0);
370
371         smbcli_blob_append_string(cli->session, tctx, &t2.in.params, 
372                                fname, STR_TERMINATE);
373
374         if (!gen_set_aliases(tctx, cli, &t2, 0))
375                 return false;
376
377         torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli->tree, fname),
378                 talloc_asprintf(tctx, "unlink: %s", smbcli_errstr(cli->tree)));
379
380         return true;
381 }
382
383
384 /* look for aliased info levels in trans2 calls */
385 struct torture_suite *torture_trans2_aliases(TALLOC_CTX *mem_ctx)
386 {
387         struct torture_suite *suite = torture_suite_create(mem_ctx, "ALIASES");
388
389         torture_suite_add_1smb_test(suite, "QFILEINFO aliases", qfsinfo_aliases);
390         torture_suite_add_1smb_test(suite, "QFSINFO aliases", qfileinfo_aliases);
391         torture_suite_add_1smb_test(suite, "QPATHINFO aliases", qpathinfo_aliases);
392         torture_suite_add_1smb_test(suite, "FINDFIRST aliases", findfirst_aliases);
393         torture_suite_add_1smb_test(suite, "setfileinfo_aliases", setfileinfo_aliases);
394         torture_suite_add_1smb_test(suite, "setpathinfo_aliases", setpathinfo_aliases);
395
396         return suite;
397 }