torture: test FSCTL_SET_SPARSE
[obnox/samba/samba-obnox.git] / source4 / torture / smb2 / ioctl.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    test suite for SMB2 ioctl operations
5
6    Copyright (C) David Disseldorp 2011-2013
7
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.
12
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.
17
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/>.
20 */
21
22 #include "includes.h"
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"
30
31 #define FNAME   "testfsctl.dat"
32 #define FNAME2  "testfsctl2.dat"
33 #define DNAME   "testfsctl_dir"
34
35 /*
36    basic testing of SMB2 shadow copy calls
37 */
38 static bool test_ioctl_get_shadow_copy(struct torture_context *torture,
39                                        struct smb2_tree *tree)
40 {
41         struct smb2_handle h;
42         uint8_t buf[100];
43         NTSTATUS status;
44         union smb_ioctl ioctl;
45         TALLOC_CTX *tmp_ctx = talloc_new(tree);
46
47         smb2_util_unlink(tree, FNAME);
48
49         status = torture_smb2_testfile(tree, FNAME, &h);
50         torture_assert_ntstatus_ok(torture, status, "create write");
51
52         ZERO_ARRAY(buf);
53         status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
54         torture_assert_ntstatus_ok(torture, status, "write");
55
56         ZERO_STRUCT(ioctl);
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;
62
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");
67         }
68         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_ENUM_SNAPS");
69
70         return true;
71 }
72
73 /*
74    basic testing of the SMB2 server side copy ioctls
75 */
76 static bool test_ioctl_req_resume_key(struct torture_context *torture,
77                                       struct smb2_tree *tree)
78 {
79         struct smb2_handle h;
80         uint8_t buf[100];
81         NTSTATUS status;
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;
86
87         smb2_util_unlink(tree, FNAME);
88
89         status = torture_smb2_testfile(tree, FNAME, &h);
90         torture_assert_ntstatus_ok(torture, status, "create write");
91
92         ZERO_ARRAY(buf);
93         status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
94         torture_assert_ntstatus_ok(torture, status, "write");
95
96         ZERO_STRUCT(ioctl);
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;
102
103         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
104         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_REQUEST_RESUME_KEY");
105
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");
110
111         ndr_print_debug((ndr_print_fn_t)ndr_print_req_resume_key_rsp, "yo", &res_key);
112
113         talloc_free(tmp_ctx);
114         return true;
115 }
116
117 static uint64_t patt_hash(uint64_t off)
118 {
119         return off;
120 }
121
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,
125                           uint64_t patt_off)
126 {
127         uint64_t i;
128         struct smb2_read r;
129         NTSTATUS status;
130
131         ZERO_STRUCT(r);
132         r.in.file.handle = h;
133         r.in.length      = len;
134         r.in.offset      = off;
135         status = smb2_read(tree, mem_ctx, &r);
136         torture_assert_ntstatus_ok(torture, status, "read");
137
138         torture_assert_u64_equal(torture, r.out.data.length, len,
139                                  "read data len mismatch");
140
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));
147         }
148
149         talloc_free(r.out.data.data);
150         return true;
151 }
152
153 static bool test_setup_open(struct torture_context *torture,
154                             struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
155                             const char *fname,
156                             struct smb2_handle *fh,
157                             uint32_t desired_access,
158                             uint32_t file_attributes)
159 {
160         struct smb2_create io;
161         NTSTATUS status;
162
163         ZERO_STRUCT(io);
164         io.in.desired_access = desired_access;
165         io.in.file_attributes = file_attributes;
166         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
167         io.in.share_access =
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;
173         }
174         io.in.fname = fname;
175
176         status = smb2_create(tree, mem_ctx, &io);
177         torture_assert_ntstatus_ok(torture, status, "file create");
178
179         *fh = io.out.file.handle;
180
181         return true;
182 }
183
184 static bool test_setup_create_fill(struct torture_context *torture,
185                                    struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
186                                    const char *fname,
187                                    struct smb2_handle *fh,
188                                    uint64_t size,
189                                    uint32_t desired_access,
190                                    uint32_t file_attributes)
191 {
192         NTSTATUS status;
193         bool ok;
194         uint64_t i;
195         uint8_t *buf = talloc_zero_size(mem_ctx, size);
196         torture_assert(torture, (buf != NULL), "no memory for file data buf");
197
198         smb2_util_unlink(tree, fname);
199
200         ok = test_setup_open(torture, tree, mem_ctx,
201                              fname,
202                              fh,
203                              desired_access,
204                              file_attributes);
205         torture_assert(torture, ok, "file open");
206
207         if (size > 0) {
208                 uint64_t cur_off = 0;
209                 for (i = 0; i <= size - 8; i += 8) {
210                         SBVAL(buf, i, patt_hash(i));
211                 }
212                 while (size > 0) {
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");
217
218                         size -= io_sz;
219                         cur_off += io_sz;
220                 }
221         }
222         return true;
223 }
224
225 static bool test_setup_copy_chunk(struct torture_context *torture,
226                                   struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
227                                   uint32_t nchunks,
228                                   struct smb2_handle *src_h,
229                                   uint64_t src_size,
230                                   uint32_t src_desired_access,
231                                   struct smb2_handle *dest_h,
232                                   uint64_t dest_size,
233                                   uint32_t dest_desired_access,
234                                   struct srv_copychunk_copy *cc_copy,
235                                   union smb_ioctl *ioctl)
236 {
237         struct req_resume_key_rsp res_key;
238         bool ok;
239         NTSTATUS status;
240         enum ndr_err_code ndr_ret;
241
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");
246
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");
251
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;
259
260         status = smb2_ioctl(tree, mem_ctx, &ioctl->smb2);
261         torture_assert_ntstatus_ok(torture, status,
262                                    "FSCTL_SRV_REQUEST_RESUME_KEY");
263
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);
266
267         torture_assert_ndr_success(torture, ndr_ret,
268                                    "ndr_pull_req_resume_key_rsp");
269
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;
276
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");
282
283         return true;
284 }
285
286
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)
292 {
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");
299         return true;
300 }
301
302 static bool test_ioctl_copy_chunk_simple(struct torture_context *torture,
303                                          struct smb2_tree *tree)
304 {
305         struct smb2_handle src_h;
306         struct smb2_handle dest_h;
307         NTSTATUS status;
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;
313         bool ok;
314
315         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
316                                    1, /* 1 chunk */
317                                    &src_h, 4096, /* fill 4096 byte src file */
318                                    SEC_RIGHTS_FILE_ALL,
319                                    &dest_h, 0,  /* 0 byte dest file */
320                                    SEC_RIGHTS_FILE_ALL,
321                                    &cc_copy,
322                                    &ioctl);
323         if (!ok) {
324                 torture_fail(torture, "setup copy chunk error");
325         }
326
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;
331
332         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
333                                        &cc_copy,
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");
337
338         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
339         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
340
341         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
342                                        &cc_rsp,
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");
346
347         ok = check_copy_chunk_rsp(torture, &cc_rsp,
348                                   1,    /* chunks written */
349                                   0,    /* chunk bytes unsuccessfully written */
350                                   4096); /* total bytes written */
351         if (!ok) {
352                 torture_fail(torture, "bad copy chunk response data");
353         }
354
355         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
356         if (!ok) {
357                 torture_fail(torture, "inconsistent file data");
358         }
359
360         smb2_util_close(tree, src_h);
361         smb2_util_close(tree, dest_h);
362         talloc_free(tmp_ctx);
363         return true;
364 }
365
366 static bool test_ioctl_copy_chunk_multi(struct torture_context *torture,
367                                         struct smb2_tree *tree)
368 {
369         struct smb2_handle src_h;
370         struct smb2_handle dest_h;
371         NTSTATUS status;
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;
377         bool ok;
378
379         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
380                                    2, /* chunks */
381                                    &src_h, 8192, /* src file */
382                                    SEC_RIGHTS_FILE_ALL,
383                                    &dest_h, 0,  /* dest file */
384                                    SEC_RIGHTS_FILE_ALL,
385                                    &cc_copy,
386                                    &ioctl);
387         if (!ok) {
388                 torture_fail(torture, "setup copy chunk error");
389         }
390
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;
395
396         cc_copy.chunks[1].source_off = 4096;
397         cc_copy.chunks[1].target_off = 4096;
398         cc_copy.chunks[1].length = 4096;
399
400         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
401                                        &cc_copy,
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");
405
406         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
407         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
408
409         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
410                                        &cc_rsp,
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");
414
415         ok = check_copy_chunk_rsp(torture, &cc_rsp,
416                                   2,    /* chunks written */
417                                   0,    /* chunk bytes unsuccessfully written */
418                                   8192);        /* total bytes written */
419         if (!ok) {
420                 torture_fail(torture, "bad copy chunk response data");
421         }
422
423         smb2_util_close(tree, src_h);
424         smb2_util_close(tree, dest_h);
425         talloc_free(tmp_ctx);
426         return true;
427 }
428
429 static bool test_ioctl_copy_chunk_tiny(struct torture_context *torture,
430                                        struct smb2_tree *tree)
431 {
432         struct smb2_handle src_h;
433         struct smb2_handle dest_h;
434         NTSTATUS status;
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;
440         bool ok;
441
442         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
443                                    2, /* chunks */
444                                    &src_h, 100, /* src file */
445                                    SEC_RIGHTS_FILE_ALL,
446                                    &dest_h, 0,  /* dest file */
447                                    SEC_RIGHTS_FILE_ALL,
448                                    &cc_copy,
449                                    &ioctl);
450         if (!ok) {
451                 torture_fail(torture, "setup copy chunk error");
452         }
453
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;
458
459         cc_copy.chunks[1].source_off = 50;
460         cc_copy.chunks[1].target_off = 50;
461         cc_copy.chunks[1].length = 50;
462
463         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
464                                        &cc_copy,
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");
468
469         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
470         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
471
472         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
473                                        &cc_rsp,
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");
477
478         ok = check_copy_chunk_rsp(torture, &cc_rsp,
479                                   2,    /* chunks written */
480                                   0,    /* chunk bytes unsuccessfully written */
481                                   100); /* total bytes written */
482         if (!ok) {
483                 torture_fail(torture, "bad copy chunk response data");
484         }
485
486         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 100, 0);
487         if (!ok) {
488                 torture_fail(torture, "inconsistent file data");
489         }
490
491         smb2_util_close(tree, src_h);
492         smb2_util_close(tree, dest_h);
493         talloc_free(tmp_ctx);
494         return true;
495 }
496
497 static bool test_ioctl_copy_chunk_over(struct torture_context *torture,
498                                        struct smb2_tree *tree)
499 {
500         struct smb2_handle src_h;
501         struct smb2_handle dest_h;
502         NTSTATUS status;
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;
508         bool ok;
509
510         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
511                                    2, /* chunks */
512                                    &src_h, 8192, /* src file */
513                                    SEC_RIGHTS_FILE_ALL,
514                                    &dest_h, 4096, /* dest file */
515                                    SEC_RIGHTS_FILE_ALL,
516                                    &cc_copy,
517                                    &ioctl);
518         if (!ok) {
519                 torture_fail(torture, "setup copy chunk error");
520         }
521
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;
526
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;
531
532         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
533                                        &cc_copy,
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");
537
538         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
539         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
540
541         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
542                                        &cc_rsp,
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");
546
547         ok = check_copy_chunk_rsp(torture, &cc_rsp,
548                                   2,    /* chunks written */
549                                   0,    /* chunk bytes unsuccessfully written */
550                                   8192); /* total bytes written */
551         if (!ok) {
552                 torture_fail(torture, "bad copy chunk response data");
553         }
554
555         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 4096);
556         if (!ok) {
557                 torture_fail(torture, "inconsistent file data");
558         }
559
560         smb2_util_close(tree, src_h);
561         smb2_util_close(tree, dest_h);
562         talloc_free(tmp_ctx);
563         return true;
564 }
565
566 static bool test_ioctl_copy_chunk_append(struct torture_context *torture,
567                                        struct smb2_tree *tree)
568 {
569         struct smb2_handle src_h;
570         struct smb2_handle dest_h;
571         NTSTATUS status;
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;
577         bool ok;
578
579         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
580                                    2, /* chunks */
581                                    &src_h, 4096, /* src file */
582                                    SEC_RIGHTS_FILE_ALL,
583                                    &dest_h, 0,  /* dest file */
584                                    SEC_RIGHTS_FILE_ALL,
585                                    &cc_copy,
586                                    &ioctl);
587         if (!ok) {
588                 torture_fail(torture, "setup copy chunk error");
589         }
590
591         cc_copy.chunks[0].source_off = 0;
592         cc_copy.chunks[0].target_off = 0;
593         cc_copy.chunks[0].length = 4096;
594
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;
599
600         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
601                                        &cc_copy,
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");
605
606         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
607         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
608
609         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
610                                        &cc_rsp,
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");
614
615         ok = check_copy_chunk_rsp(torture, &cc_rsp,
616                                   2,    /* chunks written */
617                                   0,    /* chunk bytes unsuccessfully written */
618                                   8192); /* total bytes written */
619         if (!ok) {
620                 torture_fail(torture, "bad copy chunk response data");
621         }
622
623         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
624         if (!ok) {
625                 torture_fail(torture, "inconsistent file data");
626         }
627
628         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 4096, 4096, 0);
629         if (!ok) {
630                 torture_fail(torture, "inconsistent file data");
631         }
632
633         smb2_util_close(tree, src_h);
634         smb2_util_close(tree, dest_h);
635         talloc_free(tmp_ctx);
636         return true;
637 }
638
639 static bool test_ioctl_copy_chunk_limits(struct torture_context *torture,
640                                          struct smb2_tree *tree)
641 {
642         struct smb2_handle src_h;
643         struct smb2_handle dest_h;
644         NTSTATUS status;
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;
650         bool ok;
651
652         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
653                                    1, /* chunks */
654                                    &src_h, 4096, /* src file */
655                                    SEC_RIGHTS_FILE_ALL,
656                                    &dest_h, 0,  /* dest file */
657                                    SEC_RIGHTS_FILE_ALL,
658                                    &cc_copy,
659                                    &ioctl);
660         if (!ok) {
661                 torture_fail(torture, "setup copy chunk error");
662         }
663
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;
668
669         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
670                                        &cc_copy,
671                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
672         torture_assert_ndr_success(torture, ndr_ret, "marshalling request");
673
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");
678
679         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
680                                        &cc_rsp,
681                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
682         torture_assert_ndr_success(torture, ndr_ret, "unmarshalling response");
683
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);
690
691         smb2_util_close(tree, src_h);
692         smb2_util_close(tree, dest_h);
693         talloc_free(tmp_ctx);
694         return true;
695 }
696
697 static bool test_ioctl_copy_chunk_src_lck(struct torture_context *torture,
698                                           struct smb2_tree *tree)
699 {
700         struct smb2_handle src_h;
701         struct smb2_handle src_h2;
702         struct smb2_handle dest_h;
703         NTSTATUS status;
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;
709         bool ok;
710         struct smb2_lock lck;
711         struct smb2_lock_element el[1];
712
713         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
714                                    1, /* chunks */
715                                    &src_h, 4096, /* src file */
716                                    SEC_RIGHTS_FILE_ALL,
717                                    &dest_h, 0,  /* dest file */
718                                    SEC_RIGHTS_FILE_ALL,
719                                    &cc_copy,
720                                    &ioctl);
721         if (!ok) {
722                 torture_fail(torture, "setup copy chunk error");
723         }
724
725         cc_copy.chunks[0].source_off = 0;
726         cc_copy.chunks[0].target_off = 0;
727         cc_copy.chunks[0].length = 4096;
728
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");
732
733         lck.in.lock_count       = 0x0001;
734         lck.in.lock_sequence    = 0x00000000;
735         lck.in.file.handle      = src_h2;
736         lck.in.locks            = el;
737         el[0].offset            = cc_copy.chunks[0].source_off;
738         el[0].length            = cc_copy.chunks[0].length;
739         el[0].reserved          = 0;
740         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE;
741
742         status = smb2_lock(tree, &lck);
743         torture_assert_ntstatus_ok(torture, status, "lock");
744
745         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
746                                        &cc_copy,
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");
750
751         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
752         /*
753          * 2k12 & Samba return lock_conflict, Windows 7 & 2k8 return success...
754          *
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.
759          *
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.
764          *
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.
768          */
769         torture_assert_ntstatus_equal(torture, status,
770                                       NT_STATUS_FILE_LOCK_CONFLICT,
771                                       "FSCTL_SRV_COPYCHUNK locked");
772
773         /* should get cc response data with the lock conflict status */
774         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
775                                        &cc_rsp,
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 */
783
784         lck.in.lock_count       = 0x0001;
785         lck.in.lock_sequence    = 0x00000001;
786         lck.in.file.handle      = src_h2;
787         lck.in.locks            = el;
788         el[0].offset            = cc_copy.chunks[0].source_off;
789         el[0].length            = cc_copy.chunks[0].length;
790         el[0].reserved          = 0;
791         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
792         status = smb2_lock(tree, &lck);
793         torture_assert_ntstatus_ok(torture, status, "unlock");
794
795         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
796         torture_assert_ntstatus_ok(torture, status,
797                                    "FSCTL_SRV_COPYCHUNK unlocked");
798
799         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
800                                        &cc_rsp,
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");
804
805         ok = check_copy_chunk_rsp(torture, &cc_rsp,
806                                   1,    /* chunks written */
807                                   0,    /* chunk bytes unsuccessfully written */
808                                   4096); /* total bytes written */
809         if (!ok) {
810                 torture_fail(torture, "bad copy chunk response data");
811         }
812
813         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
814         if (!ok) {
815                 torture_fail(torture, "inconsistent file data");
816         }
817
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);
822         return true;
823 }
824
825 static bool test_ioctl_copy_chunk_dest_lck(struct torture_context *torture,
826                                            struct smb2_tree *tree)
827 {
828         struct smb2_handle src_h;
829         struct smb2_handle dest_h;
830         struct smb2_handle dest_h2;
831         NTSTATUS status;
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;
837         bool ok;
838         struct smb2_lock lck;
839         struct smb2_lock_element el[1];
840
841         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
842                                    1, /* chunks */
843                                    &src_h, 4096, /* src file */
844                                    SEC_RIGHTS_FILE_ALL,
845                                    &dest_h, 4096,       /* dest file */
846                                    SEC_RIGHTS_FILE_ALL,
847                                    &cc_copy,
848                                    &ioctl);
849         if (!ok) {
850                 torture_fail(torture, "setup copy chunk error");
851         }
852
853         cc_copy.chunks[0].source_off = 0;
854         cc_copy.chunks[0].target_off = 0;
855         cc_copy.chunks[0].length = 4096;
856
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");
860
861         lck.in.lock_count       = 0x0001;
862         lck.in.lock_sequence    = 0x00000000;
863         lck.in.file.handle      = dest_h2;
864         lck.in.locks            = el;
865         el[0].offset            = cc_copy.chunks[0].target_off;
866         el[0].length            = cc_copy.chunks[0].length;
867         el[0].reserved          = 0;
868         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE;
869
870         status = smb2_lock(tree, &lck);
871         torture_assert_ntstatus_ok(torture, status, "lock");
872
873         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
874                                        &cc_copy,
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");
878
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");
883
884         lck.in.lock_count       = 0x0001;
885         lck.in.lock_sequence    = 0x00000001;
886         lck.in.file.handle      = dest_h2;
887         lck.in.locks            = el;
888         el[0].offset            = cc_copy.chunks[0].target_off;
889         el[0].length            = cc_copy.chunks[0].length;
890         el[0].reserved          = 0;
891         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
892         status = smb2_lock(tree, &lck);
893         torture_assert_ntstatus_ok(torture, status, "unlock");
894
895         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
896         torture_assert_ntstatus_ok(torture, status,
897                                    "FSCTL_SRV_COPYCHUNK unlocked");
898
899         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
900                                        &cc_rsp,
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");
904
905         ok = check_copy_chunk_rsp(torture, &cc_rsp,
906                                   1,    /* chunks written */
907                                   0,    /* chunk bytes unsuccessfully written */
908                                   4096); /* total bytes written */
909         if (!ok) {
910                 torture_fail(torture, "bad copy chunk response data");
911         }
912
913         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
914         if (!ok) {
915                 torture_fail(torture, "inconsistent file data");
916         }
917
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);
922         return true;
923 }
924
925 static bool test_ioctl_copy_chunk_bad_key(struct torture_context *torture,
926                                           struct smb2_tree *tree)
927 {
928         struct smb2_handle src_h;
929         struct smb2_handle dest_h;
930         NTSTATUS status;
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;
935         bool ok;
936
937         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
938                                    1,
939                                    &src_h, 4096,
940                                    SEC_RIGHTS_FILE_ALL,
941                                    &dest_h, 0,
942                                    SEC_RIGHTS_FILE_ALL,
943                                    &cc_copy,
944                                    &ioctl);
945         if (!ok) {
946                 torture_fail(torture, "setup copy chunk error");
947         }
948
949         /* overwrite the resume key with a bogus value */
950         memcpy(cc_copy.source_key, "deadbeefdeadbeefdeadbeef", 24);
951
952         cc_copy.chunks[0].source_off = 0;
953         cc_copy.chunks[0].target_off = 0;
954         cc_copy.chunks[0].length = 4096;
955
956         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
957                                        &cc_copy,
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");
961
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");
967
968         smb2_util_close(tree, src_h);
969         smb2_util_close(tree, dest_h);
970         talloc_free(tmp_ctx);
971         return true;
972 }
973
974 static bool test_ioctl_copy_chunk_src_is_dest(struct torture_context *torture,
975                                               struct smb2_tree *tree)
976 {
977         struct smb2_handle src_h;
978         struct smb2_handle dest_h;
979         NTSTATUS status;
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;
985         bool ok;
986
987         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
988                                    1,
989                                    &src_h, 8192,
990                                    SEC_RIGHTS_FILE_ALL,
991                                    &dest_h, 0,
992                                    SEC_RIGHTS_FILE_ALL,
993                                    &cc_copy,
994                                    &ioctl);
995         if (!ok) {
996                 torture_fail(torture, "setup copy chunk error");
997         }
998
999         /* the source is also the destination */
1000         ioctl.smb2.in.file.handle = src_h;
1001
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;
1006
1007         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1008                                        &cc_copy,
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");
1012
1013         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1014         torture_assert_ntstatus_ok(torture, status,
1015                                    "FSCTL_SRV_COPYCHUNK");
1016
1017         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
1018                                        &cc_rsp,
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");
1022
1023         ok = check_copy_chunk_rsp(torture, &cc_rsp,
1024                                   1,    /* chunks written */
1025                                   0,    /* chunk bytes unsuccessfully written */
1026                                   4096); /* total bytes written */
1027         if (!ok) {
1028                 torture_fail(torture, "bad copy chunk response data");
1029         }
1030
1031         ok = check_pattern(torture, tree, tmp_ctx, src_h, 0, 4096, 0);
1032         if (!ok) {
1033                 torture_fail(torture, "inconsistent file data");
1034         }
1035         ok = check_pattern(torture, tree, tmp_ctx, src_h, 4096, 4096, 0);
1036         if (!ok) {
1037                 torture_fail(torture, "inconsistent file data");
1038         }
1039
1040         smb2_util_close(tree, src_h);
1041         smb2_util_close(tree, dest_h);
1042         talloc_free(tmp_ctx);
1043         return true;
1044 }
1045
1046 /*
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:
1049  *
1050  * Initial State
1051  * -------------
1052  *      File:           src_and_dest
1053  *      Offset:         0123456789
1054  *      Data:           abcdefghij
1055  *
1056  * Request
1057  * -------
1058  *      FSCTL_SRV_COPYCHUNK(src_and_dest)
1059  *      SourceKey = SRV_REQUEST_RESUME_KEY(src_and_dest)
1060  *      ChunkCount = 1
1061  *      Chunks[0].SourceOffset = 0
1062  *      Chunks[0].TargetOffset = 4
1063  *      Chunks[0].Length = 6
1064  *
1065  * Resultant State
1066  * ---------------
1067  *      File:           src_and_dest
1068  *      Offset:         0123456789
1069  *      Data:           abcdabcdef
1070  *
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.
1078  *
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).
1084  *
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.
1088  */
1089 static bool
1090 test_ioctl_copy_chunk_src_is_dest_overlap(struct torture_context *torture,
1091                                           struct smb2_tree *tree)
1092 {
1093         struct smb2_handle src_h;
1094         struct smb2_handle dest_h;
1095         NTSTATUS status;
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;
1101         bool ok;
1102
1103         /* exceed the vfs_default copy buffer */
1104         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1105                                    1,
1106                                    &src_h, 2048 * 2,
1107                                    SEC_RIGHTS_FILE_ALL,
1108                                    &dest_h, 0,
1109                                    SEC_RIGHTS_FILE_ALL,
1110                                    &cc_copy,
1111                                    &ioctl);
1112         if (!ok) {
1113                 torture_fail(torture, "setup copy chunk error");
1114         }
1115
1116         /* the source is also the destination */
1117         ioctl.smb2.in.file.handle = src_h;
1118
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;
1123
1124         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1125                                        &cc_copy,
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");
1129
1130         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1131         torture_assert_ntstatus_ok(torture, status,
1132                                    "FSCTL_SRV_COPYCHUNK");
1133
1134         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
1135                                        &cc_rsp,
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");
1139
1140         ok = check_copy_chunk_rsp(torture, &cc_rsp,
1141                                   1,    /* chunks written */
1142                                   0,    /* chunk bytes unsuccessfully written */
1143                                   2048); /* total bytes written */
1144         if (!ok) {
1145                 torture_fail(torture, "bad copy chunk response data");
1146         }
1147
1148         ok = check_pattern(torture, tree, tmp_ctx, src_h, 0, 2048 - 8, 0);
1149         if (!ok) {
1150                 torture_fail(torture, "inconsistent file data");
1151         }
1152         ok = check_pattern(torture, tree, tmp_ctx, src_h, 2048 - 8, 2048, 0);
1153         if (!ok) {
1154                 torture_fail(torture, "inconsistent file data");
1155         }
1156
1157         smb2_util_close(tree, src_h);
1158         smb2_util_close(tree, dest_h);
1159         talloc_free(tmp_ctx);
1160         return true;
1161 }
1162
1163 static bool test_ioctl_copy_chunk_bad_access(struct torture_context *torture,
1164                                              struct smb2_tree *tree)
1165 {
1166         struct smb2_handle src_h;
1167         struct smb2_handle dest_h;
1168         NTSTATUS status;
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;
1173         bool ok;
1174
1175         /* no read permission on src */
1176         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1177                                    1, /* 1 chunk */
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,
1182                                    &cc_copy,
1183                                    &ioctl);
1184         if (!ok) {
1185                 torture_fail(torture, "setup copy chunk error");
1186         }
1187
1188         cc_copy.chunks[0].source_off = 0;
1189         cc_copy.chunks[0].target_off = 0;
1190         cc_copy.chunks[0].length = 4096;
1191
1192         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1193                                        &cc_copy,
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");
1197
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");
1202
1203         smb2_util_close(tree, src_h);
1204         smb2_util_close(tree, dest_h);
1205
1206         /* no write permission on dest */
1207         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1208                                    1, /* 1 chunk */
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),
1214                                    &cc_copy,
1215                                    &ioctl);
1216         if (!ok) {
1217                 torture_fail(torture, "setup copy chunk error");
1218         }
1219
1220         cc_copy.chunks[0].source_off = 0;
1221         cc_copy.chunks[0].target_off = 0;
1222         cc_copy.chunks[0].length = 4096;
1223
1224         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1225                                        &cc_copy,
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");
1229
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");
1234
1235         smb2_util_close(tree, src_h);
1236         smb2_util_close(tree, dest_h);
1237
1238         /* no read permission on dest */
1239         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1240                                    1, /* 1 chunk */
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),
1246                                    &cc_copy,
1247                                    &ioctl);
1248         if (!ok) {
1249                 torture_fail(torture, "setup copy chunk error");
1250         }
1251
1252         cc_copy.chunks[0].source_off = 0;
1253         cc_copy.chunks[0].target_off = 0;
1254         cc_copy.chunks[0].length = 4096;
1255
1256         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1257                                        &cc_copy,
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");
1261
1262         /*
1263          * FSCTL_SRV_COPYCHUNK requires read permission on dest,
1264          * FSCTL_SRV_COPYCHUNK_WRITE on the other hand does not.
1265          */
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");
1270
1271         smb2_util_close(tree, src_h);
1272         smb2_util_close(tree, dest_h);
1273         talloc_free(tmp_ctx);
1274
1275         return true;
1276 }
1277
1278 static bool test_ioctl_copy_chunk_write_access(struct torture_context *torture,
1279                                                struct smb2_tree *tree)
1280 {
1281         struct smb2_handle src_h;
1282         struct smb2_handle dest_h;
1283         NTSTATUS status;
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;
1288         bool ok;
1289
1290         /* no read permission on dest with FSCTL_SRV_COPYCHUNK_WRITE */
1291         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1292                                    1, /* 1 chunk */
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),
1298                                    &cc_copy,
1299                                    &ioctl);
1300         if (!ok) {
1301                 torture_fail(torture, "setup copy chunk error");
1302         }
1303
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;
1308
1309         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1310                                        &cc_copy,
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");
1314
1315         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1316         torture_assert_ntstatus_ok(torture, status,
1317                                    "FSCTL_SRV_COPYCHUNK_WRITE");
1318
1319         smb2_util_close(tree, src_h);
1320         smb2_util_close(tree, dest_h);
1321         talloc_free(tmp_ctx);
1322
1323         return true;
1324 }
1325
1326 static bool test_ioctl_copy_chunk_src_exceed(struct torture_context *torture,
1327                                              struct smb2_tree *tree)
1328 {
1329         struct smb2_handle src_h;
1330         struct smb2_handle dest_h;
1331         NTSTATUS status;
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;
1337         bool ok;
1338
1339         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1340                                    1, /* 1 chunk */
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,
1345                                    &cc_copy,
1346                                    &ioctl);
1347         if (!ok) {
1348                 torture_fail(torture, "setup copy chunk error");
1349         }
1350
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;
1355
1356         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1357                                        &cc_copy,
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");
1361
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");
1366
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;
1371
1372         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1373                                        &cc_copy,
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");
1377
1378         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1379         torture_assert_ntstatus_ok(torture, status,
1380                                    "FSCTL_SRV_COPYCHUNK just right");
1381
1382         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
1383                                        &cc_rsp,
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");
1387
1388         ok = check_copy_chunk_rsp(torture, &cc_rsp,
1389                                   1,    /* chunks written */
1390                                   0,    /* chunk bytes unsuccessfully written */
1391                                   3072); /* total bytes written */
1392         if (!ok) {
1393                 torture_fail(torture, "bad copy chunk response data");
1394         }
1395
1396         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 3072, 1024);
1397         if (!ok) {
1398                 torture_fail(torture, "inconsistent file data");
1399         }
1400
1401         smb2_util_close(tree, src_h);
1402         smb2_util_close(tree, dest_h);
1403         talloc_free(tmp_ctx);
1404         return true;
1405 }
1406
1407 static bool
1408 test_ioctl_copy_chunk_src_exceed_multi(struct torture_context *torture,
1409                                        struct smb2_tree *tree)
1410 {
1411         struct smb2_handle src_h;
1412         struct smb2_handle dest_h;
1413         NTSTATUS status;
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;
1419         bool ok;
1420
1421         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1422                                    2, /* 2 chunks */
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,
1427                                    &cc_copy,
1428                                    &ioctl);
1429         if (!ok) {
1430                 torture_fail(torture, "setup copy chunk error");
1431         }
1432
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;
1437
1438         cc_copy.chunks[1].source_off = 4096;
1439         cc_copy.chunks[1].target_off = 4096;
1440         cc_copy.chunks[1].length = 8192;
1441
1442         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1443                                        &cc_copy,
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");
1447
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,
1453                                        &cc_rsp,
1454                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
1455         torture_assert_ndr_success(torture, ndr_ret, "unmarshalling response");
1456
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 */
1462         if (!ok) {
1463                 torture_fail(torture, "bad copy chunk response data");
1464         }
1465         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
1466         if (!ok) {
1467                 torture_fail(torture, "inconsistent file data");
1468         }
1469
1470         smb2_util_close(tree, src_h);
1471         smb2_util_close(tree, dest_h);
1472         talloc_free(tmp_ctx);
1473         return true;
1474 }
1475
1476 static bool test_ioctl_copy_chunk_sparse_dest(struct torture_context *torture,
1477                                               struct smb2_tree *tree)
1478 {
1479         struct smb2_handle src_h;
1480         struct smb2_handle dest_h;
1481         NTSTATUS status;
1482         union smb_ioctl ioctl;
1483         struct smb2_read r;
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;
1488         bool ok;
1489         int i;
1490
1491         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1492                                    1, /* 1 chunk */
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,
1497                                    &cc_copy,
1498                                    &ioctl);
1499         if (!ok) {
1500                 torture_fail(torture, "setup copy chunk error");
1501         }
1502
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;
1507
1508         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1509                                        &cc_copy,
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");
1513
1514         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1515         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
1516
1517         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
1518                                        &cc_rsp,
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");
1522
1523         ok = check_copy_chunk_rsp(torture, &cc_rsp,
1524                                   1,    /* chunks written */
1525                                   0,    /* chunk bytes unsuccessfully written */
1526                                   4096); /* total bytes written */
1527         if (!ok) {
1528                 torture_fail(torture, "bad copy chunk response data");
1529         }
1530
1531         /* check for zeros in first 4k */
1532         ZERO_STRUCT(r);
1533         r.in.file.handle = dest_h;
1534         r.in.length      = 4096;
1535         r.in.offset      = 0;
1536         status = smb2_read(tree, tmp_ctx, &r);
1537         torture_assert_ntstatus_ok(torture, status, "read");
1538
1539         torture_assert_u64_equal(torture, r.out.data.length, 4096,
1540                                  "read data len mismatch");
1541
1542         for (i = 0; i < 4096; i++) {
1543                 torture_assert(torture, (r.out.data.data[i] == 0),
1544                                "sparse did not pass class");
1545         }
1546
1547         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 4096, 4096, 0);
1548         if (!ok) {
1549                 torture_fail(torture, "inconsistent file data");
1550         }
1551
1552         smb2_util_close(tree, src_h);
1553         smb2_util_close(tree, dest_h);
1554         talloc_free(tmp_ctx);
1555         return true;
1556 }
1557
1558 /*
1559  * set the ioctl MaxOutputResponse size to less than
1560  * sizeof(struct srv_copychunk_rsp)
1561  */
1562 static bool test_ioctl_copy_chunk_max_output_sz(struct torture_context *torture,
1563                                                 struct smb2_tree *tree)
1564 {
1565         struct smb2_handle src_h;
1566         struct smb2_handle dest_h;
1567         NTSTATUS status;
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;
1572         bool ok;
1573
1574         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1575                                    1, /* 1 chunk */
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,
1580                                    &cc_copy,
1581                                    &ioctl);
1582         if (!ok) {
1583                 torture_fail(torture, "setup copy chunk error");
1584         }
1585
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;
1591
1592         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1593                                        &cc_copy,
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");
1597
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");
1602
1603         smb2_util_close(tree, src_h);
1604         smb2_util_close(tree, dest_h);
1605         talloc_free(tmp_ctx);
1606         return true;
1607 }
1608
1609 static bool test_ioctl_copy_chunk_zero_length(struct torture_context *torture,
1610                                               struct smb2_tree *tree)
1611 {
1612         struct smb2_handle src_h;
1613         struct smb2_handle dest_h;
1614         NTSTATUS status;
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;
1621         bool ok;
1622
1623         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1624                                    1, /* 1 chunk */
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,
1629                                    &cc_copy,
1630                                    &ioctl);
1631         if (!ok) {
1632                 torture_fail(torture, "setup copy chunk error");
1633         }
1634
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;
1639
1640         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1641                                        &cc_copy,
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");
1645
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");
1650
1651         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
1652                                        &cc_rsp,
1653                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
1654         torture_assert_ndr_success(torture, ndr_ret, "unmarshalling response");
1655
1656         ZERO_STRUCT(q);
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");
1661
1662         torture_assert_int_equal(torture, q.all_info2.out.size, 0,
1663                                  "size after zero len clone");
1664
1665         smb2_util_close(tree, src_h);
1666         smb2_util_close(tree, dest_h);
1667         talloc_free(tmp_ctx);
1668         return true;
1669 }
1670
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)
1676 {
1677         NTSTATUS status;
1678         union smb_fsinfo info;
1679
1680         ZERO_STRUCT(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)) {
1685                 return status;
1686         }
1687
1688         if (info.attribute_info.out.fs_attr & FILE_FILE_COMPRESSION) {
1689                 *compress_support = true;
1690         } else {
1691                 *compress_support = false;
1692         }
1693         return NT_STATUS_OK;
1694 }
1695
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)
1701 {
1702         union smb_ioctl ioctl;
1703         struct compression_state cmpr_state;
1704         enum ndr_err_code ndr_ret;
1705         NTSTATUS status;
1706
1707         ZERO_STRUCT(ioctl);
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;
1713
1714         status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2);
1715         if (!NT_STATUS_IS_OK(status)) {
1716                 return status;
1717         }
1718
1719         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, mem_ctx,
1720                                        &cmpr_state,
1721                         (ndr_pull_flags_fn_t)ndr_pull_compression_state);
1722
1723         if (ndr_ret != NDR_ERR_SUCCESS) {
1724                 return NT_STATUS_INTERNAL_ERROR;
1725         }
1726
1727         *_compression_fmt = cmpr_state.format;
1728         return NT_STATUS_OK;
1729 }
1730
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)
1736 {
1737         union smb_ioctl ioctl;
1738         struct compression_state cmpr_state;
1739         enum ndr_err_code ndr_ret;
1740         NTSTATUS status;
1741
1742         ZERO_STRUCT(ioctl);
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;
1748
1749         cmpr_state.format = compression_fmt;
1750         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, mem_ctx,
1751                                        &cmpr_state,
1752                         (ndr_push_flags_fn_t)ndr_push_compression_state);
1753         if (ndr_ret != NDR_ERR_SUCCESS) {
1754                 return NT_STATUS_INTERNAL_ERROR;
1755         }
1756
1757         status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2);
1758         return status;
1759 }
1760
1761 static bool test_ioctl_compress_file_flag(struct torture_context *torture,
1762                                             struct smb2_tree *tree)
1763 {
1764         struct smb2_handle fh;
1765         NTSTATUS status;
1766         TALLOC_CTX *tmp_ctx = talloc_new(tree);
1767         bool ok;
1768         uint16_t compression_fmt;
1769
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");
1774
1775         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
1776                                                   &ok);
1777         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
1778         if (!ok) {
1779                 smb2_util_close(tree, fh);
1780                 torture_skip(torture, "FS compression not supported\n");
1781         }
1782
1783         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
1784                                          &compression_fmt);
1785         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
1786
1787         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
1788                        "initial compression state not NONE");
1789
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");
1793
1794         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
1795                                          &compression_fmt);
1796         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
1797
1798         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
1799                        "invalid compression state after set");
1800
1801         smb2_util_close(tree, fh);
1802         talloc_free(tmp_ctx);
1803         return true;
1804 }
1805
1806 static bool test_ioctl_compress_dir_inherit(struct torture_context *torture,
1807                                             struct smb2_tree *tree)
1808 {
1809         struct smb2_handle dirh;
1810         struct smb2_handle fh;
1811         NTSTATUS status;
1812         TALLOC_CTX *tmp_ctx = talloc_new(tree);
1813         uint16_t compression_fmt;
1814         bool ok;
1815         char path_buf[PATH_MAX];
1816
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");
1822
1823         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &dirh,
1824                                                   &ok);
1825         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
1826         if (!ok) {
1827                 smb2_util_close(tree, dirh);
1828                 smb2_deltree(tree, DNAME);
1829                 torture_skip(torture, "FS compression not supported\n");
1830         }
1831
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");
1836
1837         status = test_ioctl_compress_get(torture, tmp_ctx, tree, dirh,
1838                                          &compression_fmt);
1839         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
1840
1841         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
1842                        "invalid compression state after set");
1843
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");
1849
1850         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
1851                                          &compression_fmt);
1852         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
1853
1854         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
1855                        "compression attr not inherited by new file");
1856
1857         /* check compressed data is consistent */
1858         ok = check_pattern(torture, tree, tmp_ctx, fh, 0, 4096, 0);
1859
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");
1864
1865         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
1866                                          &compression_fmt);
1867         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
1868
1869         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
1870                        "file compression attr removed after dir change");
1871         smb2_util_close(tree, fh);
1872
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");
1879
1880         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
1881                                          &compression_fmt);
1882         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
1883
1884         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
1885                        "compression attr present on new file");
1886
1887         smb2_util_close(tree, fh);
1888         smb2_util_close(tree, dirh);
1889         smb2_deltree(tree, DNAME);
1890         talloc_free(tmp_ctx);
1891         return true;
1892 }
1893
1894 static bool test_ioctl_compress_invalid_format(struct torture_context *torture,
1895                                                struct smb2_tree *tree)
1896 {
1897         struct smb2_handle fh;
1898         NTSTATUS status;
1899         TALLOC_CTX *tmp_ctx = talloc_new(tree);
1900         bool ok;
1901         uint16_t compression_fmt;
1902
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");
1907
1908         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
1909                                                   &ok);
1910         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
1911         if (!ok) {
1912                 smb2_util_close(tree, fh);
1913                 torture_skip(torture, "FS compression not supported\n");
1914         }
1915
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");
1921
1922         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
1923                                          &compression_fmt);
1924         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
1925
1926         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
1927                        "initial compression state not NONE");
1928
1929         smb2_util_close(tree, fh);
1930         talloc_free(tmp_ctx);
1931         return true;
1932 }
1933
1934 static bool test_ioctl_compress_invalid_buf(struct torture_context *torture,
1935                                             struct smb2_tree *tree)
1936 {
1937         struct smb2_handle fh;
1938         NTSTATUS status;
1939         TALLOC_CTX *tmp_ctx = talloc_new(tree);
1940         bool ok;
1941         union smb_ioctl ioctl;
1942
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");
1947
1948         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
1949                                                   &ok);
1950         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
1951         if (!ok) {
1952                 smb2_util_close(tree, fh);
1953                 torture_skip(torture, "FS compression not supported\n");
1954         }
1955
1956         ZERO_STRUCT(ioctl);
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;
1962
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");
1969         }
1970
1971         smb2_util_close(tree, fh);
1972         talloc_free(tmp_ctx);
1973         return true;
1974 }
1975
1976 static bool test_ioctl_compress_query_file_attr(struct torture_context *torture,
1977                                                 struct smb2_tree *tree)
1978 {
1979         struct smb2_handle fh;
1980         union smb_fileinfo io;
1981         NTSTATUS status;
1982         TALLOC_CTX *tmp_ctx = talloc_new(tree);
1983         bool ok;
1984
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");
1989
1990         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
1991                                                   &ok);
1992         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
1993         if (!ok) {
1994                 smb2_util_close(tree, fh);
1995                 torture_skip(torture, "FS compression not supported\n");
1996         }
1997
1998         ZERO_STRUCT(io);
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");
2003
2004         torture_assert(torture,
2005                 ((io.all_info2.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
2006                        "compression attr before set");
2007
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");
2011
2012         ZERO_STRUCT(io);
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");
2017
2018         torture_assert(torture,
2019                        (io.basic_info.out.attrib & FILE_ATTRIBUTE_COMPRESSED),
2020                        "no compression attr after set");
2021
2022         smb2_util_close(tree, fh);
2023         talloc_free(tmp_ctx);
2024         return true;
2025 }
2026
2027 /*
2028  * Specify FILE_ATTRIBUTE_COMPRESSED on creation, Windows does not retain this
2029  * attribute.
2030  */
2031 static bool test_ioctl_compress_create_with_attr(struct torture_context *torture,
2032                                                  struct smb2_tree *tree)
2033 {
2034         struct smb2_handle fh2;
2035         union smb_fileinfo io;
2036         NTSTATUS status;
2037         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2038         uint16_t compression_fmt;
2039         bool ok;
2040
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");
2045
2046         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh2,
2047                                                   &ok);
2048         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2049         if (!ok) {
2050                 smb2_util_close(tree, fh2);
2051                 torture_skip(torture, "FS compression not supported\n");
2052         }
2053
2054         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh2,
2055                                          &compression_fmt);
2056         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
2057
2058         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
2059                        "initial compression state not NONE");
2060
2061         ZERO_STRUCT(io);
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");
2066
2067         torture_assert(torture,
2068                 ((io.all_info2.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
2069                        "incorrect compression attr");
2070
2071         smb2_util_close(tree, fh2);
2072         talloc_free(tmp_ctx);
2073         return true;
2074 }
2075
2076 static bool test_ioctl_compress_inherit_disable(struct torture_context *torture,
2077                                                 struct smb2_tree *tree)
2078 {
2079         struct smb2_handle fh;
2080         struct smb2_handle dirh;
2081         char path_buf[PATH_MAX];
2082         NTSTATUS status;
2083         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2084         bool ok;
2085         uint16_t compression_fmt;
2086
2087         struct smb2_create io;
2088
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");
2094
2095         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &dirh,
2096                                                   &ok);
2097         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2098         if (!ok) {
2099                 smb2_util_close(tree, dirh);
2100                 smb2_deltree(tree, DNAME);
2101                 torture_skip(torture, "FS compression not supported\n");
2102         }
2103
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");
2108
2109         status = test_ioctl_compress_get(torture, tmp_ctx, tree, dirh,
2110                                          &compression_fmt);
2111         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
2112
2113         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
2114                        "invalid compression state after set");
2115         smb2_util_close(tree, dirh);
2116
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");
2122
2123         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
2124                                          &compression_fmt);
2125         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
2126
2127         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
2128                        "compression attr not inherited by new file");
2129         smb2_util_close(tree, fh);
2130
2131         snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, FNAME2);
2132
2133         /* NO_COMPRESSION option should block inheritance */
2134         ZERO_STRUCT(io);
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;
2144
2145         status = smb2_create(tree, tmp_ctx, &io);
2146         torture_assert_ntstatus_ok(torture, status, "file create");
2147
2148         fh = io.out.file.handle;
2149
2150         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
2151                                          &compression_fmt);
2152         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
2153
2154         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
2155                        "compression attr inherited by NO_COMPRESSION file");
2156         smb2_util_close(tree, fh);
2157
2158
2159         snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, DNAME);
2160         ZERO_STRUCT(io);
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;
2171
2172         status = smb2_create(tree, tmp_ctx, &io);
2173         torture_assert_ntstatus_ok(torture, status, "dir create");
2174
2175         dirh = io.out.file.handle;
2176
2177         status = test_ioctl_compress_get(torture, tmp_ctx, tree, dirh,
2178                                          &compression_fmt);
2179         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
2180
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);
2185
2186         talloc_free(tmp_ctx);
2187         return true;
2188 }
2189
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)
2193 {
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;
2199         NTSTATUS status;
2200         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2201         bool ok;
2202
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");
2207
2208         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
2209                                                   &ok);
2210         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2211         if (!ok) {
2212                 smb2_util_close(tree, fh);
2213                 torture_skip(torture, "FS compression not supported\n");
2214         }
2215
2216         ZERO_STRUCT(io);
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");
2221
2222         torture_assert(torture,
2223                 ((io.basic_info.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
2224                        "compression attr before set");
2225
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");
2237
2238         ZERO_STRUCT(io);
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");
2243
2244         torture_assert(torture,
2245                 ((io.basic_info.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
2246                 "compression attr after set");
2247
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");
2254
2255         ZERO_STRUCT(io);
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");
2260
2261         torture_assert(torture,
2262                 ((io.basic_info.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
2263                        "compression attr before set");
2264
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");
2276
2277         status = test_ioctl_compress_get(torture, tmp_ctx, tree, dirh,
2278                                          &compression_fmt);
2279         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
2280
2281         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
2282                        "dir compression set after SetInfo");
2283
2284         smb2_util_close(tree, dirh);
2285         talloc_free(tmp_ctx);
2286         return true;
2287 }
2288
2289 static bool test_ioctl_compress_perms(struct torture_context *torture,
2290                                       struct smb2_tree *tree)
2291 {
2292         struct smb2_handle fh;
2293         uint16_t compression_fmt;
2294         union smb_fileinfo io;
2295         NTSTATUS status;
2296         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2297         bool ok;
2298
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");
2303
2304         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
2305                                                   &ok);
2306         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2307         smb2_util_close(tree, fh);
2308         if (!ok) {
2309                 torture_skip(torture, "FS compression not supported\n");
2310         }
2311
2312         /* attempt get compression without READ_ATTR permission */
2313         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2314                                     FNAME, &fh, 0,
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");
2320
2321         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
2322                                          &compression_fmt);
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);
2327
2328         /* set compression without WRITE_ATTR permission should succeed */
2329         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2330                                     FNAME, &fh, 0,
2331                         (SEC_RIGHTS_FILE_WRITE & ~(SEC_FILE_WRITE_ATTRIBUTE
2332                                                         | SEC_STD_WRITE_DAC
2333                                                         | SEC_FILE_WRITE_EA)),
2334                                     FILE_ATTRIBUTE_NORMAL);
2335         torture_assert(torture, ok, "setup compression file");
2336
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);
2341
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");
2346         ZERO_STRUCT(io);
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");
2351
2352         torture_assert(torture,
2353                        (io.all_info2.out.attrib & FILE_ATTRIBUTE_COMPRESSED),
2354                        "incorrect compression attr");
2355         smb2_util_close(tree, fh);
2356
2357         /* attempt get compression without READ_DATA permission */
2358         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2359                                     FNAME, &fh, 0,
2360                         (SEC_RIGHTS_FILE_READ & ~SEC_FILE_READ_DATA),
2361                                     FILE_ATTRIBUTE_NORMAL);
2362         torture_assert(torture, ok, "setup compression file");
2363
2364         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
2365                                          &compression_fmt);
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);
2370
2371         /* attempt get compression with only SYNCHRONIZE permission */
2372         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2373                                     FNAME, &fh, 0,
2374                                     SEC_STD_SYNCHRONIZE,
2375                                     FILE_ATTRIBUTE_NORMAL);
2376         torture_assert(torture, ok, "setup compression file");
2377
2378         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
2379                                          &compression_fmt);
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);
2384
2385         /* attempt to set compression without WRITE_DATA permission */
2386         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2387                                     FNAME, &fh, 0,
2388                         (SEC_RIGHTS_FILE_WRITE & (~SEC_FILE_WRITE_DATA)),
2389                                     FILE_ATTRIBUTE_NORMAL);
2390         torture_assert(torture, ok, "setup compression file");
2391
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);
2398
2399         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2400                                     FNAME, &fh, 0,
2401                         (SEC_RIGHTS_FILE_WRITE & (~SEC_FILE_WRITE_DATA)),
2402                                     FILE_ATTRIBUTE_NORMAL);
2403         torture_assert(torture, ok, "setup compression file");
2404
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);
2411
2412         talloc_free(tmp_ctx);
2413         return true;
2414 }
2415
2416 /*
2417    basic testing of the SMB2 FSCTL_QUERY_NETWORK_INTERFACE_INFO ioctl
2418 */
2419 static bool test_ioctl_network_interface_info(struct torture_context *torture,
2420                                       struct smb2_tree *tree)
2421 {
2422         union smb_ioctl ioctl;
2423         struct smb2_handle fh;
2424         NTSTATUS status;
2425         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2426         struct fsctl_net_iface_info net_iface;
2427         enum ndr_err_code ndr_ret;
2428         uint32_t caps;
2429
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");
2433         }
2434
2435         ZERO_STRUCT(ioctl);
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;
2443
2444         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
2445         torture_assert_ntstatus_ok(torture, status, "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
2446
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");
2451
2452         ndr_print_debug((ndr_print_fn_t)ndr_print_fsctl_net_iface_info
2453                         , "Network Interface Info", &net_iface);
2454
2455         talloc_free(tmp_ctx);
2456         return true;
2457 }
2458
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)
2464 {
2465         NTSTATUS status;
2466         union smb_fsinfo info;
2467
2468         ZERO_STRUCT(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)) {
2473                 return status;
2474         }
2475
2476         if (info.attribute_info.out.fs_attr & FILE_SUPPORTS_SPARSE_FILES) {
2477                 *sparse_support = true;
2478         } else {
2479                 *sparse_support = false;
2480         }
2481         return NT_STATUS_OK;
2482 }
2483
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,
2488                                       bool set)
2489 {
2490         union smb_ioctl ioctl;
2491         NTSTATUS status;
2492         uint8_t set_sparse;
2493
2494         ZERO_STRUCT(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);
2503
2504         status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2);
2505         return status;
2506 }
2507
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,
2512                                 bool *_is_sparse)
2513 {
2514         union smb_fileinfo io;
2515         NTSTATUS status;
2516
2517         ZERO_STRUCT(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)) {
2522                 return status;
2523         }
2524         *_is_sparse = !!(io.basic_info.out.attrib & FILE_ATTRIBUTE_SPARSE);
2525
2526         return status;
2527 }
2528
2529 static bool test_ioctl_sparse_file_flag(struct torture_context *torture,
2530                                         struct smb2_tree *tree)
2531 {
2532         struct smb2_handle fh;
2533         union smb_fileinfo io;
2534         NTSTATUS status;
2535         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2536         bool ok;
2537         bool is_sparse;
2538
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");
2543
2544         status = test_ioctl_sparse_fs_supported(torture, tree, tmp_ctx, &fh,
2545                                                 &ok);
2546         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2547         if (!ok) {
2548                 smb2_util_close(tree, fh);
2549                 torture_skip(torture, "Sparse files not supported\n");
2550         }
2551
2552         ZERO_STRUCT(io);
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");
2557
2558         torture_assert(torture,
2559                 ((io.all_info2.out.attrib & FILE_ATTRIBUTE_SPARSE) == 0),
2560                        "sparse attr before set");
2561
2562         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
2563         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
2564
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");
2568
2569         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, false);
2570         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
2571
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");
2575
2576         smb2_util_close(tree, fh);
2577         talloc_free(tmp_ctx);
2578         return true;
2579 }
2580
2581 static bool test_ioctl_sparse_file_attr(struct torture_context *torture,
2582                                         struct smb2_tree *tree)
2583 {
2584         struct smb2_handle fh;
2585         NTSTATUS status;
2586         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2587         bool ok;
2588         bool is_sparse;
2589
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");
2594
2595         status = test_ioctl_sparse_fs_supported(torture, tree, tmp_ctx, &fh,
2596                                                 &ok);
2597         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2598         if (!ok) {
2599                 smb2_util_close(tree, fh);
2600                 torture_skip(torture, "Sparse files not supported\n");
2601         }
2602
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");
2606
2607         smb2_util_close(tree, fh);
2608         talloc_free(tmp_ctx);
2609         return true;
2610 }
2611
2612 /*
2613    basic testing of SMB2 ioctls
2614 */
2615 struct torture_suite *torture_smb2_ioctl_init(void)
2616 {
2617         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "ioctl");
2618
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);
2683
2684         suite->description = talloc_strdup(suite, "SMB2-IOCTL tests");
2685
2686         return suite;
2687 }
2688