2 Unix SMB/CIFS implementation.
4 test suite for SMB2 ioctl operations
6 Copyright (C) David Disseldorp 2011-2013
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 "librpc/gen_ndr/security.h"
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "torture/torture.h"
27 #include "torture/smb2/proto.h"
28 #include "../libcli/smb/smbXcli_base.h"
29 #include "librpc/gen_ndr/ndr_ioctl.h"
31 #define FNAME "testfsctl.dat"
32 #define FNAME2 "testfsctl2.dat"
33 #define DNAME "testfsctl_dir"
36 basic testing of SMB2 shadow copy calls
38 static bool test_ioctl_get_shadow_copy(struct torture_context
*torture
,
39 struct smb2_tree
*tree
)
44 union smb_ioctl ioctl
;
45 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
47 smb2_util_unlink(tree
, FNAME
);
49 status
= torture_smb2_testfile(tree
, FNAME
, &h
);
50 torture_assert_ntstatus_ok(torture
, status
, "create write");
53 status
= smb2_util_write(tree
, h
, buf
, 0, ARRAY_SIZE(buf
));
54 torture_assert_ntstatus_ok(torture
, status
, "write");
57 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
58 ioctl
.smb2
.in
.file
.handle
= h
;
59 ioctl
.smb2
.in
.function
= FSCTL_SRV_ENUM_SNAPS
;
60 ioctl
.smb2
.in
.max_response_size
= 16;
61 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
63 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
64 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)
65 || NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_DEVICE_REQUEST
)) {
66 torture_skip(torture
, "FSCTL_SRV_ENUM_SNAPS not supported\n");
68 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_ENUM_SNAPS");
74 basic testing of the SMB2 server side copy ioctls
76 static bool test_ioctl_req_resume_key(struct torture_context
*torture
,
77 struct smb2_tree
*tree
)
82 union smb_ioctl ioctl
;
83 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
84 struct req_resume_key_rsp res_key
;
85 enum ndr_err_code ndr_ret
;
87 smb2_util_unlink(tree
, FNAME
);
89 status
= torture_smb2_testfile(tree
, FNAME
, &h
);
90 torture_assert_ntstatus_ok(torture
, status
, "create write");
93 status
= smb2_util_write(tree
, h
, buf
, 0, ARRAY_SIZE(buf
));
94 torture_assert_ntstatus_ok(torture
, status
, "write");
97 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
98 ioctl
.smb2
.in
.file
.handle
= h
;
99 ioctl
.smb2
.in
.function
= FSCTL_SRV_REQUEST_RESUME_KEY
;
100 ioctl
.smb2
.in
.max_response_size
= 32;
101 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
103 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
104 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_REQUEST_RESUME_KEY");
106 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
, &res_key
,
107 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
108 torture_assert_ndr_success(torture
, ndr_ret
,
109 "ndr_pull_req_resume_key_rsp");
111 ndr_print_debug((ndr_print_fn_t
)ndr_print_req_resume_key_rsp
, "yo", &res_key
);
113 talloc_free(tmp_ctx
);
117 static uint64_t patt_hash(uint64_t off
)
122 static bool check_pattern(struct torture_context
*torture
,
123 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
124 struct smb2_handle h
, uint64_t off
, uint64_t len
,
132 r
.in
.file
.handle
= h
;
135 status
= smb2_read(tree
, mem_ctx
, &r
);
136 torture_assert_ntstatus_ok(torture
, status
, "read");
138 torture_assert_u64_equal(torture
, r
.out
.data
.length
, len
,
139 "read data len mismatch");
141 for (i
= 0; i
<= len
- 8; i
+= 8, patt_off
+= 8) {
142 uint64_t data
= BVAL(r
.out
.data
.data
, i
);
143 torture_assert_u64_equal(torture
, data
, patt_hash(patt_off
),
144 talloc_asprintf(torture
, "read data "
145 "pattern bad at %llu\n",
146 (unsigned long long)i
));
149 talloc_free(r
.out
.data
.data
);
153 static bool test_setup_open(struct torture_context
*torture
,
154 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
156 struct smb2_handle
*fh
,
157 uint32_t desired_access
,
158 uint32_t file_attributes
)
160 struct smb2_create io
;
164 io
.in
.desired_access
= desired_access
;
165 io
.in
.file_attributes
= file_attributes
;
166 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
168 NTCREATEX_SHARE_ACCESS_DELETE
|
169 NTCREATEX_SHARE_ACCESS_READ
|
170 NTCREATEX_SHARE_ACCESS_WRITE
;
171 if (file_attributes
& FILE_ATTRIBUTE_DIRECTORY
) {
172 io
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
176 status
= smb2_create(tree
, mem_ctx
, &io
);
177 torture_assert_ntstatus_ok(torture
, status
, "file create");
179 *fh
= io
.out
.file
.handle
;
184 static bool test_setup_create_fill(struct torture_context
*torture
,
185 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
187 struct smb2_handle
*fh
,
189 uint32_t desired_access
,
190 uint32_t file_attributes
)
195 uint8_t *buf
= talloc_zero_size(mem_ctx
, size
);
196 torture_assert(torture
, (buf
!= NULL
), "no memory for file data buf");
198 smb2_util_unlink(tree
, fname
);
200 ok
= test_setup_open(torture
, tree
, mem_ctx
,
205 torture_assert(torture
, ok
, "file open");
208 uint64_t cur_off
= 0;
209 for (i
= 0; i
<= size
- 8; i
+= 8) {
210 SBVAL(buf
, i
, patt_hash(i
));
213 uint64_t io_sz
= MIN(1024 * 1024, size
);
214 status
= smb2_util_write(tree
, *fh
,
215 buf
+ cur_off
, cur_off
, io_sz
);
216 torture_assert_ntstatus_ok(torture
, status
, "file write");
225 static bool test_setup_copy_chunk(struct torture_context
*torture
,
226 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
228 struct smb2_handle
*src_h
,
230 uint32_t src_desired_access
,
231 struct smb2_handle
*dest_h
,
233 uint32_t dest_desired_access
,
234 struct srv_copychunk_copy
*cc_copy
,
235 union smb_ioctl
*ioctl
)
237 struct req_resume_key_rsp res_key
;
240 enum ndr_err_code ndr_ret
;
242 ok
= test_setup_create_fill(torture
, tree
, mem_ctx
, FNAME
,
243 src_h
, src_size
, src_desired_access
,
244 FILE_ATTRIBUTE_NORMAL
);
245 torture_assert(torture
, ok
, "src file create fill");
247 ok
= test_setup_create_fill(torture
, tree
, mem_ctx
, FNAME2
,
248 dest_h
, dest_size
, dest_desired_access
,
249 FILE_ATTRIBUTE_NORMAL
);
250 torture_assert(torture
, ok
, "dest file create fill");
252 ZERO_STRUCTPN(ioctl
);
253 ioctl
->smb2
.level
= RAW_IOCTL_SMB2
;
254 ioctl
->smb2
.in
.file
.handle
= *src_h
;
255 ioctl
->smb2
.in
.function
= FSCTL_SRV_REQUEST_RESUME_KEY
;
256 /* Allow for Key + ContextLength + Context */
257 ioctl
->smb2
.in
.max_response_size
= 32;
258 ioctl
->smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
260 status
= smb2_ioctl(tree
, mem_ctx
, &ioctl
->smb2
);
261 torture_assert_ntstatus_ok(torture
, status
,
262 "FSCTL_SRV_REQUEST_RESUME_KEY");
264 ndr_ret
= ndr_pull_struct_blob(&ioctl
->smb2
.out
.out
, mem_ctx
, &res_key
,
265 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
267 torture_assert_ndr_success(torture
, ndr_ret
,
268 "ndr_pull_req_resume_key_rsp");
270 ZERO_STRUCTPN(ioctl
);
271 ioctl
->smb2
.level
= RAW_IOCTL_SMB2
;
272 ioctl
->smb2
.in
.file
.handle
= *dest_h
;
273 ioctl
->smb2
.in
.function
= FSCTL_SRV_COPYCHUNK
;
274 ioctl
->smb2
.in
.max_response_size
= sizeof(struct srv_copychunk_rsp
);
275 ioctl
->smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
277 ZERO_STRUCTPN(cc_copy
);
278 memcpy(cc_copy
->source_key
, res_key
.resume_key
, ARRAY_SIZE(cc_copy
->source_key
));
279 cc_copy
->chunk_count
= nchunks
;
280 cc_copy
->chunks
= talloc_zero_array(mem_ctx
, struct srv_copychunk
, nchunks
);
281 torture_assert(torture
, (cc_copy
->chunks
!= NULL
), "no memory for chunks");
287 static bool check_copy_chunk_rsp(struct torture_context
*torture
,
288 struct srv_copychunk_rsp
*cc_rsp
,
289 uint32_t ex_chunks_written
,
290 uint32_t ex_chunk_bytes_written
,
291 uint32_t ex_total_bytes_written
)
293 torture_assert_int_equal(torture
, cc_rsp
->chunks_written
,
294 ex_chunks_written
, "num chunks");
295 torture_assert_int_equal(torture
, cc_rsp
->chunk_bytes_written
,
296 ex_chunk_bytes_written
, "chunk bytes written");
297 torture_assert_int_equal(torture
, cc_rsp
->total_bytes_written
,
298 ex_total_bytes_written
, "chunk total bytes");
302 static bool test_ioctl_copy_chunk_simple(struct torture_context
*torture
,
303 struct smb2_tree
*tree
)
305 struct smb2_handle src_h
;
306 struct smb2_handle dest_h
;
308 union smb_ioctl ioctl
;
309 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
310 struct srv_copychunk_copy cc_copy
;
311 struct srv_copychunk_rsp cc_rsp
;
312 enum ndr_err_code ndr_ret
;
315 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
317 &src_h
, 4096, /* fill 4096 byte src file */
319 &dest_h
, 0, /* 0 byte dest file */
324 torture_fail(torture
, "setup copy chunk error");
327 /* copy all src file data (via a single chunk desc) */
328 cc_copy
.chunks
[0].source_off
= 0;
329 cc_copy
.chunks
[0].target_off
= 0;
330 cc_copy
.chunks
[0].length
= 4096;
332 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
334 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
335 torture_assert_ndr_success(torture
, ndr_ret
,
336 "ndr_push_srv_copychunk_copy");
338 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
339 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
341 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
343 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
344 torture_assert_ndr_success(torture
, ndr_ret
,
345 "ndr_pull_srv_copychunk_rsp");
347 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
348 1, /* chunks written */
349 0, /* chunk bytes unsuccessfully written */
350 4096); /* total bytes written */
352 torture_fail(torture
, "bad copy chunk response data");
355 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
357 torture_fail(torture
, "inconsistent file data");
360 smb2_util_close(tree
, src_h
);
361 smb2_util_close(tree
, dest_h
);
362 talloc_free(tmp_ctx
);
366 static bool test_ioctl_copy_chunk_multi(struct torture_context
*torture
,
367 struct smb2_tree
*tree
)
369 struct smb2_handle src_h
;
370 struct smb2_handle dest_h
;
372 union smb_ioctl ioctl
;
373 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
374 struct srv_copychunk_copy cc_copy
;
375 struct srv_copychunk_rsp cc_rsp
;
376 enum ndr_err_code ndr_ret
;
379 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
381 &src_h
, 8192, /* src file */
383 &dest_h
, 0, /* dest file */
388 torture_fail(torture
, "setup copy chunk error");
391 /* copy all src file data via two chunks */
392 cc_copy
.chunks
[0].source_off
= 0;
393 cc_copy
.chunks
[0].target_off
= 0;
394 cc_copy
.chunks
[0].length
= 4096;
396 cc_copy
.chunks
[1].source_off
= 4096;
397 cc_copy
.chunks
[1].target_off
= 4096;
398 cc_copy
.chunks
[1].length
= 4096;
400 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
402 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
403 torture_assert_ndr_success(torture
, ndr_ret
,
404 "ndr_push_srv_copychunk_copy");
406 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
407 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
409 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
411 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
412 torture_assert_ndr_success(torture
, ndr_ret
,
413 "ndr_pull_srv_copychunk_rsp");
415 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
416 2, /* chunks written */
417 0, /* chunk bytes unsuccessfully written */
418 8192); /* total bytes written */
420 torture_fail(torture
, "bad copy chunk response data");
423 smb2_util_close(tree
, src_h
);
424 smb2_util_close(tree
, dest_h
);
425 talloc_free(tmp_ctx
);
429 static bool test_ioctl_copy_chunk_tiny(struct torture_context
*torture
,
430 struct smb2_tree
*tree
)
432 struct smb2_handle src_h
;
433 struct smb2_handle dest_h
;
435 union smb_ioctl ioctl
;
436 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
437 struct srv_copychunk_copy cc_copy
;
438 struct srv_copychunk_rsp cc_rsp
;
439 enum ndr_err_code ndr_ret
;
442 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
444 &src_h
, 100, /* src file */
446 &dest_h
, 0, /* dest file */
451 torture_fail(torture
, "setup copy chunk error");
454 /* copy all src file data via two chunks, sub block size chunks */
455 cc_copy
.chunks
[0].source_off
= 0;
456 cc_copy
.chunks
[0].target_off
= 0;
457 cc_copy
.chunks
[0].length
= 50;
459 cc_copy
.chunks
[1].source_off
= 50;
460 cc_copy
.chunks
[1].target_off
= 50;
461 cc_copy
.chunks
[1].length
= 50;
463 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
465 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
466 torture_assert_ndr_success(torture
, ndr_ret
,
467 "ndr_push_srv_copychunk_copy");
469 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
470 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
472 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
474 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
475 torture_assert_ndr_success(torture
, ndr_ret
,
476 "ndr_pull_srv_copychunk_rsp");
478 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
479 2, /* chunks written */
480 0, /* chunk bytes unsuccessfully written */
481 100); /* total bytes written */
483 torture_fail(torture
, "bad copy chunk response data");
486 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 100, 0);
488 torture_fail(torture
, "inconsistent file data");
491 smb2_util_close(tree
, src_h
);
492 smb2_util_close(tree
, dest_h
);
493 talloc_free(tmp_ctx
);
497 static bool test_ioctl_copy_chunk_over(struct torture_context
*torture
,
498 struct smb2_tree
*tree
)
500 struct smb2_handle src_h
;
501 struct smb2_handle dest_h
;
503 union smb_ioctl ioctl
;
504 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
505 struct srv_copychunk_copy cc_copy
;
506 struct srv_copychunk_rsp cc_rsp
;
507 enum ndr_err_code ndr_ret
;
510 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
512 &src_h
, 8192, /* src file */
514 &dest_h
, 4096, /* dest file */
519 torture_fail(torture
, "setup copy chunk error");
522 /* first chunk overwrites existing dest data */
523 cc_copy
.chunks
[0].source_off
= 0;
524 cc_copy
.chunks
[0].target_off
= 0;
525 cc_copy
.chunks
[0].length
= 4096;
527 /* second chunk overwrites the first */
528 cc_copy
.chunks
[1].source_off
= 4096;
529 cc_copy
.chunks
[1].target_off
= 0;
530 cc_copy
.chunks
[1].length
= 4096;
532 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
534 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
535 torture_assert_ndr_success(torture
, ndr_ret
,
536 "ndr_push_srv_copychunk_copy");
538 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
539 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
541 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
543 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
544 torture_assert_ndr_success(torture
, ndr_ret
,
545 "ndr_pull_srv_copychunk_rsp");
547 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
548 2, /* chunks written */
549 0, /* chunk bytes unsuccessfully written */
550 8192); /* total bytes written */
552 torture_fail(torture
, "bad copy chunk response data");
555 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 4096);
557 torture_fail(torture
, "inconsistent file data");
560 smb2_util_close(tree
, src_h
);
561 smb2_util_close(tree
, dest_h
);
562 talloc_free(tmp_ctx
);
566 static bool test_ioctl_copy_chunk_append(struct torture_context
*torture
,
567 struct smb2_tree
*tree
)
569 struct smb2_handle src_h
;
570 struct smb2_handle dest_h
;
572 union smb_ioctl ioctl
;
573 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
574 struct srv_copychunk_copy cc_copy
;
575 struct srv_copychunk_rsp cc_rsp
;
576 enum ndr_err_code ndr_ret
;
579 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
581 &src_h
, 4096, /* src file */
583 &dest_h
, 0, /* dest file */
588 torture_fail(torture
, "setup copy chunk error");
591 cc_copy
.chunks
[0].source_off
= 0;
592 cc_copy
.chunks
[0].target_off
= 0;
593 cc_copy
.chunks
[0].length
= 4096;
595 /* second chunk appends the same data to the first */
596 cc_copy
.chunks
[1].source_off
= 0;
597 cc_copy
.chunks
[1].target_off
= 4096;
598 cc_copy
.chunks
[1].length
= 4096;
600 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
602 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
603 torture_assert_ndr_success(torture
, ndr_ret
,
604 "ndr_push_srv_copychunk_copy");
606 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
607 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
609 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
611 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
612 torture_assert_ndr_success(torture
, ndr_ret
,
613 "ndr_pull_srv_copychunk_rsp");
615 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
616 2, /* chunks written */
617 0, /* chunk bytes unsuccessfully written */
618 8192); /* total bytes written */
620 torture_fail(torture
, "bad copy chunk response data");
623 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
625 torture_fail(torture
, "inconsistent file data");
628 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 4096, 4096, 0);
630 torture_fail(torture
, "inconsistent file data");
633 smb2_util_close(tree
, src_h
);
634 smb2_util_close(tree
, dest_h
);
635 talloc_free(tmp_ctx
);
639 static bool test_ioctl_copy_chunk_limits(struct torture_context
*torture
,
640 struct smb2_tree
*tree
)
642 struct smb2_handle src_h
;
643 struct smb2_handle dest_h
;
645 union smb_ioctl ioctl
;
646 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
647 struct srv_copychunk_copy cc_copy
;
648 struct srv_copychunk_rsp cc_rsp
;
649 enum ndr_err_code ndr_ret
;
652 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
654 &src_h
, 4096, /* src file */
656 &dest_h
, 0, /* dest file */
661 torture_fail(torture
, "setup copy chunk error");
664 /* send huge chunk length request */
665 cc_copy
.chunks
[0].source_off
= 0;
666 cc_copy
.chunks
[0].target_off
= 0;
667 cc_copy
.chunks
[0].length
= UINT_MAX
;
669 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
671 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
672 torture_assert_ndr_success(torture
, ndr_ret
, "marshalling request");
674 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
675 torture_assert_ntstatus_equal(torture
, status
,
676 NT_STATUS_INVALID_PARAMETER
,
677 "bad oversize chunk response");
679 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
681 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
682 torture_assert_ndr_success(torture
, ndr_ret
, "unmarshalling response");
684 torture_comment(torture
, "limit max chunks, got %u\n",
685 cc_rsp
.chunks_written
);
686 torture_comment(torture
, "limit max chunk len, got %u\n",
687 cc_rsp
.chunk_bytes_written
);
688 torture_comment(torture
, "limit max total bytes, got %u\n",
689 cc_rsp
.total_bytes_written
);
691 smb2_util_close(tree
, src_h
);
692 smb2_util_close(tree
, dest_h
);
693 talloc_free(tmp_ctx
);
697 static bool test_ioctl_copy_chunk_src_lck(struct torture_context
*torture
,
698 struct smb2_tree
*tree
)
700 struct smb2_handle src_h
;
701 struct smb2_handle src_h2
;
702 struct smb2_handle dest_h
;
704 union smb_ioctl ioctl
;
705 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
706 struct srv_copychunk_copy cc_copy
;
707 struct srv_copychunk_rsp cc_rsp
;
708 enum ndr_err_code ndr_ret
;
710 struct smb2_lock lck
;
711 struct smb2_lock_element el
[1];
713 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
715 &src_h
, 4096, /* src file */
717 &dest_h
, 0, /* dest file */
722 torture_fail(torture
, "setup copy chunk error");
725 cc_copy
.chunks
[0].source_off
= 0;
726 cc_copy
.chunks
[0].target_off
= 0;
727 cc_copy
.chunks
[0].length
= 4096;
729 /* open and lock the copychunk src file */
730 status
= torture_smb2_testfile(tree
, FNAME
, &src_h2
);
731 torture_assert_ntstatus_ok(torture
, status
, "2nd src open");
733 lck
.in
.lock_count
= 0x0001;
734 lck
.in
.lock_sequence
= 0x00000000;
735 lck
.in
.file
.handle
= src_h2
;
737 el
[0].offset
= cc_copy
.chunks
[0].source_off
;
738 el
[0].length
= cc_copy
.chunks
[0].length
;
740 el
[0].flags
= SMB2_LOCK_FLAG_EXCLUSIVE
;
742 status
= smb2_lock(tree
, &lck
);
743 torture_assert_ntstatus_ok(torture
, status
, "lock");
745 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
747 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
748 torture_assert_ndr_success(torture
, ndr_ret
,
749 "ndr_push_srv_copychunk_copy");
751 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
753 * 2k12 & Samba return lock_conflict, Windows 7 & 2k8 return success...
755 * Edgar Olougouna @ MS wrote:
756 * Regarding the FSCTL_SRV_COPYCHUNK and STATUS_FILE_LOCK_CONFLICT
757 * discrepancy observed between Windows versions, we confirm that the
758 * behavior change is expected.
760 * CopyChunk in Windows Server 2012 use regular Readfile/Writefile APIs
761 * to move the chunks from the source to the destination.
762 * These ReadFile/WriteFile APIs go through the byte-range lock checks,
763 * and this explains the observed STATUS_FILE_LOCK_CONFLICT error.
765 * Prior to Windows Server 2012, CopyChunk used mapped sections to move
766 * the data. And byte range locks are not enforced on mapped I/O, and
767 * this explains the STATUS_SUCCESS observed on Windows Server 2008 R2.
769 torture_assert_ntstatus_equal(torture
, status
,
770 NT_STATUS_FILE_LOCK_CONFLICT
,
771 "FSCTL_SRV_COPYCHUNK locked");
773 /* should get cc response data with the lock conflict status */
774 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
776 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
777 torture_assert_ndr_success(torture
, ndr_ret
,
778 "ndr_pull_srv_copychunk_rsp");
779 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
780 0, /* chunks written */
781 0, /* chunk bytes unsuccessfully written */
782 0); /* total bytes written */
784 lck
.in
.lock_count
= 0x0001;
785 lck
.in
.lock_sequence
= 0x00000001;
786 lck
.in
.file
.handle
= src_h2
;
788 el
[0].offset
= cc_copy
.chunks
[0].source_off
;
789 el
[0].length
= cc_copy
.chunks
[0].length
;
791 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
792 status
= smb2_lock(tree
, &lck
);
793 torture_assert_ntstatus_ok(torture
, status
, "unlock");
795 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
796 torture_assert_ntstatus_ok(torture
, status
,
797 "FSCTL_SRV_COPYCHUNK unlocked");
799 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
801 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
802 torture_assert_ndr_success(torture
, ndr_ret
,
803 "ndr_pull_srv_copychunk_rsp");
805 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
806 1, /* chunks written */
807 0, /* chunk bytes unsuccessfully written */
808 4096); /* total bytes written */
810 torture_fail(torture
, "bad copy chunk response data");
813 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
815 torture_fail(torture
, "inconsistent file data");
818 smb2_util_close(tree
, src_h2
);
819 smb2_util_close(tree
, src_h
);
820 smb2_util_close(tree
, dest_h
);
821 talloc_free(tmp_ctx
);
825 static bool test_ioctl_copy_chunk_dest_lck(struct torture_context
*torture
,
826 struct smb2_tree
*tree
)
828 struct smb2_handle src_h
;
829 struct smb2_handle dest_h
;
830 struct smb2_handle dest_h2
;
832 union smb_ioctl ioctl
;
833 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
834 struct srv_copychunk_copy cc_copy
;
835 struct srv_copychunk_rsp cc_rsp
;
836 enum ndr_err_code ndr_ret
;
838 struct smb2_lock lck
;
839 struct smb2_lock_element el
[1];
841 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
843 &src_h
, 4096, /* src file */
845 &dest_h
, 4096, /* dest file */
850 torture_fail(torture
, "setup copy chunk error");
853 cc_copy
.chunks
[0].source_off
= 0;
854 cc_copy
.chunks
[0].target_off
= 0;
855 cc_copy
.chunks
[0].length
= 4096;
857 /* open and lock the copychunk dest file */
858 status
= torture_smb2_testfile(tree
, FNAME2
, &dest_h2
);
859 torture_assert_ntstatus_ok(torture
, status
, "2nd src open");
861 lck
.in
.lock_count
= 0x0001;
862 lck
.in
.lock_sequence
= 0x00000000;
863 lck
.in
.file
.handle
= dest_h2
;
865 el
[0].offset
= cc_copy
.chunks
[0].target_off
;
866 el
[0].length
= cc_copy
.chunks
[0].length
;
868 el
[0].flags
= SMB2_LOCK_FLAG_EXCLUSIVE
;
870 status
= smb2_lock(tree
, &lck
);
871 torture_assert_ntstatus_ok(torture
, status
, "lock");
873 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
875 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
876 torture_assert_ndr_success(torture
, ndr_ret
,
877 "ndr_push_srv_copychunk_copy");
879 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
880 torture_assert_ntstatus_equal(torture
, status
,
881 NT_STATUS_FILE_LOCK_CONFLICT
,
882 "FSCTL_SRV_COPYCHUNK locked");
884 lck
.in
.lock_count
= 0x0001;
885 lck
.in
.lock_sequence
= 0x00000001;
886 lck
.in
.file
.handle
= dest_h2
;
888 el
[0].offset
= cc_copy
.chunks
[0].target_off
;
889 el
[0].length
= cc_copy
.chunks
[0].length
;
891 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
892 status
= smb2_lock(tree
, &lck
);
893 torture_assert_ntstatus_ok(torture
, status
, "unlock");
895 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
896 torture_assert_ntstatus_ok(torture
, status
,
897 "FSCTL_SRV_COPYCHUNK unlocked");
899 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
901 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
902 torture_assert_ndr_success(torture
, ndr_ret
,
903 "ndr_pull_srv_copychunk_rsp");
905 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
906 1, /* chunks written */
907 0, /* chunk bytes unsuccessfully written */
908 4096); /* total bytes written */
910 torture_fail(torture
, "bad copy chunk response data");
913 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
915 torture_fail(torture
, "inconsistent file data");
918 smb2_util_close(tree
, dest_h2
);
919 smb2_util_close(tree
, src_h
);
920 smb2_util_close(tree
, dest_h
);
921 talloc_free(tmp_ctx
);
925 static bool test_ioctl_copy_chunk_bad_key(struct torture_context
*torture
,
926 struct smb2_tree
*tree
)
928 struct smb2_handle src_h
;
929 struct smb2_handle dest_h
;
931 union smb_ioctl ioctl
;
932 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
933 struct srv_copychunk_copy cc_copy
;
934 enum ndr_err_code ndr_ret
;
937 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
946 torture_fail(torture
, "setup copy chunk error");
949 /* overwrite the resume key with a bogus value */
950 memcpy(cc_copy
.source_key
, "deadbeefdeadbeefdeadbeef", 24);
952 cc_copy
.chunks
[0].source_off
= 0;
953 cc_copy
.chunks
[0].target_off
= 0;
954 cc_copy
.chunks
[0].length
= 4096;
956 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
958 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
959 torture_assert_ndr_success(torture
, ndr_ret
,
960 "ndr_push_srv_copychunk_copy");
962 /* Server 2k12 returns NT_STATUS_OBJECT_NAME_NOT_FOUND */
963 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
964 torture_assert_ntstatus_equal(torture
, status
,
965 NT_STATUS_OBJECT_NAME_NOT_FOUND
,
966 "FSCTL_SRV_COPYCHUNK");
968 smb2_util_close(tree
, src_h
);
969 smb2_util_close(tree
, dest_h
);
970 talloc_free(tmp_ctx
);
974 static bool test_ioctl_copy_chunk_src_is_dest(struct torture_context
*torture
,
975 struct smb2_tree
*tree
)
977 struct smb2_handle src_h
;
978 struct smb2_handle dest_h
;
980 union smb_ioctl ioctl
;
981 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
982 struct srv_copychunk_copy cc_copy
;
983 struct srv_copychunk_rsp cc_rsp
;
984 enum ndr_err_code ndr_ret
;
987 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
996 torture_fail(torture
, "setup copy chunk error");
999 /* the source is also the destination */
1000 ioctl
.smb2
.in
.file
.handle
= src_h
;
1002 /* non-overlapping */
1003 cc_copy
.chunks
[0].source_off
= 0;
1004 cc_copy
.chunks
[0].target_off
= 4096;
1005 cc_copy
.chunks
[0].length
= 4096;
1007 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1009 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1010 torture_assert_ndr_success(torture
, ndr_ret
,
1011 "ndr_push_srv_copychunk_copy");
1013 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1014 torture_assert_ntstatus_ok(torture
, status
,
1015 "FSCTL_SRV_COPYCHUNK");
1017 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1019 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1020 torture_assert_ndr_success(torture
, ndr_ret
,
1021 "ndr_pull_srv_copychunk_rsp");
1023 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1024 1, /* chunks written */
1025 0, /* chunk bytes unsuccessfully written */
1026 4096); /* total bytes written */
1028 torture_fail(torture
, "bad copy chunk response data");
1031 ok
= check_pattern(torture
, tree
, tmp_ctx
, src_h
, 0, 4096, 0);
1033 torture_fail(torture
, "inconsistent file data");
1035 ok
= check_pattern(torture
, tree
, tmp_ctx
, src_h
, 4096, 4096, 0);
1037 torture_fail(torture
, "inconsistent file data");
1040 smb2_util_close(tree
, src_h
);
1041 smb2_util_close(tree
, dest_h
);
1042 talloc_free(tmp_ctx
);
1047 * Test a single-chunk copychunk request, where the source and target ranges
1048 * overlap, and the SourceKey refers to the same target file. E.g:
1052 * File: src_and_dest
1053 * Offset: 0123456789
1058 * FSCTL_SRV_COPYCHUNK(src_and_dest)
1059 * SourceKey = SRV_REQUEST_RESUME_KEY(src_and_dest)
1061 * Chunks[0].SourceOffset = 0
1062 * Chunks[0].TargetOffset = 4
1063 * Chunks[0].Length = 6
1067 * File: src_and_dest
1068 * Offset: 0123456789
1071 * The resultant contents of src_and_dest is dependent on the server's
1072 * copy algorithm. In the above example, the server uses an IO buffer
1073 * large enough to hold the entire six-byte source data before writing
1074 * to TargetOffset. If the server were to use a four-byte IO buffer and
1075 * started reads/writes from the lowest offset, then the two overlapping
1076 * bytes in the above example would be overwritten before being read. The
1077 * resultant file contents would be abcdabcdab.
1079 * Windows 2008r2 appears to use a 2048 byte copy buffer, overlapping bytes
1080 * after this offset are written before being read. Windows 2012 on the
1081 * other hand appears to use a buffer large enough to hold its maximum
1082 * supported chunk size (1M). Samba currently uses a 64k copy buffer by
1083 * default (vfs_cc_state.buf).
1085 * This test uses an 8-byte overlap at 2040-2048, so that it passes against
1086 * Windows 2008r2, 2012 and Samba servers. Note, 2008GM fails, as it appears
1087 * to use a different copy algorithm to 2008r2.
1090 test_ioctl_copy_chunk_src_is_dest_overlap(struct torture_context
*torture
,
1091 struct smb2_tree
*tree
)
1093 struct smb2_handle src_h
;
1094 struct smb2_handle dest_h
;
1096 union smb_ioctl ioctl
;
1097 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1098 struct srv_copychunk_copy cc_copy
;
1099 struct srv_copychunk_rsp cc_rsp
;
1100 enum ndr_err_code ndr_ret
;
1103 /* exceed the vfs_default copy buffer */
1104 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1107 SEC_RIGHTS_FILE_ALL
,
1109 SEC_RIGHTS_FILE_ALL
,
1113 torture_fail(torture
, "setup copy chunk error");
1116 /* the source is also the destination */
1117 ioctl
.smb2
.in
.file
.handle
= src_h
;
1119 /* 8 bytes overlap between source and target ranges */
1120 cc_copy
.chunks
[0].source_off
= 0;
1121 cc_copy
.chunks
[0].target_off
= 2048 - 8;
1122 cc_copy
.chunks
[0].length
= 2048;
1124 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1126 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1127 torture_assert_ndr_success(torture
, ndr_ret
,
1128 "ndr_push_srv_copychunk_copy");
1130 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1131 torture_assert_ntstatus_ok(torture
, status
,
1132 "FSCTL_SRV_COPYCHUNK");
1134 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1136 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1137 torture_assert_ndr_success(torture
, ndr_ret
,
1138 "ndr_pull_srv_copychunk_rsp");
1140 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1141 1, /* chunks written */
1142 0, /* chunk bytes unsuccessfully written */
1143 2048); /* total bytes written */
1145 torture_fail(torture
, "bad copy chunk response data");
1148 ok
= check_pattern(torture
, tree
, tmp_ctx
, src_h
, 0, 2048 - 8, 0);
1150 torture_fail(torture
, "inconsistent file data");
1152 ok
= check_pattern(torture
, tree
, tmp_ctx
, src_h
, 2048 - 8, 2048, 0);
1154 torture_fail(torture
, "inconsistent file data");
1157 smb2_util_close(tree
, src_h
);
1158 smb2_util_close(tree
, dest_h
);
1159 talloc_free(tmp_ctx
);
1163 static bool test_ioctl_copy_chunk_bad_access(struct torture_context
*torture
,
1164 struct smb2_tree
*tree
)
1166 struct smb2_handle src_h
;
1167 struct smb2_handle dest_h
;
1169 union smb_ioctl ioctl
;
1170 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1171 struct srv_copychunk_copy cc_copy
;
1172 enum ndr_err_code ndr_ret
;
1175 /* no read permission on src */
1176 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1178 &src_h
, 4096, /* fill 4096 byte src file */
1179 SEC_RIGHTS_FILE_WRITE
,
1180 &dest_h
, 0, /* 0 byte dest file */
1181 SEC_RIGHTS_FILE_ALL
,
1185 torture_fail(torture
, "setup copy chunk error");
1188 cc_copy
.chunks
[0].source_off
= 0;
1189 cc_copy
.chunks
[0].target_off
= 0;
1190 cc_copy
.chunks
[0].length
= 4096;
1192 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1194 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1195 torture_assert_ndr_success(torture
, ndr_ret
,
1196 "ndr_push_srv_copychunk_copy");
1198 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1199 torture_assert_ntstatus_equal(torture
, status
,
1200 NT_STATUS_ACCESS_DENIED
,
1201 "FSCTL_SRV_COPYCHUNK");
1203 smb2_util_close(tree
, src_h
);
1204 smb2_util_close(tree
, dest_h
);
1206 /* no write permission on dest */
1207 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1209 &src_h
, 4096, /* fill 4096 byte src file */
1210 SEC_RIGHTS_FILE_ALL
,
1211 &dest_h
, 0, /* 0 byte dest file */
1212 (SEC_RIGHTS_FILE_READ
1213 | SEC_RIGHTS_FILE_EXECUTE
),
1217 torture_fail(torture
, "setup copy chunk error");
1220 cc_copy
.chunks
[0].source_off
= 0;
1221 cc_copy
.chunks
[0].target_off
= 0;
1222 cc_copy
.chunks
[0].length
= 4096;
1224 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1226 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1227 torture_assert_ndr_success(torture
, ndr_ret
,
1228 "ndr_push_srv_copychunk_copy");
1230 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1231 torture_assert_ntstatus_equal(torture
, status
,
1232 NT_STATUS_ACCESS_DENIED
,
1233 "FSCTL_SRV_COPYCHUNK");
1235 smb2_util_close(tree
, src_h
);
1236 smb2_util_close(tree
, dest_h
);
1238 /* no read permission on dest */
1239 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1241 &src_h
, 4096, /* fill 4096 byte src file */
1242 SEC_RIGHTS_FILE_ALL
,
1243 &dest_h
, 0, /* 0 byte dest file */
1244 (SEC_RIGHTS_FILE_WRITE
1245 | SEC_RIGHTS_FILE_EXECUTE
),
1249 torture_fail(torture
, "setup copy chunk error");
1252 cc_copy
.chunks
[0].source_off
= 0;
1253 cc_copy
.chunks
[0].target_off
= 0;
1254 cc_copy
.chunks
[0].length
= 4096;
1256 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1258 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1259 torture_assert_ndr_success(torture
, ndr_ret
,
1260 "ndr_push_srv_copychunk_copy");
1263 * FSCTL_SRV_COPYCHUNK requires read permission on dest,
1264 * FSCTL_SRV_COPYCHUNK_WRITE on the other hand does not.
1266 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1267 torture_assert_ntstatus_equal(torture
, status
,
1268 NT_STATUS_ACCESS_DENIED
,
1269 "FSCTL_SRV_COPYCHUNK");
1271 smb2_util_close(tree
, src_h
);
1272 smb2_util_close(tree
, dest_h
);
1273 talloc_free(tmp_ctx
);
1278 static bool test_ioctl_copy_chunk_write_access(struct torture_context
*torture
,
1279 struct smb2_tree
*tree
)
1281 struct smb2_handle src_h
;
1282 struct smb2_handle dest_h
;
1284 union smb_ioctl ioctl
;
1285 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1286 struct srv_copychunk_copy cc_copy
;
1287 enum ndr_err_code ndr_ret
;
1290 /* no read permission on dest with FSCTL_SRV_COPYCHUNK_WRITE */
1291 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1293 &src_h
, 4096, /* fill 4096 byte src file */
1294 SEC_RIGHTS_FILE_ALL
,
1295 &dest_h
, 0, /* 0 byte dest file */
1296 (SEC_RIGHTS_FILE_WRITE
1297 | SEC_RIGHTS_FILE_EXECUTE
),
1301 torture_fail(torture
, "setup copy chunk error");
1304 ioctl
.smb2
.in
.function
= FSCTL_SRV_COPYCHUNK_WRITE
;
1305 cc_copy
.chunks
[0].source_off
= 0;
1306 cc_copy
.chunks
[0].target_off
= 0;
1307 cc_copy
.chunks
[0].length
= 4096;
1309 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1311 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1312 torture_assert_ndr_success(torture
, ndr_ret
,
1313 "ndr_push_srv_copychunk_copy");
1315 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1316 torture_assert_ntstatus_ok(torture
, status
,
1317 "FSCTL_SRV_COPYCHUNK_WRITE");
1319 smb2_util_close(tree
, src_h
);
1320 smb2_util_close(tree
, dest_h
);
1321 talloc_free(tmp_ctx
);
1326 static bool test_ioctl_copy_chunk_src_exceed(struct torture_context
*torture
,
1327 struct smb2_tree
*tree
)
1329 struct smb2_handle src_h
;
1330 struct smb2_handle dest_h
;
1332 union smb_ioctl ioctl
;
1333 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1334 struct srv_copychunk_copy cc_copy
;
1335 struct srv_copychunk_rsp cc_rsp
;
1336 enum ndr_err_code ndr_ret
;
1339 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1341 &src_h
, 4096, /* fill 4096 byte src file */
1342 SEC_RIGHTS_FILE_ALL
,
1343 &dest_h
, 0, /* 0 byte dest file */
1344 SEC_RIGHTS_FILE_ALL
,
1348 torture_fail(torture
, "setup copy chunk error");
1351 /* Request copy where off + length exceeds size of src */
1352 cc_copy
.chunks
[0].source_off
= 1024;
1353 cc_copy
.chunks
[0].target_off
= 0;
1354 cc_copy
.chunks
[0].length
= 4096;
1356 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1358 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1359 torture_assert_ndr_success(torture
, ndr_ret
,
1360 "ndr_push_srv_copychunk_copy");
1362 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1363 torture_assert_ntstatus_equal(torture
, status
,
1364 NT_STATUS_INVALID_VIEW_SIZE
,
1365 "FSCTL_SRV_COPYCHUNK oversize");
1367 /* Request copy where length exceeds size of src */
1368 cc_copy
.chunks
[0].source_off
= 1024;
1369 cc_copy
.chunks
[0].target_off
= 0;
1370 cc_copy
.chunks
[0].length
= 3072;
1372 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1374 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1375 torture_assert_ndr_success(torture
, ndr_ret
,
1376 "ndr_push_srv_copychunk_copy");
1378 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1379 torture_assert_ntstatus_ok(torture
, status
,
1380 "FSCTL_SRV_COPYCHUNK just right");
1382 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1384 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1385 torture_assert_ndr_success(torture
, ndr_ret
,
1386 "ndr_pull_srv_copychunk_rsp");
1388 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1389 1, /* chunks written */
1390 0, /* chunk bytes unsuccessfully written */
1391 3072); /* total bytes written */
1393 torture_fail(torture
, "bad copy chunk response data");
1396 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 3072, 1024);
1398 torture_fail(torture
, "inconsistent file data");
1401 smb2_util_close(tree
, src_h
);
1402 smb2_util_close(tree
, dest_h
);
1403 talloc_free(tmp_ctx
);
1408 test_ioctl_copy_chunk_src_exceed_multi(struct torture_context
*torture
,
1409 struct smb2_tree
*tree
)
1411 struct smb2_handle src_h
;
1412 struct smb2_handle dest_h
;
1414 union smb_ioctl ioctl
;
1415 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1416 struct srv_copychunk_copy cc_copy
;
1417 struct srv_copychunk_rsp cc_rsp
;
1418 enum ndr_err_code ndr_ret
;
1421 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1423 &src_h
, 8192, /* fill 8192 byte src file */
1424 SEC_RIGHTS_FILE_ALL
,
1425 &dest_h
, 0, /* 0 byte dest file */
1426 SEC_RIGHTS_FILE_ALL
,
1430 torture_fail(torture
, "setup copy chunk error");
1433 /* Request copy where off + length exceeds size of src */
1434 cc_copy
.chunks
[0].source_off
= 0;
1435 cc_copy
.chunks
[0].target_off
= 0;
1436 cc_copy
.chunks
[0].length
= 4096;
1438 cc_copy
.chunks
[1].source_off
= 4096;
1439 cc_copy
.chunks
[1].target_off
= 4096;
1440 cc_copy
.chunks
[1].length
= 8192;
1442 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1444 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1445 torture_assert_ndr_success(torture
, ndr_ret
,
1446 "ndr_push_srv_copychunk_copy");
1448 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1449 torture_assert_ntstatus_equal(torture
, status
,
1450 NT_STATUS_INVALID_VIEW_SIZE
,
1451 "FSCTL_SRV_COPYCHUNK oversize");
1452 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1454 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1455 torture_assert_ndr_success(torture
, ndr_ret
, "unmarshalling response");
1457 /* first chunk should still be written */
1458 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1459 1, /* chunks written */
1460 0, /* chunk bytes unsuccessfully written */
1461 4096); /* total bytes written */
1463 torture_fail(torture
, "bad copy chunk response data");
1465 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
1467 torture_fail(torture
, "inconsistent file data");
1470 smb2_util_close(tree
, src_h
);
1471 smb2_util_close(tree
, dest_h
);
1472 talloc_free(tmp_ctx
);
1476 static bool test_ioctl_copy_chunk_sparse_dest(struct torture_context
*torture
,
1477 struct smb2_tree
*tree
)
1479 struct smb2_handle src_h
;
1480 struct smb2_handle dest_h
;
1482 union smb_ioctl ioctl
;
1484 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1485 struct srv_copychunk_copy cc_copy
;
1486 struct srv_copychunk_rsp cc_rsp
;
1487 enum ndr_err_code ndr_ret
;
1491 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1493 &src_h
, 4096, /* fill 4096 byte src file */
1494 SEC_RIGHTS_FILE_ALL
,
1495 &dest_h
, 0, /* 0 byte dest file */
1496 SEC_RIGHTS_FILE_ALL
,
1500 torture_fail(torture
, "setup copy chunk error");
1503 /* copy all src file data (via a single chunk desc) */
1504 cc_copy
.chunks
[0].source_off
= 0;
1505 cc_copy
.chunks
[0].target_off
= 4096;
1506 cc_copy
.chunks
[0].length
= 4096;
1508 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1510 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1511 torture_assert_ndr_success(torture
, ndr_ret
,
1512 "ndr_push_srv_copychunk_copy");
1514 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1515 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
1517 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1519 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1520 torture_assert_ndr_success(torture
, ndr_ret
,
1521 "ndr_pull_srv_copychunk_rsp");
1523 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1524 1, /* chunks written */
1525 0, /* chunk bytes unsuccessfully written */
1526 4096); /* total bytes written */
1528 torture_fail(torture
, "bad copy chunk response data");
1531 /* check for zeros in first 4k */
1533 r
.in
.file
.handle
= dest_h
;
1536 status
= smb2_read(tree
, tmp_ctx
, &r
);
1537 torture_assert_ntstatus_ok(torture
, status
, "read");
1539 torture_assert_u64_equal(torture
, r
.out
.data
.length
, 4096,
1540 "read data len mismatch");
1542 for (i
= 0; i
< 4096; i
++) {
1543 torture_assert(torture
, (r
.out
.data
.data
[i
] == 0),
1544 "sparse did not pass class");
1547 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 4096, 4096, 0);
1549 torture_fail(torture
, "inconsistent file data");
1552 smb2_util_close(tree
, src_h
);
1553 smb2_util_close(tree
, dest_h
);
1554 talloc_free(tmp_ctx
);
1559 * set the ioctl MaxOutputResponse size to less than
1560 * sizeof(struct srv_copychunk_rsp)
1562 static bool test_ioctl_copy_chunk_max_output_sz(struct torture_context
*torture
,
1563 struct smb2_tree
*tree
)
1565 struct smb2_handle src_h
;
1566 struct smb2_handle dest_h
;
1568 union smb_ioctl ioctl
;
1569 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1570 struct srv_copychunk_copy cc_copy
;
1571 enum ndr_err_code ndr_ret
;
1574 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1576 &src_h
, 4096, /* fill 4096 byte src file */
1577 SEC_RIGHTS_FILE_ALL
,
1578 &dest_h
, 0, /* 0 byte dest file */
1579 SEC_RIGHTS_FILE_ALL
,
1583 torture_fail(torture
, "setup copy chunk error");
1586 cc_copy
.chunks
[0].source_off
= 0;
1587 cc_copy
.chunks
[0].target_off
= 0;
1588 cc_copy
.chunks
[0].length
= 4096;
1589 /* req is valid, but use undersize max_response_size */
1590 ioctl
.smb2
.in
.max_response_size
= sizeof(struct srv_copychunk_rsp
) - 1;
1592 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1594 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1595 torture_assert_ndr_success(torture
, ndr_ret
,
1596 "ndr_push_srv_copychunk_copy");
1598 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1599 torture_assert_ntstatus_equal(torture
, status
,
1600 NT_STATUS_INVALID_PARAMETER
,
1601 "FSCTL_SRV_COPYCHUNK");
1603 smb2_util_close(tree
, src_h
);
1604 smb2_util_close(tree
, dest_h
);
1605 talloc_free(tmp_ctx
);
1609 static bool test_ioctl_copy_chunk_zero_length(struct torture_context
*torture
,
1610 struct smb2_tree
*tree
)
1612 struct smb2_handle src_h
;
1613 struct smb2_handle dest_h
;
1615 union smb_ioctl ioctl
;
1616 union smb_fileinfo q
;
1617 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1618 struct srv_copychunk_copy cc_copy
;
1619 struct srv_copychunk_rsp cc_rsp
;
1620 enum ndr_err_code ndr_ret
;
1623 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1625 &src_h
, 4096, /* fill 4096 byte src file */
1626 SEC_RIGHTS_FILE_ALL
,
1627 &dest_h
, 0, /* 0 byte dest file */
1628 SEC_RIGHTS_FILE_ALL
,
1632 torture_fail(torture
, "setup copy chunk error");
1635 /* zero length server-side copy (via a single chunk desc) */
1636 cc_copy
.chunks
[0].source_off
= 0;
1637 cc_copy
.chunks
[0].target_off
= 0;
1638 cc_copy
.chunks
[0].length
= 0;
1640 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1642 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1643 torture_assert_ndr_success(torture
, ndr_ret
,
1644 "ndr_push_srv_copychunk_copy");
1646 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1647 torture_assert_ntstatus_equal(torture
, status
,
1648 NT_STATUS_INVALID_PARAMETER
,
1649 "bad zero-length chunk response");
1651 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1653 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1654 torture_assert_ndr_success(torture
, ndr_ret
, "unmarshalling response");
1657 q
.all_info2
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
1658 q
.all_info2
.in
.file
.handle
= dest_h
;
1659 status
= smb2_getinfo_file(tree
, torture
, &q
);
1660 torture_assert_ntstatus_ok(torture
, status
, "getinfo");
1662 torture_assert_int_equal(torture
, q
.all_info2
.out
.size
, 0,
1663 "size after zero len clone");
1665 smb2_util_close(tree
, src_h
);
1666 smb2_util_close(tree
, dest_h
);
1667 talloc_free(tmp_ctx
);
1671 static NTSTATUS
test_ioctl_compress_fs_supported(struct torture_context
*torture
,
1672 struct smb2_tree
*tree
,
1673 TALLOC_CTX
*mem_ctx
,
1674 struct smb2_handle
*fh
,
1675 bool *compress_support
)
1678 union smb_fsinfo info
;
1681 info
.generic
.level
= RAW_QFS_ATTRIBUTE_INFORMATION
;
1682 info
.generic
.handle
= *fh
;
1683 status
= smb2_getinfo_fs(tree
, tree
, &info
);
1684 if (!NT_STATUS_IS_OK(status
)) {
1688 if (info
.attribute_info
.out
.fs_attr
& FILE_FILE_COMPRESSION
) {
1689 *compress_support
= true;
1691 *compress_support
= false;
1693 return NT_STATUS_OK
;
1696 static NTSTATUS
test_ioctl_compress_get(struct torture_context
*torture
,
1697 TALLOC_CTX
*mem_ctx
,
1698 struct smb2_tree
*tree
,
1699 struct smb2_handle fh
,
1700 uint16_t *_compression_fmt
)
1702 union smb_ioctl ioctl
;
1703 struct compression_state cmpr_state
;
1704 enum ndr_err_code ndr_ret
;
1708 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
1709 ioctl
.smb2
.in
.file
.handle
= fh
;
1710 ioctl
.smb2
.in
.function
= FSCTL_GET_COMPRESSION
;
1711 ioctl
.smb2
.in
.max_response_size
= sizeof(struct compression_state
);
1712 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
1714 status
= smb2_ioctl(tree
, mem_ctx
, &ioctl
.smb2
);
1715 if (!NT_STATUS_IS_OK(status
)) {
1719 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, mem_ctx
,
1721 (ndr_pull_flags_fn_t
)ndr_pull_compression_state
);
1723 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
1724 return NT_STATUS_INTERNAL_ERROR
;
1727 *_compression_fmt
= cmpr_state
.format
;
1728 return NT_STATUS_OK
;
1731 static NTSTATUS
test_ioctl_compress_set(struct torture_context
*torture
,
1732 TALLOC_CTX
*mem_ctx
,
1733 struct smb2_tree
*tree
,
1734 struct smb2_handle fh
,
1735 uint16_t compression_fmt
)
1737 union smb_ioctl ioctl
;
1738 struct compression_state cmpr_state
;
1739 enum ndr_err_code ndr_ret
;
1743 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
1744 ioctl
.smb2
.in
.file
.handle
= fh
;
1745 ioctl
.smb2
.in
.function
= FSCTL_SET_COMPRESSION
;
1746 ioctl
.smb2
.in
.max_response_size
= 0;
1747 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
1749 cmpr_state
.format
= compression_fmt
;
1750 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, mem_ctx
,
1752 (ndr_push_flags_fn_t
)ndr_push_compression_state
);
1753 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
1754 return NT_STATUS_INTERNAL_ERROR
;
1757 status
= smb2_ioctl(tree
, mem_ctx
, &ioctl
.smb2
);
1761 static bool test_ioctl_compress_file_flag(struct torture_context
*torture
,
1762 struct smb2_tree
*tree
)
1764 struct smb2_handle fh
;
1766 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1768 uint16_t compression_fmt
;
1770 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1771 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
1772 FILE_ATTRIBUTE_NORMAL
);
1773 torture_assert(torture
, ok
, "setup compression file");
1775 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
1777 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
1779 smb2_util_close(tree
, fh
);
1780 torture_skip(torture
, "FS compression not supported\n");
1783 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1785 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1787 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
1788 "initial compression state not NONE");
1790 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
1791 COMPRESSION_FORMAT_DEFAULT
);
1792 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
1794 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1796 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1798 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
1799 "invalid compression state after set");
1801 smb2_util_close(tree
, fh
);
1802 talloc_free(tmp_ctx
);
1806 static bool test_ioctl_compress_dir_inherit(struct torture_context
*torture
,
1807 struct smb2_tree
*tree
)
1809 struct smb2_handle dirh
;
1810 struct smb2_handle fh
;
1812 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1813 uint16_t compression_fmt
;
1815 char path_buf
[PATH_MAX
];
1817 smb2_deltree(tree
, DNAME
);
1818 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1819 DNAME
, &dirh
, 0, SEC_RIGHTS_FILE_ALL
,
1820 FILE_ATTRIBUTE_DIRECTORY
);
1821 torture_assert(torture
, ok
, "setup compression directory");
1823 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &dirh
,
1825 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
1827 smb2_util_close(tree
, dirh
);
1828 smb2_deltree(tree
, DNAME
);
1829 torture_skip(torture
, "FS compression not supported\n");
1832 /* set compression on parent dir, then check for inheritance */
1833 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, dirh
,
1834 COMPRESSION_FORMAT_LZNT1
);
1835 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
1837 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, dirh
,
1839 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1841 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
1842 "invalid compression state after set");
1844 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, FNAME
);
1845 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1846 path_buf
, &fh
, 4096, SEC_RIGHTS_FILE_ALL
,
1847 FILE_ATTRIBUTE_NORMAL
);
1848 torture_assert(torture
, ok
, "setup compression file");
1850 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1852 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1854 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
1855 "compression attr not inherited by new file");
1857 /* check compressed data is consistent */
1858 ok
= check_pattern(torture
, tree
, tmp_ctx
, fh
, 0, 4096, 0);
1860 /* disable dir compression attr, file should remain compressed */
1861 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, dirh
,
1862 COMPRESSION_FORMAT_NONE
);
1863 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
1865 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1867 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1869 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
1870 "file compression attr removed after dir change");
1871 smb2_util_close(tree
, fh
);
1873 /* new files should no longer inherit compression attr */
1874 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, FNAME2
);
1875 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1876 path_buf
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
1877 FILE_ATTRIBUTE_NORMAL
);
1878 torture_assert(torture
, ok
, "setup file");
1880 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1882 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1884 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
1885 "compression attr present on new file");
1887 smb2_util_close(tree
, fh
);
1888 smb2_util_close(tree
, dirh
);
1889 smb2_deltree(tree
, DNAME
);
1890 talloc_free(tmp_ctx
);
1894 static bool test_ioctl_compress_invalid_format(struct torture_context
*torture
,
1895 struct smb2_tree
*tree
)
1897 struct smb2_handle fh
;
1899 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1901 uint16_t compression_fmt
;
1903 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1904 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
1905 FILE_ATTRIBUTE_NORMAL
);
1906 torture_assert(torture
, ok
, "setup compression file");
1908 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
1910 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
1912 smb2_util_close(tree
, fh
);
1913 torture_skip(torture
, "FS compression not supported\n");
1916 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
1917 0x0042); /* bogus */
1918 torture_assert_ntstatus_equal(torture
, status
,
1919 NT_STATUS_INVALID_PARAMETER
,
1920 "invalid FSCTL_SET_COMPRESSION");
1922 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1924 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1926 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
1927 "initial compression state not NONE");
1929 smb2_util_close(tree
, fh
);
1930 talloc_free(tmp_ctx
);
1934 static bool test_ioctl_compress_invalid_buf(struct torture_context
*torture
,
1935 struct smb2_tree
*tree
)
1937 struct smb2_handle fh
;
1939 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1941 union smb_ioctl ioctl
;
1943 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1944 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
1945 FILE_ATTRIBUTE_NORMAL
);
1946 torture_assert(torture
, ok
, "setup compression file");
1948 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
1950 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
1952 smb2_util_close(tree
, fh
);
1953 torture_skip(torture
, "FS compression not supported\n");
1957 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
1958 ioctl
.smb2
.in
.file
.handle
= fh
;
1959 ioctl
.smb2
.in
.function
= FSCTL_GET_COMPRESSION
;
1960 ioctl
.smb2
.in
.max_response_size
= 0; /* no room for rsp data */
1961 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
1963 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1964 if (!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_USER_BUFFER
)
1965 && !NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
1966 /* neither Server 2k12 nor 2k8r2 response status */
1967 torture_assert(torture
, true,
1968 "invalid FSCTL_SET_COMPRESSION");
1971 smb2_util_close(tree
, fh
);
1972 talloc_free(tmp_ctx
);
1976 static bool test_ioctl_compress_query_file_attr(struct torture_context
*torture
,
1977 struct smb2_tree
*tree
)
1979 struct smb2_handle fh
;
1980 union smb_fileinfo io
;
1982 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1985 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1986 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
1987 FILE_ATTRIBUTE_NORMAL
);
1988 torture_assert(torture
, ok
, "setup compression file");
1990 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
1992 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
1994 smb2_util_close(tree
, fh
);
1995 torture_skip(torture
, "FS compression not supported\n");
1999 io
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
2000 io
.generic
.in
.file
.handle
= fh
;
2001 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2002 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2004 torture_assert(torture
,
2005 ((io
.all_info2
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2006 "compression attr before set");
2008 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
2009 COMPRESSION_FORMAT_DEFAULT
);
2010 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
2013 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2014 io
.generic
.in
.file
.handle
= fh
;
2015 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2016 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2018 torture_assert(torture
,
2019 (io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
),
2020 "no compression attr after set");
2022 smb2_util_close(tree
, fh
);
2023 talloc_free(tmp_ctx
);
2028 * Specify FILE_ATTRIBUTE_COMPRESSED on creation, Windows does not retain this
2031 static bool test_ioctl_compress_create_with_attr(struct torture_context
*torture
,
2032 struct smb2_tree
*tree
)
2034 struct smb2_handle fh2
;
2035 union smb_fileinfo io
;
2037 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2038 uint16_t compression_fmt
;
2041 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2042 FNAME2
, &fh2
, 0, SEC_RIGHTS_FILE_ALL
,
2043 (FILE_ATTRIBUTE_NORMAL
| FILE_ATTRIBUTE_COMPRESSED
));
2044 torture_assert(torture
, ok
, "setup compression file");
2046 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh2
,
2048 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2050 smb2_util_close(tree
, fh2
);
2051 torture_skip(torture
, "FS compression not supported\n");
2054 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh2
,
2056 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2058 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2059 "initial compression state not NONE");
2062 io
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
2063 io
.generic
.in
.file
.handle
= fh2
;
2064 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2065 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2067 torture_assert(torture
,
2068 ((io
.all_info2
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2069 "incorrect compression attr");
2071 smb2_util_close(tree
, fh2
);
2072 talloc_free(tmp_ctx
);
2076 static bool test_ioctl_compress_inherit_disable(struct torture_context
*torture
,
2077 struct smb2_tree
*tree
)
2079 struct smb2_handle fh
;
2080 struct smb2_handle dirh
;
2081 char path_buf
[PATH_MAX
];
2083 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2085 uint16_t compression_fmt
;
2087 struct smb2_create io
;
2089 smb2_deltree(tree
, DNAME
);
2090 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2091 DNAME
, &dirh
, 0, SEC_RIGHTS_FILE_ALL
,
2092 FILE_ATTRIBUTE_DIRECTORY
);
2093 torture_assert(torture
, ok
, "setup compression directory");
2095 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &dirh
,
2097 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2099 smb2_util_close(tree
, dirh
);
2100 smb2_deltree(tree
, DNAME
);
2101 torture_skip(torture
, "FS compression not supported\n");
2104 /* set compression on parent dir, then check for inheritance */
2105 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, dirh
,
2106 COMPRESSION_FORMAT_LZNT1
);
2107 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
2109 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, dirh
,
2111 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2113 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
2114 "invalid compression state after set");
2115 smb2_util_close(tree
, dirh
);
2117 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, FNAME
);
2118 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2119 path_buf
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2120 FILE_ATTRIBUTE_NORMAL
);
2121 torture_assert(torture
, ok
, "setup compression file");
2123 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2125 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2127 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
2128 "compression attr not inherited by new file");
2129 smb2_util_close(tree
, fh
);
2131 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, FNAME2
);
2133 /* NO_COMPRESSION option should block inheritance */
2135 io
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
2136 io
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2137 io
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2138 io
.in
.create_options
= NTCREATEX_OPTIONS_NO_COMPRESSION
;
2139 io
.in
.share_access
=
2140 NTCREATEX_SHARE_ACCESS_DELETE
|
2141 NTCREATEX_SHARE_ACCESS_READ
|
2142 NTCREATEX_SHARE_ACCESS_WRITE
;
2143 io
.in
.fname
= path_buf
;
2145 status
= smb2_create(tree
, tmp_ctx
, &io
);
2146 torture_assert_ntstatus_ok(torture
, status
, "file create");
2148 fh
= io
.out
.file
.handle
;
2150 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2152 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2154 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2155 "compression attr inherited by NO_COMPRESSION file");
2156 smb2_util_close(tree
, fh
);
2159 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, DNAME
);
2161 io
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
2162 io
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
2163 io
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2164 io
.in
.create_options
= (NTCREATEX_OPTIONS_NO_COMPRESSION
2165 | NTCREATEX_OPTIONS_DIRECTORY
);
2166 io
.in
.share_access
=
2167 NTCREATEX_SHARE_ACCESS_DELETE
|
2168 NTCREATEX_SHARE_ACCESS_READ
|
2169 NTCREATEX_SHARE_ACCESS_WRITE
;
2170 io
.in
.fname
= path_buf
;
2172 status
= smb2_create(tree
, tmp_ctx
, &io
);
2173 torture_assert_ntstatus_ok(torture
, status
, "dir create");
2175 dirh
= io
.out
.file
.handle
;
2177 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, dirh
,
2179 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2181 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2182 "compression attr inherited by NO_COMPRESSION dir");
2183 smb2_util_close(tree
, dirh
);
2184 smb2_deltree(tree
, DNAME
);
2186 talloc_free(tmp_ctx
);
2190 /* attempting to set compression via SetInfo should not stick */
2191 static bool test_ioctl_compress_set_file_attr(struct torture_context
*torture
,
2192 struct smb2_tree
*tree
)
2194 struct smb2_handle fh
;
2195 struct smb2_handle dirh
;
2196 union smb_fileinfo io
;
2197 union smb_setfileinfo set_io
;
2198 uint16_t compression_fmt
;
2200 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2203 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2204 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2205 FILE_ATTRIBUTE_NORMAL
);
2206 torture_assert(torture
, ok
, "setup compression file");
2208 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2210 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2212 smb2_util_close(tree
, fh
);
2213 torture_skip(torture
, "FS compression not supported\n");
2217 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2218 io
.generic
.in
.file
.handle
= fh
;
2219 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2220 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2222 torture_assert(torture
,
2223 ((io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2224 "compression attr before set");
2226 ZERO_STRUCT(set_io
);
2227 set_io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2228 set_io
.basic_info
.in
.file
.handle
= fh
;
2229 set_io
.basic_info
.in
.create_time
= io
.basic_info
.out
.create_time
;
2230 set_io
.basic_info
.in
.access_time
= io
.basic_info
.out
.access_time
;
2231 set_io
.basic_info
.in
.write_time
= io
.basic_info
.out
.write_time
;
2232 set_io
.basic_info
.in
.change_time
= io
.basic_info
.out
.change_time
;
2233 set_io
.basic_info
.in
.attrib
= (io
.basic_info
.out
.attrib
2234 | FILE_ATTRIBUTE_COMPRESSED
);
2235 status
= smb2_setinfo_file(tree
, &set_io
);
2236 torture_assert_ntstatus_ok(torture
, status
, "SMB2_SETINFO_FILE");
2239 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2240 io
.generic
.in
.file
.handle
= fh
;
2241 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2242 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2244 torture_assert(torture
,
2245 ((io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2246 "compression attr after set");
2248 smb2_util_close(tree
, fh
);
2249 smb2_deltree(tree
, DNAME
);
2250 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2251 DNAME
, &dirh
, 0, SEC_RIGHTS_FILE_ALL
,
2252 FILE_ATTRIBUTE_DIRECTORY
);
2253 torture_assert(torture
, ok
, "setup compression directory");
2256 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2257 io
.generic
.in
.file
.handle
= dirh
;
2258 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2259 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2261 torture_assert(torture
,
2262 ((io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2263 "compression attr before set");
2265 ZERO_STRUCT(set_io
);
2266 set_io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2267 set_io
.basic_info
.in
.file
.handle
= dirh
;
2268 set_io
.basic_info
.in
.create_time
= io
.basic_info
.out
.create_time
;
2269 set_io
.basic_info
.in
.access_time
= io
.basic_info
.out
.access_time
;
2270 set_io
.basic_info
.in
.write_time
= io
.basic_info
.out
.write_time
;
2271 set_io
.basic_info
.in
.change_time
= io
.basic_info
.out
.change_time
;
2272 set_io
.basic_info
.in
.attrib
= (io
.basic_info
.out
.attrib
2273 | FILE_ATTRIBUTE_COMPRESSED
);
2274 status
= smb2_setinfo_file(tree
, &set_io
);
2275 torture_assert_ntstatus_ok(torture
, status
, "SMB2_SETINFO_FILE");
2277 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, dirh
,
2279 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2281 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2282 "dir compression set after SetInfo");
2284 smb2_util_close(tree
, dirh
);
2285 talloc_free(tmp_ctx
);
2289 static bool test_ioctl_compress_perms(struct torture_context
*torture
,
2290 struct smb2_tree
*tree
)
2292 struct smb2_handle fh
;
2293 uint16_t compression_fmt
;
2294 union smb_fileinfo io
;
2296 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2299 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2300 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2301 FILE_ATTRIBUTE_NORMAL
);
2302 torture_assert(torture
, ok
, "setup compression file");
2304 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2306 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2307 smb2_util_close(tree
, fh
);
2309 torture_skip(torture
, "FS compression not supported\n");
2312 /* attempt get compression without READ_ATTR permission */
2313 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2315 (SEC_RIGHTS_FILE_READ
& ~(SEC_FILE_READ_ATTRIBUTE
2316 | SEC_STD_READ_CONTROL
2317 | SEC_FILE_READ_EA
)),
2318 FILE_ATTRIBUTE_NORMAL
);
2319 torture_assert(torture
, ok
, "setup compression file");
2321 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2323 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2324 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2325 "compression set after create");
2326 smb2_util_close(tree
, fh
);
2328 /* set compression without WRITE_ATTR permission should succeed */
2329 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2331 (SEC_RIGHTS_FILE_WRITE
& ~(SEC_FILE_WRITE_ATTRIBUTE
2333 | SEC_FILE_WRITE_EA
)),
2334 FILE_ATTRIBUTE_NORMAL
);
2335 torture_assert(torture
, ok
, "setup compression file");
2337 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
2338 COMPRESSION_FORMAT_DEFAULT
);
2339 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
2340 smb2_util_close(tree
, fh
);
2342 ok
= test_setup_open(torture
, tree
, tmp_ctx
,
2343 FNAME
, &fh
, SEC_RIGHTS_FILE_ALL
,
2344 FILE_ATTRIBUTE_NORMAL
);
2345 torture_assert(torture
, ok
, "setup compression file");
2347 io
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
2348 io
.generic
.in
.file
.handle
= fh
;
2349 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2350 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2352 torture_assert(torture
,
2353 (io
.all_info2
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
),
2354 "incorrect compression attr");
2355 smb2_util_close(tree
, fh
);
2357 /* attempt get compression without READ_DATA permission */
2358 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2360 (SEC_RIGHTS_FILE_READ
& ~SEC_FILE_READ_DATA
),
2361 FILE_ATTRIBUTE_NORMAL
);
2362 torture_assert(torture
, ok
, "setup compression file");
2364 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2366 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2367 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2368 "compression enabled after set");
2369 smb2_util_close(tree
, fh
);
2371 /* attempt get compression with only SYNCHRONIZE permission */
2372 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2374 SEC_STD_SYNCHRONIZE
,
2375 FILE_ATTRIBUTE_NORMAL
);
2376 torture_assert(torture
, ok
, "setup compression file");
2378 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2380 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2381 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2382 "compression not enabled after set");
2383 smb2_util_close(tree
, fh
);
2385 /* attempt to set compression without WRITE_DATA permission */
2386 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2388 (SEC_RIGHTS_FILE_WRITE
& (~SEC_FILE_WRITE_DATA
)),
2389 FILE_ATTRIBUTE_NORMAL
);
2390 torture_assert(torture
, ok
, "setup compression file");
2392 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
2393 COMPRESSION_FORMAT_DEFAULT
);
2394 torture_assert_ntstatus_equal(torture
, status
,
2395 NT_STATUS_ACCESS_DENIED
,
2396 "FSCTL_SET_COMPRESSION permission");
2397 smb2_util_close(tree
, fh
);
2399 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2401 (SEC_RIGHTS_FILE_WRITE
& (~SEC_FILE_WRITE_DATA
)),
2402 FILE_ATTRIBUTE_NORMAL
);
2403 torture_assert(torture
, ok
, "setup compression file");
2405 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
2406 COMPRESSION_FORMAT_NONE
);
2407 torture_assert_ntstatus_equal(torture
, status
,
2408 NT_STATUS_ACCESS_DENIED
,
2409 "FSCTL_SET_COMPRESSION permission");
2410 smb2_util_close(tree
, fh
);
2412 talloc_free(tmp_ctx
);
2417 basic testing of the SMB2 FSCTL_QUERY_NETWORK_INTERFACE_INFO ioctl
2419 static bool test_ioctl_network_interface_info(struct torture_context
*torture
,
2420 struct smb2_tree
*tree
)
2422 union smb_ioctl ioctl
;
2423 struct smb2_handle fh
;
2425 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2426 struct fsctl_net_iface_info net_iface
;
2427 enum ndr_err_code ndr_ret
;
2430 caps
= smb2cli_conn_server_capabilities(tree
->session
->transport
->conn
);
2431 if (!(caps
& SMB2_CAP_MULTI_CHANNEL
)) {
2432 torture_skip(torture
, "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
2436 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
2437 fh
.data
[0] = UINT64_MAX
;
2438 fh
.data
[1] = UINT64_MAX
;
2439 ioctl
.smb2
.in
.file
.handle
= fh
;
2440 ioctl
.smb2
.in
.function
= FSCTL_QUERY_NETWORK_INTERFACE_INFO
;
2441 ioctl
.smb2
.in
.max_response_size
= 0x10000; /* Windows client sets this to 64KiB */
2442 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
2444 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
2445 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
2447 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
, &net_iface
,
2448 (ndr_pull_flags_fn_t
)ndr_pull_fsctl_net_iface_info
);
2449 torture_assert_ndr_success(torture
, ndr_ret
,
2450 "ndr_pull_fsctl_net_iface_info");
2452 ndr_print_debug((ndr_print_fn_t
)ndr_print_fsctl_net_iface_info
2453 , "Network Interface Info", &net_iface
);
2455 talloc_free(tmp_ctx
);
2459 static NTSTATUS
test_ioctl_sparse_fs_supported(struct torture_context
*torture
,
2460 struct smb2_tree
*tree
,
2461 TALLOC_CTX
*mem_ctx
,
2462 struct smb2_handle
*fh
,
2463 bool *sparse_support
)
2466 union smb_fsinfo info
;
2469 info
.generic
.level
= RAW_QFS_ATTRIBUTE_INFORMATION
;
2470 info
.generic
.handle
= *fh
;
2471 status
= smb2_getinfo_fs(tree
, tree
, &info
);
2472 if (!NT_STATUS_IS_OK(status
)) {
2476 if (info
.attribute_info
.out
.fs_attr
& FILE_SUPPORTS_SPARSE_FILES
) {
2477 *sparse_support
= true;
2479 *sparse_support
= false;
2481 return NT_STATUS_OK
;
2484 static NTSTATUS
test_ioctl_sparse_req(struct torture_context
*torture
,
2485 TALLOC_CTX
*mem_ctx
,
2486 struct smb2_tree
*tree
,
2487 struct smb2_handle fh
,
2490 union smb_ioctl ioctl
;
2495 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
2496 ioctl
.smb2
.in
.file
.handle
= fh
;
2497 ioctl
.smb2
.in
.function
= FSCTL_SET_SPARSE
;
2498 ioctl
.smb2
.in
.max_response_size
= 0;
2499 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
2500 set_sparse
= (set
? 0xFF : 0x0);
2501 ioctl
.smb2
.in
.out
.data
= &set_sparse
;
2502 ioctl
.smb2
.in
.out
.length
= sizeof(set_sparse
);
2504 status
= smb2_ioctl(tree
, mem_ctx
, &ioctl
.smb2
);
2508 static NTSTATUS
test_sparse_get(struct torture_context
*torture
,
2509 TALLOC_CTX
*mem_ctx
,
2510 struct smb2_tree
*tree
,
2511 struct smb2_handle fh
,
2514 union smb_fileinfo io
;
2518 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2519 io
.generic
.in
.file
.handle
= fh
;
2520 status
= smb2_getinfo_file(tree
, mem_ctx
, &io
);
2521 if (!NT_STATUS_IS_OK(status
)) {
2524 *_is_sparse
= !!(io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_SPARSE
);
2529 static bool test_ioctl_sparse_file_flag(struct torture_context
*torture
,
2530 struct smb2_tree
*tree
)
2532 struct smb2_handle fh
;
2533 union smb_fileinfo io
;
2535 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2539 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2540 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2541 FILE_ATTRIBUTE_NORMAL
);
2542 torture_assert(torture
, ok
, "setup file");
2544 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2546 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2548 smb2_util_close(tree
, fh
);
2549 torture_skip(torture
, "Sparse files not supported\n");
2553 io
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
2554 io
.generic
.in
.file
.handle
= fh
;
2555 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2556 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2558 torture_assert(torture
,
2559 ((io
.all_info2
.out
.attrib
& FILE_ATTRIBUTE_SPARSE
) == 0),
2560 "sparse attr before set");
2562 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, true);
2563 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
2565 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2566 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2567 torture_assert(torture
, is_sparse
, "no sparse attr after set");
2569 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, false);
2570 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
2572 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2573 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2574 torture_assert(torture
, !is_sparse
, "sparse attr after unset");
2576 smb2_util_close(tree
, fh
);
2577 talloc_free(tmp_ctx
);
2581 static bool test_ioctl_sparse_file_attr(struct torture_context
*torture
,
2582 struct smb2_tree
*tree
)
2584 struct smb2_handle fh
;
2586 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2590 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2591 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2592 (FILE_ATTRIBUTE_NORMAL
| FILE_ATTRIBUTE_SPARSE
));
2593 torture_assert(torture
, ok
, "setup file");
2595 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2597 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2599 smb2_util_close(tree
, fh
);
2600 torture_skip(torture
, "Sparse files not supported\n");
2603 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2604 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2605 torture_assert(torture
, !is_sparse
, "sparse attr on open");
2607 smb2_util_close(tree
, fh
);
2608 talloc_free(tmp_ctx
);
2613 basic testing of SMB2 ioctls
2615 struct torture_suite
*torture_smb2_ioctl_init(void)
2617 struct torture_suite
*suite
= torture_suite_create(talloc_autofree_context(), "ioctl");
2619 torture_suite_add_1smb2_test(suite
, "shadow_copy",
2620 test_ioctl_get_shadow_copy
);
2621 torture_suite_add_1smb2_test(suite
, "req_resume_key",
2622 test_ioctl_req_resume_key
);
2623 torture_suite_add_1smb2_test(suite
, "copy_chunk_simple",
2624 test_ioctl_copy_chunk_simple
);
2625 torture_suite_add_1smb2_test(suite
, "copy_chunk_multi",
2626 test_ioctl_copy_chunk_multi
);
2627 torture_suite_add_1smb2_test(suite
, "copy_chunk_tiny",
2628 test_ioctl_copy_chunk_tiny
);
2629 torture_suite_add_1smb2_test(suite
, "copy_chunk_overwrite",
2630 test_ioctl_copy_chunk_over
);
2631 torture_suite_add_1smb2_test(suite
, "copy_chunk_append",
2632 test_ioctl_copy_chunk_append
);
2633 torture_suite_add_1smb2_test(suite
, "copy_chunk_limits",
2634 test_ioctl_copy_chunk_limits
);
2635 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_lock",
2636 test_ioctl_copy_chunk_src_lck
);
2637 torture_suite_add_1smb2_test(suite
, "copy_chunk_dest_lock",
2638 test_ioctl_copy_chunk_dest_lck
);
2639 torture_suite_add_1smb2_test(suite
, "copy_chunk_bad_key",
2640 test_ioctl_copy_chunk_bad_key
);
2641 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_is_dest",
2642 test_ioctl_copy_chunk_src_is_dest
);
2643 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_is_dest_overlap",
2644 test_ioctl_copy_chunk_src_is_dest_overlap
);
2645 torture_suite_add_1smb2_test(suite
, "copy_chunk_bad_access",
2646 test_ioctl_copy_chunk_bad_access
);
2647 torture_suite_add_1smb2_test(suite
, "copy_chunk_write_access",
2648 test_ioctl_copy_chunk_write_access
);
2649 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_exceed",
2650 test_ioctl_copy_chunk_src_exceed
);
2651 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_exceed_multi",
2652 test_ioctl_copy_chunk_src_exceed_multi
);
2653 torture_suite_add_1smb2_test(suite
, "copy_chunk_sparse_dest",
2654 test_ioctl_copy_chunk_sparse_dest
);
2655 torture_suite_add_1smb2_test(suite
, "copy_chunk_max_output_sz",
2656 test_ioctl_copy_chunk_max_output_sz
);
2657 torture_suite_add_1smb2_test(suite
, "copy_chunk_zero_length",
2658 test_ioctl_copy_chunk_zero_length
);
2659 torture_suite_add_1smb2_test(suite
, "compress_file_flag",
2660 test_ioctl_compress_file_flag
);
2661 torture_suite_add_1smb2_test(suite
, "compress_dir_inherit",
2662 test_ioctl_compress_dir_inherit
);
2663 torture_suite_add_1smb2_test(suite
, "compress_invalid_format",
2664 test_ioctl_compress_invalid_format
);
2665 torture_suite_add_1smb2_test(suite
, "compress_invalid_buf",
2666 test_ioctl_compress_invalid_buf
);
2667 torture_suite_add_1smb2_test(suite
, "compress_query_file_attr",
2668 test_ioctl_compress_query_file_attr
);
2669 torture_suite_add_1smb2_test(suite
, "compress_create_with_attr",
2670 test_ioctl_compress_create_with_attr
);
2671 torture_suite_add_1smb2_test(suite
, "compress_inherit_disable",
2672 test_ioctl_compress_inherit_disable
);
2673 torture_suite_add_1smb2_test(suite
, "compress_set_file_attr",
2674 test_ioctl_compress_set_file_attr
);
2675 torture_suite_add_1smb2_test(suite
, "compress_perms",
2676 test_ioctl_compress_perms
);
2677 torture_suite_add_1smb2_test(suite
, "network_interface_info",
2678 test_ioctl_network_interface_info
);
2679 torture_suite_add_1smb2_test(suite
, "sparse_file_flag",
2680 test_ioctl_sparse_file_flag
);
2681 torture_suite_add_1smb2_test(suite
, "sparse_file_attr",
2682 test_ioctl_sparse_file_attr
);
2684 suite
->description
= talloc_strdup(suite
, "SMB2-IOCTL tests");