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 "librpc/gen_ndr/ndr_ioctl.h"
30 #define FNAME "testfsctl.dat"
31 #define FNAME2 "testfsctl2.dat"
32 #define DNAME "testfsctl_dir"
35 basic testing of SMB2 shadow copy calls
37 static bool test_ioctl_get_shadow_copy(struct torture_context
*torture
,
38 struct smb2_tree
*tree
)
43 union smb_ioctl ioctl
;
44 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
46 smb2_util_unlink(tree
, FNAME
);
48 status
= torture_smb2_testfile(tree
, FNAME
, &h
);
49 torture_assert_ntstatus_ok(torture
, status
, "create write");
52 status
= smb2_util_write(tree
, h
, buf
, 0, ARRAY_SIZE(buf
));
53 torture_assert_ntstatus_ok(torture
, status
, "write");
56 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
57 ioctl
.smb2
.in
.file
.handle
= h
;
58 ioctl
.smb2
.in
.function
= FSCTL_SRV_ENUM_SNAPS
;
59 ioctl
.smb2
.in
.max_response_size
= 16;
60 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
62 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
63 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)
64 || NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_DEVICE_REQUEST
)) {
65 torture_skip(torture
, "FSCTL_SRV_ENUM_SNAPS not supported\n");
67 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_ENUM_SNAPS");
73 basic testing of the SMB2 server side copy ioctls
75 static bool test_ioctl_req_resume_key(struct torture_context
*torture
,
76 struct smb2_tree
*tree
)
81 union smb_ioctl ioctl
;
82 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
83 struct req_resume_key_rsp res_key
;
84 enum ndr_err_code ndr_ret
;
86 smb2_util_unlink(tree
, FNAME
);
88 status
= torture_smb2_testfile(tree
, FNAME
, &h
);
89 torture_assert_ntstatus_ok(torture
, status
, "create write");
92 status
= smb2_util_write(tree
, h
, buf
, 0, ARRAY_SIZE(buf
));
93 torture_assert_ntstatus_ok(torture
, status
, "write");
96 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
97 ioctl
.smb2
.in
.file
.handle
= h
;
98 ioctl
.smb2
.in
.function
= FSCTL_SRV_REQUEST_RESUME_KEY
;
99 ioctl
.smb2
.in
.max_response_size
= 32;
100 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
102 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
103 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_REQUEST_RESUME_KEY");
105 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
, &res_key
,
106 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
107 torture_assert_ndr_success(torture
, ndr_ret
,
108 "ndr_pull_req_resume_key_rsp");
110 ndr_print_debug((ndr_print_fn_t
)ndr_print_req_resume_key_rsp
, "yo", &res_key
);
112 talloc_free(tmp_ctx
);
116 static uint64_t patt_hash(uint64_t off
)
121 static bool check_pattern(struct torture_context
*torture
,
122 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
123 struct smb2_handle h
, uint64_t off
, uint64_t len
,
131 r
.in
.file
.handle
= h
;
134 status
= smb2_read(tree
, mem_ctx
, &r
);
135 torture_assert_ntstatus_ok(torture
, status
, "read");
137 torture_assert_u64_equal(torture
, r
.out
.data
.length
, len
,
138 "read data len mismatch");
140 for (i
= 0; i
<= len
- 8; i
+= 8, patt_off
+= 8) {
141 uint64_t data
= BVAL(r
.out
.data
.data
, i
);
142 torture_assert_u64_equal(torture
, data
, patt_hash(patt_off
),
143 talloc_asprintf(torture
, "read data "
144 "pattern bad at %llu\n",
145 (unsigned long long)i
));
148 talloc_free(r
.out
.data
.data
);
152 static bool test_setup_open(struct torture_context
*torture
,
153 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
155 struct smb2_handle
*fh
,
156 uint32_t desired_access
,
157 uint32_t file_attributes
)
159 struct smb2_create io
;
163 io
.in
.desired_access
= desired_access
;
164 io
.in
.file_attributes
= file_attributes
;
165 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
167 NTCREATEX_SHARE_ACCESS_DELETE
|
168 NTCREATEX_SHARE_ACCESS_READ
|
169 NTCREATEX_SHARE_ACCESS_WRITE
;
170 if (file_attributes
& FILE_ATTRIBUTE_DIRECTORY
) {
171 io
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
175 status
= smb2_create(tree
, mem_ctx
, &io
);
176 torture_assert_ntstatus_ok(torture
, status
, "file create");
178 *fh
= io
.out
.file
.handle
;
183 static bool test_setup_create_fill(struct torture_context
*torture
,
184 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
186 struct smb2_handle
*fh
,
188 uint32_t desired_access
,
189 uint32_t file_attributes
)
194 uint8_t *buf
= talloc_zero_size(mem_ctx
, size
);
195 torture_assert(torture
, (buf
!= NULL
), "no memory for file data buf");
197 smb2_util_unlink(tree
, fname
);
199 ok
= test_setup_open(torture
, tree
, mem_ctx
,
204 torture_assert(torture
, ok
, "file open");
207 uint64_t cur_off
= 0;
208 for (i
= 0; i
<= size
- 8; i
+= 8) {
209 SBVAL(buf
, i
, patt_hash(i
));
212 uint64_t io_sz
= MIN(1024 * 1024, size
);
213 status
= smb2_util_write(tree
, *fh
,
214 buf
+ cur_off
, cur_off
, io_sz
);
215 torture_assert_ntstatus_ok(torture
, status
, "file write");
224 static bool test_setup_copy_chunk(struct torture_context
*torture
,
225 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
227 struct smb2_handle
*src_h
,
229 uint32_t src_desired_access
,
230 struct smb2_handle
*dest_h
,
232 uint32_t dest_desired_access
,
233 struct srv_copychunk_copy
*cc_copy
,
234 union smb_ioctl
*ioctl
)
236 struct req_resume_key_rsp res_key
;
239 enum ndr_err_code ndr_ret
;
241 ok
= test_setup_create_fill(torture
, tree
, mem_ctx
, FNAME
,
242 src_h
, src_size
, src_desired_access
,
243 FILE_ATTRIBUTE_NORMAL
);
244 torture_assert(torture
, ok
, "src file create fill");
246 ok
= test_setup_create_fill(torture
, tree
, mem_ctx
, FNAME2
,
247 dest_h
, dest_size
, dest_desired_access
,
248 FILE_ATTRIBUTE_NORMAL
);
249 torture_assert(torture
, ok
, "dest file create fill");
251 ZERO_STRUCTPN(ioctl
);
252 ioctl
->smb2
.level
= RAW_IOCTL_SMB2
;
253 ioctl
->smb2
.in
.file
.handle
= *src_h
;
254 ioctl
->smb2
.in
.function
= FSCTL_SRV_REQUEST_RESUME_KEY
;
255 /* Allow for Key + ContextLength + Context */
256 ioctl
->smb2
.in
.max_response_size
= 32;
257 ioctl
->smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
259 status
= smb2_ioctl(tree
, mem_ctx
, &ioctl
->smb2
);
260 torture_assert_ntstatus_ok(torture
, status
,
261 "FSCTL_SRV_REQUEST_RESUME_KEY");
263 ndr_ret
= ndr_pull_struct_blob(&ioctl
->smb2
.out
.out
, mem_ctx
, &res_key
,
264 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
266 torture_assert_ndr_success(torture
, ndr_ret
,
267 "ndr_pull_req_resume_key_rsp");
269 ZERO_STRUCTPN(ioctl
);
270 ioctl
->smb2
.level
= RAW_IOCTL_SMB2
;
271 ioctl
->smb2
.in
.file
.handle
= *dest_h
;
272 ioctl
->smb2
.in
.function
= FSCTL_SRV_COPYCHUNK
;
273 ioctl
->smb2
.in
.max_response_size
= sizeof(struct srv_copychunk_rsp
);
274 ioctl
->smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
276 ZERO_STRUCTPN(cc_copy
);
277 memcpy(cc_copy
->source_key
, res_key
.resume_key
, ARRAY_SIZE(cc_copy
->source_key
));
278 cc_copy
->chunk_count
= nchunks
;
279 cc_copy
->chunks
= talloc_zero_array(mem_ctx
, struct srv_copychunk
, nchunks
);
280 torture_assert(torture
, (cc_copy
->chunks
!= NULL
), "no memory for chunks");
286 static bool check_copy_chunk_rsp(struct torture_context
*torture
,
287 struct srv_copychunk_rsp
*cc_rsp
,
288 uint32_t ex_chunks_written
,
289 uint32_t ex_chunk_bytes_written
,
290 uint32_t ex_total_bytes_written
)
292 torture_assert_int_equal(torture
, cc_rsp
->chunks_written
,
293 ex_chunks_written
, "num chunks");
294 torture_assert_int_equal(torture
, cc_rsp
->chunk_bytes_written
,
295 ex_chunk_bytes_written
, "chunk bytes written");
296 torture_assert_int_equal(torture
, cc_rsp
->total_bytes_written
,
297 ex_total_bytes_written
, "chunk total bytes");
301 static bool test_ioctl_copy_chunk_simple(struct torture_context
*torture
,
302 struct smb2_tree
*tree
)
304 struct smb2_handle src_h
;
305 struct smb2_handle dest_h
;
307 union smb_ioctl ioctl
;
308 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
309 struct srv_copychunk_copy cc_copy
;
310 struct srv_copychunk_rsp cc_rsp
;
311 enum ndr_err_code ndr_ret
;
314 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
316 &src_h
, 4096, /* fill 4096 byte src file */
318 &dest_h
, 0, /* 0 byte dest file */
323 torture_fail(torture
, "setup copy chunk error");
326 /* copy all src file data (via a single chunk desc) */
327 cc_copy
.chunks
[0].source_off
= 0;
328 cc_copy
.chunks
[0].target_off
= 0;
329 cc_copy
.chunks
[0].length
= 4096;
331 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
333 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
334 torture_assert_ndr_success(torture
, ndr_ret
,
335 "ndr_push_srv_copychunk_copy");
337 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
338 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
340 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
342 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
343 torture_assert_ndr_success(torture
, ndr_ret
,
344 "ndr_pull_srv_copychunk_rsp");
346 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
347 1, /* chunks written */
348 0, /* chunk bytes unsuccessfully written */
349 4096); /* total bytes written */
351 torture_fail(torture
, "bad copy chunk response data");
354 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
356 torture_fail(torture
, "inconsistent file data");
359 smb2_util_close(tree
, src_h
);
360 smb2_util_close(tree
, dest_h
);
361 talloc_free(tmp_ctx
);
365 static bool test_ioctl_copy_chunk_multi(struct torture_context
*torture
,
366 struct smb2_tree
*tree
)
368 struct smb2_handle src_h
;
369 struct smb2_handle dest_h
;
371 union smb_ioctl ioctl
;
372 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
373 struct srv_copychunk_copy cc_copy
;
374 struct srv_copychunk_rsp cc_rsp
;
375 enum ndr_err_code ndr_ret
;
378 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
380 &src_h
, 8192, /* src file */
382 &dest_h
, 0, /* dest file */
387 torture_fail(torture
, "setup copy chunk error");
390 /* copy all src file data via two chunks */
391 cc_copy
.chunks
[0].source_off
= 0;
392 cc_copy
.chunks
[0].target_off
= 0;
393 cc_copy
.chunks
[0].length
= 4096;
395 cc_copy
.chunks
[1].source_off
= 4096;
396 cc_copy
.chunks
[1].target_off
= 4096;
397 cc_copy
.chunks
[1].length
= 4096;
399 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
401 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
402 torture_assert_ndr_success(torture
, ndr_ret
,
403 "ndr_push_srv_copychunk_copy");
405 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
406 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
408 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
410 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
411 torture_assert_ndr_success(torture
, ndr_ret
,
412 "ndr_pull_srv_copychunk_rsp");
414 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
415 2, /* chunks written */
416 0, /* chunk bytes unsuccessfully written */
417 8192); /* total bytes written */
419 torture_fail(torture
, "bad copy chunk response data");
422 smb2_util_close(tree
, src_h
);
423 smb2_util_close(tree
, dest_h
);
424 talloc_free(tmp_ctx
);
428 static bool test_ioctl_copy_chunk_tiny(struct torture_context
*torture
,
429 struct smb2_tree
*tree
)
431 struct smb2_handle src_h
;
432 struct smb2_handle dest_h
;
434 union smb_ioctl ioctl
;
435 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
436 struct srv_copychunk_copy cc_copy
;
437 struct srv_copychunk_rsp cc_rsp
;
438 enum ndr_err_code ndr_ret
;
441 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
443 &src_h
, 100, /* src file */
445 &dest_h
, 0, /* dest file */
450 torture_fail(torture
, "setup copy chunk error");
453 /* copy all src file data via two chunks, sub block size chunks */
454 cc_copy
.chunks
[0].source_off
= 0;
455 cc_copy
.chunks
[0].target_off
= 0;
456 cc_copy
.chunks
[0].length
= 50;
458 cc_copy
.chunks
[1].source_off
= 50;
459 cc_copy
.chunks
[1].target_off
= 50;
460 cc_copy
.chunks
[1].length
= 50;
462 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
464 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
465 torture_assert_ndr_success(torture
, ndr_ret
,
466 "ndr_push_srv_copychunk_copy");
468 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
469 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
471 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
473 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
474 torture_assert_ndr_success(torture
, ndr_ret
,
475 "ndr_pull_srv_copychunk_rsp");
477 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
478 2, /* chunks written */
479 0, /* chunk bytes unsuccessfully written */
480 100); /* total bytes written */
482 torture_fail(torture
, "bad copy chunk response data");
485 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 100, 0);
487 torture_fail(torture
, "inconsistent file data");
490 smb2_util_close(tree
, src_h
);
491 smb2_util_close(tree
, dest_h
);
492 talloc_free(tmp_ctx
);
496 static bool test_ioctl_copy_chunk_over(struct torture_context
*torture
,
497 struct smb2_tree
*tree
)
499 struct smb2_handle src_h
;
500 struct smb2_handle dest_h
;
502 union smb_ioctl ioctl
;
503 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
504 struct srv_copychunk_copy cc_copy
;
505 struct srv_copychunk_rsp cc_rsp
;
506 enum ndr_err_code ndr_ret
;
509 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
511 &src_h
, 8192, /* src file */
513 &dest_h
, 4096, /* dest file */
518 torture_fail(torture
, "setup copy chunk error");
521 /* first chunk overwrites existing dest data */
522 cc_copy
.chunks
[0].source_off
= 0;
523 cc_copy
.chunks
[0].target_off
= 0;
524 cc_copy
.chunks
[0].length
= 4096;
526 /* second chunk overwrites the first */
527 cc_copy
.chunks
[1].source_off
= 4096;
528 cc_copy
.chunks
[1].target_off
= 0;
529 cc_copy
.chunks
[1].length
= 4096;
531 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
533 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
534 torture_assert_ndr_success(torture
, ndr_ret
,
535 "ndr_push_srv_copychunk_copy");
537 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
538 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
540 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
542 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
543 torture_assert_ndr_success(torture
, ndr_ret
,
544 "ndr_pull_srv_copychunk_rsp");
546 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
547 2, /* chunks written */
548 0, /* chunk bytes unsuccessfully written */
549 8192); /* total bytes written */
551 torture_fail(torture
, "bad copy chunk response data");
554 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 4096);
556 torture_fail(torture
, "inconsistent file data");
559 smb2_util_close(tree
, src_h
);
560 smb2_util_close(tree
, dest_h
);
561 talloc_free(tmp_ctx
);
565 static bool test_ioctl_copy_chunk_append(struct torture_context
*torture
,
566 struct smb2_tree
*tree
)
568 struct smb2_handle src_h
;
569 struct smb2_handle dest_h
;
571 union smb_ioctl ioctl
;
572 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
573 struct srv_copychunk_copy cc_copy
;
574 struct srv_copychunk_rsp cc_rsp
;
575 enum ndr_err_code ndr_ret
;
578 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
580 &src_h
, 4096, /* src file */
582 &dest_h
, 0, /* dest file */
587 torture_fail(torture
, "setup copy chunk error");
590 cc_copy
.chunks
[0].source_off
= 0;
591 cc_copy
.chunks
[0].target_off
= 0;
592 cc_copy
.chunks
[0].length
= 4096;
594 /* second chunk appends the same data to the first */
595 cc_copy
.chunks
[1].source_off
= 0;
596 cc_copy
.chunks
[1].target_off
= 4096;
597 cc_copy
.chunks
[1].length
= 4096;
599 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
601 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
602 torture_assert_ndr_success(torture
, ndr_ret
,
603 "ndr_push_srv_copychunk_copy");
605 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
606 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
608 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
610 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
611 torture_assert_ndr_success(torture
, ndr_ret
,
612 "ndr_pull_srv_copychunk_rsp");
614 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
615 2, /* chunks written */
616 0, /* chunk bytes unsuccessfully written */
617 8192); /* total bytes written */
619 torture_fail(torture
, "bad copy chunk response data");
622 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
624 torture_fail(torture
, "inconsistent file data");
627 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 4096, 4096, 0);
629 torture_fail(torture
, "inconsistent file data");
632 smb2_util_close(tree
, src_h
);
633 smb2_util_close(tree
, dest_h
);
634 talloc_free(tmp_ctx
);
638 static bool test_ioctl_copy_chunk_limits(struct torture_context
*torture
,
639 struct smb2_tree
*tree
)
641 struct smb2_handle src_h
;
642 struct smb2_handle dest_h
;
644 union smb_ioctl ioctl
;
645 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
646 struct srv_copychunk_copy cc_copy
;
647 struct srv_copychunk_rsp cc_rsp
;
648 enum ndr_err_code ndr_ret
;
651 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
653 &src_h
, 4096, /* src file */
655 &dest_h
, 0, /* dest file */
660 torture_fail(torture
, "setup copy chunk error");
663 /* send huge chunk length request */
664 cc_copy
.chunks
[0].source_off
= 0;
665 cc_copy
.chunks
[0].target_off
= 0;
666 cc_copy
.chunks
[0].length
= UINT_MAX
;
668 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
670 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
671 torture_assert_ndr_success(torture
, ndr_ret
, "marshalling request");
673 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
674 torture_assert_ntstatus_equal(torture
, status
,
675 NT_STATUS_INVALID_PARAMETER
,
676 "bad oversize chunk response");
678 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
680 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
681 torture_assert_ndr_success(torture
, ndr_ret
, "unmarshalling response");
683 torture_comment(torture
, "limit max chunks, got %u\n",
684 cc_rsp
.chunks_written
);
685 torture_comment(torture
, "limit max chunk len, got %u\n",
686 cc_rsp
.chunk_bytes_written
);
687 torture_comment(torture
, "limit max total bytes, got %u\n",
688 cc_rsp
.total_bytes_written
);
690 smb2_util_close(tree
, src_h
);
691 smb2_util_close(tree
, dest_h
);
692 talloc_free(tmp_ctx
);
696 static bool test_ioctl_copy_chunk_src_lck(struct torture_context
*torture
,
697 struct smb2_tree
*tree
)
699 struct smb2_handle src_h
;
700 struct smb2_handle src_h2
;
701 struct smb2_handle dest_h
;
703 union smb_ioctl ioctl
;
704 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
705 struct srv_copychunk_copy cc_copy
;
706 struct srv_copychunk_rsp cc_rsp
;
707 enum ndr_err_code ndr_ret
;
709 struct smb2_lock lck
;
710 struct smb2_lock_element el
[1];
712 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
714 &src_h
, 4096, /* src file */
716 &dest_h
, 0, /* dest file */
721 torture_fail(torture
, "setup copy chunk error");
724 cc_copy
.chunks
[0].source_off
= 0;
725 cc_copy
.chunks
[0].target_off
= 0;
726 cc_copy
.chunks
[0].length
= 4096;
728 /* open and lock the copychunk src file */
729 status
= torture_smb2_testfile(tree
, FNAME
, &src_h2
);
730 torture_assert_ntstatus_ok(torture
, status
, "2nd src open");
732 lck
.in
.lock_count
= 0x0001;
733 lck
.in
.lock_sequence
= 0x00000000;
734 lck
.in
.file
.handle
= src_h2
;
736 el
[0].offset
= cc_copy
.chunks
[0].source_off
;
737 el
[0].length
= cc_copy
.chunks
[0].length
;
739 el
[0].flags
= SMB2_LOCK_FLAG_EXCLUSIVE
;
741 status
= smb2_lock(tree
, &lck
);
742 torture_assert_ntstatus_ok(torture
, status
, "lock");
744 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
746 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
747 torture_assert_ndr_success(torture
, ndr_ret
,
748 "ndr_push_srv_copychunk_copy");
750 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
752 * 2k12 & Samba return lock_conflict, Windows 7 & 2k8 return success...
754 * Edgar Olougouna @ MS wrote:
755 * Regarding the FSCTL_SRV_COPYCHUNK and STATUS_FILE_LOCK_CONFLICT
756 * discrepancy observed between Windows versions, we confirm that the
757 * behavior change is expected.
759 * CopyChunk in Windows Server 2012 use regular Readfile/Writefile APIs
760 * to move the chunks from the source to the destination.
761 * These ReadFile/WriteFile APIs go through the byte-range lock checks,
762 * and this explains the observed STATUS_FILE_LOCK_CONFLICT error.
764 * Prior to Windows Server 2012, CopyChunk used mapped sections to move
765 * the data. And byte range locks are not enforced on mapped I/O, and
766 * this explains the STATUS_SUCCESS observed on Windows Server 2008 R2.
768 torture_assert_ntstatus_equal(torture
, status
,
769 NT_STATUS_FILE_LOCK_CONFLICT
,
770 "FSCTL_SRV_COPYCHUNK locked");
772 /* should get cc response data with the lock conflict status */
773 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
775 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
776 torture_assert_ndr_success(torture
, ndr_ret
,
777 "ndr_pull_srv_copychunk_rsp");
778 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
779 0, /* chunks written */
780 0, /* chunk bytes unsuccessfully written */
781 0); /* total bytes written */
783 lck
.in
.lock_count
= 0x0001;
784 lck
.in
.lock_sequence
= 0x00000001;
785 lck
.in
.file
.handle
= src_h2
;
787 el
[0].offset
= cc_copy
.chunks
[0].source_off
;
788 el
[0].length
= cc_copy
.chunks
[0].length
;
790 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
791 status
= smb2_lock(tree
, &lck
);
792 torture_assert_ntstatus_ok(torture
, status
, "unlock");
794 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
795 torture_assert_ntstatus_ok(torture
, status
,
796 "FSCTL_SRV_COPYCHUNK unlocked");
798 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
800 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
801 torture_assert_ndr_success(torture
, ndr_ret
,
802 "ndr_pull_srv_copychunk_rsp");
804 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
805 1, /* chunks written */
806 0, /* chunk bytes unsuccessfully written */
807 4096); /* total bytes written */
809 torture_fail(torture
, "bad copy chunk response data");
812 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
814 torture_fail(torture
, "inconsistent file data");
817 smb2_util_close(tree
, src_h2
);
818 smb2_util_close(tree
, src_h
);
819 smb2_util_close(tree
, dest_h
);
820 talloc_free(tmp_ctx
);
824 static bool test_ioctl_copy_chunk_dest_lck(struct torture_context
*torture
,
825 struct smb2_tree
*tree
)
827 struct smb2_handle src_h
;
828 struct smb2_handle dest_h
;
829 struct smb2_handle dest_h2
;
831 union smb_ioctl ioctl
;
832 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
833 struct srv_copychunk_copy cc_copy
;
834 struct srv_copychunk_rsp cc_rsp
;
835 enum ndr_err_code ndr_ret
;
837 struct smb2_lock lck
;
838 struct smb2_lock_element el
[1];
840 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
842 &src_h
, 4096, /* src file */
844 &dest_h
, 4096, /* dest file */
849 torture_fail(torture
, "setup copy chunk error");
852 cc_copy
.chunks
[0].source_off
= 0;
853 cc_copy
.chunks
[0].target_off
= 0;
854 cc_copy
.chunks
[0].length
= 4096;
856 /* open and lock the copychunk dest file */
857 status
= torture_smb2_testfile(tree
, FNAME2
, &dest_h2
);
858 torture_assert_ntstatus_ok(torture
, status
, "2nd src open");
860 lck
.in
.lock_count
= 0x0001;
861 lck
.in
.lock_sequence
= 0x00000000;
862 lck
.in
.file
.handle
= dest_h2
;
864 el
[0].offset
= cc_copy
.chunks
[0].target_off
;
865 el
[0].length
= cc_copy
.chunks
[0].length
;
867 el
[0].flags
= SMB2_LOCK_FLAG_EXCLUSIVE
;
869 status
= smb2_lock(tree
, &lck
);
870 torture_assert_ntstatus_ok(torture
, status
, "lock");
872 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
874 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
875 torture_assert_ndr_success(torture
, ndr_ret
,
876 "ndr_push_srv_copychunk_copy");
878 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
879 torture_assert_ntstatus_equal(torture
, status
,
880 NT_STATUS_FILE_LOCK_CONFLICT
,
881 "FSCTL_SRV_COPYCHUNK locked");
883 lck
.in
.lock_count
= 0x0001;
884 lck
.in
.lock_sequence
= 0x00000001;
885 lck
.in
.file
.handle
= dest_h2
;
887 el
[0].offset
= cc_copy
.chunks
[0].target_off
;
888 el
[0].length
= cc_copy
.chunks
[0].length
;
890 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
891 status
= smb2_lock(tree
, &lck
);
892 torture_assert_ntstatus_ok(torture
, status
, "unlock");
894 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
895 torture_assert_ntstatus_ok(torture
, status
,
896 "FSCTL_SRV_COPYCHUNK unlocked");
898 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
900 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
901 torture_assert_ndr_success(torture
, ndr_ret
,
902 "ndr_pull_srv_copychunk_rsp");
904 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
905 1, /* chunks written */
906 0, /* chunk bytes unsuccessfully written */
907 4096); /* total bytes written */
909 torture_fail(torture
, "bad copy chunk response data");
912 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
914 torture_fail(torture
, "inconsistent file data");
917 smb2_util_close(tree
, dest_h2
);
918 smb2_util_close(tree
, src_h
);
919 smb2_util_close(tree
, dest_h
);
920 talloc_free(tmp_ctx
);
924 static bool test_ioctl_copy_chunk_bad_key(struct torture_context
*torture
,
925 struct smb2_tree
*tree
)
927 struct smb2_handle src_h
;
928 struct smb2_handle dest_h
;
930 union smb_ioctl ioctl
;
931 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
932 struct srv_copychunk_copy cc_copy
;
933 enum ndr_err_code ndr_ret
;
936 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
945 torture_fail(torture
, "setup copy chunk error");
948 /* overwrite the resume key with a bogus value */
949 memcpy(cc_copy
.source_key
, "deadbeefdeadbeefdeadbeef", 24);
951 cc_copy
.chunks
[0].source_off
= 0;
952 cc_copy
.chunks
[0].target_off
= 0;
953 cc_copy
.chunks
[0].length
= 4096;
955 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
957 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
958 torture_assert_ndr_success(torture
, ndr_ret
,
959 "ndr_push_srv_copychunk_copy");
961 /* Server 2k12 returns NT_STATUS_OBJECT_NAME_NOT_FOUND */
962 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
963 torture_assert_ntstatus_equal(torture
, status
,
964 NT_STATUS_OBJECT_NAME_NOT_FOUND
,
965 "FSCTL_SRV_COPYCHUNK");
967 smb2_util_close(tree
, src_h
);
968 smb2_util_close(tree
, dest_h
);
969 talloc_free(tmp_ctx
);
973 static bool test_ioctl_copy_chunk_src_is_dest(struct torture_context
*torture
,
974 struct smb2_tree
*tree
)
976 struct smb2_handle src_h
;
977 struct smb2_handle dest_h
;
979 union smb_ioctl ioctl
;
980 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
981 struct srv_copychunk_copy cc_copy
;
982 struct srv_copychunk_rsp cc_rsp
;
983 enum ndr_err_code ndr_ret
;
986 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
995 torture_fail(torture
, "setup copy chunk error");
998 /* the source is also the destination */
999 ioctl
.smb2
.in
.file
.handle
= src_h
;
1001 /* non-overlapping */
1002 cc_copy
.chunks
[0].source_off
= 0;
1003 cc_copy
.chunks
[0].target_off
= 4096;
1004 cc_copy
.chunks
[0].length
= 4096;
1006 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1008 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1009 torture_assert_ndr_success(torture
, ndr_ret
,
1010 "ndr_push_srv_copychunk_copy");
1012 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1013 torture_assert_ntstatus_ok(torture
, status
,
1014 "FSCTL_SRV_COPYCHUNK");
1016 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1018 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1019 torture_assert_ndr_success(torture
, ndr_ret
,
1020 "ndr_pull_srv_copychunk_rsp");
1022 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1023 1, /* chunks written */
1024 0, /* chunk bytes unsuccessfully written */
1025 4096); /* total bytes written */
1027 torture_fail(torture
, "bad copy chunk response data");
1030 ok
= check_pattern(torture
, tree
, tmp_ctx
, src_h
, 0, 4096, 0);
1032 torture_fail(torture
, "inconsistent file data");
1034 ok
= check_pattern(torture
, tree
, tmp_ctx
, src_h
, 4096, 4096, 0);
1036 torture_fail(torture
, "inconsistent file data");
1039 smb2_util_close(tree
, src_h
);
1040 smb2_util_close(tree
, dest_h
);
1041 talloc_free(tmp_ctx
);
1046 * Test a single-chunk copychunk request, where the source and target ranges
1047 * overlap, and the SourceKey refers to the same target file. E.g:
1051 * File: src_and_dest
1052 * Offset: 0123456789
1057 * FSCTL_SRV_COPYCHUNK(src_and_dest)
1058 * SourceKey = SRV_REQUEST_RESUME_KEY(src_and_dest)
1060 * Chunks[0].SourceOffset = 0
1061 * Chunks[0].TargetOffset = 4
1062 * Chunks[0].Length = 6
1066 * File: src_and_dest
1067 * Offset: 0123456789
1070 * The resultant contents of src_and_dest is dependent on the server's
1071 * copy algorithm. In the above example, the server uses an IO buffer
1072 * large enough to hold the entire six-byte source data before writing
1073 * to TargetOffset. If the server were to use a four-byte IO buffer and
1074 * started reads/writes from the lowest offset, then the two overlapping
1075 * bytes in the above example would be overwritten before being read. The
1076 * resultant file contents would be abcdabcdab.
1078 * Windows 2008r2 appears to use a 2048 byte copy buffer, overlapping bytes
1079 * after this offset are written before being read. Windows 2012 on the
1080 * other hand appears to use a buffer large enough to hold its maximum
1081 * supported chunk size (1M). Samba currently uses a 64k copy buffer by
1082 * default (vfs_cc_state.buf).
1084 * This test uses an 8-byte overlap at 2040-2048, so that it passes against
1085 * Windows 2008r2, 2012 and Samba servers. Note, 2008GM fails, as it appears
1086 * to use a different copy algorithm to 2008r2.
1089 test_ioctl_copy_chunk_src_is_dest_overlap(struct torture_context
*torture
,
1090 struct smb2_tree
*tree
)
1092 struct smb2_handle src_h
;
1093 struct smb2_handle dest_h
;
1095 union smb_ioctl ioctl
;
1096 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1097 struct srv_copychunk_copy cc_copy
;
1098 struct srv_copychunk_rsp cc_rsp
;
1099 enum ndr_err_code ndr_ret
;
1102 /* exceed the vfs_default copy buffer */
1103 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1106 SEC_RIGHTS_FILE_ALL
,
1108 SEC_RIGHTS_FILE_ALL
,
1112 torture_fail(torture
, "setup copy chunk error");
1115 /* the source is also the destination */
1116 ioctl
.smb2
.in
.file
.handle
= src_h
;
1118 /* 8 bytes overlap between source and target ranges */
1119 cc_copy
.chunks
[0].source_off
= 0;
1120 cc_copy
.chunks
[0].target_off
= 2048 - 8;
1121 cc_copy
.chunks
[0].length
= 2048;
1123 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1125 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1126 torture_assert_ndr_success(torture
, ndr_ret
,
1127 "ndr_push_srv_copychunk_copy");
1129 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1130 torture_assert_ntstatus_ok(torture
, status
,
1131 "FSCTL_SRV_COPYCHUNK");
1133 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1135 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1136 torture_assert_ndr_success(torture
, ndr_ret
,
1137 "ndr_pull_srv_copychunk_rsp");
1139 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1140 1, /* chunks written */
1141 0, /* chunk bytes unsuccessfully written */
1142 2048); /* total bytes written */
1144 torture_fail(torture
, "bad copy chunk response data");
1147 ok
= check_pattern(torture
, tree
, tmp_ctx
, src_h
, 0, 2048 - 8, 0);
1149 torture_fail(torture
, "inconsistent file data");
1151 ok
= check_pattern(torture
, tree
, tmp_ctx
, src_h
, 2048 - 8, 2048, 0);
1153 torture_fail(torture
, "inconsistent file data");
1156 smb2_util_close(tree
, src_h
);
1157 smb2_util_close(tree
, dest_h
);
1158 talloc_free(tmp_ctx
);
1162 static bool test_ioctl_copy_chunk_bad_access(struct torture_context
*torture
,
1163 struct smb2_tree
*tree
)
1165 struct smb2_handle src_h
;
1166 struct smb2_handle dest_h
;
1168 union smb_ioctl ioctl
;
1169 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1170 struct srv_copychunk_copy cc_copy
;
1171 enum ndr_err_code ndr_ret
;
1174 /* no read permission on src */
1175 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1177 &src_h
, 4096, /* fill 4096 byte src file */
1178 SEC_RIGHTS_FILE_WRITE
,
1179 &dest_h
, 0, /* 0 byte dest file */
1180 SEC_RIGHTS_FILE_ALL
,
1184 torture_fail(torture
, "setup copy chunk error");
1187 cc_copy
.chunks
[0].source_off
= 0;
1188 cc_copy
.chunks
[0].target_off
= 0;
1189 cc_copy
.chunks
[0].length
= 4096;
1191 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1193 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1194 torture_assert_ndr_success(torture
, ndr_ret
,
1195 "ndr_push_srv_copychunk_copy");
1197 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1198 torture_assert_ntstatus_equal(torture
, status
,
1199 NT_STATUS_ACCESS_DENIED
,
1200 "FSCTL_SRV_COPYCHUNK");
1202 smb2_util_close(tree
, src_h
);
1203 smb2_util_close(tree
, dest_h
);
1205 /* no write permission on dest */
1206 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1208 &src_h
, 4096, /* fill 4096 byte src file */
1209 SEC_RIGHTS_FILE_ALL
,
1210 &dest_h
, 0, /* 0 byte dest file */
1211 (SEC_RIGHTS_FILE_READ
1212 | SEC_RIGHTS_FILE_EXECUTE
),
1216 torture_fail(torture
, "setup copy chunk error");
1219 cc_copy
.chunks
[0].source_off
= 0;
1220 cc_copy
.chunks
[0].target_off
= 0;
1221 cc_copy
.chunks
[0].length
= 4096;
1223 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1225 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1226 torture_assert_ndr_success(torture
, ndr_ret
,
1227 "ndr_push_srv_copychunk_copy");
1229 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1230 torture_assert_ntstatus_equal(torture
, status
,
1231 NT_STATUS_ACCESS_DENIED
,
1232 "FSCTL_SRV_COPYCHUNK");
1234 smb2_util_close(tree
, src_h
);
1235 smb2_util_close(tree
, dest_h
);
1237 /* no read permission on dest */
1238 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1240 &src_h
, 4096, /* fill 4096 byte src file */
1241 SEC_RIGHTS_FILE_ALL
,
1242 &dest_h
, 0, /* 0 byte dest file */
1243 (SEC_RIGHTS_FILE_WRITE
1244 | SEC_RIGHTS_FILE_EXECUTE
),
1248 torture_fail(torture
, "setup copy chunk error");
1251 cc_copy
.chunks
[0].source_off
= 0;
1252 cc_copy
.chunks
[0].target_off
= 0;
1253 cc_copy
.chunks
[0].length
= 4096;
1255 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1257 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1258 torture_assert_ndr_success(torture
, ndr_ret
,
1259 "ndr_push_srv_copychunk_copy");
1262 * FSCTL_SRV_COPYCHUNK requires read permission on dest,
1263 * FSCTL_SRV_COPYCHUNK_WRITE on the other hand does not.
1265 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1266 torture_assert_ntstatus_equal(torture
, status
,
1267 NT_STATUS_ACCESS_DENIED
,
1268 "FSCTL_SRV_COPYCHUNK");
1270 smb2_util_close(tree
, src_h
);
1271 smb2_util_close(tree
, dest_h
);
1272 talloc_free(tmp_ctx
);
1277 static bool test_ioctl_copy_chunk_write_access(struct torture_context
*torture
,
1278 struct smb2_tree
*tree
)
1280 struct smb2_handle src_h
;
1281 struct smb2_handle dest_h
;
1283 union smb_ioctl ioctl
;
1284 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1285 struct srv_copychunk_copy cc_copy
;
1286 enum ndr_err_code ndr_ret
;
1289 /* no read permission on dest with FSCTL_SRV_COPYCHUNK_WRITE */
1290 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1292 &src_h
, 4096, /* fill 4096 byte src file */
1293 SEC_RIGHTS_FILE_ALL
,
1294 &dest_h
, 0, /* 0 byte dest file */
1295 (SEC_RIGHTS_FILE_WRITE
1296 | SEC_RIGHTS_FILE_EXECUTE
),
1300 torture_fail(torture
, "setup copy chunk error");
1303 ioctl
.smb2
.in
.function
= FSCTL_SRV_COPYCHUNK_WRITE
;
1304 cc_copy
.chunks
[0].source_off
= 0;
1305 cc_copy
.chunks
[0].target_off
= 0;
1306 cc_copy
.chunks
[0].length
= 4096;
1308 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1310 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1311 torture_assert_ndr_success(torture
, ndr_ret
,
1312 "ndr_push_srv_copychunk_copy");
1314 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1315 torture_assert_ntstatus_ok(torture
, status
,
1316 "FSCTL_SRV_COPYCHUNK_WRITE");
1318 smb2_util_close(tree
, src_h
);
1319 smb2_util_close(tree
, dest_h
);
1320 talloc_free(tmp_ctx
);
1325 static bool test_ioctl_copy_chunk_src_exceed(struct torture_context
*torture
,
1326 struct smb2_tree
*tree
)
1328 struct smb2_handle src_h
;
1329 struct smb2_handle dest_h
;
1331 union smb_ioctl ioctl
;
1332 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1333 struct srv_copychunk_copy cc_copy
;
1334 struct srv_copychunk_rsp cc_rsp
;
1335 enum ndr_err_code ndr_ret
;
1338 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1340 &src_h
, 4096, /* fill 4096 byte src file */
1341 SEC_RIGHTS_FILE_ALL
,
1342 &dest_h
, 0, /* 0 byte dest file */
1343 SEC_RIGHTS_FILE_ALL
,
1347 torture_fail(torture
, "setup copy chunk error");
1350 /* Request copy where off + length exceeds size of src */
1351 cc_copy
.chunks
[0].source_off
= 1024;
1352 cc_copy
.chunks
[0].target_off
= 0;
1353 cc_copy
.chunks
[0].length
= 4096;
1355 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1357 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1358 torture_assert_ndr_success(torture
, ndr_ret
,
1359 "ndr_push_srv_copychunk_copy");
1361 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1362 torture_assert_ntstatus_equal(torture
, status
,
1363 NT_STATUS_INVALID_VIEW_SIZE
,
1364 "FSCTL_SRV_COPYCHUNK oversize");
1366 /* Request copy where length exceeds size of src */
1367 cc_copy
.chunks
[0].source_off
= 1024;
1368 cc_copy
.chunks
[0].target_off
= 0;
1369 cc_copy
.chunks
[0].length
= 3072;
1371 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1373 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1374 torture_assert_ndr_success(torture
, ndr_ret
,
1375 "ndr_push_srv_copychunk_copy");
1377 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1378 torture_assert_ntstatus_ok(torture
, status
,
1379 "FSCTL_SRV_COPYCHUNK just right");
1381 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1383 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1384 torture_assert_ndr_success(torture
, ndr_ret
,
1385 "ndr_pull_srv_copychunk_rsp");
1387 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1388 1, /* chunks written */
1389 0, /* chunk bytes unsuccessfully written */
1390 3072); /* total bytes written */
1392 torture_fail(torture
, "bad copy chunk response data");
1395 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 3072, 1024);
1397 torture_fail(torture
, "inconsistent file data");
1400 smb2_util_close(tree
, src_h
);
1401 smb2_util_close(tree
, dest_h
);
1402 talloc_free(tmp_ctx
);
1407 test_ioctl_copy_chunk_src_exceed_multi(struct torture_context
*torture
,
1408 struct smb2_tree
*tree
)
1410 struct smb2_handle src_h
;
1411 struct smb2_handle dest_h
;
1413 union smb_ioctl ioctl
;
1414 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1415 struct srv_copychunk_copy cc_copy
;
1416 struct srv_copychunk_rsp cc_rsp
;
1417 enum ndr_err_code ndr_ret
;
1420 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1422 &src_h
, 8192, /* fill 8192 byte src file */
1423 SEC_RIGHTS_FILE_ALL
,
1424 &dest_h
, 0, /* 0 byte dest file */
1425 SEC_RIGHTS_FILE_ALL
,
1429 torture_fail(torture
, "setup copy chunk error");
1432 /* Request copy where off + length exceeds size of src */
1433 cc_copy
.chunks
[0].source_off
= 0;
1434 cc_copy
.chunks
[0].target_off
= 0;
1435 cc_copy
.chunks
[0].length
= 4096;
1437 cc_copy
.chunks
[1].source_off
= 4096;
1438 cc_copy
.chunks
[1].target_off
= 4096;
1439 cc_copy
.chunks
[1].length
= 8192;
1441 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1443 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1444 torture_assert_ndr_success(torture
, ndr_ret
,
1445 "ndr_push_srv_copychunk_copy");
1447 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1448 torture_assert_ntstatus_equal(torture
, status
,
1449 NT_STATUS_INVALID_VIEW_SIZE
,
1450 "FSCTL_SRV_COPYCHUNK oversize");
1451 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1453 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1454 torture_assert_ndr_success(torture
, ndr_ret
, "unmarshalling response");
1456 /* first chunk should still be written */
1457 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1458 1, /* chunks written */
1459 0, /* chunk bytes unsuccessfully written */
1460 4096); /* total bytes written */
1462 torture_fail(torture
, "bad copy chunk response data");
1464 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
1466 torture_fail(torture
, "inconsistent file data");
1469 smb2_util_close(tree
, src_h
);
1470 smb2_util_close(tree
, dest_h
);
1471 talloc_free(tmp_ctx
);
1475 static bool test_ioctl_copy_chunk_sparse_dest(struct torture_context
*torture
,
1476 struct smb2_tree
*tree
)
1478 struct smb2_handle src_h
;
1479 struct smb2_handle dest_h
;
1481 union smb_ioctl ioctl
;
1483 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1484 struct srv_copychunk_copy cc_copy
;
1485 struct srv_copychunk_rsp cc_rsp
;
1486 enum ndr_err_code ndr_ret
;
1490 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1492 &src_h
, 4096, /* fill 4096 byte src file */
1493 SEC_RIGHTS_FILE_ALL
,
1494 &dest_h
, 0, /* 0 byte dest file */
1495 SEC_RIGHTS_FILE_ALL
,
1499 torture_fail(torture
, "setup copy chunk error");
1502 /* copy all src file data (via a single chunk desc) */
1503 cc_copy
.chunks
[0].source_off
= 0;
1504 cc_copy
.chunks
[0].target_off
= 4096;
1505 cc_copy
.chunks
[0].length
= 4096;
1507 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1509 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1510 torture_assert_ndr_success(torture
, ndr_ret
,
1511 "ndr_push_srv_copychunk_copy");
1513 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1514 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
1516 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1518 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1519 torture_assert_ndr_success(torture
, ndr_ret
,
1520 "ndr_pull_srv_copychunk_rsp");
1522 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1523 1, /* chunks written */
1524 0, /* chunk bytes unsuccessfully written */
1525 4096); /* total bytes written */
1527 torture_fail(torture
, "bad copy chunk response data");
1530 /* check for zeros in first 4k */
1532 r
.in
.file
.handle
= dest_h
;
1535 status
= smb2_read(tree
, tmp_ctx
, &r
);
1536 torture_assert_ntstatus_ok(torture
, status
, "read");
1538 torture_assert_u64_equal(torture
, r
.out
.data
.length
, 4096,
1539 "read data len mismatch");
1541 for (i
= 0; i
< 4096; i
++) {
1542 torture_assert(torture
, (r
.out
.data
.data
[i
] == 0),
1543 "sparse did not pass class");
1546 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 4096, 4096, 0);
1548 torture_fail(torture
, "inconsistent file data");
1551 smb2_util_close(tree
, src_h
);
1552 smb2_util_close(tree
, dest_h
);
1553 talloc_free(tmp_ctx
);
1558 * set the ioctl MaxOutputResponse size to less than
1559 * sizeof(struct srv_copychunk_rsp)
1561 static bool test_ioctl_copy_chunk_max_output_sz(struct torture_context
*torture
,
1562 struct smb2_tree
*tree
)
1564 struct smb2_handle src_h
;
1565 struct smb2_handle dest_h
;
1567 union smb_ioctl ioctl
;
1568 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1569 struct srv_copychunk_copy cc_copy
;
1570 enum ndr_err_code ndr_ret
;
1573 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1575 &src_h
, 4096, /* fill 4096 byte src file */
1576 SEC_RIGHTS_FILE_ALL
,
1577 &dest_h
, 0, /* 0 byte dest file */
1578 SEC_RIGHTS_FILE_ALL
,
1582 torture_fail(torture
, "setup copy chunk error");
1585 cc_copy
.chunks
[0].source_off
= 0;
1586 cc_copy
.chunks
[0].target_off
= 0;
1587 cc_copy
.chunks
[0].length
= 4096;
1588 /* req is valid, but use undersize max_response_size */
1589 ioctl
.smb2
.in
.max_response_size
= sizeof(struct srv_copychunk_rsp
) - 1;
1591 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1593 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1594 torture_assert_ndr_success(torture
, ndr_ret
,
1595 "ndr_push_srv_copychunk_copy");
1597 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1598 torture_assert_ntstatus_equal(torture
, status
,
1599 NT_STATUS_INVALID_PARAMETER
,
1600 "FSCTL_SRV_COPYCHUNK");
1602 smb2_util_close(tree
, src_h
);
1603 smb2_util_close(tree
, dest_h
);
1604 talloc_free(tmp_ctx
);
1608 static bool test_ioctl_copy_chunk_zero_length(struct torture_context
*torture
,
1609 struct smb2_tree
*tree
)
1611 struct smb2_handle src_h
;
1612 struct smb2_handle dest_h
;
1614 union smb_ioctl ioctl
;
1615 union smb_fileinfo q
;
1616 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1617 struct srv_copychunk_copy cc_copy
;
1618 struct srv_copychunk_rsp cc_rsp
;
1619 enum ndr_err_code ndr_ret
;
1622 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1624 &src_h
, 4096, /* fill 4096 byte src file */
1625 SEC_RIGHTS_FILE_ALL
,
1626 &dest_h
, 0, /* 0 byte dest file */
1627 SEC_RIGHTS_FILE_ALL
,
1631 torture_fail(torture
, "setup copy chunk error");
1634 /* zero length server-side copy (via a single chunk desc) */
1635 cc_copy
.chunks
[0].source_off
= 0;
1636 cc_copy
.chunks
[0].target_off
= 0;
1637 cc_copy
.chunks
[0].length
= 0;
1639 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1641 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1642 torture_assert_ndr_success(torture
, ndr_ret
,
1643 "ndr_push_srv_copychunk_copy");
1645 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1646 torture_assert_ntstatus_equal(torture
, status
,
1647 NT_STATUS_INVALID_PARAMETER
,
1648 "bad zero-length chunk response");
1650 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1652 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1653 torture_assert_ndr_success(torture
, ndr_ret
, "unmarshalling response");
1656 q
.all_info2
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
1657 q
.all_info2
.in
.file
.handle
= dest_h
;
1658 status
= smb2_getinfo_file(tree
, torture
, &q
);
1659 torture_assert_ntstatus_ok(torture
, status
, "getinfo");
1661 torture_assert_int_equal(torture
, q
.all_info2
.out
.size
, 0,
1662 "size after zero len clone");
1664 smb2_util_close(tree
, src_h
);
1665 smb2_util_close(tree
, dest_h
);
1666 talloc_free(tmp_ctx
);
1670 static NTSTATUS
test_ioctl_compress_fs_supported(struct torture_context
*torture
,
1671 struct smb2_tree
*tree
,
1672 TALLOC_CTX
*mem_ctx
,
1673 struct smb2_handle
*fh
,
1674 bool *compress_support
)
1677 union smb_fsinfo info
;
1680 info
.generic
.level
= RAW_QFS_ATTRIBUTE_INFORMATION
;
1681 info
.generic
.handle
= *fh
;
1682 status
= smb2_getinfo_fs(tree
, tree
, &info
);
1683 if (!NT_STATUS_IS_OK(status
)) {
1687 if (info
.attribute_info
.out
.fs_attr
& FILE_FILE_COMPRESSION
) {
1688 *compress_support
= true;
1690 *compress_support
= false;
1692 return NT_STATUS_OK
;
1695 static NTSTATUS
test_ioctl_compress_get(struct torture_context
*torture
,
1696 TALLOC_CTX
*mem_ctx
,
1697 struct smb2_tree
*tree
,
1698 struct smb2_handle fh
,
1699 uint16_t *_compression_fmt
)
1701 union smb_ioctl ioctl
;
1702 struct compression_state cmpr_state
;
1703 enum ndr_err_code ndr_ret
;
1707 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
1708 ioctl
.smb2
.in
.file
.handle
= fh
;
1709 ioctl
.smb2
.in
.function
= FSCTL_GET_COMPRESSION
;
1710 ioctl
.smb2
.in
.max_response_size
= sizeof(struct compression_state
);
1711 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
1713 status
= smb2_ioctl(tree
, mem_ctx
, &ioctl
.smb2
);
1714 if (!NT_STATUS_IS_OK(status
)) {
1718 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, mem_ctx
,
1720 (ndr_pull_flags_fn_t
)ndr_pull_compression_state
);
1722 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
1723 return NT_STATUS_INTERNAL_ERROR
;
1726 *_compression_fmt
= cmpr_state
.format
;
1727 return NT_STATUS_OK
;
1730 static NTSTATUS
test_ioctl_compress_set(struct torture_context
*torture
,
1731 TALLOC_CTX
*mem_ctx
,
1732 struct smb2_tree
*tree
,
1733 struct smb2_handle fh
,
1734 uint16_t compression_fmt
)
1736 union smb_ioctl ioctl
;
1737 struct compression_state cmpr_state
;
1738 enum ndr_err_code ndr_ret
;
1742 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
1743 ioctl
.smb2
.in
.file
.handle
= fh
;
1744 ioctl
.smb2
.in
.function
= FSCTL_SET_COMPRESSION
;
1745 ioctl
.smb2
.in
.max_response_size
= 0;
1746 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
1748 cmpr_state
.format
= compression_fmt
;
1749 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, mem_ctx
,
1751 (ndr_push_flags_fn_t
)ndr_push_compression_state
);
1752 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
1753 return NT_STATUS_INTERNAL_ERROR
;
1756 status
= smb2_ioctl(tree
, mem_ctx
, &ioctl
.smb2
);
1760 static bool test_ioctl_compress_file_flag(struct torture_context
*torture
,
1761 struct smb2_tree
*tree
)
1763 struct smb2_handle fh
;
1765 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1767 uint16_t compression_fmt
;
1769 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1770 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
1771 FILE_ATTRIBUTE_NORMAL
);
1772 torture_assert(torture
, ok
, "setup compression file");
1774 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
1776 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
1778 smb2_util_close(tree
, fh
);
1779 torture_skip(torture
, "FS compression not supported\n");
1782 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1784 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1786 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
1787 "initial compression state not NONE");
1789 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
1790 COMPRESSION_FORMAT_DEFAULT
);
1791 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
1793 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1795 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1797 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
1798 "invalid compression state after set");
1800 smb2_util_close(tree
, fh
);
1801 talloc_free(tmp_ctx
);
1805 static bool test_ioctl_compress_dir_inherit(struct torture_context
*torture
,
1806 struct smb2_tree
*tree
)
1808 struct smb2_handle dirh
;
1809 struct smb2_handle fh
;
1811 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1812 uint16_t compression_fmt
;
1814 char path_buf
[PATH_MAX
];
1816 smb2_deltree(tree
, DNAME
);
1817 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1818 DNAME
, &dirh
, 0, SEC_RIGHTS_FILE_ALL
,
1819 FILE_ATTRIBUTE_DIRECTORY
);
1820 torture_assert(torture
, ok
, "setup compression directory");
1822 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &dirh
,
1824 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
1826 smb2_util_close(tree
, dirh
);
1827 smb2_deltree(tree
, DNAME
);
1828 torture_skip(torture
, "FS compression not supported\n");
1831 /* set compression on parent dir, then check for inheritance */
1832 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, dirh
,
1833 COMPRESSION_FORMAT_LZNT1
);
1834 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
1836 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, dirh
,
1838 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1840 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
1841 "invalid compression state after set");
1843 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, FNAME
);
1844 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1845 path_buf
, &fh
, 4096, SEC_RIGHTS_FILE_ALL
,
1846 FILE_ATTRIBUTE_NORMAL
);
1847 torture_assert(torture
, ok
, "setup compression file");
1849 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1851 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1853 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
1854 "compression attr not inherited by new file");
1856 /* check compressed data is consistent */
1857 ok
= check_pattern(torture
, tree
, tmp_ctx
, fh
, 0, 4096, 0);
1859 /* disable dir compression attr, file should remain compressed */
1860 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, dirh
,
1861 COMPRESSION_FORMAT_NONE
);
1862 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
1864 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1866 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1868 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
1869 "file compression attr removed after dir change");
1870 smb2_util_close(tree
, fh
);
1872 /* new files should no longer inherit compression attr */
1873 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, FNAME2
);
1874 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1875 path_buf
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
1876 FILE_ATTRIBUTE_NORMAL
);
1877 torture_assert(torture
, ok
, "setup file");
1879 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1881 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1883 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
1884 "compression attr present on new file");
1886 smb2_util_close(tree
, fh
);
1887 smb2_util_close(tree
, dirh
);
1888 smb2_deltree(tree
, DNAME
);
1889 talloc_free(tmp_ctx
);
1893 static bool test_ioctl_compress_invalid_format(struct torture_context
*torture
,
1894 struct smb2_tree
*tree
)
1896 struct smb2_handle fh
;
1898 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1900 uint16_t compression_fmt
;
1902 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1903 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
1904 FILE_ATTRIBUTE_NORMAL
);
1905 torture_assert(torture
, ok
, "setup compression file");
1907 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
1909 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
1911 smb2_util_close(tree
, fh
);
1912 torture_skip(torture
, "FS compression not supported\n");
1915 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
1916 0x0042); /* bogus */
1917 torture_assert_ntstatus_equal(torture
, status
,
1918 NT_STATUS_INVALID_PARAMETER
,
1919 "invalid FSCTL_SET_COMPRESSION");
1921 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1923 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1925 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
1926 "initial compression state not NONE");
1928 smb2_util_close(tree
, fh
);
1929 talloc_free(tmp_ctx
);
1933 static bool test_ioctl_compress_invalid_buf(struct torture_context
*torture
,
1934 struct smb2_tree
*tree
)
1936 struct smb2_handle fh
;
1938 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1940 union smb_ioctl ioctl
;
1942 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1943 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
1944 FILE_ATTRIBUTE_NORMAL
);
1945 torture_assert(torture
, ok
, "setup compression file");
1947 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
1949 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
1951 smb2_util_close(tree
, fh
);
1952 torture_skip(torture
, "FS compression not supported\n");
1956 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
1957 ioctl
.smb2
.in
.file
.handle
= fh
;
1958 ioctl
.smb2
.in
.function
= FSCTL_GET_COMPRESSION
;
1959 ioctl
.smb2
.in
.max_response_size
= 0; /* no room for rsp data */
1960 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
1962 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1963 if (!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_USER_BUFFER
)
1964 && !NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
1965 /* neither Server 2k12 nor 2k8r2 response status */
1966 torture_assert(torture
, true,
1967 "invalid FSCTL_SET_COMPRESSION");
1970 smb2_util_close(tree
, fh
);
1971 talloc_free(tmp_ctx
);
1975 static bool test_ioctl_compress_query_file_attr(struct torture_context
*torture
,
1976 struct smb2_tree
*tree
)
1978 struct smb2_handle fh
;
1979 union smb_fileinfo io
;
1981 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1984 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1985 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
1986 FILE_ATTRIBUTE_NORMAL
);
1987 torture_assert(torture
, ok
, "setup compression file");
1989 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
1991 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
1993 smb2_util_close(tree
, fh
);
1994 torture_skip(torture
, "FS compression not supported\n");
1998 io
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
1999 io
.generic
.in
.file
.handle
= fh
;
2000 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2001 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2003 torture_assert(torture
,
2004 ((io
.all_info2
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2005 "compression attr before set");
2007 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
2008 COMPRESSION_FORMAT_DEFAULT
);
2009 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
2012 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2013 io
.generic
.in
.file
.handle
= fh
;
2014 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2015 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2017 torture_assert(torture
,
2018 (io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
),
2019 "no compression attr after set");
2021 smb2_util_close(tree
, fh
);
2022 talloc_free(tmp_ctx
);
2027 * Specify FILE_ATTRIBUTE_COMPRESSED on creation, Windows does not retain this
2030 static bool test_ioctl_compress_create_with_attr(struct torture_context
*torture
,
2031 struct smb2_tree
*tree
)
2033 struct smb2_handle fh2
;
2034 union smb_fileinfo io
;
2036 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2037 uint16_t compression_fmt
;
2040 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2041 FNAME2
, &fh2
, 0, SEC_RIGHTS_FILE_ALL
,
2042 (FILE_ATTRIBUTE_NORMAL
| FILE_ATTRIBUTE_COMPRESSED
));
2043 torture_assert(torture
, ok
, "setup compression file");
2045 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh2
,
2047 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2049 smb2_util_close(tree
, fh2
);
2050 torture_skip(torture
, "FS compression not supported\n");
2053 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh2
,
2055 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2057 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2058 "initial compression state not NONE");
2061 io
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
2062 io
.generic
.in
.file
.handle
= fh2
;
2063 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2064 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2066 torture_assert(torture
,
2067 ((io
.all_info2
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2068 "incorrect compression attr");
2070 smb2_util_close(tree
, fh2
);
2071 talloc_free(tmp_ctx
);
2075 static bool test_ioctl_compress_inherit_disable(struct torture_context
*torture
,
2076 struct smb2_tree
*tree
)
2078 struct smb2_handle fh
;
2079 struct smb2_handle dirh
;
2080 char path_buf
[PATH_MAX
];
2082 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2084 uint16_t compression_fmt
;
2086 struct smb2_create io
;
2088 smb2_deltree(tree
, DNAME
);
2089 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2090 DNAME
, &dirh
, 0, SEC_RIGHTS_FILE_ALL
,
2091 FILE_ATTRIBUTE_DIRECTORY
);
2092 torture_assert(torture
, ok
, "setup compression directory");
2094 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &dirh
,
2096 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2098 smb2_util_close(tree
, dirh
);
2099 smb2_deltree(tree
, DNAME
);
2100 torture_skip(torture
, "FS compression not supported\n");
2103 /* set compression on parent dir, then check for inheritance */
2104 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, dirh
,
2105 COMPRESSION_FORMAT_LZNT1
);
2106 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
2108 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, dirh
,
2110 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2112 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
2113 "invalid compression state after set");
2114 smb2_util_close(tree
, dirh
);
2116 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, FNAME
);
2117 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2118 path_buf
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2119 FILE_ATTRIBUTE_NORMAL
);
2120 torture_assert(torture
, ok
, "setup compression file");
2122 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2124 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2126 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
2127 "compression attr not inherited by new file");
2128 smb2_util_close(tree
, fh
);
2130 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, FNAME2
);
2132 /* NO_COMPRESSION option should block inheritance */
2134 io
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
2135 io
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2136 io
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2137 io
.in
.create_options
= NTCREATEX_OPTIONS_NO_COMPRESSION
;
2138 io
.in
.share_access
=
2139 NTCREATEX_SHARE_ACCESS_DELETE
|
2140 NTCREATEX_SHARE_ACCESS_READ
|
2141 NTCREATEX_SHARE_ACCESS_WRITE
;
2142 io
.in
.fname
= path_buf
;
2144 status
= smb2_create(tree
, tmp_ctx
, &io
);
2145 torture_assert_ntstatus_ok(torture
, status
, "file create");
2147 fh
= io
.out
.file
.handle
;
2149 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2151 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2153 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2154 "compression attr inherited by NO_COMPRESSION file");
2155 smb2_util_close(tree
, fh
);
2158 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, DNAME
);
2160 io
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
2161 io
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
2162 io
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2163 io
.in
.create_options
= (NTCREATEX_OPTIONS_NO_COMPRESSION
2164 | NTCREATEX_OPTIONS_DIRECTORY
);
2165 io
.in
.share_access
=
2166 NTCREATEX_SHARE_ACCESS_DELETE
|
2167 NTCREATEX_SHARE_ACCESS_READ
|
2168 NTCREATEX_SHARE_ACCESS_WRITE
;
2169 io
.in
.fname
= path_buf
;
2171 status
= smb2_create(tree
, tmp_ctx
, &io
);
2172 torture_assert_ntstatus_ok(torture
, status
, "dir create");
2174 dirh
= io
.out
.file
.handle
;
2176 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, dirh
,
2178 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2180 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2181 "compression attr inherited by NO_COMPRESSION dir");
2182 smb2_util_close(tree
, dirh
);
2183 smb2_deltree(tree
, DNAME
);
2185 talloc_free(tmp_ctx
);
2189 /* attempting to set compression via SetInfo should not stick */
2190 static bool test_ioctl_compress_set_file_attr(struct torture_context
*torture
,
2191 struct smb2_tree
*tree
)
2193 struct smb2_handle fh
;
2194 struct smb2_handle dirh
;
2195 union smb_fileinfo io
;
2196 union smb_setfileinfo set_io
;
2197 uint16_t compression_fmt
;
2199 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2202 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2203 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2204 FILE_ATTRIBUTE_NORMAL
);
2205 torture_assert(torture
, ok
, "setup compression file");
2207 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2209 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2211 smb2_util_close(tree
, fh
);
2212 torture_skip(torture
, "FS compression not supported\n");
2216 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2217 io
.generic
.in
.file
.handle
= fh
;
2218 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2219 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2221 torture_assert(torture
,
2222 ((io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2223 "compression attr before set");
2225 ZERO_STRUCT(set_io
);
2226 set_io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2227 set_io
.basic_info
.in
.file
.handle
= fh
;
2228 set_io
.basic_info
.in
.create_time
= io
.basic_info
.out
.create_time
;
2229 set_io
.basic_info
.in
.access_time
= io
.basic_info
.out
.access_time
;
2230 set_io
.basic_info
.in
.write_time
= io
.basic_info
.out
.write_time
;
2231 set_io
.basic_info
.in
.change_time
= io
.basic_info
.out
.change_time
;
2232 set_io
.basic_info
.in
.attrib
= (io
.basic_info
.out
.attrib
2233 | FILE_ATTRIBUTE_COMPRESSED
);
2234 status
= smb2_setinfo_file(tree
, &set_io
);
2235 torture_assert_ntstatus_ok(torture
, status
, "SMB2_SETINFO_FILE");
2238 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2239 io
.generic
.in
.file
.handle
= fh
;
2240 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2241 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2243 torture_assert(torture
,
2244 ((io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2245 "compression attr after set");
2247 smb2_util_close(tree
, fh
);
2248 smb2_deltree(tree
, DNAME
);
2249 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2250 DNAME
, &dirh
, 0, SEC_RIGHTS_FILE_ALL
,
2251 FILE_ATTRIBUTE_DIRECTORY
);
2252 torture_assert(torture
, ok
, "setup compression directory");
2255 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2256 io
.generic
.in
.file
.handle
= dirh
;
2257 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2258 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2260 torture_assert(torture
,
2261 ((io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2262 "compression attr before set");
2264 ZERO_STRUCT(set_io
);
2265 set_io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2266 set_io
.basic_info
.in
.file
.handle
= dirh
;
2267 set_io
.basic_info
.in
.create_time
= io
.basic_info
.out
.create_time
;
2268 set_io
.basic_info
.in
.access_time
= io
.basic_info
.out
.access_time
;
2269 set_io
.basic_info
.in
.write_time
= io
.basic_info
.out
.write_time
;
2270 set_io
.basic_info
.in
.change_time
= io
.basic_info
.out
.change_time
;
2271 set_io
.basic_info
.in
.attrib
= (io
.basic_info
.out
.attrib
2272 | FILE_ATTRIBUTE_COMPRESSED
);
2273 status
= smb2_setinfo_file(tree
, &set_io
);
2274 torture_assert_ntstatus_ok(torture
, status
, "SMB2_SETINFO_FILE");
2276 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, dirh
,
2278 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2280 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2281 "dir compression set after SetInfo");
2283 smb2_util_close(tree
, dirh
);
2284 talloc_free(tmp_ctx
);
2288 static bool test_ioctl_compress_perms(struct torture_context
*torture
,
2289 struct smb2_tree
*tree
)
2291 struct smb2_handle fh
;
2292 uint16_t compression_fmt
;
2293 union smb_fileinfo io
;
2295 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2298 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2299 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2300 FILE_ATTRIBUTE_NORMAL
);
2301 torture_assert(torture
, ok
, "setup compression file");
2303 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2305 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2306 smb2_util_close(tree
, fh
);
2308 torture_skip(torture
, "FS compression not supported\n");
2311 /* attempt get compression without READ_ATTR permission */
2312 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2314 (SEC_RIGHTS_FILE_READ
& ~(SEC_FILE_READ_ATTRIBUTE
2315 | SEC_STD_READ_CONTROL
2316 | SEC_FILE_READ_EA
)),
2317 FILE_ATTRIBUTE_NORMAL
);
2318 torture_assert(torture
, ok
, "setup compression file");
2320 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2322 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2323 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2324 "compression set after create");
2325 smb2_util_close(tree
, fh
);
2327 /* set compression without WRITE_ATTR permission should succeed */
2328 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2330 (SEC_RIGHTS_FILE_WRITE
& ~(SEC_FILE_WRITE_ATTRIBUTE
2332 | SEC_FILE_WRITE_EA
)),
2333 FILE_ATTRIBUTE_NORMAL
);
2334 torture_assert(torture
, ok
, "setup compression file");
2336 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
2337 COMPRESSION_FORMAT_DEFAULT
);
2338 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
2339 smb2_util_close(tree
, fh
);
2341 ok
= test_setup_open(torture
, tree
, tmp_ctx
,
2342 FNAME
, &fh
, SEC_RIGHTS_FILE_ALL
,
2343 FILE_ATTRIBUTE_NORMAL
);
2344 torture_assert(torture
, ok
, "setup compression file");
2346 io
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
2347 io
.generic
.in
.file
.handle
= fh
;
2348 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2349 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2351 torture_assert(torture
,
2352 (io
.all_info2
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
),
2353 "incorrect compression attr");
2354 smb2_util_close(tree
, fh
);
2356 /* attempt get compression without READ_DATA permission */
2357 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2359 (SEC_RIGHTS_FILE_READ
& ~SEC_FILE_READ_DATA
),
2360 FILE_ATTRIBUTE_NORMAL
);
2361 torture_assert(torture
, ok
, "setup compression file");
2363 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2365 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2366 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2367 "compression enabled after set");
2368 smb2_util_close(tree
, fh
);
2370 /* attempt get compression with only SYNCHRONIZE permission */
2371 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2373 SEC_STD_SYNCHRONIZE
,
2374 FILE_ATTRIBUTE_NORMAL
);
2375 torture_assert(torture
, ok
, "setup compression file");
2377 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2379 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2380 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2381 "compression not enabled after set");
2382 smb2_util_close(tree
, fh
);
2384 /* attempt to set compression without WRITE_DATA permission */
2385 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2387 (SEC_RIGHTS_FILE_WRITE
& (~SEC_FILE_WRITE_DATA
)),
2388 FILE_ATTRIBUTE_NORMAL
);
2389 torture_assert(torture
, ok
, "setup compression file");
2391 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
2392 COMPRESSION_FORMAT_DEFAULT
);
2393 torture_assert_ntstatus_equal(torture
, status
,
2394 NT_STATUS_ACCESS_DENIED
,
2395 "FSCTL_SET_COMPRESSION permission");
2396 smb2_util_close(tree
, fh
);
2398 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2400 (SEC_RIGHTS_FILE_WRITE
& (~SEC_FILE_WRITE_DATA
)),
2401 FILE_ATTRIBUTE_NORMAL
);
2402 torture_assert(torture
, ok
, "setup compression file");
2404 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
2405 COMPRESSION_FORMAT_NONE
);
2406 torture_assert_ntstatus_equal(torture
, status
,
2407 NT_STATUS_ACCESS_DENIED
,
2408 "FSCTL_SET_COMPRESSION permission");
2409 smb2_util_close(tree
, fh
);
2411 talloc_free(tmp_ctx
);
2416 basic testing of SMB2 ioctls
2418 struct torture_suite
*torture_smb2_ioctl_init(void)
2420 struct torture_suite
*suite
= torture_suite_create(talloc_autofree_context(), "ioctl");
2422 torture_suite_add_1smb2_test(suite
, "shadow_copy",
2423 test_ioctl_get_shadow_copy
);
2424 torture_suite_add_1smb2_test(suite
, "req_resume_key",
2425 test_ioctl_req_resume_key
);
2426 torture_suite_add_1smb2_test(suite
, "copy_chunk_simple",
2427 test_ioctl_copy_chunk_simple
);
2428 torture_suite_add_1smb2_test(suite
, "copy_chunk_multi",
2429 test_ioctl_copy_chunk_multi
);
2430 torture_suite_add_1smb2_test(suite
, "copy_chunk_tiny",
2431 test_ioctl_copy_chunk_tiny
);
2432 torture_suite_add_1smb2_test(suite
, "copy_chunk_overwrite",
2433 test_ioctl_copy_chunk_over
);
2434 torture_suite_add_1smb2_test(suite
, "copy_chunk_append",
2435 test_ioctl_copy_chunk_append
);
2436 torture_suite_add_1smb2_test(suite
, "copy_chunk_limits",
2437 test_ioctl_copy_chunk_limits
);
2438 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_lock",
2439 test_ioctl_copy_chunk_src_lck
);
2440 torture_suite_add_1smb2_test(suite
, "copy_chunk_dest_lock",
2441 test_ioctl_copy_chunk_dest_lck
);
2442 torture_suite_add_1smb2_test(suite
, "copy_chunk_bad_key",
2443 test_ioctl_copy_chunk_bad_key
);
2444 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_is_dest",
2445 test_ioctl_copy_chunk_src_is_dest
);
2446 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_is_dest_overlap",
2447 test_ioctl_copy_chunk_src_is_dest_overlap
);
2448 torture_suite_add_1smb2_test(suite
, "copy_chunk_bad_access",
2449 test_ioctl_copy_chunk_bad_access
);
2450 torture_suite_add_1smb2_test(suite
, "copy_chunk_write_access",
2451 test_ioctl_copy_chunk_write_access
);
2452 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_exceed",
2453 test_ioctl_copy_chunk_src_exceed
);
2454 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_exceed_multi",
2455 test_ioctl_copy_chunk_src_exceed_multi
);
2456 torture_suite_add_1smb2_test(suite
, "copy_chunk_sparse_dest",
2457 test_ioctl_copy_chunk_sparse_dest
);
2458 torture_suite_add_1smb2_test(suite
, "copy_chunk_max_output_sz",
2459 test_ioctl_copy_chunk_max_output_sz
);
2460 torture_suite_add_1smb2_test(suite
, "copy_chunk_zero_length",
2461 test_ioctl_copy_chunk_zero_length
);
2462 torture_suite_add_1smb2_test(suite
, "compress_file_flag",
2463 test_ioctl_compress_file_flag
);
2464 torture_suite_add_1smb2_test(suite
, "compress_dir_inherit",
2465 test_ioctl_compress_dir_inherit
);
2466 torture_suite_add_1smb2_test(suite
, "compress_invalid_format",
2467 test_ioctl_compress_invalid_format
);
2468 torture_suite_add_1smb2_test(suite
, "compress_invalid_buf",
2469 test_ioctl_compress_invalid_buf
);
2470 torture_suite_add_1smb2_test(suite
, "compress_query_file_attr",
2471 test_ioctl_compress_query_file_attr
);
2472 torture_suite_add_1smb2_test(suite
, "compress_create_with_attr",
2473 test_ioctl_compress_create_with_attr
);
2474 torture_suite_add_1smb2_test(suite
, "compress_inherit_disable",
2475 test_ioctl_compress_inherit_disable
);
2476 torture_suite_add_1smb2_test(suite
, "compress_set_file_attr",
2477 test_ioctl_compress_set_file_attr
);
2478 torture_suite_add_1smb2_test(suite
, "compress_perms",
2479 test_ioctl_compress_perms
);
2481 suite
->description
= talloc_strdup(suite
, "SMB2-IOCTL tests");