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