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