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