r23792: convert Samba4 to GPLv3
[garming/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 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 "torture/torture.h"
22 #include "libcli/libcli.h"
23 #include "torture/util.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(struct torture_context *torture, 
245                                                  struct smbcli_state *cli)
246 {
247         int op, level;
248         const char *fname = "\\scanner.dat";
249         int fnum, dnum, qfnum;
250
251         fnum = smbcli_open(cli->tree, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
252         if (fnum == -1) {
253                 printf("file open failed - %s\n", smbcli_errstr(cli->tree));
254         }
255         dnum = smbcli_nt_create_full(cli->tree, "\\", 
256                                      0, 
257                                      SEC_RIGHTS_FILE_READ, 
258                                      FILE_ATTRIBUTE_NORMAL,
259                                      NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE, 
260                                      NTCREATEX_DISP_OPEN, 
261                                      NTCREATEX_OPTIONS_DIRECTORY, 0);
262         if (dnum == -1) {
263                 printf("directory open failed - %s\n", smbcli_errstr(cli->tree));
264         }
265         qfnum = smbcli_nt_create_full(cli->tree, "\\$Extend\\$Quota:$Q:$INDEX_ALLOCATION", 
266                                    NTCREATEX_FLAGS_EXTENDED, 
267                                    SEC_FLAG_MAXIMUM_ALLOWED, 
268                                    0,
269                                    NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE, 
270                                    NTCREATEX_DISP_OPEN, 
271                                    0, 0);
272         if (qfnum == -1) {
273                 printf("quota open failed - %s\n", smbcli_errstr(cli->tree));
274         }
275
276         for (op=OP_MIN; op<=OP_MAX; op++) {
277
278                 if (!trans2_op_exists(cli, op)) {
279                         continue;
280                 }
281
282                 for (level = 0; level <= 50; level++) {
283                         scan_trans2(cli, op, level, fnum, dnum, qfnum, fname);
284                 }
285
286                 for (level = 0x100; level <= 0x130; level++) {
287                         scan_trans2(cli, op, level, fnum, dnum, qfnum, fname);
288                 }
289
290                 for (level = 1000; level < 1050; level++) {
291                         scan_trans2(cli, op, level, fnum, dnum, qfnum, fname);
292                 }
293         }
294
295         return True;
296 }
297
298
299
300
301 /****************************************************************************
302 look for a partial hit
303 ****************************************************************************/
304 static void nttrans_check_hit(const char *format, int op, int level, NTSTATUS status)
305 {
306         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL) ||
307             NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED) ||
308             NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
309             NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL) ||
310             NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
311                 return;
312         }
313 #if VERBOSE
314                 printf("possible %s hit op=%3d level=%5d status=%s\n",
315                        format, op, level, nt_errstr(status));
316 #endif
317 }
318
319 /****************************************************************************
320 check for existence of a nttrans call
321 ****************************************************************************/
322 static NTSTATUS try_nttrans(struct smbcli_state *cli, 
323                             int op,
324                             uint8_t *param, uint8_t *data,
325                             int param_len, int data_len,
326                             int *rparam_len, int *rdata_len)
327 {
328         struct smb_nttrans parms;
329         DATA_BLOB ntparam_blob, ntdata_blob;
330         TALLOC_CTX *mem_ctx;
331         NTSTATUS status;
332
333         mem_ctx = talloc_init("try_nttrans");
334
335         ntparam_blob.length = param_len;
336         ntparam_blob.data = param;
337         ntdata_blob.length = data_len;
338         ntdata_blob.data = data;
339
340         parms.in.max_param = 64;
341         parms.in.max_data = smb_raw_max_trans_data(cli->tree, 64);
342         parms.in.max_setup = 0;
343         parms.in.setup_count = 0;
344         parms.in.function = op;
345         parms.in.params = ntparam_blob;
346         parms.in.data = ntdata_blob;
347         
348         status = smb_raw_nttrans(cli->tree, mem_ctx, &parms);
349         
350         if (NT_STATUS_IS_ERR(status)) {
351                 DEBUG(1,("Failed to send NT_TRANS\n"));
352                 talloc_free(mem_ctx);
353                 return status;
354         }
355         *rparam_len = parms.out.params.length;
356         *rdata_len = parms.out.data.length;
357
358         talloc_free(mem_ctx);
359
360         return status;
361 }
362
363
364 static NTSTATUS try_nttrans_len(struct smbcli_state *cli, 
365                              const char *format,
366                              int op, int level,
367                              uint8_t *param, uint8_t *data,
368                              int param_len, int *data_len,
369                              int *rparam_len, int *rdata_len)
370 {
371         NTSTATUS ret=NT_STATUS_OK;
372
373         ret = try_nttrans(cli, op, param, data, param_len,
374                          sizeof(pstring), rparam_len, rdata_len);
375 #if VERBOSE 
376         printf("op=%d level=%d ret=%s\n", op, level, nt_errstr(ret));
377 #endif
378         if (!NT_STATUS_IS_OK(ret)) return ret;
379
380         *data_len = 0;
381         while (*data_len < sizeof(pstring)) {
382                 ret = try_nttrans(cli, op, param, data, param_len,
383                                  *data_len, rparam_len, rdata_len);
384                 if (NT_STATUS_IS_OK(ret)) break;
385                 *data_len += 2;
386         }
387         if (NT_STATUS_IS_OK(ret)) {
388                 printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
389                        format, level, *data_len, *rparam_len, *rdata_len);
390         } else {
391                 nttrans_check_hit(format, op, level, ret);
392         }
393         return ret;
394 }
395
396 /****************************************************************************
397 check for existance of a nttrans call
398 ****************************************************************************/
399 static BOOL scan_nttrans(struct smbcli_state *cli, int op, int level, 
400                         int fnum, int dnum, const char *fname)
401 {
402         int data_len = 0;
403         int param_len = 0;
404         int rparam_len, rdata_len;
405         uint8_t param[1024], data[1024];
406         NTSTATUS status;
407
408         memset(data, 0, sizeof(data));
409         data_len = 4;
410
411         /* try with a info level only */
412         param_len = 2;
413         SSVAL(param, 0, level);
414         status = try_nttrans_len(cli, "void", op, level, param, data, param_len, &data_len, 
415                             &rparam_len, &rdata_len);
416         if (NT_STATUS_IS_OK(status)) return True;
417
418         /* try with a file descriptor */
419         param_len = 6;
420         SSVAL(param, 0, fnum);
421         SSVAL(param, 2, level);
422         SSVAL(param, 4, 0);
423         status = try_nttrans_len(cli, "fnum", op, level, param, data, param_len, &data_len, 
424                                 &rparam_len, &rdata_len);
425         if (NT_STATUS_IS_OK(status)) return True;
426
427
428         /* try with a notify style */
429         param_len = 6;
430         SSVAL(param, 0, dnum);
431         SSVAL(param, 2, dnum);
432         SSVAL(param, 4, level);
433         status = try_nttrans_len(cli, "notify", op, level, param, data, param_len, &data_len, 
434                                 &rparam_len, &rdata_len);
435         if (NT_STATUS_IS_OK(status)) return True;
436
437         /* try with a file name */
438         param_len = 6;
439         SSVAL(param, 0, level);
440         SSVAL(param, 2, 0);
441         SSVAL(param, 4, 0);
442         param_len += push_string(&param[6], fname, sizeof(pstring), STR_TERMINATE | STR_UNICODE);
443
444         status = try_nttrans_len(cli, "fname", op, level, param, data, param_len, &data_len, 
445                                 &rparam_len, &rdata_len);
446         if (NT_STATUS_IS_OK(status)) return True;
447
448         /* try with a new file name */
449         param_len = 6;
450         SSVAL(param, 0, level);
451         SSVAL(param, 2, 0);
452         SSVAL(param, 4, 0);
453         param_len += push_string(&param[6], "\\newfile.dat", sizeof(pstring), STR_TERMINATE | STR_UNICODE);
454
455         status = try_nttrans_len(cli, "newfile", op, level, param, data, param_len, &data_len, 
456                                 &rparam_len, &rdata_len);
457         smbcli_unlink(cli->tree, "\\newfile.dat");
458         smbcli_rmdir(cli->tree, "\\newfile.dat");
459         if (NT_STATUS_IS_OK(status)) return True;
460
461         /* try dfs style  */
462         smbcli_mkdir(cli->tree, "\\testdir");
463         param_len = 2;
464         SSVAL(param, 0, level);
465         param_len += push_string(&param[2], "\\testdir", sizeof(pstring), STR_TERMINATE | STR_UNICODE);
466
467         status = try_nttrans_len(cli, "dfs", op, level, param, data, param_len, &data_len, 
468                                 &rparam_len, &rdata_len);
469         smbcli_rmdir(cli->tree, "\\testdir");
470         if (NT_STATUS_IS_OK(status)) return True;
471
472         return False;
473 }
474
475
476 BOOL torture_nttrans_scan(struct torture_context *torture, 
477                                                   struct smbcli_state *cli)
478 {
479         int op, level;
480         const char *fname = "\\scanner.dat";
481         int fnum, dnum;
482
483         fnum = smbcli_open(cli->tree, fname, O_RDWR | O_CREAT | O_TRUNC, 
484                          DENY_NONE);
485         dnum = smbcli_open(cli->tree, "\\", O_RDONLY, DENY_NONE);
486
487         for (op=OP_MIN; op<=OP_MAX; op++) {
488                 printf("Scanning op=%d\n", op);
489                 for (level = 0; level <= 50; level++) {
490                         scan_nttrans(cli, op, level, fnum, dnum, fname);
491                 }
492
493                 for (level = 0x100; level <= 0x130; level++) {
494                         scan_nttrans(cli, op, level, fnum, dnum, fname);
495                 }
496
497                 for (level = 1000; level < 1050; level++) {
498                         scan_nttrans(cli, op, level, fnum, dnum, fname);
499                 }
500         }
501
502         torture_close_connection(cli);
503
504         printf("nttrans scan finished\n");
505         return True;
506 }
507
508
509 /* scan for valid base SMB requests */
510 BOOL torture_smb_scan(struct torture_context *torture)
511 {
512         static struct smbcli_state *cli;
513         int op;
514         struct smbcli_request *req;
515         NTSTATUS status;
516
517         for (op=0x0;op<=0xFF;op++) {
518                 if (op == SMBreadbraw) continue;
519
520                 if (!torture_open_connection(&cli, 0)) {
521                         return False;
522                 }
523
524                 req = smbcli_request_setup(cli->tree, op, 0, 0);
525
526                 if (!smbcli_request_send(req)) {
527                         smbcli_request_destroy(req);
528                         break;
529                 }
530
531                 usleep(10000);
532                 smbcli_transport_process(cli->transport);
533                 if (req->state > SMBCLI_REQUEST_RECV) {
534                         status = smbcli_request_simple_recv(req);
535                         printf("op=0x%x status=%s\n", op, nt_errstr(status));
536                         torture_close_connection(cli);
537                         continue;
538                 }
539
540                 sleep(1);
541                 smbcli_transport_process(cli->transport);
542                 if (req->state > SMBCLI_REQUEST_RECV) {
543                         status = smbcli_request_simple_recv(req);
544                         printf("op=0x%x status=%s\n", op, nt_errstr(status));
545                 } else {
546                         printf("op=0x%x no reply\n", op);
547                         smbcli_request_destroy(req);
548                         continue; /* don't attempt close! */
549                 }
550
551                 torture_close_connection(cli);
552         }
553
554
555         printf("smb scan finished\n");
556         return True;
557 }