2 Unix SMB/CIFS implementation.
3 SMB torture tester - scanning functions
4 Copyright (C) Andrew Tridgell 2001
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.
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.
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/>.
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"
31 #define PARAM_SIZE 1024
33 /****************************************************************************
34 look for a partial hit
35 ****************************************************************************/
36 static void trans2_check_hit(const char *format
, int op
, int level
, NTSTATUS status
)
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
)) {
46 printf("possible %s hit op=%3d level=%5d status=%s\n",
47 format
, op
, level
, nt_errstr(status
));
51 /****************************************************************************
52 check for existance of a trans2 call
53 ****************************************************************************/
54 static NTSTATUS
try_trans2(struct smbcli_state
*cli
,
56 uint8_t *param
, uint8_t *data
,
57 int param_len
, int data_len
,
58 int *rparam_len
, int *rdata_len
)
65 mem_ctx
= talloc_init("try_trans2");
67 t2
.in
.max_param
= UINT16_MAX
;
68 t2
.in
.max_data
= UINT16_MAX
;
72 t2
.in
.setup_count
= 1;
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
;
79 status
= smb_raw_trans2(cli
->tree
, mem_ctx
, &t2
);
81 *rparam_len
= t2
.out
.params
.length
;
82 *rdata_len
= t2
.out
.data
.length
;
90 static NTSTATUS
try_trans2_len(struct smbcli_state
*cli
,
93 uint8_t *param
, uint8_t *data
,
94 int param_len
, int *data_len
,
95 int *rparam_len
, int *rdata_len
)
97 NTSTATUS ret
=NT_STATUS_OK
;
99 ret
= try_trans2(cli
, op
, param
, data
, param_len
,
100 PARAM_SIZE
, rparam_len
, rdata_len
);
102 printf("op=%d level=%d ret=%s\n", op
, level
, nt_errstr(ret
));
104 if (!NT_STATUS_IS_OK(ret
)) return ret
;
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;
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
);
117 trans2_check_hit(format
, op
, level
, ret
);
123 /****************************************************************************
124 check whether a trans2 opnum exists at all
125 ****************************************************************************/
126 static bool trans2_op_exists(struct smbcli_state
*cli
, int op
)
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
;
135 mem_ctx
= talloc_init("trans2_op_exists");
137 /* try with a info level only */
139 param
= talloc_array(mem_ctx
, uint8_t, param_len
);
140 data
= talloc_array(mem_ctx
, uint8_t, data_len
);
142 memset(param
, 0xFF, param_len
);
143 memset(data
, 0xFF, data_len
);
145 status1
= try_trans2(cli
, 0xFFFF, param
, data
, param_len
, data_len
,
146 &rparam_len
, &rdata_len
);
148 status2
= try_trans2(cli
, op
, param
, data
, param_len
, data_len
,
149 &rparam_len
, &rdata_len
);
151 if (NT_STATUS_EQUAL(status1
, status2
)) {
152 talloc_free(mem_ctx
);
156 printf("Found op %d (status=%s)\n", op
, nt_errstr(status2
));
158 talloc_free(mem_ctx
);
162 /****************************************************************************
163 check for existance 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
)
171 int rparam_len
, rdata_len
;
172 uint8_t *param
, *data
;
176 mem_ctx
= talloc_init("scan_trans2");
178 data
= talloc_array(mem_ctx
, uint8_t, PARAM_SIZE
);
179 param
= talloc_array(mem_ctx
, uint8_t, PARAM_SIZE
);
181 memset(data
, 0, PARAM_SIZE
);
184 /* try with a info level only */
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
);
194 /* try with a file descriptor */
196 SSVAL(param
, 0, fnum
);
197 SSVAL(param
, 2, level
);
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
);
206 /* try with a quota file descriptor */
208 SSVAL(param
, 0, qfnum
);
209 SSVAL(param
, 2, level
);
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
);
218 /* try with a notify style */
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
);
230 /* try with a file name */
232 SSVAL(param
, 0, level
);
235 param_len
+= push_string(
236 ¶m
[6], fname
, PARAM_SIZE
-7,
237 STR_TERMINATE
|STR_UNICODE
);
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
);
246 /* try with a new file name */
248 SSVAL(param
, 0, level
);
251 param_len
+= push_string(
252 ¶m
[6], "\\newfile.dat", PARAM_SIZE
-7,
253 STR_TERMINATE
|STR_UNICODE
);
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
);
265 smbcli_mkdir(cli
->tree
, "\\testdir");
267 SSVAL(param
, 0, level
);
268 param_len
+= push_string(
269 ¶m
[2], "\\testdir", PARAM_SIZE
-3,
270 STR_TERMINATE
|STR_UNICODE
);
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
);
280 talloc_free(mem_ctx
);
284 bool torture_trans2_scan(struct torture_context
*torture
,
285 struct smbcli_state
*cli
)
288 const char *fname
= "\\scanner.dat";
289 int fnum
, dnum
, qfnum
;
291 fnum
= smbcli_open(cli
->tree
, fname
, O_RDWR
| O_CREAT
| O_TRUNC
, DENY_NONE
);
293 printf("file open failed - %s\n", smbcli_errstr(cli
->tree
));
295 dnum
= smbcli_nt_create_full(cli
->tree
, "\\",
297 SEC_RIGHTS_FILE_READ
,
298 FILE_ATTRIBUTE_NORMAL
,
299 NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
,
301 NTCREATEX_OPTIONS_DIRECTORY
, 0);
303 printf("directory open failed - %s\n", smbcli_errstr(cli
->tree
));
305 qfnum
= smbcli_nt_create_full(cli
->tree
, "\\$Extend\\$Quota:$Q:$INDEX_ALLOCATION",
306 NTCREATEX_FLAGS_EXTENDED
,
307 SEC_FLAG_MAXIMUM_ALLOWED
,
309 NTCREATEX_SHARE_ACCESS_READ
|NTCREATEX_SHARE_ACCESS_WRITE
,
313 printf("quota open failed - %s\n", smbcli_errstr(cli
->tree
));
316 for (op
=OP_MIN
; op
<=OP_MAX
; op
++) {
318 if (!trans2_op_exists(cli
, op
)) {
322 for (level
= 0; level
<= 50; level
++) {
323 scan_trans2(cli
, op
, level
, fnum
, dnum
, qfnum
, fname
);
326 for (level
= 0x100; level
<= 0x130; level
++) {
327 scan_trans2(cli
, op
, level
, fnum
, dnum
, qfnum
, fname
);
330 for (level
= 1000; level
< 1050; level
++) {
331 scan_trans2(cli
, op
, level
, fnum
, dnum
, qfnum
, fname
);
341 /****************************************************************************
342 look for a partial hit
343 ****************************************************************************/
344 static void nttrans_check_hit(const char *format
, int op
, int level
, NTSTATUS status
)
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
)) {
354 printf("possible %s hit op=%3d level=%5d status=%s\n",
355 format
, op
, level
, nt_errstr(status
));
359 /****************************************************************************
360 check for existence of a nttrans call
361 ****************************************************************************/
362 static NTSTATUS
try_nttrans(struct smbcli_state
*cli
,
364 uint8_t *param
, uint8_t *data
,
365 int param_len
, int data_len
,
366 int *rparam_len
, int *rdata_len
)
368 struct smb_nttrans parms
;
369 DATA_BLOB ntparam_blob
, ntdata_blob
;
373 mem_ctx
= talloc_init("try_nttrans");
375 ntparam_blob
.length
= param_len
;
376 ntparam_blob
.data
= param
;
377 ntdata_blob
.length
= data_len
;
378 ntdata_blob
.data
= data
;
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
;
388 status
= smb_raw_nttrans(cli
->tree
, mem_ctx
, &parms
);
390 if (NT_STATUS_IS_ERR(status
)) {
391 DEBUG(1,("Failed to send NT_TRANS\n"));
392 talloc_free(mem_ctx
);
395 *rparam_len
= parms
.out
.params
.length
;
396 *rdata_len
= parms
.out
.data
.length
;
398 talloc_free(mem_ctx
);
404 static NTSTATUS
try_nttrans_len(struct smbcli_state
*cli
,
407 uint8_t *param
, uint8_t *data
,
408 int param_len
, int *data_len
,
409 int *rparam_len
, int *rdata_len
)
411 NTSTATUS ret
=NT_STATUS_OK
;
413 ret
= try_nttrans(cli
, op
, param
, data
, param_len
,
414 PARAM_SIZE
, rparam_len
, rdata_len
);
416 printf("op=%d level=%d ret=%s\n", op
, level
, nt_errstr(ret
));
418 if (!NT_STATUS_IS_OK(ret
)) return ret
;
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;
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
);
431 nttrans_check_hit(format
, op
, level
, ret
);
436 /****************************************************************************
437 check for existance 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
)
444 int rparam_len
, rdata_len
;
445 uint8_t *param
, *data
;
449 mem_ctx
= talloc_init("scan_nttrans");
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
);
456 /* try with a info level only */
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
);
466 /* try with a file descriptor */
468 SSVAL(param
, 0, fnum
);
469 SSVAL(param
, 2, level
);
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
);
478 /* try with a notify style */
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
);
490 /* try with a file name */
492 SSVAL(param
, 0, level
);
495 param_len
+= push_string(
496 ¶m
[6], fname
, PARAM_SIZE
,
497 STR_TERMINATE
| STR_UNICODE
);
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
);
506 /* try with a new file name */
508 SSVAL(param
, 0, level
);
511 param_len
+= push_string(
512 ¶m
[6], "\\newfile.dat", PARAM_SIZE
,
513 STR_TERMINATE
| STR_UNICODE
);
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
);
525 smbcli_mkdir(cli
->tree
, "\\testdir");
527 SSVAL(param
, 0, level
);
528 param_len
+= push_string(¶m
[2], "\\testdir", PARAM_SIZE
,
529 STR_TERMINATE
| STR_UNICODE
);
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
);
539 talloc_free(mem_ctx
);
544 bool torture_nttrans_scan(struct torture_context
*torture
,
545 struct smbcli_state
*cli
)
548 const char *fname
= "\\scanner.dat";
551 fnum
= smbcli_open(cli
->tree
, fname
, O_RDWR
| O_CREAT
| O_TRUNC
,
553 dnum
= smbcli_open(cli
->tree
, "\\", O_RDONLY
, DENY_NONE
);
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
);
561 for (level
= 0x100; level
<= 0x130; level
++) {
562 scan_nttrans(cli
, op
, level
, fnum
, dnum
, fname
);
565 for (level
= 1000; level
< 1050; level
++) {
566 scan_nttrans(cli
, op
, level
, fnum
, dnum
, fname
);
570 printf("nttrans scan finished\n");
575 /* scan for valid base SMB requests */
576 bool torture_smb_scan(struct torture_context
*torture
)
578 static struct smbcli_state
*cli
;
580 struct smbcli_request
*req
;
583 for (op
=0x0;op
<=0xFF;op
++) {
584 if (op
== SMBreadbraw
) continue;
586 if (!torture_open_connection(&cli
, torture
, 0)) {
590 req
= smbcli_request_setup(cli
->tree
, op
, 0, 0);
592 if (!smbcli_request_send(req
)) {
593 smbcli_request_destroy(req
);
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
);
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
));
612 printf("op=0x%x no reply\n", op
);
613 smbcli_request_destroy(req
);
614 continue; /* don't attempt close! */
617 torture_close_connection(cli
);
621 printf("smb scan finished\n");