Get medieval on our ass about SMB1 file descriptors being 16 bits, not an int.
[sfrench/samba-autobuild/.git] / source3 / torture / scanner.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB torture tester - scanning functions
4    Copyright (C) Andrew Tridgell 2001
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
22 #define VERBOSE 0
23 #define OP_MIN 0
24 #define OP_MAX 20
25
26 #define DATA_SIZE 1024
27 #define PARAM_SIZE 1024
28
29 /****************************************************************************
30 look for a partial hit
31 ****************************************************************************/
32 static void trans2_check_hit(const char *format, int op, int level, NTSTATUS status)
33 {
34         if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_LEVEL) ||
35             NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ||
36             NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_SUPPORTED) ||
37             NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) ||
38             NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) {
39                 return;
40         }
41 #if VERBOSE
42         printf("possible %s hit op=%3d level=%5d status=%s\n",
43                format, op, level, nt_errstr(status));
44 #endif
45 }
46
47 /****************************************************************************
48 check for existance of a trans2 call
49 ****************************************************************************/
50 static NTSTATUS try_trans2(struct cli_state *cli, 
51                          int op,
52                          char *param, char *data,
53                          int param_len, int data_len,
54                          unsigned int *rparam_len, unsigned int *rdata_len)
55 {
56         uint16 setup = op;
57         char *rparam=NULL, *rdata=NULL;
58
59         if (!cli_send_trans(cli, SMBtrans2, 
60                             NULL,                           /* name */
61                             -1, 0,                          /* fid, flags */
62                             &setup, 1, 0,                   /* setup, length, max */
63                             param, param_len, 2,            /* param, length, max */
64                             data, data_len, cli->max_xmit   /* data, length, max */
65                            )) {
66                 return cli_nt_error(cli);
67         }
68
69         cli_receive_trans(cli, SMBtrans2,
70                            &rparam, rparam_len,
71                            &rdata, rdata_len);
72
73         SAFE_FREE(rdata);
74         SAFE_FREE(rparam);
75
76         return cli_nt_error(cli);
77 }
78
79
80 static NTSTATUS try_trans2_len(struct cli_state *cli, 
81                              const char *format,
82                              int op, int level,
83                              char *param, char *data,
84                              int param_len, int *data_len,
85                              unsigned int *rparam_len, unsigned int *rdata_len)
86 {
87         NTSTATUS ret=NT_STATUS_OK;
88
89         ret = try_trans2(cli, op, param, data, param_len,
90                          DATA_SIZE, rparam_len, rdata_len);
91 #if VERBOSE 
92         printf("op=%d level=%d ret=%s\n", op, level, nt_errstr(ret));
93 #endif
94         if (!NT_STATUS_IS_OK(ret)) return ret;
95
96         *data_len = 0;
97         while (*data_len < DATA_SIZE) {
98                 ret = try_trans2(cli, op, param, data, param_len,
99                                  *data_len, rparam_len, rdata_len);
100                 if (NT_STATUS_IS_OK(ret)) break;
101                 *data_len += 2;
102         }
103         if (NT_STATUS_IS_OK(ret)) {
104                 printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
105                        format, level, *data_len, *rparam_len, *rdata_len);
106         } else {
107                 trans2_check_hit(format, op, level, ret);
108         }
109         return ret;
110 }
111
112 /****************************************************************************
113 check for existance of a trans2 call
114 ****************************************************************************/
115 static bool scan_trans2(struct cli_state *cli, int op, int level, 
116                         int fnum, int dnum, const char *fname)
117 {
118         int data_len = 0;
119         int param_len = 0;
120         unsigned int rparam_len, rdata_len;
121         char param[PARAM_SIZE], data[DATA_SIZE];
122         NTSTATUS status;
123
124         memset(data, 0, sizeof(data));
125         data_len = 4;
126
127         /* try with a info level only */
128         param_len = 2;
129         SSVAL(param, 0, level);
130         status = try_trans2_len(cli, "void", op, level, param, data, param_len, &data_len, 
131                             &rparam_len, &rdata_len);
132         if (NT_STATUS_IS_OK(status)) return True;
133
134         /* try with a file descriptor */
135         param_len = 6;
136         SSVAL(param, 0, fnum);
137         SSVAL(param, 2, level);
138         SSVAL(param, 4, 0);
139         status = try_trans2_len(cli, "fnum", op, level, param, data, param_len, &data_len, 
140                                 &rparam_len, &rdata_len);
141         if (NT_STATUS_IS_OK(status)) return True;
142
143
144         /* try with a notify style */
145         param_len = 6;
146         SSVAL(param, 0, dnum);
147         SSVAL(param, 2, dnum);
148         SSVAL(param, 4, level);
149         status = try_trans2_len(cli, "notify", op, level, param, data, param_len, &data_len, 
150                                 &rparam_len, &rdata_len);
151         if (NT_STATUS_IS_OK(status)) return True;
152
153         /* try with a file name */
154         param_len = 6;
155         SSVAL(param, 0, level);
156         SSVAL(param, 2, 0);
157         SSVAL(param, 4, 0);
158         param_len += clistr_push(cli, &param[6], fname, -1, STR_TERMINATE);
159
160         status = try_trans2_len(cli, "fname", op, level, param, data, param_len, &data_len, 
161                                 &rparam_len, &rdata_len);
162         if (NT_STATUS_IS_OK(status)) return True;
163
164         /* try with a new file name */
165         param_len = 6;
166         SSVAL(param, 0, level);
167         SSVAL(param, 2, 0);
168         SSVAL(param, 4, 0);
169         param_len += clistr_push(cli, &param[6], "\\newfile.dat", -1, STR_TERMINATE);
170
171         status = try_trans2_len(cli, "newfile", op, level, param, data, param_len, &data_len, 
172                                 &rparam_len, &rdata_len);
173         cli_unlink(cli, "\\newfile.dat", aSYSTEM | aHIDDEN);
174         cli_rmdir(cli, "\\newfile.dat");
175         if (NT_STATUS_IS_OK(status)) return True;
176
177         /* try dfs style  */
178         cli_mkdir(cli, "\\testdir");
179         param_len = 2;
180         SSVAL(param, 0, level);
181         param_len += clistr_push(cli, &param[2], "\\testdir", -1, STR_TERMINATE);
182
183         status = try_trans2_len(cli, "dfs", op, level, param, data, param_len, &data_len, 
184                                 &rparam_len, &rdata_len);
185         cli_rmdir(cli, "\\testdir");
186         if (NT_STATUS_IS_OK(status)) return True;
187
188         return False;
189 }
190
191
192 bool torture_trans2_scan(int dummy)
193 {
194         static struct cli_state *cli;
195         int op, level;
196         const char *fname = "\\scanner.dat";
197         uint16_t fnum, dnum;
198
199         printf("starting trans2 scan test\n");
200
201         if (!torture_open_connection(&cli, 0)) {
202                 return False;
203         }
204
205         if (!NT_STATUS_IS_OK(cli_open(cli, fname, O_RDWR | O_CREAT | O_TRUNC, 
206                          DENY_NONE, &fnum))) {
207                 printf("open of %s failed\n", fname);
208                 return false;
209         }
210         if (!NT_STATUS_IS_OK(cli_open(cli, "\\", O_RDONLY, DENY_NONE, &dnum))) {
211                 printf("open of \\ failed\n");
212                 return false;
213         }
214
215         for (op=OP_MIN; op<=OP_MAX; op++) {
216                 printf("Scanning op=%d\n", op);
217                 for (level = 0; level <= 50; level++) {
218                         scan_trans2(cli, op, level, fnum, dnum, fname);
219                 }
220
221                 for (level = 0x100; level <= 0x130; level++) {
222                         scan_trans2(cli, op, level, fnum, dnum, fname);
223                 }
224
225                 for (level = 1000; level < 1050; level++) {
226                         scan_trans2(cli, op, level, fnum, dnum, fname);
227                 }
228         }
229
230         torture_close_connection(cli);
231
232         printf("trans2 scan finished\n");
233         return True;
234 }
235
236
237
238
239 /****************************************************************************
240 look for a partial hit
241 ****************************************************************************/
242 static void nttrans_check_hit(const char *format, int op, int level, NTSTATUS status)
243 {
244         if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_LEVEL) ||
245             NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ||
246             NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_SUPPORTED) ||
247             NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) ||
248             NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) {
249                 return;
250         }
251 #if VERBOSE
252                 printf("possible %s hit op=%3d level=%5d status=%s\n",
253                        format, op, level, nt_errstr(status));
254 #endif
255 }
256
257 /****************************************************************************
258 check for existance of a nttrans call
259 ****************************************************************************/
260 static NTSTATUS try_nttrans(struct cli_state *cli, 
261                          int op,
262                          char *param, char *data,
263                          int param_len, int data_len,
264                          unsigned int *rparam_len, unsigned int *rdata_len)
265 {
266         char *rparam=NULL, *rdata=NULL;
267
268         if (!cli_send_nt_trans(cli, op, 
269                                0,   
270                                NULL, 0, 0,
271                                param, param_len, 2,            /* param, length, max */
272                                data, data_len, cli->max_xmit   /* data, length, max */
273                            )) {
274                 return cli_nt_error(cli);
275         }
276
277         cli_receive_nt_trans(cli,
278                              &rparam, rparam_len,
279                              &rdata, rdata_len);
280
281         SAFE_FREE(rdata);
282         SAFE_FREE(rparam);
283
284         return cli_nt_error(cli);
285 }
286
287
288 static NTSTATUS try_nttrans_len(struct cli_state *cli, 
289                              const char *format,
290                              int op, int level,
291                              char *param, char *data,
292                              int param_len, int *data_len,
293                              unsigned int *rparam_len, unsigned int *rdata_len)
294 {
295         NTSTATUS ret=NT_STATUS_OK;
296
297         ret = try_nttrans(cli, op, param, data, param_len,
298                          DATA_SIZE, rparam_len, rdata_len);
299 #if VERBOSE 
300         printf("op=%d level=%d ret=%s\n", op, level, nt_errstr(ret));
301 #endif
302         if (!NT_STATUS_IS_OK(ret)) return ret;
303
304         *data_len = 0;
305         while (*data_len < DATA_SIZE) {
306                 ret = try_nttrans(cli, op, param, data, param_len,
307                                  *data_len, rparam_len, rdata_len);
308                 if (NT_STATUS_IS_OK(ret)) break;
309                 *data_len += 2;
310         }
311         if (NT_STATUS_IS_OK(ret)) {
312                 printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
313                        format, level, *data_len, *rparam_len, *rdata_len);
314         } else {
315                 nttrans_check_hit(format, op, level, ret);
316         }
317         return ret;
318 }
319
320 /****************************************************************************
321 check for existance of a nttrans call
322 ****************************************************************************/
323 static bool scan_nttrans(struct cli_state *cli, int op, int level, 
324                         int fnum, int dnum, const char *fname)
325 {
326         int data_len = 0;
327         int param_len = 0;
328         unsigned int rparam_len, rdata_len;
329         char param[PARAM_SIZE], data[DATA_SIZE];
330         NTSTATUS status;
331
332         memset(data, 0, sizeof(data));
333         data_len = 4;
334
335         /* try with a info level only */
336         param_len = 2;
337         SSVAL(param, 0, level);
338         status = try_nttrans_len(cli, "void", op, level, param, data, param_len, &data_len, 
339                             &rparam_len, &rdata_len);
340         if (NT_STATUS_IS_OK(status)) return True;
341
342         /* try with a file descriptor */
343         param_len = 6;
344         SSVAL(param, 0, fnum);
345         SSVAL(param, 2, level);
346         SSVAL(param, 4, 0);
347         status = try_nttrans_len(cli, "fnum", op, level, param, data, param_len, &data_len, 
348                                 &rparam_len, &rdata_len);
349         if (NT_STATUS_IS_OK(status)) return True;
350
351
352         /* try with a notify style */
353         param_len = 6;
354         SSVAL(param, 0, dnum);
355         SSVAL(param, 2, dnum);
356         SSVAL(param, 4, level);
357         status = try_nttrans_len(cli, "notify", op, level, param, data, param_len, &data_len, 
358                                 &rparam_len, &rdata_len);
359         if (NT_STATUS_IS_OK(status)) return True;
360
361         /* try with a file name */
362         param_len = 6;
363         SSVAL(param, 0, level);
364         SSVAL(param, 2, 0);
365         SSVAL(param, 4, 0);
366         param_len += clistr_push(cli, &param[6], fname, -1, STR_TERMINATE);
367
368         status = try_nttrans_len(cli, "fname", op, level, param, data, param_len, &data_len, 
369                                 &rparam_len, &rdata_len);
370         if (NT_STATUS_IS_OK(status)) return True;
371
372         /* try with a new file name */
373         param_len = 6;
374         SSVAL(param, 0, level);
375         SSVAL(param, 2, 0);
376         SSVAL(param, 4, 0);
377         param_len += clistr_push(cli, &param[6], "\\newfile.dat", -1, STR_TERMINATE);
378
379         status = try_nttrans_len(cli, "newfile", op, level, param, data, param_len, &data_len, 
380                                 &rparam_len, &rdata_len);
381         cli_unlink(cli, "\\newfile.dat", aSYSTEM | aHIDDEN);
382         cli_rmdir(cli, "\\newfile.dat");
383         if (NT_STATUS_IS_OK(status)) return True;
384
385         /* try dfs style  */
386         cli_mkdir(cli, "\\testdir");
387         param_len = 2;
388         SSVAL(param, 0, level);
389         param_len += clistr_push(cli, &param[2], "\\testdir", -1, STR_TERMINATE);
390
391         status = try_nttrans_len(cli, "dfs", op, level, param, data, param_len, &data_len, 
392                                 &rparam_len, &rdata_len);
393         cli_rmdir(cli, "\\testdir");
394         if (NT_STATUS_IS_OK(status)) return True;
395
396         return False;
397 }
398
399
400 bool torture_nttrans_scan(int dummy)
401 {
402         static struct cli_state *cli;
403         int op, level;
404         const char *fname = "\\scanner.dat";
405         uint16_t fnum, dnum;
406
407         printf("starting nttrans scan test\n");
408
409         if (!torture_open_connection(&cli, 0)) {
410                 return False;
411         }
412
413         cli_open(cli, fname, O_RDWR | O_CREAT | O_TRUNC, 
414                          DENY_NONE, &fnum);
415         cli_open(cli, "\\", O_RDONLY, DENY_NONE, &dnum);
416
417         for (op=OP_MIN; op<=OP_MAX; op++) {
418                 printf("Scanning op=%d\n", op);
419                 for (level = 0; level <= 50; level++) {
420                         scan_nttrans(cli, op, level, fnum, dnum, fname);
421                 }
422
423                 for (level = 0x100; level <= 0x130; level++) {
424                         scan_nttrans(cli, op, level, fnum, dnum, fname);
425                 }
426
427                 for (level = 1000; level < 1050; level++) {
428                         scan_nttrans(cli, op, level, fnum, dnum, fname);
429                 }
430         }
431
432         torture_close_connection(cli);
433
434         printf("nttrans scan finished\n");
435         return True;
436 }