2 Unix SMB/CIFS implementation.
6 Copyright (C) Andrew Tridgell 2008
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
27 #include "torture/torture.h"
28 #include "torture/smb2/proto.h"
29 #include "../libcli/smb/smbXcli_base.h"
30 #include "librpc/gen_ndr/ndr_ioctl.h"
33 #define CHECK_STATUS(_status, _expected) \
34 torture_assert_ntstatus_equal_goto(torture, _status, _expected, \
35 ret, done, "Incorrect status")
37 #define CHECK_VALUE(v, correct) \
38 torture_assert_int_equal_goto(torture, v, correct, \
39 ret, done, "Incorrect value")
41 #define FNAME "smb2_readtest.dat"
42 #define DNAME "smb2_readtest.dir"
44 static bool test_read_eof(struct torture_context
*torture
, struct smb2_tree
*tree
)
51 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
55 smb2_util_unlink(tree
, FNAME
);
57 status
= torture_smb2_testfile(tree
, FNAME
, &h
);
58 CHECK_STATUS(status
, NT_STATUS_OK
);
61 rd
.in
.file
.handle
= h
;
64 status
= smb2_read(tree
, tree
, &rd
);
65 CHECK_STATUS(status
, NT_STATUS_END_OF_FILE
);
67 status
= smb2_util_write(tree
, h
, buf
, 0, ARRAY_SIZE(buf
));
68 CHECK_STATUS(status
, NT_STATUS_OK
);
71 rd
.in
.file
.handle
= h
;
76 status
= smb2_read(tree
, tmp_ctx
, &rd
);
77 CHECK_STATUS(status
, NT_STATUS_OK
);
78 CHECK_VALUE(rd
.out
.data
.length
, 10);
82 rd
.in
.offset
= sizeof(buf
);
83 status
= smb2_read(tree
, tmp_ctx
, &rd
);
84 CHECK_STATUS(status
, NT_STATUS_END_OF_FILE
);
88 rd
.in
.offset
= sizeof(buf
);
89 status
= smb2_read(tree
, tmp_ctx
, &rd
);
90 CHECK_STATUS(status
, NT_STATUS_OK
);
91 CHECK_VALUE(rd
.out
.data
.length
, 0);
95 rd
.in
.offset
= sizeof(buf
);
96 status
= smb2_read(tree
, tmp_ctx
, &rd
);
97 CHECK_STATUS(status
, NT_STATUS_END_OF_FILE
);
101 rd
.in
.offset
= sizeof(buf
) - 1;
102 status
= smb2_read(tree
, tmp_ctx
, &rd
);
103 CHECK_STATUS(status
, NT_STATUS_OK
);
104 CHECK_VALUE(rd
.out
.data
.length
, 1);
108 rd
.in
.offset
= sizeof(buf
) - 1;
109 status
= smb2_read(tree
, tmp_ctx
, &rd
);
110 CHECK_STATUS(status
, NT_STATUS_END_OF_FILE
);
112 rd
.in
.min_count
= 0x10000;
115 status
= smb2_read(tree
, tmp_ctx
, &rd
);
116 CHECK_STATUS(status
, NT_STATUS_END_OF_FILE
);
118 rd
.in
.min_count
= 0x10000 - 2;
121 status
= smb2_read(tree
, tmp_ctx
, &rd
);
122 CHECK_STATUS(status
, NT_STATUS_END_OF_FILE
);
124 rd
.in
.min_count
= 10;
127 status
= smb2_read(tree
, tmp_ctx
, &rd
);
128 CHECK_STATUS(status
, NT_STATUS_END_OF_FILE
);
131 talloc_free(tmp_ctx
);
136 static bool test_read_position(struct torture_context
*torture
, struct smb2_tree
*tree
)
140 struct smb2_handle h
;
141 uint8_t buf
[64*1024];
143 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
144 union smb_fileinfo info
;
148 smb2_util_unlink(tree
, FNAME
);
150 status
= torture_smb2_testfile(tree
, FNAME
, &h
);
151 CHECK_STATUS(status
, NT_STATUS_OK
);
153 status
= smb2_util_write(tree
, h
, buf
, 0, ARRAY_SIZE(buf
));
154 CHECK_STATUS(status
, NT_STATUS_OK
);
157 rd
.in
.file
.handle
= h
;
162 status
= smb2_read(tree
, tmp_ctx
, &rd
);
163 CHECK_STATUS(status
, NT_STATUS_OK
);
164 CHECK_VALUE(rd
.out
.data
.length
, 10);
166 info
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
167 info
.generic
.in
.file
.handle
= h
;
169 status
= smb2_getinfo_file(tree
, tmp_ctx
, &info
);
170 CHECK_STATUS(status
, NT_STATUS_OK
);
171 if (torture_setting_bool(torture
, "windows", false)) {
172 CHECK_VALUE(info
.all_info2
.out
.position
, 0);
174 CHECK_VALUE(info
.all_info2
.out
.position
, 10);
179 talloc_free(tmp_ctx
);
183 static bool test_read_dir(struct torture_context
*torture
, struct smb2_tree
*tree
)
187 struct smb2_handle h
;
189 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
191 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
192 if (!NT_STATUS_IS_OK(status
)) {
193 printf(__location__
" Unable to create test directory '%s' - %s\n", DNAME
, nt_errstr(status
));
198 rd
.in
.file
.handle
= h
;
203 status
= smb2_read(tree
, tmp_ctx
, &rd
);
204 CHECK_STATUS(status
, NT_STATUS_INVALID_DEVICE_REQUEST
);
206 rd
.in
.min_count
= 11;
207 status
= smb2_read(tree
, tmp_ctx
, &rd
);
208 CHECK_STATUS(status
, NT_STATUS_INVALID_DEVICE_REQUEST
);
211 rd
.in
.min_count
= 2592;
212 status
= smb2_read(tree
, tmp_ctx
, &rd
);
213 if (torture_setting_bool(torture
, "windows", false)) {
214 CHECK_STATUS(status
, NT_STATUS_END_OF_FILE
);
216 CHECK_STATUS(status
, NT_STATUS_INVALID_DEVICE_REQUEST
);
222 status
= smb2_read(tree
, tmp_ctx
, &rd
);
223 if (torture_setting_bool(torture
, "windows", false)) {
224 CHECK_STATUS(status
, NT_STATUS_OK
);
226 CHECK_STATUS(status
, NT_STATUS_INVALID_DEVICE_REQUEST
);
230 talloc_free(tmp_ctx
);
234 static bool test_read_access(struct torture_context
*torture
,
235 struct smb2_tree
*tree
)
239 struct smb2_handle h
;
240 uint8_t buf
[64 * 1024];
242 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
247 smb2_util_unlink(tree
, FNAME
);
249 status
= torture_smb2_testfile(tree
, FNAME
, &h
);
250 CHECK_STATUS(status
, NT_STATUS_OK
);
252 status
= smb2_util_write(tree
, h
, buf
, 0, ARRAY_SIZE(buf
));
253 CHECK_STATUS(status
, NT_STATUS_OK
);
255 status
= smb2_util_close(tree
, h
);
256 CHECK_STATUS(status
, NT_STATUS_OK
);
258 /* open w/ READ access - success */
259 status
= torture_smb2_testfile_access(
260 tree
, FNAME
, &h
, SEC_FILE_READ_ATTRIBUTE
| SEC_FILE_READ_DATA
);
261 CHECK_STATUS(status
, NT_STATUS_OK
);
264 rd
.in
.file
.handle
= h
;
267 status
= smb2_read(tree
, tree
, &rd
);
268 CHECK_STATUS(status
, NT_STATUS_OK
);
270 status
= smb2_util_close(tree
, h
);
271 CHECK_STATUS(status
, NT_STATUS_OK
);
273 /* open w/ EXECUTE access - success */
274 status
= torture_smb2_testfile_access(
275 tree
, FNAME
, &h
, SEC_FILE_READ_ATTRIBUTE
| SEC_FILE_EXECUTE
);
276 CHECK_STATUS(status
, NT_STATUS_OK
);
279 rd
.in
.file
.handle
= h
;
282 status
= smb2_read(tree
, tree
, &rd
);
283 CHECK_STATUS(status
, NT_STATUS_OK
);
285 status
= smb2_util_close(tree
, h
);
286 CHECK_STATUS(status
, NT_STATUS_OK
);
288 /* open without READ or EXECUTE access - access denied */
289 status
= torture_smb2_testfile_access(tree
, FNAME
, &h
,
290 SEC_FILE_READ_ATTRIBUTE
);
291 CHECK_STATUS(status
, NT_STATUS_OK
);
294 rd
.in
.file
.handle
= h
;
297 status
= smb2_read(tree
, tree
, &rd
);
298 CHECK_STATUS(status
, NT_STATUS_ACCESS_DENIED
);
300 status
= smb2_util_close(tree
, h
);
301 CHECK_STATUS(status
, NT_STATUS_OK
);
304 talloc_free(tmp_ctx
);
309 basic regression test for BUG 14607
310 https://bugzilla.samba.org/show_bug.cgi?id=14607
312 static bool test_read_bug14607(struct torture_context
*torture
,
313 struct smb2_tree
*tree
)
317 struct smb2_handle h
;
318 uint8_t buf
[64 * 1024];
320 uint32_t timeout_msec
;
321 DATA_BLOB out_input_buffer
= data_blob_null
;
322 DATA_BLOB out_output_buffer
= data_blob_null
;
323 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
324 uint8_t *data
= NULL
;
325 uint32_t data_length
= 0;
327 memset(buf
, 0x1f, ARRAY_SIZE(buf
));
330 smb2_util_unlink(tree
, FNAME
);
332 status
= torture_smb2_testfile(tree
, FNAME
, &h
);
333 CHECK_STATUS(status
, NT_STATUS_OK
);
335 status
= smb2_util_write(tree
, h
, buf
, 0, ARRAY_SIZE(buf
));
336 CHECK_STATUS(status
, NT_STATUS_OK
);
339 rd
.in
.file
.handle
= h
;
340 rd
.in
.length
= ARRAY_SIZE(buf
);
342 status
= smb2_read(tree
, tree
, &rd
);
343 CHECK_STATUS(status
, NT_STATUS_OK
);
344 CHECK_VALUE(rd
.out
.data
.length
, ARRAY_SIZE(buf
));
345 torture_assert_mem_equal_goto(torture
, rd
.out
.data
.data
,
346 buf
, ARRAY_SIZE(buf
),
348 "Invalid content smb2_read");
350 timeout_msec
= tree
->session
->transport
->options
.request_timeout
* 1000;
352 status
= smb2cli_read(tree
->session
->transport
->conn
,
354 tree
->session
->smbXcli
,
363 &data
, &data_length
);
364 CHECK_STATUS(status
, NT_STATUS_OK
);
365 CHECK_VALUE(data_length
, ARRAY_SIZE(buf
));
366 torture_assert_mem_equal_goto(torture
, data
,
367 buf
, ARRAY_SIZE(buf
),
369 "Invalid content smb2cli_read");
371 status
= smb2cli_ioctl(tree
->session
->transport
->conn
,
373 tree
->session
->smbXcli
,
375 UINT64_MAX
, /* in_fid_persistent */
376 UINT64_MAX
, /* in_fid_volatile */
377 FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8
,
378 0, /* in_max_input_length */
379 NULL
, /* in_input_buffer */
380 1, /* in_max_output_length */
381 NULL
, /* in_output_buffer */
382 SMB2_IOCTL_FLAG_IS_FSCTL
,
386 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
) ||
387 NT_STATUS_EQUAL(status
, NT_STATUS_FILE_CLOSED
) ||
388 NT_STATUS_EQUAL(status
, NT_STATUS_FS_DRIVER_REQUIRED
) ||
389 NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_DEVICE_REQUEST
))
391 torture_comment(torture
,
392 "FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8: %s\n",
394 torture_skip(torture
, "server doesn't support FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8\n");
396 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8");
398 torture_assert_int_equal(torture
, out_output_buffer
.length
, 0,
402 rd
.in
.file
.handle
= h
;
403 rd
.in
.length
= ARRAY_SIZE(buf
);
405 status
= smb2_read(tree
, tree
, &rd
);
406 CHECK_STATUS(status
, NT_STATUS_OK
);
407 CHECK_VALUE(rd
.out
.data
.length
, ARRAY_SIZE(buf
));
408 torture_assert_mem_equal_goto(torture
, rd
.out
.data
.data
,
409 buf
, ARRAY_SIZE(buf
),
411 "Invalid content after padding smb2_read");
413 status
= smb2cli_read(tree
->session
->transport
->conn
,
415 tree
->session
->smbXcli
,
424 &data
, &data_length
);
425 CHECK_STATUS(status
, NT_STATUS_OK
);
426 CHECK_VALUE(data_length
, ARRAY_SIZE(buf
));
427 torture_assert_mem_equal_goto(torture
, data
,
428 buf
, ARRAY_SIZE(buf
),
430 "Invalid content after padding smb2cli_read");
432 status
= smb2_util_close(tree
, h
);
433 CHECK_STATUS(status
, NT_STATUS_OK
);
436 talloc_free(tmp_ctx
);
441 basic testing of SMB2 read
443 struct torture_suite
*torture_smb2_read_init(TALLOC_CTX
*ctx
)
445 struct torture_suite
*suite
= torture_suite_create(ctx
, "read");
447 torture_suite_add_1smb2_test(suite
, "eof", test_read_eof
);
448 torture_suite_add_1smb2_test(suite
, "position", test_read_position
);
449 torture_suite_add_1smb2_test(suite
, "dir", test_read_dir
);
450 torture_suite_add_1smb2_test(suite
, "access", test_read_access
);
451 torture_suite_add_1smb2_test(suite
, "bug14607",
454 suite
->description
= talloc_strdup(suite
, "SMB2-READ tests");
459 static bool test_aio_cancel(struct torture_context
*tctx
,
460 struct smb2_tree
*tree
)
462 struct smb2_handle h
;
463 uint8_t buf
[64 * 1024];
465 struct smb2_request
*req
= NULL
;
472 smb2_util_unlink(tree
, FNAME
);
474 status
= torture_smb2_testfile(tree
, FNAME
, &h
);
475 torture_assert_ntstatus_ok_goto(
480 "torture_smb2_testfile failed\n");
482 status
= smb2_util_write(tree
, h
, buf
, 0, ARRAY_SIZE(buf
));
483 torture_assert_ntstatus_ok_goto(
488 "smb2_util_write failed\n");
490 status
= smb2_util_close(tree
, h
);
491 torture_assert_ntstatus_ok_goto(
496 "smb2_util_close failed\n");
498 status
= torture_smb2_testfile_access(
499 tree
, FNAME
, &h
, SEC_RIGHTS_FILE_ALL
);
500 torture_assert_ntstatus_ok_goto(
505 "torture_smb2_testfile_access failed\n");
507 r
= (struct smb2_read
) {
514 req
= smb2_read_send(tree
, &r
);
520 "smb2_read_send failed\n");
522 while (!req
->cancel
.can_cancel
) {
523 rc
= tevent_loop_once(tctx
->ev
);
529 "tevent_loop_once failed\n");
532 status
= smb2_cancel(req
);
533 torture_assert_ntstatus_ok_goto(
538 "smb2_cancel failed\n");
540 status
= smb2_read_recv(req
, tree
, &r
);
541 torture_assert_ntstatus_ok_goto(
546 "smb2_read_recv failed\n");
548 status
= smb2_util_close(tree
, h
);
549 torture_assert_ntstatus_ok_goto(
554 "smb2_util_close failed\n");
557 smb2_util_unlink(tree
, FNAME
);
562 * aio testing against share with VFS module "delay_inject"
564 struct torture_suite
*torture_smb2_aio_delay_init(TALLOC_CTX
*ctx
)
566 struct torture_suite
*suite
= torture_suite_create(ctx
, "aio_delay");
568 torture_suite_add_1smb2_test(suite
, "aio_cancel", test_aio_cancel
);
570 suite
->description
= talloc_strdup(suite
, "SMB2 delayed aio tests");