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