More strlcat/strlcpy truncate checks.
[amitay/samba.git] / source3 / torture / 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 "system/filesys.h"
22 #include "torture/proto.h"
23 #include "libsmb/libsmb.h"
24
25 #define VERBOSE 0
26 #define OP_MIN 0
27 #define OP_MAX 20
28
29 #define DATA_SIZE 1024
30 #define PARAM_SIZE 1024
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_V(status) == NT_STATUS_V(NT_STATUS_INVALID_LEVEL) ||
38             NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ||
39             NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_SUPPORTED) ||
40             NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) ||
41             NT_STATUS_V(status) == NT_STATUS_V(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 cli_state *cli, 
54                          int op,
55                          uint8_t *param, uint8_t *data,
56                          uint32_t param_len, uint32_t data_len,
57                          uint32_t *rparam_len, uint32_t *rdata_len)
58 {
59         uint16_t setup[1];
60         uint8_t *rparam=NULL, *rdata=NULL;
61         NTSTATUS status;
62
63         SSVAL(setup+0, 0, op);
64
65         status = cli_trans(talloc_tos(), cli, SMBtrans2,
66                            NULL, -1, /* name, fid */
67                            op, 0,
68                            NULL, 0, 0, /* setup */
69                            param, param_len, 2,
70                            data, data_len, CLI_BUFFER_SIZE,
71                            NULL,                /* recv_flags2 */
72                            NULL, 0, NULL,       /* rsetup */
73                            &rparam, 0, rparam_len,
74                            &rdata, 0, rdata_len);
75
76         TALLOC_FREE(rdata);
77         TALLOC_FREE(rparam);
78
79         return status;
80 }
81
82
83 static NTSTATUS try_trans2_len(struct cli_state *cli, 
84                              const char *format,
85                              int op, int level,
86                              uint8_t *param, uint8_t *data,
87                              uint32_t param_len, uint32_t *data_len,
88                              uint32_t *rparam_len, uint32_t *rdata_len)
89 {
90         NTSTATUS ret=NT_STATUS_OK;
91
92         ret = try_trans2(cli, op, param, data, param_len,
93                          DATA_SIZE, rparam_len, rdata_len);
94 #if VERBOSE 
95         printf("op=%d level=%d ret=%s\n", op, level, nt_errstr(ret));
96 #endif
97         if (!NT_STATUS_IS_OK(ret)) return ret;
98
99         *data_len = 0;
100         while (*data_len < DATA_SIZE) {
101                 ret = try_trans2(cli, op, param, data, param_len,
102                                  *data_len, rparam_len, rdata_len);
103                 if (NT_STATUS_IS_OK(ret)) break;
104                 *data_len += 2;
105         }
106         if (NT_STATUS_IS_OK(ret)) {
107                 printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
108                        format, level, *data_len, *rparam_len, *rdata_len);
109         } else {
110                 trans2_check_hit(format, op, level, ret);
111         }
112         return ret;
113 }
114
115 /****************************************************************************
116 check for existance of a trans2 call
117 ****************************************************************************/
118 static bool scan_trans2(struct cli_state *cli, int op, int level, 
119                         int fnum, int dnum, const char *fname)
120 {
121         uint32_t data_len = 0;
122         uint32_t param_len = 0;
123         uint32_t rparam_len, rdata_len;
124         uint8_t *param = NULL;
125         uint8_t data[DATA_SIZE];
126         const char *newfname;
127         const char *dname;
128         NTSTATUS status;
129
130         memset(data, 0, sizeof(data));
131         data_len = 4;
132
133         /* try with a info level only */
134         TALLOC_FREE(param);
135         param = talloc_array(talloc_tos(), uint8_t, 2);
136         if (param == NULL) return True;
137
138         SSVAL(param, 0, level);
139
140         param_len = talloc_get_size(param);
141         status = try_trans2_len(cli, "void", op, level, param, data, param_len, &data_len, 
142                             &rparam_len, &rdata_len);
143         if (NT_STATUS_IS_OK(status)) return True;
144
145         /* try with a file descriptor */
146         TALLOC_FREE(param);
147         param = talloc_array(talloc_tos(), uint8_t, 6);
148         if (param == NULL) return True;
149
150         SSVAL(param, 0, fnum);
151         SSVAL(param, 2, level);
152         SSVAL(param, 4, 0);
153
154         param_len = talloc_get_size(param);
155         status = try_trans2_len(cli, "fnum", op, level, param, data, param_len, &data_len, 
156                                 &rparam_len, &rdata_len);
157         if (NT_STATUS_IS_OK(status)) return True;
158
159
160         /* try with a notify style */
161         TALLOC_FREE(param);
162         param = talloc_array(talloc_tos(), uint8_t, 6);
163         if (param == NULL) return True;
164
165         SSVAL(param, 0, dnum);
166         SSVAL(param, 2, dnum);
167         SSVAL(param, 4, level);
168
169         param_len = talloc_get_size(param);
170         status = try_trans2_len(cli, "notify", op, level, param, data, param_len, &data_len, 
171                                 &rparam_len, &rdata_len);
172         if (NT_STATUS_IS_OK(status)) return True;
173
174         /* try with a file name */
175         TALLOC_FREE(param);
176         param = talloc_array(talloc_tos(), uint8_t, 6);
177         if (param == NULL) return True;
178
179         SSVAL(param, 0, level);
180         SSVAL(param, 2, 0);
181         SSVAL(param, 4, 0);
182         param = trans2_bytes_push_str(param, cli_ucs2(cli),
183                                       fname, strlen(fname)+1, NULL);
184         if (param == NULL) return True;
185
186         param_len = talloc_get_size(param);
187         status = try_trans2_len(cli, "fname", op, level, param, data, param_len, &data_len, 
188                                 &rparam_len, &rdata_len);
189         if (NT_STATUS_IS_OK(status)) return True;
190
191         /* try with a new file name */
192         newfname = "\\newfile.dat";
193         TALLOC_FREE(param);
194         param = talloc_array(talloc_tos(), uint8_t, 6);
195         if (param == NULL) return True;
196
197         SSVAL(param, 0, level);
198         SSVAL(param, 2, 0);
199         SSVAL(param, 4, 0);
200         param = trans2_bytes_push_str(param, cli_ucs2(cli),
201                                       newfname, strlen(newfname)+1, NULL);
202         if (param == NULL) return True;
203
204         param_len = talloc_get_size(param);
205         status = try_trans2_len(cli, "newfile", op, level, param, data, param_len, &data_len, 
206                                 &rparam_len, &rdata_len);
207         cli_unlink(cli, newfname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
208         cli_rmdir(cli, newfname);
209         if (NT_STATUS_IS_OK(status)) return True;
210
211         /* try dfs style  */
212         dname = "\\testdir";
213         cli_mkdir(cli, dname);
214         TALLOC_FREE(param);
215         param = talloc_array(talloc_tos(), uint8_t, 2);
216         if (param == NULL) return True;
217
218         SSVAL(param, 0, level);
219         param = trans2_bytes_push_str(param, cli_ucs2(cli),
220                                       dname, strlen(dname)+1, NULL);
221         if (param == NULL) return True;
222
223         param_len = talloc_get_size(param);
224         status = try_trans2_len(cli, "dfs", op, level, param, data, param_len, &data_len, 
225                                 &rparam_len, &rdata_len);
226         cli_rmdir(cli, dname);
227         if (NT_STATUS_IS_OK(status)) return True;
228
229         return False;
230 }
231
232
233 bool torture_trans2_scan(int dummy)
234 {
235         static struct cli_state *cli;
236         int op, level;
237         const char *fname = "\\scanner.dat";
238         uint16_t fnum, dnum;
239
240         printf("starting trans2 scan test\n");
241
242         if (!torture_open_connection(&cli, 0)) {
243                 return False;
244         }
245
246         if (!NT_STATUS_IS_OK(cli_openx(cli, fname, O_RDWR | O_CREAT | O_TRUNC, 
247                          DENY_NONE, &fnum))) {
248                 printf("open of %s failed\n", fname);
249                 return false;
250         }
251         if (!NT_STATUS_IS_OK(cli_openx(cli, "\\", O_RDONLY, DENY_NONE, &dnum))) {
252                 printf("open of \\ failed\n");
253                 return false;
254         }
255
256         for (op=OP_MIN; op<=OP_MAX; op++) {
257                 printf("Scanning op=%d\n", op);
258                 for (level = 0; level <= 50; level++) {
259                         scan_trans2(cli, op, level, fnum, dnum, fname);
260                 }
261
262                 for (level = 0x100; level <= 0x130; level++) {
263                         scan_trans2(cli, op, level, fnum, dnum, fname);
264                 }
265
266                 for (level = 1000; level < 1050; level++) {
267                         scan_trans2(cli, op, level, fnum, dnum, fname);
268                 }
269         }
270
271         torture_close_connection(cli);
272
273         printf("trans2 scan finished\n");
274         return True;
275 }
276
277
278
279
280 /****************************************************************************
281 look for a partial hit
282 ****************************************************************************/
283 static void nttrans_check_hit(const char *format, int op, int level, NTSTATUS status)
284 {
285         if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_LEVEL) ||
286             NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ||
287             NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_SUPPORTED) ||
288             NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) ||
289             NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) {
290                 return;
291         }
292 #if VERBOSE
293                 printf("possible %s hit op=%3d level=%5d status=%s\n",
294                        format, op, level, nt_errstr(status));
295 #endif
296 }
297
298 /****************************************************************************
299 check for existance of a nttrans call
300 ****************************************************************************/
301 static NTSTATUS try_nttrans(struct cli_state *cli, 
302                             int op,
303                             uint8_t *param, uint8_t *data,
304                             int32_t param_len, uint32_t data_len,
305                             uint32_t *rparam_len,
306                             uint32_t *rdata_len)
307 {
308         uint8_t *rparam=NULL, *rdata=NULL;
309         NTSTATUS status;
310
311         status = cli_trans(talloc_tos(), cli, SMBnttrans,
312                            NULL, -1, /* name, fid */
313                            op, 0,
314                            NULL, 0, 0, /* setup */
315                            param, param_len, 2,
316                            data, data_len, CLI_BUFFER_SIZE,
317                            NULL,                /* recv_flags2 */
318                            NULL, 0, NULL,       /* rsetup */
319                            &rparam, 0, rparam_len,
320                            &rdata, 0, rdata_len);
321         SAFE_FREE(rdata);
322         SAFE_FREE(rparam);
323
324         return status;
325 }
326
327
328 static NTSTATUS try_nttrans_len(struct cli_state *cli, 
329                              const char *format,
330                              int op, int level,
331                              uint8_t *param, uint8_t *data,
332                              int param_len, uint32_t *data_len,
333                              uint32_t *rparam_len, uint32_t *rdata_len)
334 {
335         NTSTATUS ret=NT_STATUS_OK;
336
337         ret = try_nttrans(cli, op, param, data, param_len,
338                          DATA_SIZE, rparam_len, rdata_len);
339 #if VERBOSE 
340         printf("op=%d level=%d ret=%s\n", op, level, nt_errstr(ret));
341 #endif
342         if (!NT_STATUS_IS_OK(ret)) return ret;
343
344         *data_len = 0;
345         while (*data_len < DATA_SIZE) {
346                 ret = try_nttrans(cli, op, param, data, param_len,
347                                  *data_len, rparam_len, rdata_len);
348                 if (NT_STATUS_IS_OK(ret)) break;
349                 *data_len += 2;
350         }
351         if (NT_STATUS_IS_OK(ret)) {
352                 printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
353                        format, level, *data_len, *rparam_len, *rdata_len);
354         } else {
355                 nttrans_check_hit(format, op, level, ret);
356         }
357         return ret;
358 }
359
360 /****************************************************************************
361 check for existance of a nttrans call
362 ****************************************************************************/
363 static bool scan_nttrans(struct cli_state *cli, int op, int level, 
364                         int fnum, int dnum, const char *fname)
365 {
366         uint32_t data_len = 0;
367         uint32_t param_len = 0;
368         uint32_t rparam_len, rdata_len;
369         uint8_t *param = NULL;
370         uint8_t data[DATA_SIZE];
371         NTSTATUS status;
372         const char *newfname;
373         const char *dname;
374
375         memset(data, 0, sizeof(data));
376         data_len = 4;
377
378         /* try with a info level only */
379         TALLOC_FREE(param);
380         param = talloc_array(talloc_tos(), uint8_t, 2);
381         if (param == NULL) return True;
382
383         SSVAL(param, 0, level);
384
385         param_len = talloc_get_size(param);
386         status = try_nttrans_len(cli, "void", op, level, param, data, param_len, &data_len, 
387                             &rparam_len, &rdata_len);
388         if (NT_STATUS_IS_OK(status)) return True;
389
390         /* try with a file descriptor */
391         TALLOC_FREE(param);
392         param = talloc_array(talloc_tos(), uint8_t, 6);
393         if (param == NULL) return True;
394
395         SSVAL(param, 0, fnum);
396         SSVAL(param, 2, level);
397         SSVAL(param, 4, 0);
398
399         param_len = talloc_get_size(param);
400         status = try_nttrans_len(cli, "fnum", op, level, param, data, param_len, &data_len, 
401                                 &rparam_len, &rdata_len);
402         if (NT_STATUS_IS_OK(status)) return True;
403
404
405         /* try with a notify style */
406         TALLOC_FREE(param);
407         param = talloc_array(talloc_tos(), uint8_t, 6);
408         if (param == NULL) return True;
409
410         SSVAL(param, 0, dnum);
411         SSVAL(param, 2, dnum);
412         SSVAL(param, 4, level);
413
414         param_len = talloc_get_size(param);
415         status = try_nttrans_len(cli, "notify", op, level, param, data, param_len, &data_len, 
416                                 &rparam_len, &rdata_len);
417         if (NT_STATUS_IS_OK(status)) return True;
418
419         /* try with a file name */
420         TALLOC_FREE(param);
421         param = talloc_array(talloc_tos(), uint8_t, 6);
422         if (param == NULL) return True;
423
424         SSVAL(param, 0, level);
425         SSVAL(param, 2, 0);
426         SSVAL(param, 4, 0);
427         param = trans2_bytes_push_str(param, cli_ucs2(cli),
428                                       fname, strlen(fname)+1, NULL);
429         if (param == NULL) return True;
430
431         param_len = talloc_get_size(param);
432         status = try_nttrans_len(cli, "fname", op, level, param, data, param_len, &data_len, 
433                                 &rparam_len, &rdata_len);
434         if (NT_STATUS_IS_OK(status)) return True;
435
436         /* try with a new file name */
437         newfname = "\\newfile.dat";
438         TALLOC_FREE(param);
439         param = talloc_array(talloc_tos(), uint8_t, 6);
440         if (param == NULL) return True;
441
442         SSVAL(param, 0, level);
443         SSVAL(param, 2, 0);
444         SSVAL(param, 4, 0);
445         param = trans2_bytes_push_str(param, cli_ucs2(cli),
446                                       newfname, strlen(newfname)+1, NULL);
447         if (param == NULL) return True;
448
449         param_len = talloc_get_size(param);
450         status = try_nttrans_len(cli, "newfile", op, level, param, data, param_len, &data_len, 
451                                 &rparam_len, &rdata_len);
452         cli_unlink(cli, newfname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
453         cli_rmdir(cli, newfname);
454         if (NT_STATUS_IS_OK(status)) return True;
455
456         /* try dfs style  */
457         dname = "\\testdir";
458         cli_mkdir(cli, dname);
459         TALLOC_FREE(param);
460         param = talloc_array(talloc_tos(), uint8_t, 2);
461         if (param == NULL) return True;
462
463         SSVAL(param, 0, level);
464         param = trans2_bytes_push_str(param, cli_ucs2(cli),
465                                       dname, strlen(dname)+1, NULL);
466         if (param == NULL) return True;
467
468         param_len = talloc_get_size(param);
469         status = try_nttrans_len(cli, "dfs", op, level, param, data, param_len, &data_len, 
470                                 &rparam_len, &rdata_len);
471         cli_rmdir(cli, dname);
472         if (NT_STATUS_IS_OK(status)) return True;
473
474         return False;
475 }
476
477
478 bool torture_nttrans_scan(int dummy)
479 {
480         static struct cli_state *cli;
481         int op, level;
482         const char *fname = "\\scanner.dat";
483         uint16_t fnum, dnum;
484
485         printf("starting nttrans scan test\n");
486
487         if (!torture_open_connection(&cli, 0)) {
488                 return False;
489         }
490
491         cli_openx(cli, fname, O_RDWR | O_CREAT | O_TRUNC, 
492                          DENY_NONE, &fnum);
493         cli_openx(cli, "\\", O_RDONLY, DENY_NONE, &dnum);
494
495         for (op=OP_MIN; op<=OP_MAX; op++) {
496                 printf("Scanning op=%d\n", op);
497                 for (level = 0; level <= 50; level++) {
498                         scan_nttrans(cli, op, level, fnum, dnum, fname);
499                 }
500
501                 for (level = 0x100; level <= 0x130; level++) {
502                         scan_nttrans(cli, op, level, fnum, dnum, fname);
503                 }
504
505                 for (level = 1000; level < 1050; level++) {
506                         scan_nttrans(cli, op, level, fnum, dnum, fname);
507                 }
508         }
509
510         torture_close_connection(cli);
511
512         printf("nttrans scan finished\n");
513         return True;
514 }