0aa37141526f465995a92e603b221e2747d10702
[gd/samba-autobuild/.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-2015
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 write_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         NTSTATUS status;
128         uint64_t i;
129         uint8_t *buf;
130         uint64_t io_sz = MIN(1024 * 64, len);
131
132         if (len == 0) {
133                 return true;
134         }
135
136         torture_assert(torture, (len % 8) == 0, "invalid write len");
137
138         buf = talloc_zero_size(mem_ctx, io_sz);
139         torture_assert(torture, (buf != NULL), "no memory for file data buf");
140
141         while (len > 0) {
142                 for (i = 0; i <= io_sz - 8; i += 8) {
143                         SBVAL(buf, i, patt_hash(patt_off));
144                         patt_off += 8;
145                 }
146
147                 status = smb2_util_write(tree, h,
148                                          buf, off, io_sz);
149                 torture_assert_ntstatus_ok(torture, status, "file write");
150
151                 len -= io_sz;
152                 off += io_sz;
153         }
154
155         talloc_free(buf);
156
157         return true;
158 }
159
160 static bool check_pattern(struct torture_context *torture,
161                           struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
162                           struct smb2_handle h, uint64_t off, uint64_t len,
163                           uint64_t patt_off)
164 {
165         if (len == 0) {
166                 return true;
167         }
168
169         torture_assert(torture, (len % 8) == 0, "invalid read len");
170
171         while (len > 0) {
172                 uint64_t i;
173                 struct smb2_read r;
174                 NTSTATUS status;
175                 uint64_t io_sz = MIN(1024 * 64, len);
176
177                 ZERO_STRUCT(r);
178                 r.in.file.handle = h;
179                 r.in.length      = io_sz;
180                 r.in.offset      = off;
181                 status = smb2_read(tree, mem_ctx, &r);
182                 torture_assert_ntstatus_ok(torture, status, "read");
183
184                 torture_assert_u64_equal(torture, r.out.data.length, io_sz,
185                                          "read data len mismatch");
186
187                 for (i = 0; i <= io_sz - 8; i += 8, patt_off += 8) {
188                         uint64_t data = BVAL(r.out.data.data, i);
189                         torture_assert_u64_equal(torture, data, patt_hash(patt_off),
190                                                  talloc_asprintf(torture, "read data "
191                                                                  "pattern bad at %llu\n",
192                                                                  (unsigned long long)off + i));
193                 }
194                 talloc_free(r.out.data.data);
195                 len -= io_sz;
196                 off += io_sz;
197         }
198
199         return true;
200 }
201
202 static bool check_zero(struct torture_context *torture,
203                        struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
204                        struct smb2_handle h, uint64_t off, uint64_t len)
205 {
206         uint64_t i;
207         struct smb2_read r;
208         NTSTATUS status;
209
210         if (len == 0) {
211                 return true;
212         }
213
214         ZERO_STRUCT(r);
215         r.in.file.handle = h;
216         r.in.length      = len;
217         r.in.offset      = off;
218         status = smb2_read(tree, mem_ctx, &r);
219         torture_assert_ntstatus_ok(torture, status, "read");
220
221         torture_assert_u64_equal(torture, r.out.data.length, len,
222                                  "read data len mismatch");
223
224         for (i = 0; i <= len - 8; i += 8) {
225                 uint64_t data = BVAL(r.out.data.data, i);
226                 torture_assert_u64_equal(torture, data, 0,
227                                          talloc_asprintf(mem_ctx, "read zero "
228                                                          "bad at %llu\n",
229                                                          (unsigned long long)i));
230         }
231
232         talloc_free(r.out.data.data);
233         return true;
234 }
235
236 static bool test_setup_open(struct torture_context *torture,
237                             struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
238                             const char *fname,
239                             struct smb2_handle *fh,
240                             uint32_t desired_access,
241                             uint32_t file_attributes)
242 {
243         struct smb2_create io;
244         NTSTATUS status;
245
246         ZERO_STRUCT(io);
247         io.in.desired_access = desired_access;
248         io.in.file_attributes = file_attributes;
249         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
250         io.in.share_access =
251                 NTCREATEX_SHARE_ACCESS_DELETE|
252                 NTCREATEX_SHARE_ACCESS_READ|
253                 NTCREATEX_SHARE_ACCESS_WRITE;
254         if (file_attributes & FILE_ATTRIBUTE_DIRECTORY) {
255                 io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
256         }
257         io.in.fname = fname;
258
259         status = smb2_create(tree, mem_ctx, &io);
260         torture_assert_ntstatus_ok(torture, status, "file create");
261
262         *fh = io.out.file.handle;
263
264         return true;
265 }
266
267 static bool test_setup_create_fill(struct torture_context *torture,
268                                    struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
269                                    const char *fname,
270                                    struct smb2_handle *fh,
271                                    uint64_t size,
272                                    uint32_t desired_access,
273                                    uint32_t file_attributes)
274 {
275         bool ok;
276         uint32_t initial_access = desired_access;
277
278         if (size > 0) {
279                 initial_access |= SEC_FILE_APPEND_DATA;
280         }
281
282         smb2_util_unlink(tree, fname);
283
284         ok = test_setup_open(torture, tree, mem_ctx,
285                              fname,
286                              fh,
287                              initial_access,
288                              file_attributes);
289         torture_assert(torture, ok, "file create");
290
291         if (size > 0) {
292                 ok = write_pattern(torture, tree, mem_ctx, *fh, 0, size, 0);
293                 torture_assert(torture, ok, "write pattern");
294         }
295
296         if (initial_access != desired_access) {
297                 smb2_util_close(tree, *fh);
298                 ok = test_setup_open(torture, tree, mem_ctx,
299                                      fname,
300                                      fh,
301                                      desired_access,
302                                      file_attributes);
303                 torture_assert(torture, ok, "file open");
304         }
305
306         return true;
307 }
308
309 static bool test_setup_copy_chunk(struct torture_context *torture,
310                                   struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
311                                   uint32_t nchunks,
312                                   struct smb2_handle *src_h,
313                                   uint64_t src_size,
314                                   uint32_t src_desired_access,
315                                   struct smb2_handle *dest_h,
316                                   uint64_t dest_size,
317                                   uint32_t dest_desired_access,
318                                   struct srv_copychunk_copy *cc_copy,
319                                   union smb_ioctl *ioctl)
320 {
321         struct req_resume_key_rsp res_key;
322         bool ok;
323         NTSTATUS status;
324         enum ndr_err_code ndr_ret;
325
326         ok = test_setup_create_fill(torture, tree, mem_ctx, FNAME,
327                                     src_h, src_size, src_desired_access,
328                                     FILE_ATTRIBUTE_NORMAL);
329         torture_assert(torture, ok, "src file create fill");
330
331         ok = test_setup_create_fill(torture, tree, mem_ctx, FNAME2,
332                                     dest_h, dest_size, dest_desired_access,
333                                     FILE_ATTRIBUTE_NORMAL);
334         torture_assert(torture, ok, "dest file create fill");
335
336         ZERO_STRUCTPN(ioctl);
337         ioctl->smb2.level = RAW_IOCTL_SMB2;
338         ioctl->smb2.in.file.handle = *src_h;
339         ioctl->smb2.in.function = FSCTL_SRV_REQUEST_RESUME_KEY;
340         /* Allow for Key + ContextLength + Context */
341         ioctl->smb2.in.max_response_size = 32;
342         ioctl->smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
343
344         status = smb2_ioctl(tree, mem_ctx, &ioctl->smb2);
345         torture_assert_ntstatus_ok(torture, status,
346                                    "FSCTL_SRV_REQUEST_RESUME_KEY");
347
348         ndr_ret = ndr_pull_struct_blob(&ioctl->smb2.out.out, mem_ctx, &res_key,
349                         (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
350
351         torture_assert_ndr_success(torture, ndr_ret,
352                                    "ndr_pull_req_resume_key_rsp");
353
354         ZERO_STRUCTPN(ioctl);
355         ioctl->smb2.level = RAW_IOCTL_SMB2;
356         ioctl->smb2.in.file.handle = *dest_h;
357         ioctl->smb2.in.function = FSCTL_SRV_COPYCHUNK;
358         ioctl->smb2.in.max_response_size = sizeof(struct srv_copychunk_rsp);
359         ioctl->smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
360
361         ZERO_STRUCTPN(cc_copy);
362         memcpy(cc_copy->source_key, res_key.resume_key, ARRAY_SIZE(cc_copy->source_key));
363         cc_copy->chunk_count = nchunks;
364         cc_copy->chunks = talloc_zero_array(mem_ctx, struct srv_copychunk, nchunks);
365         torture_assert(torture, (cc_copy->chunks != NULL), "no memory for chunks");
366
367         return true;
368 }
369
370
371 static bool check_copy_chunk_rsp(struct torture_context *torture,
372                                  struct srv_copychunk_rsp *cc_rsp,
373                                  uint32_t ex_chunks_written,
374                                  uint32_t ex_chunk_bytes_written,
375                                  uint32_t ex_total_bytes_written)
376 {
377         torture_assert_int_equal(torture, cc_rsp->chunks_written,
378                                  ex_chunks_written, "num chunks");
379         torture_assert_int_equal(torture, cc_rsp->chunk_bytes_written,
380                                  ex_chunk_bytes_written, "chunk bytes written");
381         torture_assert_int_equal(torture, cc_rsp->total_bytes_written,
382                                  ex_total_bytes_written, "chunk total bytes");
383         return true;
384 }
385
386 static bool test_ioctl_copy_chunk_simple(struct torture_context *torture,
387                                          struct smb2_tree *tree)
388 {
389         struct smb2_handle src_h;
390         struct smb2_handle dest_h;
391         NTSTATUS status;
392         union smb_ioctl ioctl;
393         TALLOC_CTX *tmp_ctx = talloc_new(tree);
394         struct srv_copychunk_copy cc_copy;
395         struct srv_copychunk_rsp cc_rsp;
396         enum ndr_err_code ndr_ret;
397         bool ok;
398
399         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
400                                    1, /* 1 chunk */
401                                    &src_h, 4096, /* fill 4096 byte src file */
402                                    SEC_RIGHTS_FILE_ALL,
403                                    &dest_h, 0,  /* 0 byte dest file */
404                                    SEC_RIGHTS_FILE_ALL,
405                                    &cc_copy,
406                                    &ioctl);
407         if (!ok) {
408                 torture_fail(torture, "setup copy chunk error");
409         }
410
411         /* copy all src file data (via a single chunk desc) */
412         cc_copy.chunks[0].source_off = 0;
413         cc_copy.chunks[0].target_off = 0;
414         cc_copy.chunks[0].length = 4096;
415
416         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
417                                        &cc_copy,
418                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
419         torture_assert_ndr_success(torture, ndr_ret,
420                                    "ndr_push_srv_copychunk_copy");
421
422         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
423         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
424
425         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
426                                        &cc_rsp,
427                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
428         torture_assert_ndr_success(torture, ndr_ret,
429                                    "ndr_pull_srv_copychunk_rsp");
430
431         ok = check_copy_chunk_rsp(torture, &cc_rsp,
432                                   1,    /* chunks written */
433                                   0,    /* chunk bytes unsuccessfully written */
434                                   4096); /* total bytes written */
435         if (!ok) {
436                 torture_fail(torture, "bad copy chunk response data");
437         }
438
439         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
440         if (!ok) {
441                 torture_fail(torture, "inconsistent file data");
442         }
443
444         smb2_util_close(tree, src_h);
445         smb2_util_close(tree, dest_h);
446         talloc_free(tmp_ctx);
447         return true;
448 }
449
450 static bool test_ioctl_copy_chunk_multi(struct torture_context *torture,
451                                         struct smb2_tree *tree)
452 {
453         struct smb2_handle src_h;
454         struct smb2_handle dest_h;
455         NTSTATUS status;
456         union smb_ioctl ioctl;
457         TALLOC_CTX *tmp_ctx = talloc_new(tree);
458         struct srv_copychunk_copy cc_copy;
459         struct srv_copychunk_rsp cc_rsp;
460         enum ndr_err_code ndr_ret;
461         bool ok;
462
463         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
464                                    2, /* chunks */
465                                    &src_h, 8192, /* src file */
466                                    SEC_RIGHTS_FILE_ALL,
467                                    &dest_h, 0,  /* dest file */
468                                    SEC_RIGHTS_FILE_ALL,
469                                    &cc_copy,
470                                    &ioctl);
471         if (!ok) {
472                 torture_fail(torture, "setup copy chunk error");
473         }
474
475         /* copy all src file data via two chunks */
476         cc_copy.chunks[0].source_off = 0;
477         cc_copy.chunks[0].target_off = 0;
478         cc_copy.chunks[0].length = 4096;
479
480         cc_copy.chunks[1].source_off = 4096;
481         cc_copy.chunks[1].target_off = 4096;
482         cc_copy.chunks[1].length = 4096;
483
484         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
485                                        &cc_copy,
486                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
487         torture_assert_ndr_success(torture, ndr_ret,
488                                    "ndr_push_srv_copychunk_copy");
489
490         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
491         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
492
493         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
494                                        &cc_rsp,
495                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
496         torture_assert_ndr_success(torture, ndr_ret,
497                                    "ndr_pull_srv_copychunk_rsp");
498
499         ok = check_copy_chunk_rsp(torture, &cc_rsp,
500                                   2,    /* chunks written */
501                                   0,    /* chunk bytes unsuccessfully written */
502                                   8192);        /* total bytes written */
503         if (!ok) {
504                 torture_fail(torture, "bad copy chunk response data");
505         }
506
507         smb2_util_close(tree, src_h);
508         smb2_util_close(tree, dest_h);
509         talloc_free(tmp_ctx);
510         return true;
511 }
512
513 static bool test_ioctl_copy_chunk_tiny(struct torture_context *torture,
514                                        struct smb2_tree *tree)
515 {
516         struct smb2_handle src_h;
517         struct smb2_handle dest_h;
518         NTSTATUS status;
519         union smb_ioctl ioctl;
520         TALLOC_CTX *tmp_ctx = talloc_new(tree);
521         struct srv_copychunk_copy cc_copy;
522         struct srv_copychunk_rsp cc_rsp;
523         enum ndr_err_code ndr_ret;
524         bool ok;
525
526         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
527                                    2, /* chunks */
528                                    &src_h, 96, /* src file */
529                                    SEC_RIGHTS_FILE_ALL,
530                                    &dest_h, 0,  /* dest file */
531                                    SEC_RIGHTS_FILE_ALL,
532                                    &cc_copy,
533                                    &ioctl);
534         if (!ok) {
535                 torture_fail(torture, "setup copy chunk error");
536         }
537
538         /* copy all src file data via two chunks, sub block size chunks */
539         cc_copy.chunks[0].source_off = 0;
540         cc_copy.chunks[0].target_off = 0;
541         cc_copy.chunks[0].length = 48;
542
543         cc_copy.chunks[1].source_off = 48;
544         cc_copy.chunks[1].target_off = 48;
545         cc_copy.chunks[1].length = 48;
546
547         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
548                                        &cc_copy,
549                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
550         torture_assert_ndr_success(torture, ndr_ret,
551                                    "ndr_push_srv_copychunk_copy");
552
553         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
554         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
555
556         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
557                                        &cc_rsp,
558                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
559         torture_assert_ndr_success(torture, ndr_ret,
560                                    "ndr_pull_srv_copychunk_rsp");
561
562         ok = check_copy_chunk_rsp(torture, &cc_rsp,
563                                   2,    /* chunks written */
564                                   0,    /* chunk bytes unsuccessfully written */
565                                   96);  /* total bytes written */
566         if (!ok) {
567                 torture_fail(torture, "bad copy chunk response data");
568         }
569
570         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 96, 0);
571         if (!ok) {
572                 torture_fail(torture, "inconsistent file data");
573         }
574
575         smb2_util_close(tree, src_h);
576         smb2_util_close(tree, dest_h);
577         talloc_free(tmp_ctx);
578         return true;
579 }
580
581 static bool test_ioctl_copy_chunk_over(struct torture_context *torture,
582                                        struct smb2_tree *tree)
583 {
584         struct smb2_handle src_h;
585         struct smb2_handle dest_h;
586         NTSTATUS status;
587         union smb_ioctl ioctl;
588         TALLOC_CTX *tmp_ctx = talloc_new(tree);
589         struct srv_copychunk_copy cc_copy;
590         struct srv_copychunk_rsp cc_rsp;
591         enum ndr_err_code ndr_ret;
592         bool ok;
593
594         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
595                                    2, /* chunks */
596                                    &src_h, 8192, /* src file */
597                                    SEC_RIGHTS_FILE_ALL,
598                                    &dest_h, 4096, /* dest file */
599                                    SEC_RIGHTS_FILE_ALL,
600                                    &cc_copy,
601                                    &ioctl);
602         if (!ok) {
603                 torture_fail(torture, "setup copy chunk error");
604         }
605
606         /* first chunk overwrites existing dest data */
607         cc_copy.chunks[0].source_off = 0;
608         cc_copy.chunks[0].target_off = 0;
609         cc_copy.chunks[0].length = 4096;
610
611         /* second chunk overwrites the first */
612         cc_copy.chunks[1].source_off = 4096;
613         cc_copy.chunks[1].target_off = 0;
614         cc_copy.chunks[1].length = 4096;
615
616         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
617                                        &cc_copy,
618                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
619         torture_assert_ndr_success(torture, ndr_ret,
620                                    "ndr_push_srv_copychunk_copy");
621
622         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
623         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
624
625         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
626                                        &cc_rsp,
627                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
628         torture_assert_ndr_success(torture, ndr_ret,
629                                    "ndr_pull_srv_copychunk_rsp");
630
631         ok = check_copy_chunk_rsp(torture, &cc_rsp,
632                                   2,    /* chunks written */
633                                   0,    /* chunk bytes unsuccessfully written */
634                                   8192); /* total bytes written */
635         if (!ok) {
636                 torture_fail(torture, "bad copy chunk response data");
637         }
638
639         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 4096);
640         if (!ok) {
641                 torture_fail(torture, "inconsistent file data");
642         }
643
644         smb2_util_close(tree, src_h);
645         smb2_util_close(tree, dest_h);
646         talloc_free(tmp_ctx);
647         return true;
648 }
649
650 static bool test_ioctl_copy_chunk_append(struct torture_context *torture,
651                                        struct smb2_tree *tree)
652 {
653         struct smb2_handle src_h;
654         struct smb2_handle dest_h;
655         NTSTATUS status;
656         union smb_ioctl ioctl;
657         TALLOC_CTX *tmp_ctx = talloc_new(tree);
658         struct srv_copychunk_copy cc_copy;
659         struct srv_copychunk_rsp cc_rsp;
660         enum ndr_err_code ndr_ret;
661         bool ok;
662
663         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
664                                    2, /* chunks */
665                                    &src_h, 4096, /* src file */
666                                    SEC_RIGHTS_FILE_ALL,
667                                    &dest_h, 0,  /* dest file */
668                                    SEC_RIGHTS_FILE_ALL,
669                                    &cc_copy,
670                                    &ioctl);
671         if (!ok) {
672                 torture_fail(torture, "setup copy chunk error");
673         }
674
675         cc_copy.chunks[0].source_off = 0;
676         cc_copy.chunks[0].target_off = 0;
677         cc_copy.chunks[0].length = 4096;
678
679         /* second chunk appends the same data to the first */
680         cc_copy.chunks[1].source_off = 0;
681         cc_copy.chunks[1].target_off = 4096;
682         cc_copy.chunks[1].length = 4096;
683
684         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
685                                        &cc_copy,
686                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
687         torture_assert_ndr_success(torture, ndr_ret,
688                                    "ndr_push_srv_copychunk_copy");
689
690         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
691         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
692
693         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
694                                        &cc_rsp,
695                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
696         torture_assert_ndr_success(torture, ndr_ret,
697                                    "ndr_pull_srv_copychunk_rsp");
698
699         ok = check_copy_chunk_rsp(torture, &cc_rsp,
700                                   2,    /* chunks written */
701                                   0,    /* chunk bytes unsuccessfully written */
702                                   8192); /* total bytes written */
703         if (!ok) {
704                 torture_fail(torture, "bad copy chunk response data");
705         }
706
707         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
708         if (!ok) {
709                 torture_fail(torture, "inconsistent file data");
710         }
711
712         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 4096, 4096, 0);
713         if (!ok) {
714                 torture_fail(torture, "inconsistent file data");
715         }
716
717         smb2_util_close(tree, src_h);
718         smb2_util_close(tree, dest_h);
719         talloc_free(tmp_ctx);
720         return true;
721 }
722
723 static bool test_ioctl_copy_chunk_limits(struct torture_context *torture,
724                                          struct smb2_tree *tree)
725 {
726         struct smb2_handle src_h;
727         struct smb2_handle dest_h;
728         NTSTATUS status;
729         union smb_ioctl ioctl;
730         TALLOC_CTX *tmp_ctx = talloc_new(tree);
731         struct srv_copychunk_copy cc_copy;
732         struct srv_copychunk_rsp cc_rsp;
733         enum ndr_err_code ndr_ret;
734         bool ok;
735
736         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
737                                    1, /* chunks */
738                                    &src_h, 4096, /* src file */
739                                    SEC_RIGHTS_FILE_ALL,
740                                    &dest_h, 0,  /* dest file */
741                                    SEC_RIGHTS_FILE_ALL,
742                                    &cc_copy,
743                                    &ioctl);
744         if (!ok) {
745                 torture_fail(torture, "setup copy chunk error");
746         }
747
748         /* send huge chunk length request */
749         cc_copy.chunks[0].source_off = 0;
750         cc_copy.chunks[0].target_off = 0;
751         cc_copy.chunks[0].length = UINT_MAX;
752
753         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
754                                        &cc_copy,
755                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
756         torture_assert_ndr_success(torture, ndr_ret, "marshalling request");
757
758         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
759         torture_assert_ntstatus_equal(torture, status,
760                                       NT_STATUS_INVALID_PARAMETER,
761                                       "bad oversize chunk response");
762
763         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
764                                        &cc_rsp,
765                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
766         torture_assert_ndr_success(torture, ndr_ret, "unmarshalling response");
767
768         torture_comment(torture, "limit max chunks, got %u\n",
769                         cc_rsp.chunks_written);
770         torture_comment(torture, "limit max chunk len, got %u\n",
771                         cc_rsp.chunk_bytes_written);
772         torture_comment(torture, "limit max total bytes, got %u\n",
773                         cc_rsp.total_bytes_written);
774
775         smb2_util_close(tree, src_h);
776         smb2_util_close(tree, dest_h);
777         talloc_free(tmp_ctx);
778         return true;
779 }
780
781 static bool test_ioctl_copy_chunk_src_lck(struct torture_context *torture,
782                                           struct smb2_tree *tree)
783 {
784         struct smb2_handle src_h;
785         struct smb2_handle src_h2;
786         struct smb2_handle dest_h;
787         NTSTATUS status;
788         union smb_ioctl ioctl;
789         TALLOC_CTX *tmp_ctx = talloc_new(tree);
790         struct srv_copychunk_copy cc_copy;
791         struct srv_copychunk_rsp cc_rsp;
792         enum ndr_err_code ndr_ret;
793         bool ok;
794         struct smb2_lock lck;
795         struct smb2_lock_element el[1];
796
797         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
798                                    1, /* chunks */
799                                    &src_h, 4096, /* src file */
800                                    SEC_RIGHTS_FILE_ALL,
801                                    &dest_h, 0,  /* dest file */
802                                    SEC_RIGHTS_FILE_ALL,
803                                    &cc_copy,
804                                    &ioctl);
805         if (!ok) {
806                 torture_fail(torture, "setup copy chunk error");
807         }
808
809         cc_copy.chunks[0].source_off = 0;
810         cc_copy.chunks[0].target_off = 0;
811         cc_copy.chunks[0].length = 4096;
812
813         /* open and lock the copychunk src file */
814         status = torture_smb2_testfile(tree, FNAME, &src_h2);
815         torture_assert_ntstatus_ok(torture, status, "2nd src open");
816
817         lck.in.lock_count       = 0x0001;
818         lck.in.lock_sequence    = 0x00000000;
819         lck.in.file.handle      = src_h2;
820         lck.in.locks            = el;
821         el[0].offset            = cc_copy.chunks[0].source_off;
822         el[0].length            = cc_copy.chunks[0].length;
823         el[0].reserved          = 0;
824         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE;
825
826         status = smb2_lock(tree, &lck);
827         torture_assert_ntstatus_ok(torture, status, "lock");
828
829         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
830                                        &cc_copy,
831                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
832         torture_assert_ndr_success(torture, ndr_ret,
833                                    "ndr_push_srv_copychunk_copy");
834
835         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
836         /*
837          * 2k12 & Samba return lock_conflict, Windows 7 & 2k8 return success...
838          *
839          * Edgar Olougouna @ MS wrote:
840          * Regarding the FSCTL_SRV_COPYCHUNK and STATUS_FILE_LOCK_CONFLICT
841          * discrepancy observed between Windows versions, we confirm that the
842          * behavior change is expected.
843          *
844          * CopyChunk in Windows Server 2012 use regular Readfile/Writefile APIs
845          * to move the chunks from the source to the destination.
846          * These ReadFile/WriteFile APIs go through the byte-range lock checks,
847          * and this explains the observed STATUS_FILE_LOCK_CONFLICT error.
848          *
849          * Prior to Windows Server 2012, CopyChunk used mapped sections to move
850          * the data. And byte range locks are not enforced on mapped I/O, and
851          * this explains the STATUS_SUCCESS observed on Windows Server 2008 R2.
852          */
853         torture_assert_ntstatus_equal(torture, status,
854                                       NT_STATUS_FILE_LOCK_CONFLICT,
855                                       "FSCTL_SRV_COPYCHUNK locked");
856
857         /* should get cc response data with the lock conflict status */
858         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
859                                        &cc_rsp,
860                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
861         torture_assert_ndr_success(torture, ndr_ret,
862                                    "ndr_pull_srv_copychunk_rsp");
863         ok = check_copy_chunk_rsp(torture, &cc_rsp,
864                                   0,    /* chunks written */
865                                   0,    /* chunk bytes unsuccessfully written */
866                                   0);   /* total bytes written */
867
868         lck.in.lock_count       = 0x0001;
869         lck.in.lock_sequence    = 0x00000001;
870         lck.in.file.handle      = src_h2;
871         lck.in.locks            = el;
872         el[0].offset            = cc_copy.chunks[0].source_off;
873         el[0].length            = cc_copy.chunks[0].length;
874         el[0].reserved          = 0;
875         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
876         status = smb2_lock(tree, &lck);
877         torture_assert_ntstatus_ok(torture, status, "unlock");
878
879         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
880         torture_assert_ntstatus_ok(torture, status,
881                                    "FSCTL_SRV_COPYCHUNK unlocked");
882
883         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
884                                        &cc_rsp,
885                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
886         torture_assert_ndr_success(torture, ndr_ret,
887                                    "ndr_pull_srv_copychunk_rsp");
888
889         ok = check_copy_chunk_rsp(torture, &cc_rsp,
890                                   1,    /* chunks written */
891                                   0,    /* chunk bytes unsuccessfully written */
892                                   4096); /* total bytes written */
893         if (!ok) {
894                 torture_fail(torture, "bad copy chunk response data");
895         }
896
897         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
898         if (!ok) {
899                 torture_fail(torture, "inconsistent file data");
900         }
901
902         smb2_util_close(tree, src_h2);
903         smb2_util_close(tree, src_h);
904         smb2_util_close(tree, dest_h);
905         talloc_free(tmp_ctx);
906         return true;
907 }
908
909 static bool test_ioctl_copy_chunk_dest_lck(struct torture_context *torture,
910                                            struct smb2_tree *tree)
911 {
912         struct smb2_handle src_h;
913         struct smb2_handle dest_h;
914         struct smb2_handle dest_h2;
915         NTSTATUS status;
916         union smb_ioctl ioctl;
917         TALLOC_CTX *tmp_ctx = talloc_new(tree);
918         struct srv_copychunk_copy cc_copy;
919         struct srv_copychunk_rsp cc_rsp;
920         enum ndr_err_code ndr_ret;
921         bool ok;
922         struct smb2_lock lck;
923         struct smb2_lock_element el[1];
924
925         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
926                                    1, /* chunks */
927                                    &src_h, 4096, /* src file */
928                                    SEC_RIGHTS_FILE_ALL,
929                                    &dest_h, 4096,       /* dest file */
930                                    SEC_RIGHTS_FILE_ALL,
931                                    &cc_copy,
932                                    &ioctl);
933         if (!ok) {
934                 torture_fail(torture, "setup copy chunk error");
935         }
936
937         cc_copy.chunks[0].source_off = 0;
938         cc_copy.chunks[0].target_off = 0;
939         cc_copy.chunks[0].length = 4096;
940
941         /* open and lock the copychunk dest file */
942         status = torture_smb2_testfile(tree, FNAME2, &dest_h2);
943         torture_assert_ntstatus_ok(torture, status, "2nd src open");
944
945         lck.in.lock_count       = 0x0001;
946         lck.in.lock_sequence    = 0x00000000;
947         lck.in.file.handle      = dest_h2;
948         lck.in.locks            = el;
949         el[0].offset            = cc_copy.chunks[0].target_off;
950         el[0].length            = cc_copy.chunks[0].length;
951         el[0].reserved          = 0;
952         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE;
953
954         status = smb2_lock(tree, &lck);
955         torture_assert_ntstatus_ok(torture, status, "lock");
956
957         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
958                                        &cc_copy,
959                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
960         torture_assert_ndr_success(torture, ndr_ret,
961                                    "ndr_push_srv_copychunk_copy");
962
963         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
964         torture_assert_ntstatus_equal(torture, status,
965                                       NT_STATUS_FILE_LOCK_CONFLICT,
966                                       "FSCTL_SRV_COPYCHUNK locked");
967
968         lck.in.lock_count       = 0x0001;
969         lck.in.lock_sequence    = 0x00000001;
970         lck.in.file.handle      = dest_h2;
971         lck.in.locks            = el;
972         el[0].offset            = cc_copy.chunks[0].target_off;
973         el[0].length            = cc_copy.chunks[0].length;
974         el[0].reserved          = 0;
975         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
976         status = smb2_lock(tree, &lck);
977         torture_assert_ntstatus_ok(torture, status, "unlock");
978
979         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
980         torture_assert_ntstatus_ok(torture, status,
981                                    "FSCTL_SRV_COPYCHUNK unlocked");
982
983         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
984                                        &cc_rsp,
985                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
986         torture_assert_ndr_success(torture, ndr_ret,
987                                    "ndr_pull_srv_copychunk_rsp");
988
989         ok = check_copy_chunk_rsp(torture, &cc_rsp,
990                                   1,    /* chunks written */
991                                   0,    /* chunk bytes unsuccessfully written */
992                                   4096); /* total bytes written */
993         if (!ok) {
994                 torture_fail(torture, "bad copy chunk response data");
995         }
996
997         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
998         if (!ok) {
999                 torture_fail(torture, "inconsistent file data");
1000         }
1001
1002         smb2_util_close(tree, dest_h2);
1003         smb2_util_close(tree, src_h);
1004         smb2_util_close(tree, dest_h);
1005         talloc_free(tmp_ctx);
1006         return true;
1007 }
1008
1009 static bool test_ioctl_copy_chunk_bad_key(struct torture_context *torture,
1010                                           struct smb2_tree *tree)
1011 {
1012         struct smb2_handle src_h;
1013         struct smb2_handle dest_h;
1014         NTSTATUS status;
1015         union smb_ioctl ioctl;
1016         TALLOC_CTX *tmp_ctx = talloc_new(tree);
1017         struct srv_copychunk_copy cc_copy;
1018         enum ndr_err_code ndr_ret;
1019         bool ok;
1020
1021         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1022                                    1,
1023                                    &src_h, 4096,
1024                                    SEC_RIGHTS_FILE_ALL,
1025                                    &dest_h, 0,
1026                                    SEC_RIGHTS_FILE_ALL,
1027                                    &cc_copy,
1028                                    &ioctl);
1029         if (!ok) {
1030                 torture_fail(torture, "setup copy chunk error");
1031         }
1032
1033         /* overwrite the resume key with a bogus value */
1034         memcpy(cc_copy.source_key, "deadbeefdeadbeefdeadbeef", 24);
1035
1036         cc_copy.chunks[0].source_off = 0;
1037         cc_copy.chunks[0].target_off = 0;
1038         cc_copy.chunks[0].length = 4096;
1039
1040         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1041                                        &cc_copy,
1042                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
1043         torture_assert_ndr_success(torture, ndr_ret,
1044                                    "ndr_push_srv_copychunk_copy");
1045
1046         /* Server 2k12 returns NT_STATUS_OBJECT_NAME_NOT_FOUND */
1047         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1048         torture_assert_ntstatus_equal(torture, status,
1049                                       NT_STATUS_OBJECT_NAME_NOT_FOUND,
1050                                       "FSCTL_SRV_COPYCHUNK");
1051
1052         smb2_util_close(tree, src_h);
1053         smb2_util_close(tree, dest_h);
1054         talloc_free(tmp_ctx);
1055         return true;
1056 }
1057
1058 static bool test_ioctl_copy_chunk_src_is_dest(struct torture_context *torture,
1059                                               struct smb2_tree *tree)
1060 {
1061         struct smb2_handle src_h;
1062         struct smb2_handle dest_h;
1063         NTSTATUS status;
1064         union smb_ioctl ioctl;
1065         TALLOC_CTX *tmp_ctx = talloc_new(tree);
1066         struct srv_copychunk_copy cc_copy;
1067         struct srv_copychunk_rsp cc_rsp;
1068         enum ndr_err_code ndr_ret;
1069         bool ok;
1070
1071         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1072                                    1,
1073                                    &src_h, 8192,
1074                                    SEC_RIGHTS_FILE_ALL,
1075                                    &dest_h, 0,
1076                                    SEC_RIGHTS_FILE_ALL,
1077                                    &cc_copy,
1078                                    &ioctl);
1079         if (!ok) {
1080                 torture_fail(torture, "setup copy chunk error");
1081         }
1082
1083         /* the source is also the destination */
1084         ioctl.smb2.in.file.handle = src_h;
1085
1086         /* non-overlapping */
1087         cc_copy.chunks[0].source_off = 0;
1088         cc_copy.chunks[0].target_off = 4096;
1089         cc_copy.chunks[0].length = 4096;
1090
1091         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1092                                        &cc_copy,
1093                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
1094         torture_assert_ndr_success(torture, ndr_ret,
1095                                    "ndr_push_srv_copychunk_copy");
1096
1097         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1098         torture_assert_ntstatus_ok(torture, status,
1099                                    "FSCTL_SRV_COPYCHUNK");
1100
1101         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
1102                                        &cc_rsp,
1103                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
1104         torture_assert_ndr_success(torture, ndr_ret,
1105                                    "ndr_pull_srv_copychunk_rsp");
1106
1107         ok = check_copy_chunk_rsp(torture, &cc_rsp,
1108                                   1,    /* chunks written */
1109                                   0,    /* chunk bytes unsuccessfully written */
1110                                   4096); /* total bytes written */
1111         if (!ok) {
1112                 torture_fail(torture, "bad copy chunk response data");
1113         }
1114
1115         ok = check_pattern(torture, tree, tmp_ctx, src_h, 0, 4096, 0);
1116         if (!ok) {
1117                 torture_fail(torture, "inconsistent file data");
1118         }
1119         ok = check_pattern(torture, tree, tmp_ctx, src_h, 4096, 4096, 0);
1120         if (!ok) {
1121                 torture_fail(torture, "inconsistent file data");
1122         }
1123
1124         smb2_util_close(tree, src_h);
1125         smb2_util_close(tree, dest_h);
1126         talloc_free(tmp_ctx);
1127         return true;
1128 }
1129
1130 /*
1131  * Test a single-chunk copychunk request, where the source and target ranges
1132  * overlap, and the SourceKey refers to the same target file. E.g:
1133  *
1134  * Initial State
1135  * -------------
1136  *      File:           src_and_dest
1137  *      Offset:         0123456789
1138  *      Data:           abcdefghij
1139  *
1140  * Request
1141  * -------
1142  *      FSCTL_SRV_COPYCHUNK(src_and_dest)
1143  *      SourceKey = SRV_REQUEST_RESUME_KEY(src_and_dest)
1144  *      ChunkCount = 1
1145  *      Chunks[0].SourceOffset = 0
1146  *      Chunks[0].TargetOffset = 4
1147  *      Chunks[0].Length = 6
1148  *
1149  * Resultant State
1150  * ---------------
1151  *      File:           src_and_dest
1152  *      Offset:         0123456789
1153  *      Data:           abcdabcdef
1154  *
1155  * The resultant contents of src_and_dest is dependent on the server's
1156  * copy algorithm. In the above example, the server uses an IO buffer
1157  * large enough to hold the entire six-byte source data before writing
1158  * to TargetOffset. If the server were to use a four-byte IO buffer and
1159  * started reads/writes from the lowest offset, then the two overlapping
1160  * bytes in the above example would be overwritten before being read. The
1161  * resultant file contents would be abcdabcdab.
1162  *
1163  * Windows 2008r2 appears to use a 2048 byte copy buffer, overlapping bytes
1164  * after this offset are written before being read. Windows 2012 on the
1165  * other hand appears to use a buffer large enough to hold its maximum
1166  * supported chunk size (1M). Samba currently uses a 64k copy buffer by
1167  * default (vfs_cc_state.buf).
1168  *
1169  * This test uses an 8-byte overlap at 2040-2048, so that it passes against
1170  * Windows 2008r2, 2012 and Samba servers. Note, 2008GM fails, as it appears
1171  * to use a different copy algorithm to 2008r2.
1172  */
1173 static bool
1174 test_ioctl_copy_chunk_src_is_dest_overlap(struct torture_context *torture,
1175                                           struct smb2_tree *tree)
1176 {
1177         struct smb2_handle src_h;
1178         struct smb2_handle dest_h;
1179         NTSTATUS status;
1180         union smb_ioctl ioctl;
1181         TALLOC_CTX *tmp_ctx = talloc_new(tree);
1182         struct srv_copychunk_copy cc_copy;
1183         struct srv_copychunk_rsp cc_rsp;
1184         enum ndr_err_code ndr_ret;
1185         bool ok;
1186
1187         /* exceed the vfs_default copy buffer */
1188         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1189                                    1,
1190                                    &src_h, 2048 * 2,
1191                                    SEC_RIGHTS_FILE_ALL,
1192                                    &dest_h, 0,
1193                                    SEC_RIGHTS_FILE_ALL,
1194                                    &cc_copy,
1195                                    &ioctl);
1196         if (!ok) {
1197                 torture_fail(torture, "setup copy chunk error");
1198         }
1199
1200         /* the source is also the destination */
1201         ioctl.smb2.in.file.handle = src_h;
1202
1203         /* 8 bytes overlap between source and target ranges */
1204         cc_copy.chunks[0].source_off = 0;
1205         cc_copy.chunks[0].target_off = 2048 - 8;
1206         cc_copy.chunks[0].length = 2048;
1207
1208         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1209                                        &cc_copy,
1210                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
1211         torture_assert_ndr_success(torture, ndr_ret,
1212                                    "ndr_push_srv_copychunk_copy");
1213
1214         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1215         torture_assert_ntstatus_ok(torture, status,
1216                                    "FSCTL_SRV_COPYCHUNK");
1217
1218         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
1219                                        &cc_rsp,
1220                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
1221         torture_assert_ndr_success(torture, ndr_ret,
1222                                    "ndr_pull_srv_copychunk_rsp");
1223
1224         ok = check_copy_chunk_rsp(torture, &cc_rsp,
1225                                   1,    /* chunks written */
1226                                   0,    /* chunk bytes unsuccessfully written */
1227                                   2048); /* total bytes written */
1228         if (!ok) {
1229                 torture_fail(torture, "bad copy chunk response data");
1230         }
1231
1232         ok = check_pattern(torture, tree, tmp_ctx, src_h, 0, 2048 - 8, 0);
1233         if (!ok) {
1234                 torture_fail(torture, "inconsistent file data");
1235         }
1236         ok = check_pattern(torture, tree, tmp_ctx, src_h, 2048 - 8, 2048, 0);
1237         if (!ok) {
1238                 torture_fail(torture, "inconsistent file data");
1239         }
1240
1241         smb2_util_close(tree, src_h);
1242         smb2_util_close(tree, dest_h);
1243         talloc_free(tmp_ctx);
1244         return true;
1245 }
1246
1247 static bool test_ioctl_copy_chunk_bad_access(struct torture_context *torture,
1248                                              struct smb2_tree *tree)
1249 {
1250         struct smb2_handle src_h;
1251         struct smb2_handle dest_h;
1252         NTSTATUS status;
1253         union smb_ioctl ioctl;
1254         TALLOC_CTX *tmp_ctx = talloc_new(tree);
1255         struct srv_copychunk_copy cc_copy;
1256         enum ndr_err_code ndr_ret;
1257         bool ok;
1258         /* read permission on src */
1259         ok = test_setup_copy_chunk(torture, tree, tmp_ctx, 1, /* 1 chunk */
1260                                    &src_h, 4096, /* fill 4096 byte src file */
1261                                    SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE,
1262                                    &dest_h, 0, /* 0 byte dest file */
1263                                    SEC_RIGHTS_FILE_ALL, &cc_copy, &ioctl);
1264         if (!ok) {
1265                 torture_fail(torture, "setup copy chunk error");
1266         }
1267
1268         cc_copy.chunks[0].source_off = 0;
1269         cc_copy.chunks[0].target_off = 0;
1270         cc_copy.chunks[0].length = 4096;
1271
1272         ndr_ret = ndr_push_struct_blob(
1273             &ioctl.smb2.in.out, tmp_ctx, &cc_copy,
1274             (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
1275         torture_assert_ndr_success(torture, ndr_ret,
1276                                    "ndr_push_srv_copychunk_copy");
1277
1278         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1279         torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK,
1280                                       "FSCTL_SRV_COPYCHUNK");
1281
1282         smb2_util_close(tree, src_h);
1283         smb2_util_close(tree, dest_h);
1284
1285         /* execute permission on src */
1286         ok = test_setup_copy_chunk(torture, tree, tmp_ctx, 1, /* 1 chunk */
1287                                    &src_h, 4096, /* fill 4096 byte src file */
1288                                    SEC_FILE_EXECUTE | SEC_FILE_READ_ATTRIBUTE,
1289                                    &dest_h, 0, /* 0 byte dest file */
1290                                    SEC_RIGHTS_FILE_ALL, &cc_copy, &ioctl);
1291         if (!ok) {
1292                 torture_fail(torture, "setup copy chunk error");
1293         }
1294
1295         cc_copy.chunks[0].source_off = 0;
1296         cc_copy.chunks[0].target_off = 0;
1297         cc_copy.chunks[0].length = 4096;
1298
1299         ndr_ret = ndr_push_struct_blob(
1300             &ioctl.smb2.in.out, tmp_ctx, &cc_copy,
1301             (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
1302         torture_assert_ndr_success(torture, ndr_ret,
1303                                    "ndr_push_srv_copychunk_copy");
1304
1305         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1306         torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK,
1307                                       "FSCTL_SRV_COPYCHUNK");
1308
1309         smb2_util_close(tree, src_h);
1310         smb2_util_close(tree, dest_h);
1311
1312         /* neither read nor execute permission on src */
1313         ok = test_setup_copy_chunk(torture, tree, tmp_ctx, 1, /* 1 chunk */
1314                                    &src_h, 4096, /* fill 4096 byte src file */
1315                                    SEC_FILE_READ_ATTRIBUTE, &dest_h,
1316                                    0, /* 0 byte dest file */
1317                                    SEC_RIGHTS_FILE_ALL, &cc_copy, &ioctl);
1318         if (!ok) {
1319                 torture_fail(torture, "setup copy chunk error");
1320         }
1321
1322         cc_copy.chunks[0].source_off = 0;
1323         cc_copy.chunks[0].target_off = 0;
1324         cc_copy.chunks[0].length = 4096;
1325
1326         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1327                                        &cc_copy,
1328                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
1329         torture_assert_ndr_success(torture, ndr_ret,
1330                                    "ndr_push_srv_copychunk_copy");
1331
1332         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1333         torture_assert_ntstatus_equal(torture, status,
1334                                       NT_STATUS_ACCESS_DENIED,
1335                                       "FSCTL_SRV_COPYCHUNK");
1336
1337         smb2_util_close(tree, src_h);
1338         smb2_util_close(tree, dest_h);
1339
1340         /* no write permission on dest */
1341         ok = test_setup_copy_chunk(
1342             torture, tree, tmp_ctx, 1, /* 1 chunk */
1343             &src_h, 4096,             /* fill 4096 byte src file */
1344             SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE, &dest_h,
1345             0, /* 0 byte dest file */
1346             (SEC_RIGHTS_FILE_ALL &
1347              ~(SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)),
1348             &cc_copy, &ioctl);
1349         if (!ok) {
1350                 torture_fail(torture, "setup copy chunk error");
1351         }
1352
1353         cc_copy.chunks[0].source_off = 0;
1354         cc_copy.chunks[0].target_off = 0;
1355         cc_copy.chunks[0].length = 4096;
1356
1357         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1358                                        &cc_copy,
1359                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
1360         torture_assert_ndr_success(torture, ndr_ret,
1361                                    "ndr_push_srv_copychunk_copy");
1362
1363         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1364         torture_assert_ntstatus_equal(torture, status,
1365                                       NT_STATUS_ACCESS_DENIED,
1366                                       "FSCTL_SRV_COPYCHUNK");
1367
1368         smb2_util_close(tree, src_h);
1369         smb2_util_close(tree, dest_h);
1370
1371         /* no read permission on dest */
1372         ok = test_setup_copy_chunk(torture, tree, tmp_ctx, 1, /* 1 chunk */
1373                                    &src_h, 4096, /* fill 4096 byte src file */
1374                                    SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE,
1375                                    &dest_h, 0, /* 0 byte dest file */
1376                                    (SEC_RIGHTS_FILE_ALL & ~SEC_FILE_READ_DATA),
1377                                    &cc_copy, &ioctl);
1378         if (!ok) {
1379                 torture_fail(torture, "setup copy chunk error");
1380         }
1381
1382         cc_copy.chunks[0].source_off = 0;
1383         cc_copy.chunks[0].target_off = 0;
1384         cc_copy.chunks[0].length = 4096;
1385
1386         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1387                                        &cc_copy,
1388                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
1389         torture_assert_ndr_success(torture, ndr_ret,
1390                                    "ndr_push_srv_copychunk_copy");
1391
1392         /*
1393          * FSCTL_SRV_COPYCHUNK requires read permission on dest,
1394          * FSCTL_SRV_COPYCHUNK_WRITE on the other hand does not.
1395          */
1396         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1397         torture_assert_ntstatus_equal(torture, status,
1398                                       NT_STATUS_ACCESS_DENIED,
1399                                       "FSCTL_SRV_COPYCHUNK");
1400
1401         smb2_util_close(tree, src_h);
1402         smb2_util_close(tree, dest_h);
1403         talloc_free(tmp_ctx);
1404
1405         return true;
1406 }
1407
1408 static bool test_ioctl_copy_chunk_write_access(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         enum ndr_err_code ndr_ret;
1418         bool ok;
1419
1420         /* no read permission on dest with FSCTL_SRV_COPYCHUNK_WRITE */
1421         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1422                                    1, /* 1 chunk */
1423                                    &src_h, 4096, /* fill 4096 byte src file */
1424                                    SEC_RIGHTS_FILE_ALL,
1425                                    &dest_h, 0,  /* 0 byte dest file */
1426                                    (SEC_RIGHTS_FILE_WRITE
1427                                     | SEC_RIGHTS_FILE_EXECUTE),
1428                                    &cc_copy,
1429                                    &ioctl);
1430         if (!ok) {
1431                 torture_fail(torture, "setup copy chunk error");
1432         }
1433
1434         ioctl.smb2.in.function = FSCTL_SRV_COPYCHUNK_WRITE;
1435         cc_copy.chunks[0].source_off = 0;
1436         cc_copy.chunks[0].target_off = 0;
1437         cc_copy.chunks[0].length = 4096;
1438
1439         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1440                                        &cc_copy,
1441                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
1442         torture_assert_ndr_success(torture, ndr_ret,
1443                                    "ndr_push_srv_copychunk_copy");
1444
1445         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1446         torture_assert_ntstatus_ok(torture, status,
1447                                    "FSCTL_SRV_COPYCHUNK_WRITE");
1448
1449         smb2_util_close(tree, src_h);
1450         smb2_util_close(tree, dest_h);
1451         talloc_free(tmp_ctx);
1452
1453         return true;
1454 }
1455
1456 static bool test_ioctl_copy_chunk_src_exceed(struct torture_context *torture,
1457                                              struct smb2_tree *tree)
1458 {
1459         struct smb2_handle src_h;
1460         struct smb2_handle dest_h;
1461         NTSTATUS status;
1462         union smb_ioctl ioctl;
1463         TALLOC_CTX *tmp_ctx = talloc_new(tree);
1464         struct srv_copychunk_copy cc_copy;
1465         struct srv_copychunk_rsp cc_rsp;
1466         enum ndr_err_code ndr_ret;
1467         bool ok;
1468
1469         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1470                                    1, /* 1 chunk */
1471                                    &src_h, 4096, /* fill 4096 byte src file */
1472                                    SEC_RIGHTS_FILE_ALL,
1473                                    &dest_h, 0,  /* 0 byte dest file */
1474                                    SEC_RIGHTS_FILE_ALL,
1475                                    &cc_copy,
1476                                    &ioctl);
1477         if (!ok) {
1478                 torture_fail(torture, "setup copy chunk error");
1479         }
1480
1481         /* Request copy where off + length exceeds size of src */
1482         cc_copy.chunks[0].source_off = 1024;
1483         cc_copy.chunks[0].target_off = 0;
1484         cc_copy.chunks[0].length = 4096;
1485
1486         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1487                                        &cc_copy,
1488                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
1489         torture_assert_ndr_success(torture, ndr_ret,
1490                                    "ndr_push_srv_copychunk_copy");
1491
1492         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1493         torture_assert_ntstatus_equal(torture, status,
1494                                       NT_STATUS_INVALID_VIEW_SIZE,
1495                                       "FSCTL_SRV_COPYCHUNK oversize");
1496
1497         /* Request copy where length exceeds size of src */
1498         cc_copy.chunks[0].source_off = 1024;
1499         cc_copy.chunks[0].target_off = 0;
1500         cc_copy.chunks[0].length = 3072;
1501
1502         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1503                                        &cc_copy,
1504                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
1505         torture_assert_ndr_success(torture, ndr_ret,
1506                                    "ndr_push_srv_copychunk_copy");
1507
1508         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1509         torture_assert_ntstatus_ok(torture, status,
1510                                    "FSCTL_SRV_COPYCHUNK just right");
1511
1512         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
1513                                        &cc_rsp,
1514                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
1515         torture_assert_ndr_success(torture, ndr_ret,
1516                                    "ndr_pull_srv_copychunk_rsp");
1517
1518         ok = check_copy_chunk_rsp(torture, &cc_rsp,
1519                                   1,    /* chunks written */
1520                                   0,    /* chunk bytes unsuccessfully written */
1521                                   3072); /* total bytes written */
1522         if (!ok) {
1523                 torture_fail(torture, "bad copy chunk response data");
1524         }
1525
1526         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 3072, 1024);
1527         if (!ok) {
1528                 torture_fail(torture, "inconsistent file data");
1529         }
1530
1531         smb2_util_close(tree, src_h);
1532         smb2_util_close(tree, dest_h);
1533         talloc_free(tmp_ctx);
1534         return true;
1535 }
1536
1537 static bool
1538 test_ioctl_copy_chunk_src_exceed_multi(struct torture_context *torture,
1539                                        struct smb2_tree *tree)
1540 {
1541         struct smb2_handle src_h;
1542         struct smb2_handle dest_h;
1543         NTSTATUS status;
1544         union smb_ioctl ioctl;
1545         TALLOC_CTX *tmp_ctx = talloc_new(tree);
1546         struct srv_copychunk_copy cc_copy;
1547         struct srv_copychunk_rsp cc_rsp;
1548         enum ndr_err_code ndr_ret;
1549         bool ok;
1550
1551         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1552                                    2, /* 2 chunks */
1553                                    &src_h, 8192, /* fill 8192 byte src file */
1554                                    SEC_RIGHTS_FILE_ALL,
1555                                    &dest_h, 0,  /* 0 byte dest file */
1556                                    SEC_RIGHTS_FILE_ALL,
1557                                    &cc_copy,
1558                                    &ioctl);
1559         if (!ok) {
1560                 torture_fail(torture, "setup copy chunk error");
1561         }
1562
1563         /* Request copy where off + length exceeds size of src */
1564         cc_copy.chunks[0].source_off = 0;
1565         cc_copy.chunks[0].target_off = 0;
1566         cc_copy.chunks[0].length = 4096;
1567
1568         cc_copy.chunks[1].source_off = 4096;
1569         cc_copy.chunks[1].target_off = 4096;
1570         cc_copy.chunks[1].length = 8192;
1571
1572         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1573                                        &cc_copy,
1574                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
1575         torture_assert_ndr_success(torture, ndr_ret,
1576                                    "ndr_push_srv_copychunk_copy");
1577
1578         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1579         torture_assert_ntstatus_equal(torture, status,
1580                                       NT_STATUS_INVALID_VIEW_SIZE,
1581                                       "FSCTL_SRV_COPYCHUNK oversize");
1582         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
1583                                        &cc_rsp,
1584                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
1585         torture_assert_ndr_success(torture, ndr_ret, "unmarshalling response");
1586
1587         /* first chunk should still be written */
1588         ok = check_copy_chunk_rsp(torture, &cc_rsp,
1589                                   1,    /* chunks written */
1590                                   0,    /* chunk bytes unsuccessfully written */
1591                                   4096); /* total bytes written */
1592         if (!ok) {
1593                 torture_fail(torture, "bad copy chunk response data");
1594         }
1595         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
1596         if (!ok) {
1597                 torture_fail(torture, "inconsistent file data");
1598         }
1599
1600         smb2_util_close(tree, src_h);
1601         smb2_util_close(tree, dest_h);
1602         talloc_free(tmp_ctx);
1603         return true;
1604 }
1605
1606 static bool test_ioctl_copy_chunk_sparse_dest(struct torture_context *torture,
1607                                               struct smb2_tree *tree)
1608 {
1609         struct smb2_handle src_h;
1610         struct smb2_handle dest_h;
1611         NTSTATUS status;
1612         union smb_ioctl ioctl;
1613         struct smb2_read r;
1614         TALLOC_CTX *tmp_ctx = talloc_new(tree);
1615         struct srv_copychunk_copy cc_copy;
1616         struct srv_copychunk_rsp cc_rsp;
1617         enum ndr_err_code ndr_ret;
1618         bool ok;
1619         int i;
1620
1621         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1622                                    1, /* 1 chunk */
1623                                    &src_h, 4096, /* fill 4096 byte src file */
1624                                    SEC_RIGHTS_FILE_ALL,
1625                                    &dest_h, 0,  /* 0 byte dest file */
1626                                    SEC_RIGHTS_FILE_ALL,
1627                                    &cc_copy,
1628                                    &ioctl);
1629         if (!ok) {
1630                 torture_fail(torture, "setup copy chunk error");
1631         }
1632
1633         /* copy all src file data (via a single chunk desc) */
1634         cc_copy.chunks[0].source_off = 0;
1635         cc_copy.chunks[0].target_off = 4096;
1636         cc_copy.chunks[0].length = 4096;
1637
1638         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1639                                        &cc_copy,
1640                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
1641         torture_assert_ndr_success(torture, ndr_ret,
1642                                    "ndr_push_srv_copychunk_copy");
1643
1644         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1645         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
1646
1647         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
1648                                        &cc_rsp,
1649                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
1650         torture_assert_ndr_success(torture, ndr_ret,
1651                                    "ndr_pull_srv_copychunk_rsp");
1652
1653         ok = check_copy_chunk_rsp(torture, &cc_rsp,
1654                                   1,    /* chunks written */
1655                                   0,    /* chunk bytes unsuccessfully written */
1656                                   4096); /* total bytes written */
1657         if (!ok) {
1658                 torture_fail(torture, "bad copy chunk response data");
1659         }
1660
1661         /* check for zeros in first 4k */
1662         ZERO_STRUCT(r);
1663         r.in.file.handle = dest_h;
1664         r.in.length      = 4096;
1665         r.in.offset      = 0;
1666         status = smb2_read(tree, tmp_ctx, &r);
1667         torture_assert_ntstatus_ok(torture, status, "read");
1668
1669         torture_assert_u64_equal(torture, r.out.data.length, 4096,
1670                                  "read data len mismatch");
1671
1672         for (i = 0; i < 4096; i++) {
1673                 torture_assert(torture, (r.out.data.data[i] == 0),
1674                                "sparse did not pass class");
1675         }
1676
1677         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 4096, 4096, 0);
1678         if (!ok) {
1679                 torture_fail(torture, "inconsistent file data");
1680         }
1681
1682         smb2_util_close(tree, src_h);
1683         smb2_util_close(tree, dest_h);
1684         talloc_free(tmp_ctx);
1685         return true;
1686 }
1687
1688 /*
1689  * set the ioctl MaxOutputResponse size to less than
1690  * sizeof(struct srv_copychunk_rsp)
1691  */
1692 static bool test_ioctl_copy_chunk_max_output_sz(struct torture_context *torture,
1693                                                 struct smb2_tree *tree)
1694 {
1695         struct smb2_handle src_h;
1696         struct smb2_handle dest_h;
1697         NTSTATUS status;
1698         union smb_ioctl ioctl;
1699         TALLOC_CTX *tmp_ctx = talloc_new(tree);
1700         struct srv_copychunk_copy cc_copy;
1701         enum ndr_err_code ndr_ret;
1702         bool ok;
1703
1704         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1705                                    1, /* 1 chunk */
1706                                    &src_h, 4096, /* fill 4096 byte src file */
1707                                    SEC_RIGHTS_FILE_ALL,
1708                                    &dest_h, 0,  /* 0 byte dest file */
1709                                    SEC_RIGHTS_FILE_ALL,
1710                                    &cc_copy,
1711                                    &ioctl);
1712         if (!ok) {
1713                 torture_fail(torture, "setup copy chunk error");
1714         }
1715
1716         cc_copy.chunks[0].source_off = 0;
1717         cc_copy.chunks[0].target_off = 0;
1718         cc_copy.chunks[0].length = 4096;
1719         /* req is valid, but use undersize max_response_size */
1720         ioctl.smb2.in.max_response_size = sizeof(struct srv_copychunk_rsp) - 1;
1721
1722         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1723                                        &cc_copy,
1724                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
1725         torture_assert_ndr_success(torture, ndr_ret,
1726                                    "ndr_push_srv_copychunk_copy");
1727
1728         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1729         torture_assert_ntstatus_equal(torture, status,
1730                                       NT_STATUS_INVALID_PARAMETER,
1731                                       "FSCTL_SRV_COPYCHUNK");
1732
1733         smb2_util_close(tree, src_h);
1734         smb2_util_close(tree, dest_h);
1735         talloc_free(tmp_ctx);
1736         return true;
1737 }
1738
1739 static bool test_ioctl_copy_chunk_zero_length(struct torture_context *torture,
1740                                               struct smb2_tree *tree)
1741 {
1742         struct smb2_handle src_h;
1743         struct smb2_handle dest_h;
1744         NTSTATUS status;
1745         union smb_ioctl ioctl;
1746         union smb_fileinfo q;
1747         TALLOC_CTX *tmp_ctx = talloc_new(tree);
1748         struct srv_copychunk_copy cc_copy;
1749         struct srv_copychunk_rsp cc_rsp;
1750         enum ndr_err_code ndr_ret;
1751         bool ok;
1752
1753         ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1754                                    1, /* 1 chunk */
1755                                    &src_h, 4096, /* fill 4096 byte src file */
1756                                    SEC_RIGHTS_FILE_ALL,
1757                                    &dest_h, 0,  /* 0 byte dest file */
1758                                    SEC_RIGHTS_FILE_ALL,
1759                                    &cc_copy,
1760                                    &ioctl);
1761         if (!ok) {
1762                 torture_fail(torture, "setup copy chunk error");
1763         }
1764
1765         /* zero length server-side copy (via a single chunk desc) */
1766         cc_copy.chunks[0].source_off = 0;
1767         cc_copy.chunks[0].target_off = 0;
1768         cc_copy.chunks[0].length = 0;
1769
1770         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
1771                                        &cc_copy,
1772                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
1773         torture_assert_ndr_success(torture, ndr_ret,
1774                                    "ndr_push_srv_copychunk_copy");
1775
1776         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
1777         torture_assert_ntstatus_equal(torture, status,
1778                                       NT_STATUS_INVALID_PARAMETER,
1779                                       "bad zero-length chunk response");
1780
1781         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
1782                                        &cc_rsp,
1783                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
1784         torture_assert_ndr_success(torture, ndr_ret, "unmarshalling response");
1785
1786         ZERO_STRUCT(q);
1787         q.all_info2.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
1788         q.all_info2.in.file.handle = dest_h;
1789         status = smb2_getinfo_file(tree, torture, &q);
1790         torture_assert_ntstatus_ok(torture, status, "getinfo");
1791
1792         torture_assert_int_equal(torture, q.all_info2.out.size, 0,
1793                                  "size after zero len clone");
1794
1795         smb2_util_close(tree, src_h);
1796         smb2_util_close(tree, dest_h);
1797         talloc_free(tmp_ctx);
1798         return true;
1799 }
1800
1801 static NTSTATUS test_ioctl_compress_fs_supported(struct torture_context *torture,
1802                                                  struct smb2_tree *tree,
1803                                                  TALLOC_CTX *mem_ctx,
1804                                                  struct smb2_handle *fh,
1805                                                  bool *compress_support)
1806 {
1807         NTSTATUS status;
1808         union smb_fsinfo info;
1809
1810         ZERO_STRUCT(info);
1811         info.generic.level = RAW_QFS_ATTRIBUTE_INFORMATION;
1812         info.generic.handle = *fh;
1813         status = smb2_getinfo_fs(tree, tree, &info);
1814         if (!NT_STATUS_IS_OK(status)) {
1815                 return status;
1816         }
1817
1818         if (info.attribute_info.out.fs_attr & FILE_FILE_COMPRESSION) {
1819                 *compress_support = true;
1820         } else {
1821                 *compress_support = false;
1822         }
1823         return NT_STATUS_OK;
1824 }
1825
1826 static NTSTATUS test_ioctl_compress_get(struct torture_context *torture,
1827                                         TALLOC_CTX *mem_ctx,
1828                                         struct smb2_tree *tree,
1829                                         struct smb2_handle fh,
1830                                         uint16_t *_compression_fmt)
1831 {
1832         union smb_ioctl ioctl;
1833         struct compression_state cmpr_state;
1834         enum ndr_err_code ndr_ret;
1835         NTSTATUS status;
1836
1837         ZERO_STRUCT(ioctl);
1838         ioctl.smb2.level = RAW_IOCTL_SMB2;
1839         ioctl.smb2.in.file.handle = fh;
1840         ioctl.smb2.in.function = FSCTL_GET_COMPRESSION;
1841         ioctl.smb2.in.max_response_size = sizeof(struct compression_state);
1842         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
1843
1844         status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2);
1845         if (!NT_STATUS_IS_OK(status)) {
1846                 return status;
1847         }
1848
1849         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, mem_ctx,
1850                                        &cmpr_state,
1851                         (ndr_pull_flags_fn_t)ndr_pull_compression_state);
1852
1853         if (ndr_ret != NDR_ERR_SUCCESS) {
1854                 return NT_STATUS_INTERNAL_ERROR;
1855         }
1856
1857         *_compression_fmt = cmpr_state.format;
1858         return NT_STATUS_OK;
1859 }
1860
1861 static NTSTATUS test_ioctl_compress_set(struct torture_context *torture,
1862                                         TALLOC_CTX *mem_ctx,
1863                                         struct smb2_tree *tree,
1864                                         struct smb2_handle fh,
1865                                         uint16_t compression_fmt)
1866 {
1867         union smb_ioctl ioctl;
1868         struct compression_state cmpr_state;
1869         enum ndr_err_code ndr_ret;
1870         NTSTATUS status;
1871
1872         ZERO_STRUCT(ioctl);
1873         ioctl.smb2.level = RAW_IOCTL_SMB2;
1874         ioctl.smb2.in.file.handle = fh;
1875         ioctl.smb2.in.function = FSCTL_SET_COMPRESSION;
1876         ioctl.smb2.in.max_response_size = 0;
1877         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
1878
1879         cmpr_state.format = compression_fmt;
1880         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, mem_ctx,
1881                                        &cmpr_state,
1882                         (ndr_push_flags_fn_t)ndr_push_compression_state);
1883         if (ndr_ret != NDR_ERR_SUCCESS) {
1884                 return NT_STATUS_INTERNAL_ERROR;
1885         }
1886
1887         status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2);
1888         return status;
1889 }
1890
1891 static bool test_ioctl_compress_file_flag(struct torture_context *torture,
1892                                             struct smb2_tree *tree)
1893 {
1894         struct smb2_handle fh;
1895         NTSTATUS status;
1896         TALLOC_CTX *tmp_ctx = talloc_new(tree);
1897         bool ok;
1898         uint16_t compression_fmt;
1899
1900         ok = test_setup_create_fill(torture, tree, tmp_ctx,
1901                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
1902                                     FILE_ATTRIBUTE_NORMAL);
1903         torture_assert(torture, ok, "setup compression file");
1904
1905         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
1906                                                   &ok);
1907         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
1908         if (!ok) {
1909                 smb2_util_close(tree, fh);
1910                 torture_skip(torture, "FS compression not supported\n");
1911         }
1912
1913         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
1914                                          &compression_fmt);
1915         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
1916
1917         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
1918                        "initial compression state not NONE");
1919
1920         status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
1921                                          COMPRESSION_FORMAT_DEFAULT);
1922         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
1923
1924         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
1925                                          &compression_fmt);
1926         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
1927
1928         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
1929                        "invalid compression state after set");
1930
1931         smb2_util_close(tree, fh);
1932         talloc_free(tmp_ctx);
1933         return true;
1934 }
1935
1936 static bool test_ioctl_compress_dir_inherit(struct torture_context *torture,
1937                                             struct smb2_tree *tree)
1938 {
1939         struct smb2_handle dirh;
1940         struct smb2_handle fh;
1941         NTSTATUS status;
1942         TALLOC_CTX *tmp_ctx = talloc_new(tree);
1943         uint16_t compression_fmt;
1944         bool ok;
1945         char path_buf[PATH_MAX];
1946
1947         smb2_deltree(tree, DNAME);
1948         ok = test_setup_create_fill(torture, tree, tmp_ctx,
1949                                     DNAME, &dirh, 0, SEC_RIGHTS_FILE_ALL,
1950                                     FILE_ATTRIBUTE_DIRECTORY);
1951         torture_assert(torture, ok, "setup compression directory");
1952
1953         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &dirh,
1954                                                   &ok);
1955         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
1956         if (!ok) {
1957                 smb2_util_close(tree, dirh);
1958                 smb2_deltree(tree, DNAME);
1959                 torture_skip(torture, "FS compression not supported\n");
1960         }
1961
1962         /* set compression on parent dir, then check for inheritance */
1963         status = test_ioctl_compress_set(torture, tmp_ctx, tree, dirh,
1964                                          COMPRESSION_FORMAT_LZNT1);
1965         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
1966
1967         status = test_ioctl_compress_get(torture, tmp_ctx, tree, dirh,
1968                                          &compression_fmt);
1969         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
1970
1971         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
1972                        "invalid compression state after set");
1973
1974         snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, FNAME);
1975         ok = test_setup_create_fill(torture, tree, tmp_ctx,
1976                                     path_buf, &fh, 4096, SEC_RIGHTS_FILE_ALL,
1977                                     FILE_ATTRIBUTE_NORMAL);
1978         torture_assert(torture, ok, "setup compression file");
1979
1980         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
1981                                          &compression_fmt);
1982         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
1983
1984         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
1985                        "compression attr not inherited by new file");
1986
1987         /* check compressed data is consistent */
1988         ok = check_pattern(torture, tree, tmp_ctx, fh, 0, 4096, 0);
1989
1990         /* disable dir compression attr, file should remain compressed */
1991         status = test_ioctl_compress_set(torture, tmp_ctx, tree, dirh,
1992                                          COMPRESSION_FORMAT_NONE);
1993         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
1994
1995         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
1996                                          &compression_fmt);
1997         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
1998
1999         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
2000                        "file compression attr removed after dir change");
2001         smb2_util_close(tree, fh);
2002
2003         /* new files should no longer inherit compression attr */
2004         snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, FNAME2);
2005         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2006                                     path_buf, &fh, 0, SEC_RIGHTS_FILE_ALL,
2007                                     FILE_ATTRIBUTE_NORMAL);
2008         torture_assert(torture, ok, "setup file");
2009
2010         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
2011                                          &compression_fmt);
2012         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
2013
2014         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
2015                        "compression attr present on new file");
2016
2017         smb2_util_close(tree, fh);
2018         smb2_util_close(tree, dirh);
2019         smb2_deltree(tree, DNAME);
2020         talloc_free(tmp_ctx);
2021         return true;
2022 }
2023
2024 static bool test_ioctl_compress_invalid_format(struct torture_context *torture,
2025                                                struct smb2_tree *tree)
2026 {
2027         struct smb2_handle fh;
2028         NTSTATUS status;
2029         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2030         bool ok;
2031         uint16_t compression_fmt;
2032
2033         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2034                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
2035                                     FILE_ATTRIBUTE_NORMAL);
2036         torture_assert(torture, ok, "setup compression file");
2037
2038         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
2039                                                   &ok);
2040         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2041         if (!ok) {
2042                 smb2_util_close(tree, fh);
2043                 torture_skip(torture, "FS compression not supported\n");
2044         }
2045
2046         status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
2047                                          0x0042); /* bogus */
2048         torture_assert_ntstatus_equal(torture, status,
2049                                       NT_STATUS_INVALID_PARAMETER,
2050                                       "invalid FSCTL_SET_COMPRESSION");
2051
2052         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
2053                                          &compression_fmt);
2054         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
2055
2056         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
2057                        "initial compression state not NONE");
2058
2059         smb2_util_close(tree, fh);
2060         talloc_free(tmp_ctx);
2061         return true;
2062 }
2063
2064 static bool test_ioctl_compress_invalid_buf(struct torture_context *torture,
2065                                             struct smb2_tree *tree)
2066 {
2067         struct smb2_handle fh;
2068         NTSTATUS status;
2069         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2070         bool ok;
2071         union smb_ioctl ioctl;
2072
2073         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2074                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
2075                                     FILE_ATTRIBUTE_NORMAL);
2076         torture_assert(torture, ok, "setup compression file");
2077
2078         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
2079                                                   &ok);
2080         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2081         if (!ok) {
2082                 smb2_util_close(tree, fh);
2083                 torture_skip(torture, "FS compression not supported\n");
2084         }
2085
2086         ZERO_STRUCT(ioctl);
2087         ioctl.smb2.level = RAW_IOCTL_SMB2;
2088         ioctl.smb2.in.file.handle = fh;
2089         ioctl.smb2.in.function = FSCTL_GET_COMPRESSION;
2090         ioctl.smb2.in.max_response_size = 0;    /* no room for rsp data */
2091         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
2092
2093         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
2094         if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_USER_BUFFER)
2095          && !NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
2096                 /* neither Server 2k12 nor 2k8r2 response status */
2097                 torture_assert(torture, true,
2098                                "invalid FSCTL_SET_COMPRESSION");
2099         }
2100
2101         smb2_util_close(tree, fh);
2102         talloc_free(tmp_ctx);
2103         return true;
2104 }
2105
2106 static bool test_ioctl_compress_query_file_attr(struct torture_context *torture,
2107                                                 struct smb2_tree *tree)
2108 {
2109         struct smb2_handle fh;
2110         union smb_fileinfo io;
2111         NTSTATUS status;
2112         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2113         bool ok;
2114
2115         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2116                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
2117                                     FILE_ATTRIBUTE_NORMAL);
2118         torture_assert(torture, ok, "setup compression file");
2119
2120         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
2121                                                   &ok);
2122         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2123         if (!ok) {
2124                 smb2_util_close(tree, fh);
2125                 torture_skip(torture, "FS compression not supported\n");
2126         }
2127
2128         ZERO_STRUCT(io);
2129         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2130         io.generic.in.file.handle = fh;
2131         status = smb2_getinfo_file(tree, tmp_ctx, &io);
2132         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
2133
2134         torture_assert(torture,
2135                 ((io.all_info2.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
2136                        "compression attr before set");
2137
2138         status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
2139                                          COMPRESSION_FORMAT_DEFAULT);
2140         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
2141
2142         ZERO_STRUCT(io);
2143         io.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
2144         io.generic.in.file.handle = fh;
2145         status = smb2_getinfo_file(tree, tmp_ctx, &io);
2146         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
2147
2148         torture_assert(torture,
2149                        (io.basic_info.out.attrib & FILE_ATTRIBUTE_COMPRESSED),
2150                        "no compression attr after set");
2151
2152         smb2_util_close(tree, fh);
2153         talloc_free(tmp_ctx);
2154         return true;
2155 }
2156
2157 /*
2158  * Specify FILE_ATTRIBUTE_COMPRESSED on creation, Windows does not retain this
2159  * attribute.
2160  */
2161 static bool test_ioctl_compress_create_with_attr(struct torture_context *torture,
2162                                                  struct smb2_tree *tree)
2163 {
2164         struct smb2_handle fh2;
2165         union smb_fileinfo io;
2166         NTSTATUS status;
2167         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2168         uint16_t compression_fmt;
2169         bool ok;
2170
2171         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2172                                     FNAME2, &fh2, 0, SEC_RIGHTS_FILE_ALL,
2173                         (FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_COMPRESSED));
2174         torture_assert(torture, ok, "setup compression file");
2175
2176         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh2,
2177                                                   &ok);
2178         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2179         if (!ok) {
2180                 smb2_util_close(tree, fh2);
2181                 torture_skip(torture, "FS compression not supported\n");
2182         }
2183
2184         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh2,
2185                                          &compression_fmt);
2186         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
2187
2188         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
2189                        "initial compression state not NONE");
2190
2191         ZERO_STRUCT(io);
2192         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2193         io.generic.in.file.handle = fh2;
2194         status = smb2_getinfo_file(tree, tmp_ctx, &io);
2195         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
2196
2197         torture_assert(torture,
2198                 ((io.all_info2.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
2199                        "incorrect compression attr");
2200
2201         smb2_util_close(tree, fh2);
2202         talloc_free(tmp_ctx);
2203         return true;
2204 }
2205
2206 static bool test_ioctl_compress_inherit_disable(struct torture_context *torture,
2207                                                 struct smb2_tree *tree)
2208 {
2209         struct smb2_handle fh;
2210         struct smb2_handle dirh;
2211         char path_buf[PATH_MAX];
2212         NTSTATUS status;
2213         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2214         bool ok;
2215         uint16_t compression_fmt;
2216
2217         struct smb2_create io;
2218
2219         smb2_deltree(tree, DNAME);
2220         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2221                                     DNAME, &dirh, 0, SEC_RIGHTS_FILE_ALL,
2222                                     FILE_ATTRIBUTE_DIRECTORY);
2223         torture_assert(torture, ok, "setup compression directory");
2224
2225         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &dirh,
2226                                                   &ok);
2227         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2228         if (!ok) {
2229                 smb2_util_close(tree, dirh);
2230                 smb2_deltree(tree, DNAME);
2231                 torture_skip(torture, "FS compression not supported\n");
2232         }
2233
2234         /* set compression on parent dir, then check for inheritance */
2235         status = test_ioctl_compress_set(torture, tmp_ctx, tree, dirh,
2236                                          COMPRESSION_FORMAT_LZNT1);
2237         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
2238
2239         status = test_ioctl_compress_get(torture, tmp_ctx, tree, dirh,
2240                                          &compression_fmt);
2241         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
2242
2243         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
2244                        "invalid compression state after set");
2245         smb2_util_close(tree, dirh);
2246
2247         snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, FNAME);
2248         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2249                                     path_buf, &fh, 0, SEC_RIGHTS_FILE_ALL,
2250                                     FILE_ATTRIBUTE_NORMAL);
2251         torture_assert(torture, ok, "setup compression file");
2252
2253         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
2254                                          &compression_fmt);
2255         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
2256
2257         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
2258                        "compression attr not inherited by new file");
2259         smb2_util_close(tree, fh);
2260
2261         snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, FNAME2);
2262
2263         /* NO_COMPRESSION option should block inheritance */
2264         ZERO_STRUCT(io);
2265         io.in.desired_access = SEC_RIGHTS_FILE_ALL;
2266         io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2267         io.in.create_disposition = NTCREATEX_DISP_CREATE;
2268         io.in.create_options = NTCREATEX_OPTIONS_NO_COMPRESSION;
2269         io.in.share_access =
2270                 NTCREATEX_SHARE_ACCESS_DELETE|
2271                 NTCREATEX_SHARE_ACCESS_READ|
2272                 NTCREATEX_SHARE_ACCESS_WRITE;
2273         io.in.fname = path_buf;
2274
2275         status = smb2_create(tree, tmp_ctx, &io);
2276         torture_assert_ntstatus_ok(torture, status, "file create");
2277
2278         fh = io.out.file.handle;
2279
2280         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
2281                                          &compression_fmt);
2282         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
2283
2284         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
2285                        "compression attr inherited by NO_COMPRESSION file");
2286         smb2_util_close(tree, fh);
2287
2288
2289         snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, DNAME);
2290         ZERO_STRUCT(io);
2291         io.in.desired_access = SEC_RIGHTS_FILE_ALL;
2292         io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
2293         io.in.create_disposition = NTCREATEX_DISP_CREATE;
2294         io.in.create_options = (NTCREATEX_OPTIONS_NO_COMPRESSION
2295                                 | NTCREATEX_OPTIONS_DIRECTORY);
2296         io.in.share_access =
2297                 NTCREATEX_SHARE_ACCESS_DELETE|
2298                 NTCREATEX_SHARE_ACCESS_READ|
2299                 NTCREATEX_SHARE_ACCESS_WRITE;
2300         io.in.fname = path_buf;
2301
2302         status = smb2_create(tree, tmp_ctx, &io);
2303         torture_assert_ntstatus_ok(torture, status, "dir create");
2304
2305         dirh = io.out.file.handle;
2306
2307         status = test_ioctl_compress_get(torture, tmp_ctx, tree, dirh,
2308                                          &compression_fmt);
2309         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
2310
2311         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
2312                        "compression attr inherited by NO_COMPRESSION dir");
2313         smb2_util_close(tree, dirh);
2314         smb2_deltree(tree, DNAME);
2315
2316         talloc_free(tmp_ctx);
2317         return true;
2318 }
2319
2320 /* attempting to set compression via SetInfo should not stick */
2321 static bool test_ioctl_compress_set_file_attr(struct torture_context *torture,
2322                                               struct smb2_tree *tree)
2323 {
2324         struct smb2_handle fh;
2325         struct smb2_handle dirh;
2326         union smb_fileinfo io;
2327         union smb_setfileinfo set_io;
2328         uint16_t compression_fmt;
2329         NTSTATUS status;
2330         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2331         bool ok;
2332
2333         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2334                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
2335                                     FILE_ATTRIBUTE_NORMAL);
2336         torture_assert(torture, ok, "setup compression file");
2337
2338         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
2339                                                   &ok);
2340         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2341         if (!ok) {
2342                 smb2_util_close(tree, fh);
2343                 torture_skip(torture, "FS compression not supported\n");
2344         }
2345
2346         ZERO_STRUCT(io);
2347         io.generic.level = RAW_FILEINFO_BASIC_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.basic_info.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
2354                        "compression attr before set");
2355
2356         ZERO_STRUCT(set_io);
2357         set_io.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
2358         set_io.basic_info.in.file.handle = fh;
2359         set_io.basic_info.in.create_time = io.basic_info.out.create_time;
2360         set_io.basic_info.in.access_time = io.basic_info.out.access_time;
2361         set_io.basic_info.in.write_time = io.basic_info.out.write_time;
2362         set_io.basic_info.in.change_time = io.basic_info.out.change_time;
2363         set_io.basic_info.in.attrib = (io.basic_info.out.attrib
2364                                                 | FILE_ATTRIBUTE_COMPRESSED);
2365         status = smb2_setinfo_file(tree, &set_io);
2366         torture_assert_ntstatus_ok(torture, status, "SMB2_SETINFO_FILE");
2367
2368         ZERO_STRUCT(io);
2369         io.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
2370         io.generic.in.file.handle = fh;
2371         status = smb2_getinfo_file(tree, tmp_ctx, &io);
2372         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
2373
2374         torture_assert(torture,
2375                 ((io.basic_info.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
2376                 "compression attr after set");
2377
2378         smb2_util_close(tree, fh);
2379         smb2_deltree(tree, DNAME);
2380         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2381                                     DNAME, &dirh, 0, SEC_RIGHTS_FILE_ALL,
2382                                     FILE_ATTRIBUTE_DIRECTORY);
2383         torture_assert(torture, ok, "setup compression directory");
2384
2385         ZERO_STRUCT(io);
2386         io.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
2387         io.generic.in.file.handle = dirh;
2388         status = smb2_getinfo_file(tree, tmp_ctx, &io);
2389         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
2390
2391         torture_assert(torture,
2392                 ((io.basic_info.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
2393                        "compression attr before set");
2394
2395         ZERO_STRUCT(set_io);
2396         set_io.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
2397         set_io.basic_info.in.file.handle = dirh;
2398         set_io.basic_info.in.create_time = io.basic_info.out.create_time;
2399         set_io.basic_info.in.access_time = io.basic_info.out.access_time;
2400         set_io.basic_info.in.write_time = io.basic_info.out.write_time;
2401         set_io.basic_info.in.change_time = io.basic_info.out.change_time;
2402         set_io.basic_info.in.attrib = (io.basic_info.out.attrib
2403                                                 | FILE_ATTRIBUTE_COMPRESSED);
2404         status = smb2_setinfo_file(tree, &set_io);
2405         torture_assert_ntstatus_ok(torture, status, "SMB2_SETINFO_FILE");
2406
2407         status = test_ioctl_compress_get(torture, tmp_ctx, tree, dirh,
2408                                          &compression_fmt);
2409         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
2410
2411         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
2412                        "dir compression set after SetInfo");
2413
2414         smb2_util_close(tree, dirh);
2415         talloc_free(tmp_ctx);
2416         return true;
2417 }
2418
2419 static bool test_ioctl_compress_perms(struct torture_context *torture,
2420                                       struct smb2_tree *tree)
2421 {
2422         struct smb2_handle fh;
2423         uint16_t compression_fmt;
2424         union smb_fileinfo io;
2425         NTSTATUS status;
2426         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2427         bool ok;
2428
2429         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2430                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
2431                                     FILE_ATTRIBUTE_NORMAL);
2432         torture_assert(torture, ok, "setup compression file");
2433
2434         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
2435                                                   &ok);
2436         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2437         smb2_util_close(tree, fh);
2438         if (!ok) {
2439                 torture_skip(torture, "FS compression not supported\n");
2440         }
2441
2442         /* attempt get compression without READ_ATTR permission */
2443         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2444                                     FNAME, &fh, 0,
2445                         (SEC_RIGHTS_FILE_READ & ~(SEC_FILE_READ_ATTRIBUTE
2446                                                         | SEC_STD_READ_CONTROL
2447                                                         | SEC_FILE_READ_EA)),
2448                                     FILE_ATTRIBUTE_NORMAL);
2449         torture_assert(torture, ok, "setup compression file");
2450
2451         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
2452                                          &compression_fmt);
2453         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
2454         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
2455                        "compression set after create");
2456         smb2_util_close(tree, fh);
2457
2458         /* set compression without WRITE_ATTR permission should succeed */
2459         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2460                                     FNAME, &fh, 0,
2461                         (SEC_RIGHTS_FILE_WRITE & ~(SEC_FILE_WRITE_ATTRIBUTE
2462                                                         | SEC_STD_WRITE_DAC
2463                                                         | SEC_FILE_WRITE_EA)),
2464                                     FILE_ATTRIBUTE_NORMAL);
2465         torture_assert(torture, ok, "setup compression file");
2466
2467         status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
2468                                          COMPRESSION_FORMAT_DEFAULT);
2469         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
2470         smb2_util_close(tree, fh);
2471
2472         ok = test_setup_open(torture, tree, tmp_ctx,
2473                                     FNAME, &fh, SEC_RIGHTS_FILE_ALL,
2474                                     FILE_ATTRIBUTE_NORMAL);
2475         torture_assert(torture, ok, "setup compression file");
2476         ZERO_STRUCT(io);
2477         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2478         io.generic.in.file.handle = fh;
2479         status = smb2_getinfo_file(tree, tmp_ctx, &io);
2480         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
2481
2482         torture_assert(torture,
2483                        (io.all_info2.out.attrib & FILE_ATTRIBUTE_COMPRESSED),
2484                        "incorrect compression attr");
2485         smb2_util_close(tree, fh);
2486
2487         /* attempt get compression without READ_DATA permission */
2488         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2489                                     FNAME, &fh, 0,
2490                         (SEC_RIGHTS_FILE_READ & ~SEC_FILE_READ_DATA),
2491                                     FILE_ATTRIBUTE_NORMAL);
2492         torture_assert(torture, ok, "setup compression file");
2493
2494         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
2495                                          &compression_fmt);
2496         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
2497         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
2498                        "compression enabled after set");
2499         smb2_util_close(tree, fh);
2500
2501         /* attempt get compression with only SYNCHRONIZE permission */
2502         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2503                                     FNAME, &fh, 0,
2504                                     SEC_STD_SYNCHRONIZE,
2505                                     FILE_ATTRIBUTE_NORMAL);
2506         torture_assert(torture, ok, "setup compression file");
2507
2508         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
2509                                          &compression_fmt);
2510         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
2511         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
2512                        "compression not enabled after set");
2513         smb2_util_close(tree, fh);
2514
2515         /* attempt to set compression without WRITE_DATA permission */
2516         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2517                                     FNAME, &fh, 0,
2518                         (SEC_RIGHTS_FILE_WRITE & (~SEC_FILE_WRITE_DATA)),
2519                                     FILE_ATTRIBUTE_NORMAL);
2520         torture_assert(torture, ok, "setup compression file");
2521
2522         status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
2523                                          COMPRESSION_FORMAT_DEFAULT);
2524         torture_assert_ntstatus_equal(torture, status,
2525                                       NT_STATUS_ACCESS_DENIED,
2526                                       "FSCTL_SET_COMPRESSION permission");
2527         smb2_util_close(tree, fh);
2528
2529         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2530                                     FNAME, &fh, 0,
2531                         (SEC_RIGHTS_FILE_WRITE & (~SEC_FILE_WRITE_DATA)),
2532                                     FILE_ATTRIBUTE_NORMAL);
2533         torture_assert(torture, ok, "setup compression file");
2534
2535         status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
2536                                          COMPRESSION_FORMAT_NONE);
2537         torture_assert_ntstatus_equal(torture, status,
2538                                       NT_STATUS_ACCESS_DENIED,
2539                                       "FSCTL_SET_COMPRESSION permission");
2540         smb2_util_close(tree, fh);
2541
2542         talloc_free(tmp_ctx);
2543         return true;
2544 }
2545
2546 /*
2547    basic testing of the SMB2 FSCTL_QUERY_NETWORK_INTERFACE_INFO ioctl
2548 */
2549 static bool test_ioctl_network_interface_info(struct torture_context *torture,
2550                                       struct smb2_tree *tree)
2551 {
2552         union smb_ioctl ioctl;
2553         struct smb2_handle fh;
2554         NTSTATUS status;
2555         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2556         struct fsctl_net_iface_info net_iface;
2557         enum ndr_err_code ndr_ret;
2558         uint32_t caps;
2559
2560         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2561         if (!(caps & SMB2_CAP_MULTI_CHANNEL)) {
2562                 torture_skip(torture, "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
2563         }
2564
2565         ZERO_STRUCT(ioctl);
2566         ioctl.smb2.level = RAW_IOCTL_SMB2;
2567         fh.data[0] = UINT64_MAX;
2568         fh.data[1] = UINT64_MAX;
2569         ioctl.smb2.in.file.handle = fh;
2570         ioctl.smb2.in.function = FSCTL_QUERY_NETWORK_INTERFACE_INFO;
2571         ioctl.smb2.in.max_response_size = 0x10000; /* Windows client sets this to 64KiB */
2572         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
2573
2574         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
2575         torture_assert_ntstatus_ok(torture, status, "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
2576
2577         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx, &net_iface,
2578                         (ndr_pull_flags_fn_t)ndr_pull_fsctl_net_iface_info);
2579         torture_assert_ndr_success(torture, ndr_ret,
2580                                    "ndr_pull_fsctl_net_iface_info");
2581
2582         ndr_print_debug((ndr_print_fn_t)ndr_print_fsctl_net_iface_info,
2583                         "Network Interface Info", &net_iface);
2584
2585         talloc_free(tmp_ctx);
2586         return true;
2587 }
2588
2589 static NTSTATUS test_ioctl_sparse_fs_supported(struct torture_context *torture,
2590                                                struct smb2_tree *tree,
2591                                                TALLOC_CTX *mem_ctx,
2592                                                struct smb2_handle *fh,
2593                                                bool *sparse_support)
2594 {
2595         NTSTATUS status;
2596         union smb_fsinfo info;
2597
2598         ZERO_STRUCT(info);
2599         info.generic.level = RAW_QFS_ATTRIBUTE_INFORMATION;
2600         info.generic.handle = *fh;
2601         status = smb2_getinfo_fs(tree, tree, &info);
2602         if (!NT_STATUS_IS_OK(status)) {
2603                 return status;
2604         }
2605
2606         if (info.attribute_info.out.fs_attr & FILE_SUPPORTS_SPARSE_FILES) {
2607                 *sparse_support = true;
2608         } else {
2609                 *sparse_support = false;
2610         }
2611         return NT_STATUS_OK;
2612 }
2613
2614 static NTSTATUS test_ioctl_sparse_req(struct torture_context *torture,
2615                                       TALLOC_CTX *mem_ctx,
2616                                       struct smb2_tree *tree,
2617                                       struct smb2_handle fh,
2618                                       bool set)
2619 {
2620         union smb_ioctl ioctl;
2621         NTSTATUS status;
2622         uint8_t set_sparse;
2623
2624         ZERO_STRUCT(ioctl);
2625         ioctl.smb2.level = RAW_IOCTL_SMB2;
2626         ioctl.smb2.in.file.handle = fh;
2627         ioctl.smb2.in.function = FSCTL_SET_SPARSE;
2628         ioctl.smb2.in.max_response_size = 0;
2629         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
2630         set_sparse = (set ? 0xFF : 0x0);
2631         ioctl.smb2.in.out.data = &set_sparse;
2632         ioctl.smb2.in.out.length = sizeof(set_sparse);
2633
2634         status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2);
2635         return status;
2636 }
2637
2638 static NTSTATUS test_sparse_get(struct torture_context *torture,
2639                                 TALLOC_CTX *mem_ctx,
2640                                 struct smb2_tree *tree,
2641                                 struct smb2_handle fh,
2642                                 bool *_is_sparse)
2643 {
2644         union smb_fileinfo io;
2645         NTSTATUS status;
2646
2647         ZERO_STRUCT(io);
2648         io.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
2649         io.generic.in.file.handle = fh;
2650         status = smb2_getinfo_file(tree, mem_ctx, &io);
2651         if (!NT_STATUS_IS_OK(status)) {
2652                 return status;
2653         }
2654         *_is_sparse = !!(io.basic_info.out.attrib & FILE_ATTRIBUTE_SPARSE);
2655
2656         return status;
2657 }
2658
2659 static bool test_ioctl_sparse_file_flag(struct torture_context *torture,
2660                                         struct smb2_tree *tree)
2661 {
2662         struct smb2_handle fh;
2663         union smb_fileinfo io;
2664         NTSTATUS status;
2665         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2666         bool ok;
2667         bool is_sparse;
2668
2669         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2670                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
2671                                     FILE_ATTRIBUTE_NORMAL);
2672         torture_assert(torture, ok, "setup file");
2673
2674         status = test_ioctl_sparse_fs_supported(torture, tree, tmp_ctx, &fh,
2675                                                 &ok);
2676         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2677         if (!ok) {
2678                 smb2_util_close(tree, fh);
2679                 torture_skip(torture, "Sparse files not supported\n");
2680         }
2681
2682         ZERO_STRUCT(io);
2683         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2684         io.generic.in.file.handle = fh;
2685         status = smb2_getinfo_file(tree, tmp_ctx, &io);
2686         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
2687
2688         torture_assert(torture,
2689                 ((io.all_info2.out.attrib & FILE_ATTRIBUTE_SPARSE) == 0),
2690                        "sparse attr before set");
2691
2692         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
2693         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
2694
2695         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
2696         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
2697         torture_assert(torture, is_sparse, "no sparse attr after set");
2698
2699         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, false);
2700         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
2701
2702         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
2703         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
2704         torture_assert(torture, !is_sparse, "sparse attr after unset");
2705
2706         smb2_util_close(tree, fh);
2707         talloc_free(tmp_ctx);
2708         return true;
2709 }
2710
2711 static bool test_ioctl_sparse_file_attr(struct torture_context *torture,
2712                                         struct smb2_tree *tree)
2713 {
2714         struct smb2_handle fh;
2715         NTSTATUS status;
2716         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2717         bool ok;
2718         bool is_sparse;
2719
2720         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2721                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
2722                         (FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_SPARSE));
2723         torture_assert(torture, ok, "setup file");
2724
2725         status = test_ioctl_sparse_fs_supported(torture, tree, tmp_ctx, &fh,
2726                                                 &ok);
2727         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2728         if (!ok) {
2729                 smb2_util_close(tree, fh);
2730                 torture_skip(torture, "Sparse files not supported\n");
2731         }
2732
2733         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
2734         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
2735         torture_assert(torture, !is_sparse, "sparse attr on open");
2736
2737         smb2_util_close(tree, fh);
2738         talloc_free(tmp_ctx);
2739         return true;
2740 }
2741
2742 static bool test_ioctl_sparse_dir_flag(struct torture_context *torture,
2743                                         struct smb2_tree *tree)
2744 {
2745         struct smb2_handle dirh;
2746         NTSTATUS status;
2747         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2748         bool ok;
2749
2750         smb2_deltree(tree, DNAME);
2751         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2752                                     DNAME, &dirh, 0, SEC_RIGHTS_FILE_ALL,
2753                                     FILE_ATTRIBUTE_DIRECTORY);
2754         torture_assert(torture, ok, "setup sparse directory");
2755
2756         status = test_ioctl_sparse_fs_supported(torture, tree, tmp_ctx, &dirh,
2757                                                 &ok);
2758         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2759         if (!ok) {
2760                 smb2_util_close(tree, dirh);
2761                 smb2_deltree(tree, DNAME);
2762                 torture_skip(torture, "Sparse files not supported\n");
2763         }
2764
2765         /* set sparse dir should fail, check for 2k12 & 2k8 response */
2766         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, dirh, true);
2767         torture_assert_ntstatus_equal(torture, status,
2768                                       NT_STATUS_INVALID_PARAMETER,
2769                                       "dir FSCTL_SET_SPARSE status");
2770
2771         smb2_util_close(tree, dirh);
2772         smb2_deltree(tree, DNAME);
2773         talloc_free(tmp_ctx);
2774         return true;
2775 }
2776
2777 /*
2778  * FSCTL_SET_SPARSE can be sent with (already tested) or without a SetSparse
2779  * buffer to indicate whether the flag should be set or cleared. When sent
2780  * without a buffer, it must be handled as if SetSparse=TRUE.
2781  */
2782 static bool test_ioctl_sparse_set_nobuf(struct torture_context *torture,
2783                                         struct smb2_tree *tree)
2784 {
2785         struct smb2_handle fh;
2786         union smb_ioctl ioctl;
2787         NTSTATUS status;
2788         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2789         bool ok;
2790         bool is_sparse;
2791
2792         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2793                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
2794                                     FILE_ATTRIBUTE_NORMAL);
2795         torture_assert(torture, ok, "setup file");
2796
2797         status = test_ioctl_sparse_fs_supported(torture, tree, tmp_ctx, &fh,
2798                                                 &ok);
2799         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2800         if (!ok) {
2801                 smb2_util_close(tree, fh);
2802                 torture_skip(torture, "Sparse files not supported\n");
2803         }
2804
2805         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
2806         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
2807         torture_assert(torture, !is_sparse, "sparse attr before set");
2808
2809         ZERO_STRUCT(ioctl);
2810         ioctl.smb2.level = RAW_IOCTL_SMB2;
2811         ioctl.smb2.in.file.handle = fh;
2812         ioctl.smb2.in.function = FSCTL_SET_SPARSE;
2813         ioctl.smb2.in.max_response_size = 0;
2814         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
2815         /* ioctl.smb2.in.out is zeroed, no SetSparse buffer */
2816
2817         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
2818         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
2819
2820         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
2821         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
2822         torture_assert(torture, is_sparse, "no sparse attr after set");
2823
2824         /* second non-SetSparse request shouldn't toggle sparse */
2825         ZERO_STRUCT(ioctl);
2826         ioctl.smb2.level = RAW_IOCTL_SMB2;
2827         ioctl.smb2.in.file.handle = fh;
2828         ioctl.smb2.in.function = FSCTL_SET_SPARSE;
2829         ioctl.smb2.in.max_response_size = 0;
2830         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
2831
2832         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
2833         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
2834
2835         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
2836         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
2837         torture_assert(torture, is_sparse, "no sparse attr after 2nd set");
2838
2839         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, false);
2840         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
2841
2842         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
2843         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
2844         torture_assert(torture, !is_sparse, "sparse attr after unset");
2845
2846         smb2_util_close(tree, fh);
2847         talloc_free(tmp_ctx);
2848         return true;
2849 }
2850
2851 static bool test_ioctl_sparse_set_oversize(struct torture_context *torture,
2852                                            struct smb2_tree *tree)
2853 {
2854         struct smb2_handle fh;
2855         union smb_ioctl ioctl;
2856         NTSTATUS status;
2857         TALLOC_CTX *tmp_ctx = talloc_new(tree);
2858         bool ok;
2859         bool is_sparse;
2860         uint8_t buf[100];
2861
2862         ok = test_setup_create_fill(torture, tree, tmp_ctx,
2863                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
2864                                     FILE_ATTRIBUTE_NORMAL);
2865         torture_assert(torture, ok, "setup file");
2866
2867         status = test_ioctl_sparse_fs_supported(torture, tree, tmp_ctx, &fh,
2868                                                 &ok);
2869         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
2870         if (!ok) {
2871                 smb2_util_close(tree, fh);
2872                 torture_skip(torture, "Sparse files not supported\n");
2873         }
2874
2875         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
2876         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
2877         torture_assert(torture, !is_sparse, "sparse attr before set");
2878
2879         ZERO_STRUCT(ioctl);
2880         ioctl.smb2.level = RAW_IOCTL_SMB2;
2881         ioctl.smb2.in.file.handle = fh;
2882         ioctl.smb2.in.function = FSCTL_SET_SPARSE;
2883         ioctl.smb2.in.max_response_size = 0;
2884         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
2885
2886         /*
2887          * Attach a request buffer larger than FILE_SET_SPARSE_BUFFER
2888          * Windows still successfully processes the request.
2889          */
2890         ZERO_ARRAY(buf);
2891         buf[0] = 0xFF; /* attempt to set sparse */
2892         ioctl.smb2.in.out.data = buf;
2893         ioctl.smb2.in.out.length = ARRAY_SIZE(buf);
2894
2895         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
2896         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
2897
2898         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
2899         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
2900         torture_assert(torture, is_sparse, "no sparse attr after set");
2901
2902         ZERO_STRUCT(ioctl);
2903         ioctl.smb2.level = RAW_IOCTL_SMB2;
2904         ioctl.smb2.in.file.handle = fh;
2905         ioctl.smb2.in.function = FSCTL_SET_SPARSE;
2906         ioctl.smb2.in.max_response_size = 0;
2907         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
2908
2909         ZERO_ARRAY(buf); /* clear sparse */
2910         ioctl.smb2.in.out.data = buf;
2911         ioctl.smb2.in.out.length = ARRAY_SIZE(buf);
2912
2913         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
2914         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
2915
2916         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
2917         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
2918         torture_assert(torture, !is_sparse, "sparse attr after clear");
2919
2920         smb2_util_close(tree, fh);
2921         talloc_free(tmp_ctx);
2922         return true;
2923 }
2924
2925 static NTSTATUS test_ioctl_qar_req(struct torture_context *torture,
2926                                    TALLOC_CTX *mem_ctx,
2927                                    struct smb2_tree *tree,
2928                                    struct smb2_handle fh,
2929                                    int64_t req_off,
2930                                    int64_t req_len,
2931                                    struct file_alloced_range_buf **_rsp,
2932                                    uint64_t *_rsp_count)
2933 {
2934         union smb_ioctl ioctl;
2935         NTSTATUS status;
2936         enum ndr_err_code ndr_ret;
2937         struct file_alloced_range_buf far_buf;
2938         struct file_alloced_range_buf *far_rsp = NULL;
2939         uint64_t far_count = 0;
2940         int i;
2941         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2942         if (tmp_ctx == NULL) {
2943                 return NT_STATUS_NO_MEMORY;
2944         }
2945
2946         ZERO_STRUCT(ioctl);
2947         ioctl.smb2.level = RAW_IOCTL_SMB2;
2948         ioctl.smb2.in.file.handle = fh;
2949         ioctl.smb2.in.function = FSCTL_QUERY_ALLOCATED_RANGES;
2950         ioctl.smb2.in.max_response_size = 1024;
2951         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
2952
2953         far_buf.file_off = req_off;
2954         far_buf.len = req_len;
2955
2956         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
2957                                        &far_buf,
2958                         (ndr_push_flags_fn_t)ndr_push_file_alloced_range_buf);
2959         if (ndr_ret != NDR_ERR_SUCCESS) {
2960                 status = NT_STATUS_UNSUCCESSFUL;
2961                 goto err_out;
2962         }
2963
2964         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
2965         if (!NT_STATUS_IS_OK(status)) {
2966                 goto err_out;
2967         }
2968
2969         if (ioctl.smb2.out.out.length == 0) {
2970                 goto done;
2971         }
2972
2973         if ((ioctl.smb2.out.out.length % sizeof(far_buf)) != 0) {
2974                 torture_comment(torture, "invalid qry_alloced rsp len: %zd:",
2975                                 ioctl.smb2.out.out.length);
2976                 status = NT_STATUS_INVALID_VIEW_SIZE;
2977                 goto err_out;
2978         }
2979
2980         far_count = (ioctl.smb2.out.out.length / sizeof(far_buf));
2981         far_rsp = talloc_array(mem_ctx, struct file_alloced_range_buf,
2982                                far_count);
2983         if (far_rsp == NULL) {
2984                 status = NT_STATUS_NO_MEMORY;
2985                 goto err_out;
2986         }
2987
2988         for (i = 0; i < far_count; i++) {
2989                 ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
2990                                                &far_rsp[i],
2991                         (ndr_pull_flags_fn_t)ndr_pull_file_alloced_range_buf);
2992                 if (ndr_ret != NDR_ERR_SUCCESS) {
2993                         status = NT_STATUS_UNSUCCESSFUL;
2994                         goto err_out;
2995                 }
2996                 /* move to next buffer */
2997                 ioctl.smb2.out.out.data += sizeof(far_buf);
2998                 ioctl.smb2.out.out.length -= sizeof(far_buf);
2999         }
3000
3001 done:
3002         *_rsp = far_rsp;
3003         *_rsp_count = far_count;
3004         status = NT_STATUS_OK;
3005 err_out:
3006         talloc_free(tmp_ctx);
3007         return status;
3008 }
3009
3010 static bool test_ioctl_sparse_qar(struct torture_context *torture,
3011                                   struct smb2_tree *tree)
3012 {
3013         struct smb2_handle fh;
3014         NTSTATUS status;
3015         TALLOC_CTX *tmp_ctx = talloc_new(tree);
3016         bool ok;
3017         bool is_sparse;
3018         struct file_alloced_range_buf *far_rsp = NULL;
3019         uint64_t far_count = 0;
3020
3021         /* zero length file, shouldn't have any ranges */
3022         ok = test_setup_create_fill(torture, tree, tmp_ctx,
3023                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
3024                                     FILE_ATTRIBUTE_NORMAL);
3025         torture_assert(torture, ok, "setup file");
3026
3027         status = test_ioctl_sparse_fs_supported(torture, tree, tmp_ctx, &fh,
3028                                                 &ok);
3029         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
3030         if (!ok) {
3031                 smb2_util_close(tree, fh);
3032                 torture_skip(torture, "Sparse files not supported\n");
3033         }
3034
3035         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
3036         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
3037         torture_assert(torture, !is_sparse, "sparse attr before set");
3038
3039         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
3040                                     0,  /* off */
3041                                     0,  /* len */
3042                                     &far_rsp,
3043                                     &far_count);
3044         torture_assert_ntstatus_ok(torture, status,
3045                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3046         torture_assert_u64_equal(torture, far_count, 0,
3047                                  "unexpected response len");
3048
3049         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
3050                                     0,  /* off */
3051                                     1024,       /* len */
3052                                     &far_rsp,
3053                                     &far_count);
3054         torture_assert_ntstatus_ok(torture, status,
3055                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3056         torture_assert_u64_equal(torture, far_count, 0,
3057                                  "unexpected response len");
3058
3059         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
3060         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
3061
3062         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
3063         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
3064         torture_assert(torture, is_sparse, "no sparse attr after set");
3065
3066         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
3067                                     0,  /* off */
3068                                     1024,       /* len */
3069                                     &far_rsp,
3070                                     &far_count);
3071         torture_assert_ntstatus_ok(torture, status,
3072                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3073         torture_assert_u64_equal(torture, far_count, 0,
3074                                  "unexpected response len");
3075
3076         /* write into the (now) sparse file at 4k offset */
3077         ok = write_pattern(torture, tree, tmp_ctx, fh,
3078                            4096,        /* off */
3079                            1024,        /* len */
3080                            4096);       /* pattern offset */
3081         torture_assert(torture, ok, "write pattern");
3082
3083         /*
3084          * Query range before write off. Whether it's allocated or not is FS
3085          * dependent. NTFS deallocates chunks in 64K increments, but others
3086          * (e.g. XFS, Btrfs, etc.) may deallocate 4K chunks.
3087          */
3088         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
3089                                     0,  /* off */
3090                                     4096,       /* len */
3091                                     &far_rsp,
3092                                     &far_count);
3093         torture_assert_ntstatus_ok(torture, status,
3094                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3095         if (far_count == 0) {
3096                 torture_comment(torture, "FS deallocated 4K chunk\n");
3097         } else {
3098                 /* expect fully allocated */
3099                 torture_assert_u64_equal(torture, far_count, 1,
3100                                          "unexpected response len");
3101                 torture_assert_u64_equal(torture, far_rsp[0].file_off, 0, "far offset");
3102                 torture_assert_u64_equal(torture, far_rsp[0].len, 4096, "far len");
3103         }
3104
3105         /*
3106          * Query range before and past write, it should be allocated up to the
3107          * end of the write.
3108          */
3109         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
3110                                     0,  /* off */
3111                                     8192,       /* len */
3112                                     &far_rsp,
3113                                     &far_count);
3114         torture_assert_ntstatus_ok(torture, status,
3115                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3116         torture_assert_u64_equal(torture, far_count, 1,
3117                                  "unexpected response len");
3118         /* FS dependent */
3119         if (far_rsp[0].file_off == 4096) {
3120                 /* 4K chunk unallocated */
3121                 torture_assert_u64_equal(torture, far_rsp[0].file_off, 4096, "far offset");
3122                 torture_assert_u64_equal(torture, far_rsp[0].len, 1024, "far len");
3123         } else {
3124                 /* expect fully allocated */
3125                 torture_assert_u64_equal(torture, far_rsp[0].file_off, 0, "far offset");
3126                 torture_assert_u64_equal(torture, far_rsp[0].len, 5120, "far len");
3127         }
3128
3129         smb2_util_close(tree, fh);
3130         talloc_free(tmp_ctx);
3131         return true;
3132 }
3133
3134 static bool test_ioctl_sparse_qar_malformed(struct torture_context *torture,
3135                                             struct smb2_tree *tree)
3136 {
3137         struct smb2_handle fh;
3138         union smb_ioctl ioctl;
3139         struct file_alloced_range_buf far_buf;
3140         NTSTATUS status;
3141         enum ndr_err_code ndr_ret;
3142         TALLOC_CTX *tmp_ctx = talloc_new(tree);
3143         bool ok;
3144         size_t old_len;
3145
3146         /* zero length file, shouldn't have any ranges */
3147         ok = test_setup_create_fill(torture, tree, tmp_ctx,
3148                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
3149                                     FILE_ATTRIBUTE_NORMAL);
3150         torture_assert(torture, ok, "setup file");
3151
3152         status = test_ioctl_sparse_fs_supported(torture, tree, tmp_ctx, &fh,
3153                                                 &ok);
3154         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
3155         if (!ok) {
3156                 smb2_util_close(tree, fh);
3157                 torture_skip(torture, "Sparse files not supported\n");
3158         }
3159
3160         /* no allocated ranges, no space for range response, should pass */
3161         ZERO_STRUCT(ioctl);
3162         ioctl.smb2.level = RAW_IOCTL_SMB2;
3163         ioctl.smb2.in.file.handle = fh;
3164         ioctl.smb2.in.function = FSCTL_QUERY_ALLOCATED_RANGES;
3165         ioctl.smb2.in.max_response_size = 0;
3166         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
3167
3168         far_buf.file_off = 0;
3169         far_buf.len = 1024;
3170         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
3171                                        &far_buf,
3172                         (ndr_push_flags_fn_t)ndr_push_file_alloced_range_buf);
3173         torture_assert_ndr_success(torture, ndr_ret, "push far ndr buf");
3174
3175         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
3176         torture_assert_ntstatus_ok(torture, status, "FSCTL_QUERY_ALLOCATED_RANGES");
3177
3178         /* write into the file at 4k offset */
3179         ok = write_pattern(torture, tree, tmp_ctx, fh,
3180                            0,           /* off */
3181                            1024,        /* len */
3182                            0);          /* pattern offset */
3183         torture_assert(torture, ok, "write pattern");
3184
3185         /* allocated range, no space for range response, should fail */
3186         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
3187         torture_assert_ntstatus_equal(torture, status,
3188                                       NT_STATUS_BUFFER_TOO_SMALL, "qar no space");
3189
3190         /* oversize (2x) file_alloced_range_buf in request, should pass */
3191         ioctl.smb2.in.max_response_size = 1024;
3192         old_len = ioctl.smb2.in.out.length;
3193         ok = data_blob_realloc(tmp_ctx, &ioctl.smb2.in.out,
3194                                (ioctl.smb2.in.out.length * 2));
3195         torture_assert(torture, ok, "2x data buffer");
3196         memcpy(ioctl.smb2.in.out.data + old_len, ioctl.smb2.in.out.data,
3197                old_len);
3198         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
3199         torture_assert_ntstatus_ok(torture, status, "qar too big");
3200
3201         /* no file_alloced_range_buf in request, should fail */
3202         data_blob_free(&ioctl.smb2.in.out);
3203         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
3204         torture_assert_ntstatus_equal(torture, status,
3205                                       NT_STATUS_INVALID_PARAMETER, "qar empty");
3206
3207         return true;
3208 }
3209
3210 /*
3211  * 2.3.57 FSCTL_SET_ZERO_DATA Request
3212  *
3213  * How an implementation zeros data within a file is implementation-dependent.
3214  * A file system MAY choose to deallocate regions of disk space that have been
3215  * zeroed.<50>
3216  * <50>
3217  * ... NTFS might deallocate disk space in the file if the file is stored on an
3218  * NTFS volume, and the file is sparse or compressed. It will free any allocated
3219  * space in chunks of 64 kilobytes that begin at an offset that is a multiple of
3220  * 64 kilobytes. Other bytes in the file (prior to the first freed 64-kilobyte
3221  * chunk and after the last freed 64-kilobyte chunk) will be zeroed but not
3222  * deallocated.
3223  */
3224 static NTSTATUS test_ioctl_zdata_req(struct torture_context *torture,
3225                                      TALLOC_CTX *mem_ctx,
3226                                      struct smb2_tree *tree,
3227                                      struct smb2_handle fh,
3228                                      int64_t off,
3229                                      int64_t beyond_final_zero)
3230 {
3231         union smb_ioctl ioctl;
3232         NTSTATUS status;
3233         enum ndr_err_code ndr_ret;
3234         struct file_zero_data_info zdata_info;
3235         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3236         if (tmp_ctx == NULL) {
3237                 return NT_STATUS_NO_MEMORY;
3238         }
3239
3240         ZERO_STRUCT(ioctl);
3241         ioctl.smb2.level = RAW_IOCTL_SMB2;
3242         ioctl.smb2.in.file.handle = fh;
3243         ioctl.smb2.in.function = FSCTL_SET_ZERO_DATA;
3244         ioctl.smb2.in.max_response_size = 0;
3245         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
3246
3247         zdata_info.file_off = off;
3248         zdata_info.beyond_final_zero = beyond_final_zero;
3249
3250         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
3251                                        &zdata_info,
3252                         (ndr_push_flags_fn_t)ndr_push_file_zero_data_info);
3253         if (ndr_ret != NDR_ERR_SUCCESS) {
3254                 status = NT_STATUS_UNSUCCESSFUL;
3255                 goto err_out;
3256         }
3257
3258         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
3259         if (!NT_STATUS_IS_OK(status)) {
3260                 goto err_out;
3261         }
3262
3263         status = NT_STATUS_OK;
3264 err_out:
3265         talloc_free(tmp_ctx);
3266         return status;
3267 }
3268
3269 static bool test_ioctl_sparse_punch(struct torture_context *torture,
3270                                     struct smb2_tree *tree)
3271 {
3272         struct smb2_handle fh;
3273         NTSTATUS status;
3274         TALLOC_CTX *tmp_ctx = talloc_new(tree);
3275         bool ok;
3276         bool is_sparse;
3277         struct file_alloced_range_buf *far_rsp = NULL;
3278         uint64_t far_count = 0;
3279
3280         ok = test_setup_create_fill(torture, tree, tmp_ctx,
3281                                     FNAME, &fh, 4096, SEC_RIGHTS_FILE_ALL,
3282                                     FILE_ATTRIBUTE_NORMAL);
3283         torture_assert(torture, ok, "setup file");
3284
3285         status = test_ioctl_sparse_fs_supported(torture, tree, tmp_ctx, &fh,
3286                                                 &ok);
3287         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
3288         if (!ok) {
3289                 smb2_util_close(tree, fh);
3290                 torture_skip(torture, "Sparse files not supported\n");
3291         }
3292
3293         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
3294         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
3295         torture_assert(torture, !is_sparse, "sparse attr before set");
3296
3297         /* zero (hole-punch) the data, without sparse flag */
3298         status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
3299                                       0,        /* off */
3300                                       4096);    /* beyond_final_zero */
3301         torture_assert_ntstatus_ok(torture, status, "zero_data");
3302
3303         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
3304                                     0,          /* off */
3305                                     4096,       /* len */
3306                                     &far_rsp,
3307                                     &far_count);
3308         torture_assert_ntstatus_ok(torture, status,
3309                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3310         torture_assert_u64_equal(torture, far_count, 1,
3311                                  "unexpected response len");
3312
3313         /* expect fully allocated */
3314         torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
3315                                  "unexpected far off");
3316         torture_assert_u64_equal(torture, far_rsp[0].len, 4096,
3317                                  "unexpected far len");
3318         /* check that the data is now zeroed */
3319         ok = check_zero(torture, tree, tmp_ctx, fh, 0, 4096);
3320         torture_assert(torture, ok, "non-sparse zeroed range");
3321
3322         /* set sparse */
3323         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
3324         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
3325
3326         /* still fully allocated on NTFS, see note below for Samba */
3327         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
3328                                     0,          /* off */
3329                                     4096,       /* len */
3330                                     &far_rsp,
3331                                     &far_count);
3332         torture_assert_ntstatus_ok(torture, status,
3333                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3334         /*
3335          * FS specific: Samba uses PUNCH_HOLE to zero the range, and
3336          * subsequently uses fallocate() to allocate the punched range if the
3337          * file is marked non-sparse and "strict allocate" is enabled. In both
3338          * cases, the zeroed range will not be detected by SEEK_DATA, so the
3339          * range won't be present in QAR responses until the file is marked
3340          * non-sparse again.
3341          */
3342         if (far_count == 0) {
3343                 torture_comment(torture, "non-sparse zeroed range disappeared "
3344                                 "after marking sparse\n");
3345         } else {
3346                 /* NTFS: range remains fully allocated */
3347                 torture_assert_u64_equal(torture, far_count, 1,
3348                                          "unexpected response len");
3349                 torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
3350                                          "unexpected far off");
3351                 torture_assert_u64_equal(torture, far_rsp[0].len, 4096,
3352                                          "unexpected far len");
3353         }
3354
3355         /* zero (hole-punch) the data, _with_ sparse flag */
3356         status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
3357                                       0,        /* off */
3358                                       4096);    /* beyond_final_zero */
3359         torture_assert_ntstatus_ok(torture, status, "zero_data");
3360
3361         /* the range should no longer be alloced */
3362         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
3363                                     0,          /* off */
3364                                     4096,       /* len */
3365                                     &far_rsp,
3366                                     &far_count);
3367         torture_assert_ntstatus_ok(torture, status,
3368                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3369         torture_assert_u64_equal(torture, far_count, 0,
3370                                  "unexpected response len");
3371
3372         ok = check_zero(torture, tree, tmp_ctx, fh, 0, 4096);
3373         torture_assert(torture, ok, "sparse zeroed range");
3374
3375         /* remove sparse flag, this should "unsparse" the zeroed range */
3376         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, false);
3377         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
3378
3379         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
3380                                     0,          /* off */
3381                                     4096,       /* len */
3382                                     &far_rsp,
3383                                     &far_count);
3384         torture_assert_ntstatus_ok(torture, status,
3385                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3386         torture_assert_u64_equal(torture, far_count, 1,
3387                                  "unexpected response len");
3388         /* expect fully allocated */
3389         torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
3390                                  "unexpected far off");
3391         torture_assert_u64_equal(torture, far_rsp[0].len, 4096,
3392                                  "unexpected far len");
3393
3394         ok = check_zero(torture, tree, tmp_ctx, fh, 0, 4096);
3395         torture_assert(torture, ok, "sparse zeroed range");