r13170: Remove some dependencies on -1 implying the size of pstring
[ira/wip.git] / source / torture / basic / 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 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "torture/torture.h"
23 #include "libcli/libcli.h"
24 #include "libcli/raw/libcliraw.h"
25 #include "system/filesys.h"
26 #include "pstring.h"
27
28 #define VERBOSE 0
29 #define OP_MIN 0
30 #define OP_MAX 100
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_EQUAL(status, NT_STATUS_INVALID_LEVEL) ||
38             NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED) ||
39             NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
40             NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL) ||
41             NT_STATUS_EQUAL(status, 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 smbcli_state *cli, 
54                            int op,
55                            uint8_t *param, uint8_t *data,
56                            int param_len, int data_len,
57                            int *rparam_len, int *rdata_len)
58 {
59         NTSTATUS status;
60         struct smb_trans2 t2;
61         uint16_t setup = op;
62         TALLOC_CTX *mem_ctx;
63
64         mem_ctx = talloc_init("try_trans2");
65
66         t2.in.max_param = 64;
67         t2.in.max_data = smb_raw_max_trans_data(cli->tree, 64);
68         t2.in.max_setup = 10;
69         t2.in.flags = 0;
70         t2.in.timeout = 0;
71         t2.in.setup_count = 1;
72         t2.in.setup = &setup;
73         t2.in.params.data = param;
74         t2.in.params.length = param_len;
75         t2.in.data.data = data;
76         t2.in.data.length = data_len;
77
78         status = smb_raw_trans2(cli->tree, mem_ctx, &t2);
79
80         *rparam_len = t2.out.params.length;
81         *rdata_len = t2.out.data.length;
82
83         talloc_free(mem_ctx);
84         
85         return status;
86 }
87
88
89 static NTSTATUS try_trans2_len(struct smbcli_state *cli, 
90                              const char *format,
91                              int op, int level,
92                              uint8_t *param, uint8_t *data,
93                              int param_len, int *data_len,
94                              int *rparam_len, int *rdata_len)
95 {
96         NTSTATUS ret=NT_STATUS_OK;
97
98         ret = try_trans2(cli, op, param, data, param_len,
99                          sizeof(pstring), rparam_len, rdata_len);
100 #if VERBOSE 
101         printf("op=%d level=%d ret=%s\n", op, level, nt_errstr(ret));
102 #endif
103         if (!NT_STATUS_IS_OK(ret)) return ret;
104
105         *data_len = 0;
106         while (*data_len < sizeof(pstring)) {
107                 ret = try_trans2(cli, op, param, data, param_len,
108                                  *data_len, rparam_len, rdata_len);
109                 if (NT_STATUS_IS_OK(ret)) break;
110                 *data_len += 2;
111         }
112         if (NT_STATUS_IS_OK(ret)) {
113                 printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
114                        format, level, *data_len, *rparam_len, *rdata_len);
115         } else {
116                 trans2_check_hit(format, op, level, ret);
117         }
118         return ret;
119 }
120
121
122 /****************************************************************************
123 check whether a trans2 opnum exists at all
124 ****************************************************************************/
125 static BOOL trans2_op_exists(struct smbcli_state *cli, int op)
126 {
127         int data_len = 0;
128         int param_len = 0;
129         int rparam_len, rdata_len;
130         uint8_t param[1024], data[1024];
131         NTSTATUS status1, status2;
132
133         memset(data, 0, sizeof(data));
134         data_len = 4;
135
136         /* try with a info level only */
137         param_len = sizeof(param);
138         data_len = sizeof(data);
139
140         memset(param, 0xFF, sizeof(param));
141         memset(data, 0xFF, sizeof(data));
142         
143         status1 = try_trans2(cli, 0xFFFF, param, data, param_len, data_len, 
144                              &rparam_len, &rdata_len);
145
146         status2 = try_trans2(cli, op, param, data, param_len, data_len, 
147                              &rparam_len, &rdata_len);
148
149         if (NT_STATUS_EQUAL(status1, status2)) return False;
150
151         printf("Found op %d (status=%s)\n", op, nt_errstr(status2));
152
153         return True;
154 }
155
156 /****************************************************************************
157 check for existance of a trans2 call
158 ****************************************************************************/
159 static BOOL scan_trans2(struct smbcli_state *cli, int op, int level, 
160                         int fnum, int dnum, int qfnum, const char *fname)
161 {
162         int data_len = 0;
163         int param_len = 0;
164         int rparam_len, rdata_len;
165         uint8_t param[1024], data[1024];
166         NTSTATUS status;
167
168         memset(data, 0, sizeof(data));
169         data_len = 4;
170
171         /* try with a info level only */
172         param_len = 2;
173         SSVAL(param, 0, level);
174         status = try_trans2_len(cli, "void", op, level, param, data, param_len, &data_len, 
175                             &rparam_len, &rdata_len);
176         if (NT_STATUS_IS_OK(status)) return True;
177
178         /* try with a file descriptor */
179         param_len = 6;
180         SSVAL(param, 0, fnum);
181         SSVAL(param, 2, level);
182         SSVAL(param, 4, 0);
183         status = try_trans2_len(cli, "fnum", op, level, param, data, param_len, &data_len, 
184                                 &rparam_len, &rdata_len);
185         if (NT_STATUS_IS_OK(status)) return True;
186
187         /* try with a quota file descriptor */
188         param_len = 6;
189         SSVAL(param, 0, qfnum);
190         SSVAL(param, 2, level);
191         SSVAL(param, 4, 0);
192         status = try_trans2_len(cli, "qfnum", op, level, param, data, param_len, &data_len, 
193                                 &rparam_len, &rdata_len);
194         if (NT_STATUS_IS_OK(status)) return True;
195
196         /* try with a notify style */
197         param_len = 6;
198         SSVAL(param, 0, dnum);
199         SSVAL(param, 2, dnum);
200         SSVAL(param, 4, level);
201         status = try_trans2_len(cli, "notify", op, level, param, data, param_len, &data_len, 
202                                 &rparam_len, &rdata_len);
203         if (NT_STATUS_IS_OK(status)) return True;
204
205         /* try with a file name */
206         param_len = 6;
207         SSVAL(param, 0, level);
208         SSVAL(param, 2, 0);
209         SSVAL(param, 4, 0);
210         param_len += push_string(&param[6], fname, sizeof(pstring)-7, STR_TERMINATE|STR_UNICODE);
211
212         status = try_trans2_len(cli, "fname", op, level, param, data, param_len, &data_len, 
213                                 &rparam_len, &rdata_len);
214         if (NT_STATUS_IS_OK(status)) return True;
215
216         /* try with a new file name */
217         param_len = 6;
218         SSVAL(param, 0, level);
219         SSVAL(param, 2, 0);
220         SSVAL(param, 4, 0);
221         param_len += push_string(&param[6], "\\newfile.dat", sizeof(pstring)-7, STR_TERMINATE|STR_UNICODE);
222
223         status = try_trans2_len(cli, "newfile", op, level, param, data, param_len, &data_len, 
224                                 &rparam_len, &rdata_len);
225         smbcli_unlink(cli->tree, "\\newfile.dat");
226         smbcli_rmdir(cli->tree, "\\newfile.dat");
227         if (NT_STATUS_IS_OK(status)) return True;
228
229         /* try dfs style  */
230         smbcli_mkdir(cli->tree, "\\testdir");
231         param_len = 2;
232         SSVAL(param, 0, level);
233         param_len += push_string(&param[2], "\\testdir", sizeof(pstring)-3, STR_TERMINATE|STR_UNICODE);
234
235         status = try_trans2_len(cli, "dfs", op, level, param, data, param_len, &data_len, 
236                                 &rparam_len, &rdata_len);
237         smbcli_rmdir(cli->tree, "\\testdir");
238         if (NT_STATUS_IS_OK(status)) return True;
239
240         return False;
241 }
242
243
244 BOOL torture_trans2_scan(void)
245 {
246         static struct smbcli_state *cli;
247         int op, level;
248         const char *fname = "\\scanner.dat";
249         int fnum, dnum, qfnum;
250
251         printf("starting trans2 scan test\n");
252
253         if (!torture_open_connection(&cli)) {
254                 return False;
255         }
256
257         fnum = smbcli_open(cli->tree, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
258         if (fnum == -1) {
259                 printf("file open failed - %s\n", smbcli_errstr(cli->tree));
260         }
261         dnum = smbcli_nt_create_full(cli->tree, "\\", 
262                                      0, 
263                                      SEC_RIGHTS_FILE_READ, 
264                                      FILE_ATTRIBUTE_NORMAL,
265                                      NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE, 
266                                      NTCREATEX_DISP_OPEN, 
267                                      NTCREATEX_OPTIONS_DIRECTORY, 0);
268         if (dnum == -1) {
269                 printf("directory open failed - %s\n", smbcli_errstr(cli->tree));
270         }
271         qfnum = smbcli_nt_create_full(cli->tree, "\\$Extend\\$Quota:$Q:$INDEX_ALLOCATION", 
272                                    NTCREATEX_FLAGS_EXTENDED, 
273                                    SEC_FLAG_MAXIMUM_ALLOWED, 
274                                    0,
275                                    NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE, 
276                                    NTCREATEX_DISP_OPEN, 
277                                    0, 0);
278         if (qfnum == -1) {
279                 printf("quota open failed - %s\n", smbcli_errstr(cli->tree));
280         }
281
282         for (op=OP_MIN; op<=OP_MAX; op++) {
283
284                 if (!trans2_op_exists(cli, op)) {
285                         continue;
286                 }
287
288                 for (level = 0; level <= 50; level++) {
289                         scan_trans2(cli, op, level, fnum, dnum, qfnum, fname);
290                 }
291
292                 for (level = 0x100; level <= 0x130; level++) {
293                         scan_trans2(cli, op, level, fnum, dnum, qfnum, fname);
294                 }
295
296                 for (level = 1000; level < 1050; level++) {
297                         scan_trans2(cli, op, level, fnum, dnum, qfnum, fname);
298                 }
299         }
300
301         torture_close_connection(cli);
302
303         printf("trans2 scan finished\n");
304         return True;
305 }
306
307
308
309
310 /****************************************************************************
311 look for a partial hit
312 ****************************************************************************/
313 static void nttrans_check_hit(const char *format, int op, int level, NTSTATUS status)
314 {
315         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL) ||
316             NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED) ||
317             NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
318             NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL) ||
319             NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
320                 return;
321         }
322 #if VERBOSE
323                 printf("possible %s hit op=%3d level=%5d status=%s\n",
324                        format, op, level, nt_errstr(status));
325 #endif
326 }
327
328 /****************************************************************************
329 check for existence of a nttrans call
330 ****************************************************************************/
331 static NTSTATUS try_nttrans(struct smbcli_state *cli, 
332                             int op,
333                             uint8_t *param, uint8_t *data,
334                             int param_len, int data_len,
335                             int *rparam_len, int *rdata_len)
336 {
337         struct smb_nttrans parms;
338         DATA_BLOB ntparam_blob, ntdata_blob;
339         TALLOC_CTX *mem_ctx;
340         NTSTATUS status;
341
342         mem_ctx = talloc_init("try_nttrans");
343
344         ntparam_blob.length = param_len;
345         ntparam_blob.data = param;
346         ntdata_blob.length = data_len;
347         ntdata_blob.data = data;
348
349         parms.in.max_param = 64;
350         parms.in.max_data = smb_raw_max_trans_data(cli->tree, 64);
351         parms.in.max_setup = 0;
352         parms.in.setup_count = 0;
353         parms.in.function = op;
354         parms.in.params = ntparam_blob;
355         parms.in.data = ntdata_blob;
356         
357         status = smb_raw_nttrans(cli->tree, mem_ctx, &parms);
358         
359         if (NT_STATUS_IS_ERR(status)) {
360                 DEBUG(1,("Failed to send NT_TRANS\n"));
361                 talloc_free(mem_ctx);
362                 return status;
363         }
364         *rparam_len = parms.out.params.length;
365         *rdata_len = parms.out.data.length;
366
367         talloc_free(mem_ctx);
368
369         return status;
370 }
371
372
373 static NTSTATUS try_nttrans_len(struct smbcli_state *cli, 
374                              const char *format,
375                              int op, int level,
376                              uint8_t *param, uint8_t *data,
377                              int param_len, int *data_len,
378                              int *rparam_len, int *rdata_len)
379 {
380         NTSTATUS ret=NT_STATUS_OK;
381
382         ret = try_nttrans(cli, op, param, data, param_len,
383                          sizeof(pstring), rparam_len, rdata_len);
384 #if VERBOSE 
385         printf("op=%d level=%d ret=%s\n", op, level, nt_errstr(ret));
386 #endif
387         if (!NT_STATUS_IS_OK(ret)) return ret;
388
389         *data_len = 0;
390         while (*data_len < sizeof(pstring)) {
391                 ret = try_nttrans(cli, op, param, data, param_len,
392                                  *data_len, rparam_len, rdata_len);
393                 if (NT_STATUS_IS_OK(ret)) break;
394                 *data_len += 2;
395         }
396         if (NT_STATUS_IS_OK(ret)) {
397                 printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
398                        format, level, *data_len, *rparam_len, *rdata_len);
399         } else {
400                 nttrans_check_hit(format, op, level, ret);
401         }
402         return ret;
403 }
404
405 /****************************************************************************
406 check for existance of a nttrans call
407 ****************************************************************************/
408 static BOOL scan_nttrans(struct smbcli_state *cli, int op, int level, 
409                         int fnum, int dnum, const char *fname)
410 {
411         int data_len = 0;
412         int param_len = 0;
413         int rparam_len, rdata_len;
414         uint8_t param[1024], data[1024];
415         NTSTATUS status;
416
417         memset(data, 0, sizeof(data));
418         data_len = 4;
419
420         /* try with a info level only */
421         param_len = 2;
422         SSVAL(param, 0, level);
423         status = try_nttrans_len(cli, "void", op, level, param, data, param_len, &data_len, 
424                             &rparam_len, &rdata_len);
425         if (NT_STATUS_IS_OK(status)) return True;
426
427         /* try with a file descriptor */
428         param_len = 6;
429         SSVAL(param, 0, fnum);
430         SSVAL(param, 2, level);
431         SSVAL(param, 4, 0);
432         status = try_nttrans_len(cli, "fnum", op, level, param, data, param_len, &data_len, 
433                                 &rparam_len, &rdata_len);
434         if (NT_STATUS_IS_OK(status)) return True;
435
436
437         /* try with a notify style */
438         param_len = 6;
439         SSVAL(param, 0, dnum);
440         SSVAL(param, 2, dnum);
441         SSVAL(param, 4, level);
442         status = try_nttrans_len(cli, "notify", op, level, param, data, param_len, &data_len, 
443                                 &rparam_len, &rdata_len);
444         if (NT_STATUS_IS_OK(status)) return True;
445
446         /* try with a file name */
447         param_len = 6;
448         SSVAL(param, 0, level);
449         SSVAL(param, 2, 0);
450         SSVAL(param, 4, 0);
451         param_len += push_string(&param[6], fname, sizeof(pstring), STR_TERMINATE | STR_UNICODE);
452
453         status = try_nttrans_len(cli, "fname", op, level, param, data, param_len, &data_len, 
454                                 &rparam_len, &rdata_len);
455         if (NT_STATUS_IS_OK(status)) return True;
456
457         /* try with a new file name */
458         param_len = 6;
459         SSVAL(param, 0, level);
460         SSVAL(param, 2, 0);
461         SSVAL(param, 4, 0);
462         param_len += push_string(&param[6], "\\newfile.dat", sizeof(pstring), STR_TERMINATE | STR_UNICODE);
463
464         status = try_nttrans_len(cli, "newfile", op, level, param, data, param_len, &data_len, 
465                                 &rparam_len, &rdata_len);
466         smbcli_unlink(cli->tree, "\\newfile.dat");
467         smbcli_rmdir(cli->tree, "\\newfile.dat");
468         if (NT_STATUS_IS_OK(status)) return True;
469
470         /* try dfs style  */
471         smbcli_mkdir(cli->tree, "\\testdir");
472         param_len = 2;
473         SSVAL(param, 0, level);
474         param_len += push_string(&param[2], "\\testdir", sizeof(pstring), STR_TERMINATE | STR_UNICODE);
475
476         status = try_nttrans_len(cli, "dfs", op, level, param, data, param_len, &data_len, 
477                                 &rparam_len, &rdata_len);
478         smbcli_rmdir(cli->tree, "\\testdir");
479         if (NT_STATUS_IS_OK(status)) return True;
480
481         return False;
482 }
483
484
485 BOOL torture_nttrans_scan(void)
486 {
487         static struct smbcli_state *cli;
488         int op, level;
489         const char *fname = "\\scanner.dat";
490         int fnum, dnum;
491
492         printf("starting nttrans scan test\n");
493
494         if (!torture_open_connection(&cli)) {
495                 return False;
496         }
497
498         fnum = smbcli_open(cli->tree, fname, O_RDWR | O_CREAT | O_TRUNC, 
499                          DENY_NONE);
500         dnum = smbcli_open(cli->tree, "\\", O_RDONLY, DENY_NONE);
501
502         for (op=OP_MIN; op<=OP_MAX; op++) {
503                 printf("Scanning op=%d\n", op);
504                 for (level = 0; level <= 50; level++) {
505                         scan_nttrans(cli, op, level, fnum, dnum, fname);
506                 }
507
508                 for (level = 0x100; level <= 0x130; level++) {
509                         scan_nttrans(cli, op, level, fnum, dnum, fname);
510                 }
511
512                 for (level = 1000; level < 1050; level++) {
513                         scan_nttrans(cli, op, level, fnum, dnum, fname);
514                 }
515         }
516
517         torture_close_connection(cli);
518
519         printf("nttrans scan finished\n");
520         return True;
521 }
522
523
524 /* scan for valid base SMB requests */
525 BOOL torture_smb_scan(void)
526 {
527         static struct smbcli_state *cli;
528         int op;
529         struct smbcli_request *req;
530         NTSTATUS status;
531
532         for (op=0x0;op<=0xFF;op++) {
533                 if (op == SMBreadbraw) continue;
534
535                 if (!torture_open_connection(&cli)) {
536                         return False;
537                 }
538
539                 req = smbcli_request_setup(cli->tree, op, 0, 0);
540
541                 if (!smbcli_request_send(req)) {
542                         smbcli_request_destroy(req);
543                         break;
544                 }
545
546                 usleep(10000);
547                 smbcli_transport_process(cli->transport);
548                 if (req->state > SMBCLI_REQUEST_RECV) {
549                         status = smbcli_request_simple_recv(req);
550                         printf("op=0x%x status=%s\n", op, nt_errstr(status));
551                         torture_close_connection(cli);
552                         continue;
553                 }
554
555                 sleep(1);
556                 smbcli_transport_process(cli->transport);
557                 if (req->state > SMBCLI_REQUEST_RECV) {
558                         status = smbcli_request_simple_recv(req);
559                         printf("op=0x%x status=%s\n", op, nt_errstr(status));
560                 } else {
561                         printf("op=0x%x no reply\n", op);
562                         smbcli_request_destroy(req);
563                         continue; /* don't attempt close! */
564                 }
565
566                 torture_close_connection(cli);
567         }
568
569
570         printf("smb scan finished\n");
571         return True;
572 }