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"
30 #define PARAM_SIZE 1024
32 /****************************************************************************
33 look for a partial hit
34 ****************************************************************************/
35 static void trans2_check_hit(const char *format
, int op
, int level
, NTSTATUS status
)
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
)) {
45 printf("possible %s hit op=%3d level=%5d status=%s\n",
46 format
, op
, level
, nt_errstr(status
));
50 /****************************************************************************
51 check for existance of a trans2 call
52 ****************************************************************************/
53 static NTSTATUS
try_trans2(struct smbcli_state
*cli
,
55 uint8_t *param
, uint8_t *data
,
56 int param_len
, int data_len
,
57 int *rparam_len
, int *rdata_len
)
64 mem_ctx
= talloc_init("try_trans2");
66 t2
.in
.max_param
= UINT16_MAX
;
67 t2
.in
.max_data
= UINT16_MAX
;
71 t2
.in
.setup_count
= 1;
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
;
78 status
= smb_raw_trans2(cli
->tree
, mem_ctx
, &t2
);
80 *rparam_len
= t2
.out
.params
.length
;
81 *rdata_len
= t2
.out
.data
.length
;
89 static NTSTATUS
try_trans2_len(struct smbcli_state
*cli
,
92 uint8_t *param
, uint8_t *data
,
93 int param_len
, int *data_len
,
94 int *rparam_len
, int *rdata_len
)
96 NTSTATUS ret
=NT_STATUS_OK
;
98 ret
= try_trans2(cli
, op
, param
, data
, param_len
,
99 PARAM_SIZE
, rparam_len
, rdata_len
);
101 printf("op=%d level=%d ret=%s\n", op
, level
, nt_errstr(ret
));
103 if (!NT_STATUS_IS_OK(ret
)) return ret
;
106 while (*data_len
< PARAM_SIZE
) {
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;
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
);
116 trans2_check_hit(format
, op
, level
, ret
);
122 /****************************************************************************
123 check whether a trans2 opnum exists at all
124 ****************************************************************************/
125 static bool trans2_op_exists(struct smbcli_state
*cli
, int op
)
127 int data_len
= PARAM_SIZE
;
128 int param_len
= PARAM_SIZE
;
129 int rparam_len
, rdata_len
;
130 uint8_t *param
, *data
;
131 NTSTATUS status1
, status2
;
134 mem_ctx
= talloc_init("trans2_op_exists");
136 /* try with a info level only */
138 param
= talloc_array(mem_ctx
, uint8_t, param_len
);
139 data
= talloc_array(mem_ctx
, uint8_t, data_len
);
141 memset(param
, 0xFF, param_len
);
142 memset(data
, 0xFF, data_len
);
144 status1
= try_trans2(cli
, 0xFFFF, param
, data
, param_len
, data_len
,
145 &rparam_len
, &rdata_len
);
147 status2
= try_trans2(cli
, op
, param
, data
, param_len
, data_len
,
148 &rparam_len
, &rdata_len
);
150 if (NT_STATUS_EQUAL(status1
, status2
)) {
151 talloc_free(mem_ctx
);
155 printf("Found op %d (status=%s)\n", op
, nt_errstr(status2
));
157 talloc_free(mem_ctx
);
161 /****************************************************************************
162 check for existance of a trans2 call
163 ****************************************************************************/
164 static bool scan_trans2(
165 struct smbcli_state
*cli
, int op
, int level
,
166 int fnum
, int dnum
, int qfnum
, const char *fname
)
170 int rparam_len
, rdata_len
;
171 uint8_t *param
, *data
;
175 mem_ctx
= talloc_init("scan_trans2");
177 data
= talloc_array(mem_ctx
, uint8_t, PARAM_SIZE
);
178 param
= talloc_array(mem_ctx
, uint8_t, PARAM_SIZE
);
180 memset(data
, 0, PARAM_SIZE
);
183 /* try with a info level only */
185 SSVAL(param
, 0, level
);
186 status
= try_trans2_len(cli
, "void", op
, level
, param
, data
, param_len
,
187 &data_len
, &rparam_len
, &rdata_len
);
188 if (NT_STATUS_IS_OK(status
)) {
189 talloc_free(mem_ctx
);
193 /* try with a file descriptor */
195 SSVAL(param
, 0, fnum
);
196 SSVAL(param
, 2, level
);
198 status
= try_trans2_len(cli
, "fnum", op
, level
, param
, data
, param_len
,
199 &data_len
, &rparam_len
, &rdata_len
);
200 if (NT_STATUS_IS_OK(status
)) {
201 talloc_free(mem_ctx
);
205 /* try with a quota file descriptor */
207 SSVAL(param
, 0, qfnum
);
208 SSVAL(param
, 2, level
);
210 status
= try_trans2_len(cli
, "qfnum", op
, level
, param
, data
, param_len
,
211 &data_len
, &rparam_len
, &rdata_len
);
212 if (NT_STATUS_IS_OK(status
)) {
213 talloc_free(mem_ctx
);
217 /* try with a notify style */
219 SSVAL(param
, 0, dnum
);
220 SSVAL(param
, 2, dnum
);
221 SSVAL(param
, 4, level
);
222 status
= try_trans2_len(cli
, "notify", op
, level
, param
, data
,
223 param_len
, &data_len
, &rparam_len
, &rdata_len
);
224 if (NT_STATUS_IS_OK(status
)) {
225 talloc_free(mem_ctx
);
229 /* try with a file name */
231 SSVAL(param
, 0, level
);
234 param_len
+= push_string(
235 ¶m
[6], fname
, PARAM_SIZE
-7,
236 STR_TERMINATE
|STR_UNICODE
);
238 status
= try_trans2_len(cli
, "fname", op
, level
, param
, data
, param_len
,
239 &data_len
, &rparam_len
, &rdata_len
);
240 if (NT_STATUS_IS_OK(status
)) {
241 talloc_free(mem_ctx
);
245 /* try with a new file name */
247 SSVAL(param
, 0, level
);
250 param_len
+= push_string(
251 ¶m
[6], "\\newfile.dat", PARAM_SIZE
-7,
252 STR_TERMINATE
|STR_UNICODE
);
254 status
= try_trans2_len(cli
, "newfile", op
, level
, param
, data
,
255 param_len
, &data_len
, &rparam_len
, &rdata_len
);
256 smbcli_unlink(cli
->tree
, "\\newfile.dat");
257 smbcli_rmdir(cli
->tree
, "\\newfile.dat");
258 if (NT_STATUS_IS_OK(status
)) {
259 talloc_free(mem_ctx
);
264 smbcli_mkdir(cli
->tree
, "\\testdir");
266 SSVAL(param
, 0, level
);
267 param_len
+= push_string(
268 ¶m
[2], "\\testdir", PARAM_SIZE
-3,
269 STR_TERMINATE
|STR_UNICODE
);
271 status
= try_trans2_len(cli
, "dfs", op
, level
, param
, data
, param_len
,
272 &data_len
, &rparam_len
, &rdata_len
);
273 smbcli_rmdir(cli
->tree
, "\\testdir");
274 if (NT_STATUS_IS_OK(status
)) {
275 talloc_free(mem_ctx
);
279 talloc_free(mem_ctx
);
283 bool torture_trans2_scan(struct torture_context
*torture
,
284 struct smbcli_state
*cli
)
287 const char *fname
= "\\scanner.dat";
288 int fnum
, dnum
, qfnum
;
290 fnum
= smbcli_open(cli
->tree
, fname
, O_RDWR
| O_CREAT
| O_TRUNC
, DENY_NONE
);
292 printf("file open failed - %s\n", smbcli_errstr(cli
->tree
));
294 dnum
= smbcli_nt_create_full(cli
->tree
, "\\",
296 SEC_RIGHTS_FILE_READ
,
297 FILE_ATTRIBUTE_NORMAL
,
298 NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
,
300 NTCREATEX_OPTIONS_DIRECTORY
, 0);
302 printf("directory open failed - %s\n", smbcli_errstr(cli
->tree
));
304 qfnum
= smbcli_nt_create_full(cli
->tree
, "\\$Extend\\$Quota:$Q:$INDEX_ALLOCATION",
305 NTCREATEX_FLAGS_EXTENDED
,
306 SEC_FLAG_MAXIMUM_ALLOWED
,
308 NTCREATEX_SHARE_ACCESS_READ
|NTCREATEX_SHARE_ACCESS_WRITE
,
312 printf("quota open failed - %s\n", smbcli_errstr(cli
->tree
));
315 for (op
=OP_MIN
; op
<=OP_MAX
; op
++) {
317 if (!trans2_op_exists(cli
, op
)) {
321 for (level
= 0; level
<= 50; level
++) {
322 scan_trans2(cli
, op
, level
, fnum
, dnum
, qfnum
, fname
);
325 for (level
= 0x100; level
<= 0x130; level
++) {
326 scan_trans2(cli
, op
, level
, fnum
, dnum
, qfnum
, fname
);
329 for (level
= 1000; level
< 1050; level
++) {
330 scan_trans2(cli
, op
, level
, fnum
, dnum
, qfnum
, fname
);
340 /****************************************************************************
341 look for a partial hit
342 ****************************************************************************/
343 static void nttrans_check_hit(const char *format
, int op
, int level
, NTSTATUS status
)
345 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_LEVEL
) ||
346 NT_STATUS_EQUAL(status
, NT_STATUS_NOT_IMPLEMENTED
) ||
347 NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
) ||
348 NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
) ||
349 NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_INFO_CLASS
)) {
353 printf("possible %s hit op=%3d level=%5d status=%s\n",
354 format
, op
, level
, nt_errstr(status
));
358 /****************************************************************************
359 check for existence of a nttrans call
360 ****************************************************************************/
361 static NTSTATUS
try_nttrans(struct smbcli_state
*cli
,
363 uint8_t *param
, uint8_t *data
,
364 int param_len
, int data_len
,
365 int *rparam_len
, int *rdata_len
)
367 struct smb_nttrans parms
;
368 DATA_BLOB ntparam_blob
, ntdata_blob
;
372 mem_ctx
= talloc_init("try_nttrans");
374 ntparam_blob
.length
= param_len
;
375 ntparam_blob
.data
= param
;
376 ntdata_blob
.length
= data_len
;
377 ntdata_blob
.data
= data
;
379 parms
.in
.max_param
= UINT32_MAX
;
380 parms
.in
.max_data
= UINT32_MAX
;
381 parms
.in
.max_setup
= 0;
382 parms
.in
.setup_count
= 0;
383 parms
.in
.function
= op
;
384 parms
.in
.params
= ntparam_blob
;
385 parms
.in
.data
= ntdata_blob
;
387 status
= smb_raw_nttrans(cli
->tree
, mem_ctx
, &parms
);
389 if (NT_STATUS_IS_ERR(status
)) {
390 DEBUG(1,("Failed to send NT_TRANS\n"));
391 talloc_free(mem_ctx
);
394 *rparam_len
= parms
.out
.params
.length
;
395 *rdata_len
= parms
.out
.data
.length
;
397 talloc_free(mem_ctx
);
403 static NTSTATUS
try_nttrans_len(struct smbcli_state
*cli
,
406 uint8_t *param
, uint8_t *data
,
407 int param_len
, int *data_len
,
408 int *rparam_len
, int *rdata_len
)
410 NTSTATUS ret
=NT_STATUS_OK
;
412 ret
= try_nttrans(cli
, op
, param
, data
, param_len
,
413 PARAM_SIZE
, rparam_len
, rdata_len
);
415 printf("op=%d level=%d ret=%s\n", op
, level
, nt_errstr(ret
));
417 if (!NT_STATUS_IS_OK(ret
)) return ret
;
420 while (*data_len
< PARAM_SIZE
) {
421 ret
= try_nttrans(cli
, op
, param
, data
, param_len
,
422 *data_len
, rparam_len
, rdata_len
);
423 if (NT_STATUS_IS_OK(ret
)) break;
426 if (NT_STATUS_IS_OK(ret
)) {
427 printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
428 format
, level
, *data_len
, *rparam_len
, *rdata_len
);
430 nttrans_check_hit(format
, op
, level
, ret
);
435 /****************************************************************************
436 check for existance of a nttrans call
437 ****************************************************************************/
438 static bool scan_nttrans(struct smbcli_state
*cli
, int op
, int level
,
439 int fnum
, int dnum
, const char *fname
)
443 int rparam_len
, rdata_len
;
444 uint8_t *param
, *data
;
448 mem_ctx
= talloc_init("scan_nttrans");
450 param
= talloc_array(mem_ctx
, uint8_t, PARAM_SIZE
);
451 data
= talloc_array(mem_ctx
, uint8_t, PARAM_SIZE
);
452 memset(data
, 0, PARAM_SIZE
);
455 /* try with a info level only */
457 SSVAL(param
, 0, level
);
458 status
= try_nttrans_len(cli
, "void", op
, level
, param
, data
, param_len
,
459 &data_len
, &rparam_len
, &rdata_len
);
460 if (NT_STATUS_IS_OK(status
)) {
461 talloc_free(mem_ctx
);
465 /* try with a file descriptor */
467 SSVAL(param
, 0, fnum
);
468 SSVAL(param
, 2, level
);
470 status
= try_nttrans_len(cli
, "fnum", op
, level
, param
, data
, param_len
,
471 &data_len
, &rparam_len
, &rdata_len
);
472 if (NT_STATUS_IS_OK(status
)) {
473 talloc_free(mem_ctx
);
477 /* try with a notify style */
479 SSVAL(param
, 0, dnum
);
480 SSVAL(param
, 2, dnum
);
481 SSVAL(param
, 4, level
);
482 status
= try_nttrans_len(cli
, "notify", op
, level
, param
, data
,
483 param_len
, &data_len
, &rparam_len
, &rdata_len
);
484 if (NT_STATUS_IS_OK(status
)) {
485 talloc_free(mem_ctx
);
489 /* try with a file name */
491 SSVAL(param
, 0, level
);
494 param_len
+= push_string(
495 ¶m
[6], fname
, PARAM_SIZE
,
496 STR_TERMINATE
| STR_UNICODE
);
498 status
= try_nttrans_len(cli
, "fname", op
, level
, param
, data
,
499 param_len
, &data_len
, &rparam_len
, &rdata_len
);
500 if (NT_STATUS_IS_OK(status
)) {
501 talloc_free(mem_ctx
);
505 /* try with a new file name */
507 SSVAL(param
, 0, level
);
510 param_len
+= push_string(
511 ¶m
[6], "\\newfile.dat", PARAM_SIZE
,
512 STR_TERMINATE
| STR_UNICODE
);
514 status
= try_nttrans_len(cli
, "newfile", op
, level
, param
, data
,
515 param_len
, &data_len
, &rparam_len
, &rdata_len
);
516 smbcli_unlink(cli
->tree
, "\\newfile.dat");
517 smbcli_rmdir(cli
->tree
, "\\newfile.dat");
518 if (NT_STATUS_IS_OK(status
)) {
519 talloc_free(mem_ctx
);
524 smbcli_mkdir(cli
->tree
, "\\testdir");
526 SSVAL(param
, 0, level
);
527 param_len
+= push_string(¶m
[2], "\\testdir", PARAM_SIZE
,
528 STR_TERMINATE
| STR_UNICODE
);
530 status
= try_nttrans_len(cli
, "dfs", op
, level
, param
, data
, param_len
,
531 &data_len
, &rparam_len
, &rdata_len
);
532 smbcli_rmdir(cli
->tree
, "\\testdir");
533 if (NT_STATUS_IS_OK(status
)) {
534 talloc_free(mem_ctx
);
538 talloc_free(mem_ctx
);
543 bool torture_nttrans_scan(struct torture_context
*torture
,
544 struct smbcli_state
*cli
)
547 const char *fname
= "\\scanner.dat";
550 fnum
= smbcli_open(cli
->tree
, fname
, O_RDWR
| O_CREAT
| O_TRUNC
,
552 dnum
= smbcli_open(cli
->tree
, "\\", O_RDONLY
, DENY_NONE
);
554 for (op
=OP_MIN
; op
<=OP_MAX
; op
++) {
555 printf("Scanning op=%d\n", op
);
556 for (level
= 0; level
<= 50; level
++) {
557 scan_nttrans(cli
, op
, level
, fnum
, dnum
, fname
);
560 for (level
= 0x100; level
<= 0x130; level
++) {
561 scan_nttrans(cli
, op
, level
, fnum
, dnum
, fname
);
564 for (level
= 1000; level
< 1050; level
++) {
565 scan_nttrans(cli
, op
, level
, fnum
, dnum
, fname
);
569 printf("nttrans scan finished\n");
574 /* scan for valid base SMB requests */
575 bool torture_smb_scan(struct torture_context
*torture
)
577 static struct smbcli_state
*cli
;
579 struct smbcli_request
*req
;
582 for (op
=0x0;op
<=0xFF;op
++) {
583 if (op
== SMBreadbraw
) continue;
585 if (!torture_open_connection(&cli
, torture
, 0)) {
589 req
= smbcli_request_setup(cli
->tree
, op
, 0, 0);
591 if (!smbcli_request_send(req
)) {
592 smbcli_request_destroy(req
);
597 smbcli_transport_process(cli
->transport
);
598 if (req
->state
> SMBCLI_REQUEST_RECV
) {
599 status
= smbcli_request_simple_recv(req
);
600 printf("op=0x%x status=%s\n", op
, nt_errstr(status
));
601 torture_close_connection(cli
);
606 smbcli_transport_process(cli
->transport
);
607 if (req
->state
> SMBCLI_REQUEST_RECV
) {
608 status
= smbcli_request_simple_recv(req
);
609 printf("op=0x%x status=%s\n", op
, nt_errstr(status
));
611 printf("op=0x%x no reply\n", op
);
612 smbcli_request_destroy(req
);
613 continue; /* don't attempt close! */
616 torture_close_connection(cli
);
620 printf("smb scan finished\n");