s4: torture: CHECK ret value and fail if false
[kseeger/samba-autobuild-v4-15-test/.git] / source4 / torture / smb2 / streams.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    test alternate data streams
5
6    Copyright (C) Andrew Tridgell 2004
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 "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
25
26 #include "torture/torture.h"
27 #include "torture/smb2/proto.h"
28
29 #include "system/filesys.h"
30 #include "system/locale.h"
31 #include "lib/util/tsort.h"
32
33 #define DNAME "teststreams"
34
35 #define CHECK_STATUS(status, correct) do { \
36         if (!NT_STATUS_EQUAL(status, correct)) { \
37                 torture_result(tctx, TORTURE_FAIL, \
38                     "(%s) Incorrect status %s - should be %s\n", \
39                     __location__, nt_errstr(status), nt_errstr(correct)); \
40                 ret = false; \
41                 goto done; \
42         }} while (0)
43
44 #define CHECK_VALUE(v, correct) do { \
45         if ((v) != (correct)) { \
46                 torture_result(tctx, TORTURE_FAIL, \
47                     "(%s) Incorrect value %s=%d - should be %d\n", \
48                     __location__, #v, (int)v, (int)correct); \
49                 ret = false; \
50         }} while (0)
51
52 #define CHECK_NTTIME(v, correct) do { \
53         if ((v) != (correct)) { \
54                 torture_result(tctx, TORTURE_FAIL, \
55                     "(%s) Incorrect value %s=%llu - should be %llu\n", \
56                     __location__, #v, (unsigned long long)v, \
57                     (unsigned long long)correct); \
58                 ret = false; \
59         }} while (0)
60
61 #define CHECK_STR(v, correct) do { \
62         bool ok; \
63         if ((v) && !(correct)) { \
64                 ok = false; \
65         } else if (!(v) && (correct)) { \
66                 ok = false; \
67         } else if (!(v) && !(correct)) { \
68                 ok = true; \
69         } else if (strcmp((v), (correct)) == 0) { \
70                 ok = true; \
71         } else { \
72                 ok = false; \
73         } \
74         if (!ok) { \
75                 torture_result(tctx, TORTURE_FAIL, \
76                                "(%s) Incorrect value %s='%s' - "        \
77                                "should be '%s'\n",                      \
78                                __location__, #v, (v)?(v):"NULL",        \
79                                (correct)?(correct):"NULL");             \
80                 ret = false;                                            \
81         }} while (0)
82
83
84 static int qsort_string(char * const *s1, char * const *s2)
85 {
86         return strcmp(*s1, *s2);
87 }
88
89 static int qsort_stream(const struct stream_struct * s1, const struct stream_struct *s2)
90 {
91         return strcmp(s1->stream_name.s, s2->stream_name.s);
92 }
93
94 static bool check_stream(struct torture_context *tctx,
95                          struct smb2_tree *tree,
96                          const char *location,
97                          TALLOC_CTX *mem_ctx,
98                          const char *fname,
99                          const char *sname,
100                          const char *value)
101 {
102         struct smb2_handle handle;
103         struct smb2_create create;
104         struct smb2_read r;
105         NTSTATUS status;
106         const char *full_name;
107
108         full_name = talloc_asprintf(mem_ctx, "%s:%s", fname, sname);
109
110         ZERO_STRUCT(create);
111         create.in.desired_access = SEC_RIGHTS_FILE_ALL;
112         create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
113         create.in.create_disposition = NTCREATEX_DISP_OPEN;
114         create.in.fname = full_name;
115
116         status = smb2_create(tree, mem_ctx, &create);
117         if (!NT_STATUS_IS_OK(status)) {
118                 if (value == NULL) {
119                         return true;
120                 } else {
121                         torture_comment(tctx, "Unable to open stream %s\n",
122                             full_name);
123                         return false;
124                 }
125         }
126
127         handle = create.out.file.handle;
128         if (value == NULL) {
129                 return true;
130         }
131
132
133         ZERO_STRUCT(r);
134         r.in.file.handle = handle;
135         r.in.length      = strlen(value)+11;
136         r.in.offset      = 0;
137
138         status = smb2_read(tree, tree, &r);
139
140         if (!NT_STATUS_IS_OK(status)) {
141                 torture_comment(tctx, "(%s) Failed to read %lu bytes from "
142                     "stream '%s'\n", location, (long)strlen(value), full_name);
143                 return false;
144         }
145
146         if (memcmp(r.out.data.data, value, strlen(value)) != 0) {
147                 torture_comment(tctx, "(%s) Bad data in stream\n", location);
148                 return false;
149         }
150
151         smb2_util_close(tree, handle);
152         return true;
153 }
154
155 static bool check_stream_list(struct smb2_tree *tree,
156                               struct torture_context *tctx,
157                               const char *fname,
158                               int num_exp,
159                               const char **exp,
160                               struct smb2_handle h)
161 {
162         union smb_fileinfo finfo;
163         NTSTATUS status;
164         int i;
165         TALLOC_CTX *tmp_ctx = talloc_new(tctx);
166         char **exp_sort;
167         struct stream_struct *stream_sort;
168         bool ret = false;
169
170         finfo.generic.level = RAW_FILEINFO_STREAM_INFORMATION;
171         finfo.generic.in.file.handle = h;
172
173         status = smb2_getinfo_file(tree, tctx, &finfo);
174         if (!NT_STATUS_IS_OK(status)) {
175                 torture_comment(tctx, "(%s) smb_raw_pathinfo failed: %s\n",
176                     __location__, nt_errstr(status));
177                 goto fail;
178         }
179
180         if (finfo.stream_info.out.num_streams != num_exp) {
181                 torture_comment(tctx, "(%s) expected %d streams, got %d\n",
182                     __location__, num_exp, finfo.stream_info.out.num_streams);
183                 goto fail;
184         }
185
186         if (num_exp == 0) {
187                 ret = true;
188                 goto fail;
189         }
190
191         exp_sort = talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp));
192
193         if (exp_sort == NULL) {
194                 goto fail;
195         }
196
197         TYPESAFE_QSORT(exp_sort, num_exp, qsort_string);
198
199         stream_sort = talloc_memdup(tmp_ctx, finfo.stream_info.out.streams,
200                                     finfo.stream_info.out.num_streams *
201                                     sizeof(*stream_sort));
202
203         if (stream_sort == NULL) {
204                 goto fail;
205         }
206
207         TYPESAFE_QSORT(stream_sort, finfo.stream_info.out.num_streams, qsort_stream);
208
209         for (i=0; i<num_exp; i++) {
210                 if (strcmp(exp_sort[i], stream_sort[i].stream_name.s) != 0) {
211                         torture_comment(tctx,
212                             "(%s) expected stream name %s, got %s\n",
213                             __location__, exp_sort[i],
214                             stream_sort[i].stream_name.s);
215                         goto fail;
216                 }
217         }
218
219         ret = true;
220  fail:
221         talloc_free(tmp_ctx);
222         return ret;
223 }
224
225
226 static bool test_stream_dir(struct torture_context *tctx,
227                             struct smb2_tree *tree)
228 {
229         TALLOC_CTX *mem_ctx = talloc_new(tctx);
230         NTSTATUS status;
231         union smb_open io;
232         const char *fname = DNAME "\\stream.txt";
233         const char *sname1;
234         bool ret = true;
235         const char *basedir_data;
236         struct smb2_handle h;
237
238         smb2_util_unlink(tree, fname);
239         smb2_deltree(tree, DNAME);
240
241         status = torture_smb2_testdir(tree, DNAME, &h);
242         CHECK_STATUS(status, NT_STATUS_OK);
243
244         basedir_data = talloc_asprintf(mem_ctx, "%s::$DATA", DNAME);
245         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
246         torture_comment(tctx, "%s\n", sname1);
247
248         torture_comment(tctx, "(%s) opening non-existent directory stream\n",
249             __location__);
250         ZERO_STRUCT(io.smb2);
251         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
252         io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
253         io.smb2.in.file_attributes   = FILE_ATTRIBUTE_NORMAL;
254         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
255         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
256         io.smb2.in.share_access = 0;
257         io.smb2.in.alloc_size = 0;
258         io.smb2.in.security_flags = 0;
259         io.smb2.in.fname = sname1;
260         io.smb2.in.create_flags = 0;
261         status = smb2_create(tree, mem_ctx, &(io.smb2));
262         CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
263
264         torture_comment(tctx, "(%s) opening basedir  stream\n", __location__);
265         ZERO_STRUCT(io.smb2);
266         io.smb2.in.create_flags = 0;
267         io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
268         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
269         io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
270         io.smb2.in.share_access = 0;
271         io.smb2.in.alloc_size = 0;
272         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
273         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
274         io.smb2.in.security_flags = 0;
275         io.smb2.in.fname = basedir_data;
276         status = smb2_create(tree, mem_ctx, &(io.smb2));
277         CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
278
279         torture_comment(tctx, "(%s) opening basedir ::$DATA stream\n",
280             __location__);
281         ZERO_STRUCT(io.smb2);
282         io.smb2.in.create_flags = 0x10;
283         io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
284         io.smb2.in.create_options = 0;
285         io.smb2.in.file_attributes = 0;
286         io.smb2.in.share_access = 0;
287         io.smb2.in.alloc_size = 0;
288         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
289         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
290         io.smb2.in.security_flags = 0;
291         io.smb2.in.fname = basedir_data;
292         status = smb2_create(tree, mem_ctx, &(io.smb2));
293         CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
294
295         torture_comment(tctx, "(%s) list the streams on the basedir\n",
296             __location__);
297         ret &= check_stream_list(tree, mem_ctx, DNAME, 0, NULL, h);
298 done:
299         smb2_util_unlink(tree, fname);
300         smb2_deltree(tree, DNAME);
301         talloc_free(mem_ctx);
302
303         return ret;
304 }
305
306 static bool test_stream_io(struct torture_context *tctx,
307                            struct smb2_tree *tree)
308 {
309         TALLOC_CTX *mem_ctx = talloc_new(tctx);
310         NTSTATUS status;
311         union smb_open io;
312         const char *fname = DNAME "\\stream.txt";
313         const char *sname1, *sname2;
314         bool ret = true;
315         struct smb2_handle h, h2;
316
317         const char *one[] = { "::$DATA" };
318         const char *two[] = { "::$DATA", ":Second Stream:$DATA" };
319         const char *three[] = { "::$DATA", ":Stream One:$DATA",
320                                 ":Second Stream:$DATA" };
321
322         ZERO_STRUCT(h);
323         ZERO_STRUCT(h2);
324
325         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
326         sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
327                                  "Second Stream");
328
329         smb2_util_unlink(tree, fname);
330         smb2_deltree(tree, DNAME);
331
332         status = torture_smb2_testdir(tree, DNAME, &h);
333         CHECK_STATUS(status, NT_STATUS_OK);
334
335         torture_comment(tctx, "(%s) creating a stream on a non-existent file\n",
336                 __location__);
337
338         ZERO_STRUCT(io.smb2);
339         io.smb2.in.create_flags = 0;
340         io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
341         io.smb2.in.create_options = 0;
342         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
343         io.smb2.in.share_access = 0;
344         io.smb2.in.alloc_size = 0;
345         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
346         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
347         io.smb2.in.security_flags = 0;
348         io.smb2.in.fname = sname1;
349         status = smb2_create(tree, mem_ctx, &(io.smb2));
350         CHECK_STATUS(status, NT_STATUS_OK);
351         h2 = io.smb2.out.file.handle;
352
353         ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
354                             "Stream One", NULL);
355
356         torture_comment(tctx, "(%s) check that open of base file is allowed\n", __location__);
357         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
358         io.smb2.in.fname = fname;
359         status = smb2_create(tree, mem_ctx, &(io.smb2));
360         CHECK_STATUS(status, NT_STATUS_OK);
361         smb2_util_close(tree, io.smb2.out.file.handle);
362
363         torture_comment(tctx, "(%s) writing to stream\n", __location__);
364         status = smb2_util_write(tree, h2, "test data", 0, 9);
365         CHECK_STATUS(status, NT_STATUS_OK);
366
367         smb2_util_close(tree, h2);
368
369         ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
370                             "Stream One", "test data");
371
372         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
373         io.smb2.in.fname = sname1;
374         status = smb2_create(tree, mem_ctx, &(io.smb2));
375         CHECK_STATUS(status, NT_STATUS_OK);
376         h2 = io.smb2.out.file.handle;
377
378         torture_comment(tctx, "(%s) modifying stream\n", __location__);
379         status = smb2_util_write(tree, h2, "MORE DATA ", 5, 10);
380         CHECK_STATUS(status, NT_STATUS_OK);
381
382         smb2_util_close(tree, h2);
383
384         ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
385                             "Stream One:$FOO", NULL);
386
387         torture_comment(tctx, "(%s) creating a stream2 on a existing file\n",
388             __location__);
389         io.smb2.in.fname = sname2;
390         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
391         status = smb2_create(tree, mem_ctx, &(io.smb2));
392         CHECK_STATUS(status, NT_STATUS_OK);
393         h2 = io.smb2.out.file.handle;
394
395         torture_comment(tctx, "(%s) modifying stream\n", __location__);
396         status= smb2_util_write(tree, h2, "SECOND STREAM", 0, 13);
397         CHECK_STATUS(status, NT_STATUS_OK);
398         smb2_util_close(tree, h2);
399
400         ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
401                              "Stream One", "test MORE DATA ");
402
403         ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
404                             "Stream One:$DATA", "test MORE DATA ");
405
406         ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
407                             "Stream One:", NULL);
408
409         if (!ret) {
410                 torture_result(tctx, TORTURE_FAIL,
411                     "check_stream(\"Stream One:*\") failed\n");
412                 goto done;
413         }
414
415         ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
416                             "Second Stream", "SECOND STREAM");
417
418         ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
419                             "SECOND STREAM:$DATA", "SECOND STREAM");
420         ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
421                             "Second Stream:$DATA", "SECOND STREAM");
422
423         ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
424                             "Second Stream:", NULL);
425
426         ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
427                             "Second Stream:$FOO", NULL);
428
429         if (!ret) {
430                 torture_result(tctx, TORTURE_FAIL,
431                     "check_stream(\"Second Stream:*\") failed\n");
432                 goto done;
433         }
434
435         io.smb2.in.fname = sname2;
436         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
437         status = smb2_create(tree, mem_ctx, &(io.smb2));
438         CHECK_STATUS(status, NT_STATUS_OK);
439         h2 = io.smb2.out.file.handle;
440         check_stream_list(tree, tctx, fname, 3, three, h2);
441
442         smb2_util_close(tree, h2);
443
444         torture_comment(tctx, "(%s) deleting stream\n", __location__);
445         status = smb2_util_unlink(tree, sname1);
446         CHECK_STATUS(status, NT_STATUS_OK);
447
448         io.smb2.in.fname = sname2;
449         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
450         status = smb2_create(tree, mem_ctx, &(io.smb2));
451         CHECK_STATUS(status, NT_STATUS_OK);
452         h2 = io.smb2.out.file.handle;
453         check_stream_list(tree, tctx, fname, 2, two, h2);
454         smb2_util_close(tree, h2);
455
456         torture_comment(tctx, "(%s) delete a stream via delete-on-close\n",
457             __location__);
458         io.smb2.in.fname = sname2;
459         io.smb2.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
460         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
461         io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
462         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
463
464         status = smb2_create(tree, mem_ctx, &(io.smb2));
465         CHECK_STATUS(status, NT_STATUS_OK);
466         h2 = io.smb2.out.file.handle;
467
468         smb2_util_close(tree, h2);
469         status = smb2_util_unlink(tree, sname2);
470         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
471
472         io.smb2.in.fname = fname;
473         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
474         status = smb2_create(tree, mem_ctx, &(io.smb2));
475         h2 = io.smb2.out.file.handle;
476         check_stream_list(tree,tctx, fname, 1, one, h2);
477         smb2_util_close(tree, h2);
478
479         if (!torture_setting_bool(tctx, "samba4", false)) {
480                 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
481                 io.smb2.in.fname = sname1;
482                 status = smb2_create(tree, mem_ctx, &(io.smb2));
483                 CHECK_STATUS(status, NT_STATUS_OK);
484                 smb2_util_close(tree, io.ntcreatex.out.file.handle);
485                 io.smb2.in.fname = sname2;
486                 status = smb2_create(tree, mem_ctx, &(io.smb2));
487                 CHECK_STATUS(status, NT_STATUS_OK);
488                 smb2_util_close(tree, io.ntcreatex.out.file.handle);
489                 torture_comment(tctx, "(%s) deleting file\n", __location__);
490                 status = smb2_util_unlink(tree, fname);
491                 CHECK_STATUS(status, NT_STATUS_OK);
492         }
493
494
495 done:
496         smb2_util_close(tree, h2);
497         smb2_deltree(tree, DNAME);
498         talloc_free(mem_ctx);
499
500         return ret;
501 }
502
503 static bool test_zero_byte_stream(struct torture_context *tctx,
504                                   struct smb2_tree *tree)
505 {
506         TALLOC_CTX *mem_ctx = talloc_new(tctx);
507         NTSTATUS status;
508         union smb_open io;
509         const char *fname = DNAME "\\stream.txt";
510         const char *sname;
511         bool ret = true;
512         struct smb2_handle h, bh;
513         const char *streams[] = { "::$DATA", ":foo:$DATA" };
514
515         sname = talloc_asprintf(mem_ctx, "%s:%s", fname, "foo");
516
517         smb2_util_unlink(tree, fname);
518         smb2_deltree(tree, DNAME);
519
520         status = torture_smb2_testdir(tree, DNAME, &h);
521         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "testdir");
522         smb2_util_close(tree, h);
523
524         torture_comment(tctx, "(%s) Check 0 byte named stream\n",
525             __location__);
526
527         /* Create basefile */
528         ZERO_STRUCT(io);
529         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
530         io.smb2.in.fname = fname;
531         io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
532                 SEC_FILE_WRITE_ATTRIBUTE |
533                 SEC_FILE_READ_DATA |
534                 SEC_FILE_WRITE_DATA;
535         status = smb2_create(tree, mem_ctx, &(io.smb2));
536         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "create");
537         smb2_util_close(tree, io.smb2.out.file.handle);
538
539         /* Create named stream and close it */
540         ZERO_STRUCT(io);
541         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
542         io.smb2.in.fname = sname;
543         io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
544                 SEC_FILE_WRITE_ATTRIBUTE |
545                 SEC_FILE_READ_DATA |
546                 SEC_FILE_WRITE_DATA;
547         status = smb2_create(tree, mem_ctx, &(io.smb2));
548         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "create");
549         smb2_util_close(tree, io.smb2.out.file.handle);
550
551         /*
552          * Check stream list, the 0 byte stream MUST be returned by
553          * the server.
554          */
555         ZERO_STRUCT(io);
556         io.smb2.in.fname = fname;
557         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
558         io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
559                 SEC_FILE_WRITE_ATTRIBUTE |
560                 SEC_FILE_READ_DATA |
561                 SEC_FILE_WRITE_DATA;
562         status = smb2_create(tree, mem_ctx, &(io.smb2));
563         bh = io.smb2.out.file.handle;
564
565         ret = check_stream_list(tree,tctx, fname, 2, streams, bh);
566         torture_assert_goto(tctx, ret == true, ret, done, "smb2_create");
567         smb2_util_close(tree, bh);
568
569 done:
570         smb2_deltree(tree, DNAME);
571         talloc_free(mem_ctx);
572
573         return ret;
574 }
575
576 /*
577   test stream sharemodes
578 */
579 static bool test_stream_sharemodes(struct torture_context *tctx,
580                                    struct smb2_tree *tree)
581 {
582         TALLOC_CTX *mem_ctx = talloc_new(tctx);
583         NTSTATUS status;
584         union smb_open io;
585         const char *fname = DNAME "\\stream_share.txt";
586         const char *sname1, *sname2;
587         bool ret = true;
588         struct smb2_handle h, h1, h2;
589
590         ZERO_STRUCT(h);
591         ZERO_STRUCT(h1);
592         ZERO_STRUCT(h2);
593
594         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
595         sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
596                                  "Second Stream");
597
598         smb2_util_unlink(tree, fname);
599         smb2_deltree(tree, DNAME);
600
601         status = torture_smb2_testdir(tree, DNAME, &h);
602         CHECK_STATUS(status, NT_STATUS_OK);
603
604         torture_comment(tctx, "(%s) Testing stream share mode conflicts\n",
605             __location__);
606         ZERO_STRUCT(io.smb2);
607         io.generic.level = RAW_OPEN_SMB2;
608         io.smb2.in.create_flags = 0;
609         io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
610         io.smb2.in.create_options = 0;
611         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
612         io.smb2.in.share_access = 0;
613         io.smb2.in.alloc_size = 0;
614         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
615         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
616         io.smb2.in.security_flags = 0;
617         io.smb2.in.fname = sname1;
618
619         status = smb2_create(tree, mem_ctx, &(io.smb2));
620         CHECK_STATUS(status, NT_STATUS_OK);
621         h1 = io.smb2.out.file.handle;
622
623         /*
624          * A different stream does not give a sharing violation
625          */
626
627         io.smb2.in.fname = sname2;
628         status = smb2_create(tree, mem_ctx, &(io.smb2));
629         CHECK_STATUS(status, NT_STATUS_OK);
630         h2 = io.smb2.out.file.handle;
631
632         /*
633          * ... whereas the same stream does with unchanged access/share_access
634          * flags
635          */
636
637         io.smb2.in.fname = sname1;
638         io.smb2.in.create_disposition = 0;
639         status = smb2_create(tree, mem_ctx, &(io.smb2));
640         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
641
642         io.smb2.in.fname = sname2;
643         status = smb2_create(tree, mem_ctx, &(io.smb2));
644         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
645
646 done:
647         smb2_util_close(tree, h1);
648         smb2_util_close(tree, h2);
649         status = smb2_util_unlink(tree, fname);
650         smb2_deltree(tree, DNAME);
651         talloc_free(mem_ctx);
652
653         return ret;
654 }
655
656 /*
657  *  Test FILE_SHARE_DELETE on streams
658  *
659  * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
660  * with SEC_STD_DELETE.
661  *
662  * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
663  * be opened with SEC_STD_DELETE.
664  *
665  * A stream held open with FILE_SHARE_DELETE allows the file to be
666  * deleted. After the main file is deleted, access to the open file descriptor
667  * still works, but all name-based access to both the main file as well as the
668  * stream is denied with DELETE pending.
669  *
670  * This means, an open of the main file with SEC_STD_DELETE should walk all
671  * streams and also open them with SEC_STD_DELETE. If any of these opens gives
672  * SHARING_VIOLATION, the main open fails.
673  *
674  * Closing the main file after delete_on_close has been set does not really
675  * unlink it but leaves the corresponding share mode entry with
676  * delete_on_close being set around until all streams are closed.
677  *
678  * Opening a stream must also look at the main file's share mode entry, look
679  * at the delete_on_close bit and potentially return DELETE_PENDING.
680  */
681
682 static bool test_stream_delete(struct torture_context *tctx,
683                                struct smb2_tree *tree)
684 {
685         TALLOC_CTX *mem_ctx = talloc_new(tctx);
686         NTSTATUS status;
687         union smb_open io;
688         const char *fname = DNAME "\\stream_delete.txt";
689         const char *sname1;
690         bool ret = true;
691         struct smb2_handle h = {{0}};
692         struct smb2_handle h1 = {{0}};
693         struct smb2_read r;
694
695         if (torture_setting_bool(tctx, "samba4", false)) {
696                 torture_comment(tctx, "Skipping test as samba4 is enabled\n");
697                 goto done;
698         }
699
700         ZERO_STRUCT(h);
701         ZERO_STRUCT(h1);
702
703         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
704
705         /* clean slate .. */
706         smb2_util_unlink(tree, fname);
707         smb2_deltree(tree, fname);
708         smb2_deltree(tree, DNAME);
709
710         status = torture_smb2_testdir(tree, DNAME, &h);
711         CHECK_STATUS(status, NT_STATUS_OK);
712
713         torture_comment(tctx, "(%s) opening non-existent file stream\n",
714             __location__);
715         ZERO_STRUCT(io.smb2);
716         io.smb2.in.create_flags = 0;
717         io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
718         io.smb2.in.create_options = 0;
719         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
720         io.smb2.in.share_access = 0;
721         io.smb2.in.alloc_size = 0;
722         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
723         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
724         io.smb2.in.security_flags = 0;
725         io.smb2.in.fname = sname1;
726
727         status = smb2_create(tree, mem_ctx, &(io.smb2));
728         CHECK_STATUS(status, NT_STATUS_OK);
729         h1 = io.smb2.out.file.handle;
730
731         status = smb2_util_write(tree, h1, "test data", 0, 9);
732         CHECK_STATUS(status, NT_STATUS_OK);
733
734         /*
735          * One stream opened without FILE_SHARE_DELETE prevents the main file
736          * to be deleted or even opened with DELETE access
737          */
738
739         status = smb2_util_unlink(tree, fname);
740         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
741
742         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
743         io.smb2.in.fname = fname;
744         io.smb2.in.desired_access = SEC_STD_DELETE;
745         status = smb2_create(tree, mem_ctx, &(io.smb2));
746         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
747
748         smb2_util_close(tree, h1);
749
750         /*
751          * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
752          */
753
754         io.smb2.in.fname = sname1;
755         io.smb2.in.desired_access = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
756         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
757                         NTCREATEX_SHARE_ACCESS_READ |
758                         NTCREATEX_SHARE_ACCESS_WRITE;
759         status = smb2_create(tree, mem_ctx, &(io.smb2));
760         CHECK_STATUS(status, NT_STATUS_OK);
761         h1 = io.smb2.out.file.handle;
762
763         status = smb2_util_unlink(tree, fname);
764         CHECK_STATUS(status, NT_STATUS_OK);
765
766         /*
767          * file access still works on the stream while the main file is closed
768          */
769         ZERO_STRUCT(r);
770         r.in.file.handle = h1;
771         r.in.length      = 9;
772         r.in.offset      = 0;
773
774         status = smb2_read(tree, tree, &r);
775         CHECK_STATUS(status, NT_STATUS_OK);
776
777         /*
778          * name-based access to both the main file and the stream does not
779          * work anymore but gives DELETE_PENDING
780          */
781
782         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
783         io.smb2.in.fname = fname;
784         status = smb2_create(tree, mem_ctx, &(io.smb2));
785         CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
786
787         /*
788          * older S3 doesn't do this
789          */
790
791         io.smb2.in.fname = sname1;
792         status = smb2_create(tree, mem_ctx, &(io.smb2));
793         CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
794
795         smb2_util_close(tree, h1);
796         ZERO_STRUCT(h1);
797
798         /*
799          * After closing the stream the file is really gone.
800          */
801
802         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
803         io.smb2.in.fname = fname;
804         status = smb2_create(tree, mem_ctx, &(io.smb2));
805         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
806
807 done:
808         if (!smb2_util_handle_empty(h1)) {
809                 smb2_util_close(tree, h1);
810         }
811         smb2_util_unlink(tree, fname);
812         smb2_deltree(tree, DNAME);
813         talloc_free(mem_ctx);
814
815         return ret;
816 }
817
818 /*
819   test stream names
820 */
821 static bool test_stream_names(struct torture_context *tctx,
822                               struct smb2_tree *tree)
823 {
824         TALLOC_CTX *mem_ctx = talloc_new(tctx);
825         NTSTATUS status;
826         union smb_open io;
827         union smb_fileinfo finfo;
828         union smb_fileinfo stinfo;
829         union smb_setfileinfo sinfo;
830         const char *fname = DNAME "\\stream_names.txt";
831         const char *sname1, *sname1b, *sname1c, *sname1d;
832         const char *sname2, *snamew, *snamew2;
833         const char *snamer1;
834         bool ret = true;
835         struct smb2_handle h, h1, h2, h3;
836         int i;
837         const char *four[4] = {
838                 "::$DATA",
839                 ":\x05Stream\n One:$DATA",
840                 ":MStream Two:$DATA",
841                 ":?Stream*:$DATA"
842         };
843         const char *five1[5] = {
844                 "::$DATA",
845                 ":\x05Stream\n One:$DATA",
846                 ":BeforeRename:$DATA",
847                 ":MStream Two:$DATA",
848                 ":?Stream*:$DATA"
849         };
850         const char *five2[5] = {
851                 "::$DATA",
852                 ":\x05Stream\n One:$DATA",
853                 ":AfterRename:$DATA",
854                 ":MStream Two:$DATA",
855                 ":?Stream*:$DATA"
856         };
857
858         ZERO_STRUCT(h);
859         ZERO_STRUCT(h1);
860         ZERO_STRUCT(h2);
861         ZERO_STRUCT(h3);
862
863         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "\x05Stream\n One");
864         sname1b = talloc_asprintf(mem_ctx, "%s:", sname1);
865         sname1c = talloc_asprintf(mem_ctx, "%s:$FOO", sname1);
866         sname1d = talloc_asprintf(mem_ctx, "%s:?D*a", sname1);
867         sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "MStream Two");
868         snamew = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname, "?Stream*");
869         snamew2 = talloc_asprintf(mem_ctx, "%s\\stream*:%s:$DATA", DNAME,
870                                   "?Stream*");
871         snamer1 = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname,
872                                   "BeforeRename");
873
874         /* clean slate ...*/
875         smb2_util_unlink(tree, fname);
876         smb2_deltree(tree, fname);
877         smb2_deltree(tree, DNAME);
878
879         status = torture_smb2_testdir(tree, DNAME, &h);
880         CHECK_STATUS(status, NT_STATUS_OK);
881
882         torture_comment(tctx, "(%s) testing stream names\n", __location__);
883         ZERO_STRUCT(io.smb2);
884         io.smb2.in.create_flags = 0;
885         io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
886         io.smb2.in.create_options = 0;
887         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
888         io.smb2.in.share_access = 0;
889         io.smb2.in.alloc_size = 0;
890         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
891         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
892         io.smb2.in.security_flags = 0;
893         io.smb2.in.fname = sname1;
894
895         status = smb2_create(tree, mem_ctx, &(io.smb2));
896         CHECK_STATUS(status, NT_STATUS_OK);
897         h1 = io.smb2.out.file.handle;
898
899         /*
900          * A different stream does not give a sharing violation
901          */
902
903         io.smb2.in.fname = sname2;
904         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
905         status = smb2_create(tree, mem_ctx, &(io.smb2));
906         CHECK_STATUS(status, NT_STATUS_OK);
907         h2 = io.smb2.out.file.handle;
908
909         /*
910          * ... whereas the same stream does with unchanged access/share_access
911          * flags
912          */
913
914         io.smb2.in.fname = sname1;
915         io.smb2.in.create_disposition = NTCREATEX_DISP_SUPERSEDE;
916         status = smb2_create(tree, mem_ctx, &(io.smb2));
917         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
918
919         io.smb2.in.fname = sname1b;
920         status = smb2_create(tree, mem_ctx, &(io.smb2));
921         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
922
923         io.smb2.in.fname = sname1c;
924         status = smb2_create(tree, mem_ctx, &(io.smb2));
925         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
926                 /* w2k returns INVALID_PARAMETER */
927                 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
928         } else {
929                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
930         }
931
932         io.smb2.in.fname = sname1d;
933         status = smb2_create(tree, mem_ctx, &(io.smb2));
934         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
935                 /* w2k returns INVALID_PARAMETER */
936                 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
937         } else {
938                 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
939         }
940
941         io.smb2.in.fname = sname2;
942         status = smb2_create(tree, mem_ctx, &(io.smb2));
943         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
944
945         io.smb2.in.fname = snamew;
946         status = smb2_create(tree, mem_ctx, &(io.smb2));
947         CHECK_STATUS(status, NT_STATUS_OK);
948         h3 = io.smb2.out.file.handle;
949
950         io.smb2.in.fname = snamew2;
951         status = smb2_create(tree, mem_ctx, &(io.smb2));
952         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
953
954         io.smb2.in.fname = fname;
955         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
956         status = smb2_create(tree, mem_ctx, &(io.smb2));
957         CHECK_STATUS(status, NT_STATUS_OK);
958         ret &= check_stream_list(tree, tctx, fname, 4, four,
959                                  io.smb2.out.file.handle);
960         CHECK_VALUE(ret, true);
961         smb2_util_close(tree, h1);
962         smb2_util_close(tree, h2);
963         smb2_util_close(tree, h3);
964
965         if (torture_setting_bool(tctx, "samba4", true)) {
966                 goto done;
967         }
968
969         finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
970         finfo.generic.in.file.handle = io.smb2.out.file.handle;
971         status = smb2_getinfo_file(tree, mem_ctx, &finfo);
972         CHECK_STATUS(status, NT_STATUS_OK);
973         ret &= check_stream_list(tree, tctx, fname, 4, four,
974                                  io.smb2.out.file.handle);
975
976         CHECK_VALUE(ret, true);
977         for (i=0; i < 4; i++) {
978                 NTTIME write_time;
979                 uint64_t stream_size;
980                 char *path = talloc_asprintf(tctx, "%s%s",
981                                              fname, four[i]);
982
983                 char *rpath = talloc_strdup(path, path);
984                 char *p = strrchr(rpath, ':');
985                 /* eat :$DATA */
986                 *p = 0;
987                 p--;
988                 if (*p == ':') {
989                         /* eat ::$DATA */
990                         *p = 0;
991                 }
992                 torture_comment(tctx, "(%s): i[%u][%s]\n",
993                     __location__, i,path);
994                 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
995                 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
996                                 SEC_FILE_WRITE_ATTRIBUTE |
997                                 SEC_RIGHTS_FILE_ALL;
998                 io.smb2.in.fname = path;
999                 status = smb2_create(tree, mem_ctx, &(io.smb2));
1000                 CHECK_STATUS(status, NT_STATUS_OK);
1001                 h1 = io.smb2.out.file.handle;
1002
1003                 finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
1004                 finfo.generic.in.file.path = fname;
1005                 status = smb2_getinfo_file(tree, mem_ctx, &finfo);
1006                 CHECK_STATUS(status, NT_STATUS_OK);
1007
1008                 stinfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
1009                 stinfo.generic.in.file.handle = h1;
1010                 status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
1011                 CHECK_STATUS(status, NT_STATUS_OK);
1012                 if (!torture_setting_bool(tctx, "samba3", false)) {
1013                         CHECK_NTTIME(stinfo.all_info.out.create_time,
1014                                      finfo.all_info.out.create_time);
1015                         CHECK_NTTIME(stinfo.all_info.out.access_time,
1016                                      finfo.all_info.out.access_time);
1017                         CHECK_NTTIME(stinfo.all_info.out.write_time,
1018                                      finfo.all_info.out.write_time);
1019                         CHECK_NTTIME(stinfo.all_info.out.change_time,
1020                                      finfo.all_info.out.change_time);
1021                 }
1022                 CHECK_VALUE(stinfo.all_info.out.attrib,
1023                             finfo.all_info.out.attrib);
1024                 CHECK_VALUE(stinfo.all_info.out.size,
1025                             finfo.all_info.out.size);
1026                 CHECK_VALUE(stinfo.all_info.out.delete_pending,
1027                             finfo.all_info.out.delete_pending);
1028                 CHECK_VALUE(stinfo.all_info.out.directory,
1029                             finfo.all_info.out.directory);
1030                 CHECK_VALUE(stinfo.all_info.out.ea_size,
1031                             finfo.all_info.out.ea_size);
1032
1033                 stinfo.generic.level = RAW_FILEINFO_NAME_INFORMATION;
1034                 stinfo.generic.in.file.handle = h1;
1035                 status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
1036                 CHECK_STATUS(status, NT_STATUS_OK);
1037                 if (!torture_setting_bool(tctx, "samba3", false)) {
1038                         CHECK_STR(rpath, stinfo.name_info.out.fname.s);
1039                 }
1040
1041                 write_time = finfo.all_info.out.write_time;
1042                 write_time += i*1000000;
1043                 write_time /= 1000000;
1044                 write_time *= 1000000;
1045
1046                 ZERO_STRUCT(sinfo);
1047                 sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
1048                 sinfo.basic_info.in.file.handle = h1;
1049                 sinfo.basic_info.in.write_time = write_time;
1050                 sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
1051                 status = smb2_setinfo_file(tree, &sinfo);
1052                 CHECK_STATUS(status, NT_STATUS_OK);
1053
1054                 stream_size = i*8192;
1055
1056                 ZERO_STRUCT(sinfo);
1057                 sinfo.end_of_file_info.level =
1058                         RAW_SFILEINFO_END_OF_FILE_INFORMATION;
1059                 sinfo.end_of_file_info.in.file.handle = h1;
1060                 sinfo.end_of_file_info.in.size = stream_size;
1061                 status = smb2_setinfo_file(tree, &sinfo);
1062                 CHECK_STATUS(status, NT_STATUS_OK);
1063
1064                 stinfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
1065                 stinfo.generic.in.file.handle = h1;
1066                 status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
1067                 CHECK_STATUS(status, NT_STATUS_OK);
1068                 if (!torture_setting_bool(tctx, "samba3", false)) {
1069                         CHECK_NTTIME(stinfo.all_info.out.write_time,
1070                                      write_time);
1071                         CHECK_VALUE(stinfo.all_info.out.attrib,
1072                                     finfo.all_info.out.attrib);
1073                 }
1074                 CHECK_VALUE(stinfo.all_info.out.size,
1075                             stream_size);
1076                 CHECK_VALUE(stinfo.all_info.out.delete_pending,
1077                             finfo.all_info.out.delete_pending);
1078                 CHECK_VALUE(stinfo.all_info.out.directory,
1079                             finfo.all_info.out.directory);
1080                 CHECK_VALUE(stinfo.all_info.out.ea_size,
1081                             finfo.all_info.out.ea_size);
1082
1083                 io.smb2.in.fname = fname;
1084                 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1085                 status = smb2_create(tree, mem_ctx, &(io.smb2));
1086                 CHECK_STATUS(status, NT_STATUS_OK);
1087                 ret &= check_stream_list(tree, tctx, fname, 4, four,
1088                                          io.smb2.out.file.handle);
1089
1090                 smb2_util_close(tree, h1);
1091                 talloc_free(path);
1092         }
1093
1094         torture_comment(tctx, "(%s): testing stream renames\n", __location__);
1095         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1096         io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1097                                 SEC_FILE_WRITE_ATTRIBUTE |
1098                                 SEC_RIGHTS_FILE_ALL;
1099         io.smb2.in.fname = snamer1;
1100         status = smb2_create(tree, mem_ctx, &(io.smb2));
1101         CHECK_STATUS(status, NT_STATUS_OK);
1102         h1 = io.smb2.out.file.handle;
1103         ret &= check_stream_list(tree,tctx, fname, 5, five1,
1104                                  io.smb2.out.file.handle);
1105
1106         ZERO_STRUCT(sinfo);
1107         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1108         sinfo.rename_information.in.file.handle = h1;
1109         sinfo.rename_information.in.overwrite = true;
1110         sinfo.rename_information.in.root_fid = 0;
1111         sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
1112         status = smb2_setinfo_file(tree, &sinfo);
1113         CHECK_STATUS(status, NT_STATUS_OK);
1114
1115         ret &= check_stream_list(tree,tctx, fname, 5, five2,
1116                                  io.smb2.out.file.handle);
1117
1118         CHECK_VALUE(ret, true);
1119         ZERO_STRUCT(sinfo);
1120         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1121         sinfo.rename_information.in.file.handle = h1;
1122         sinfo.rename_information.in.overwrite = false;
1123         sinfo.rename_information.in.root_fid = 0;
1124         sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
1125         status = smb2_setinfo_file(tree, &sinfo);
1126         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
1127
1128         ret &= check_stream_list(tree,tctx, fname, 5, five2,
1129                                  io.smb2.out.file.handle);
1130
1131         ZERO_STRUCT(sinfo);
1132         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1133         sinfo.rename_information.in.file.handle = h1;
1134         sinfo.rename_information.in.overwrite = true;
1135         sinfo.rename_information.in.root_fid = 0;
1136         sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
1137         status = smb2_setinfo_file(tree, &sinfo);
1138         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1139
1140         ret &= check_stream_list(tree,tctx, fname, 5, five2,
1141                                  io.smb2.out.file.handle);
1142
1143         CHECK_VALUE(ret, true);
1144         /* TODO: we need to test more rename combinations */
1145
1146 done:
1147         smb2_util_close(tree, h1);
1148         status = smb2_util_unlink(tree, fname);
1149         smb2_deltree(tree, DNAME);
1150         talloc_free(mem_ctx);
1151
1152         return ret;
1153 }
1154
1155 /*
1156   test stream names
1157 */
1158 static bool test_stream_names2(struct torture_context *tctx,
1159                                struct smb2_tree *tree)
1160 {
1161         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1162         NTSTATUS status;
1163         union smb_open io;
1164         const char *fname = DNAME "\\stream_names2.txt";
1165         bool ret = true;
1166         struct smb2_handle h = {{0}};
1167         struct smb2_handle h1 = {{0}};
1168         uint8_t i;
1169
1170         smb2_util_unlink(tree, fname);
1171         smb2_deltree(tree, DNAME);
1172
1173         status = torture_smb2_testdir(tree, DNAME, &h);
1174         CHECK_STATUS(status, NT_STATUS_OK);
1175
1176         torture_comment(tctx, "(%s) testing stream names\n", __location__);
1177         ZERO_STRUCT(io.smb2);
1178         io.smb2.in.create_flags = 0;
1179         io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
1180         io.smb2.in.create_options = 0;
1181         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1182         io.smb2.in.share_access = 0;
1183         io.smb2.in.alloc_size = 0;
1184         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1185         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1186         io.smb2.in.security_flags = 0;
1187         io.smb2.in.fname = fname;
1188         status = smb2_create(tree, mem_ctx, &(io.smb2));
1189         CHECK_STATUS(status, NT_STATUS_OK);
1190         h1 = io.smb2.out.file.handle;
1191
1192         for (i=0x01; i < 0x7F; i++) {
1193                 char *path = talloc_asprintf(mem_ctx, "%s:Stream%c0x%02X:$DATA",
1194                                              fname, i, i);
1195                 NTSTATUS expected;
1196
1197                 switch (i) {
1198                 case '/':/*0x2F*/
1199                 case ':':/*0x3A*/
1200                 case '\\':/*0x5C*/
1201                         expected = NT_STATUS_OBJECT_NAME_INVALID;
1202                         break;
1203                 default:
1204                         expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1205                         break;
1206                 }
1207
1208
1209                 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1210                 io.smb2.in.fname = path;
1211                 status = smb2_create(tree, mem_ctx, &(io.smb2));
1212                 if (!NT_STATUS_EQUAL(status, expected)) {
1213                         torture_comment(tctx,
1214                             "(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1215                             __location__, fname, isprint(i)?(char)i:' ', i,
1216                             isprint(i)?"":" (not printable)",
1217                             nt_errstr(expected));
1218                 }
1219                 CHECK_STATUS(status, expected);
1220
1221                 talloc_free(path);
1222         }
1223
1224 done:
1225         smb2_util_close(tree, h1);
1226         status = smb2_util_unlink(tree, fname);
1227         smb2_deltree(tree, DNAME);
1228         talloc_free(mem_ctx);
1229
1230         return ret;
1231 }
1232
1233 /*
1234   test case insensitive stream names
1235 */
1236 static bool test_stream_names3(struct torture_context *tctx,
1237                                struct smb2_tree *tree)
1238 {
1239         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1240         NTSTATUS status;
1241         union smb_fsinfo info;
1242         const char *fname = DNAME "\\stream_names3.txt";
1243         const char *sname = NULL;
1244         const char *snamel = NULL;
1245         const char *snameu = NULL;
1246         const char *sdname = NULL;
1247         const char *sdnamel = NULL;
1248         const char *sdnameu = NULL;
1249         bool ret = true;
1250         struct smb2_handle h = {{0}};
1251         struct smb2_handle hf = {{0}};
1252         struct smb2_handle hs = {{0}};
1253         struct smb2_handle hsl = {{0}};
1254         struct smb2_handle hsu = {{0}};
1255         struct smb2_handle hsd = {{0}};
1256         struct smb2_handle hsdl = {{0}};
1257         struct smb2_handle hsdu = {{0}};
1258         const char *streams[] = { "::$DATA", ":StreamName:$DATA", };
1259
1260         smb2_deltree(tree, DNAME);
1261         status = torture_smb2_testdir(tree, DNAME, &h);
1262         CHECK_STATUS(status, NT_STATUS_OK);
1263
1264         ZERO_STRUCT(info);
1265         info.generic.level = RAW_QFS_ATTRIBUTE_INFORMATION;
1266         info.generic.handle = h;
1267         status = smb2_getinfo_fs(tree, tree, &info);
1268         CHECK_STATUS(status, NT_STATUS_OK);
1269         if (!(info.attribute_info.out.fs_attr & FILE_CASE_SENSITIVE_SEARCH)) {
1270                 torture_skip(tctx, "No FILE_CASE_SENSITIVE_SEARCH supported");
1271         }
1272
1273         /*
1274          * We create the following file:
1275          *
1276          *   teststreams\\stream_names3.txt
1277          *
1278          * and add a stream named 'StreamName'
1279          *
1280          * Then we try to open the stream using the following names:
1281          *
1282          * teststreams\\stream_names3.txt:StreamName
1283          * teststreams\\stream_names3.txt:streamname
1284          * teststreams\\stream_names3.txt:STREAMNAME
1285          * teststreams\\stream_names3.txt:StreamName:$dAtA
1286          * teststreams\\stream_names3.txt:streamname:$data
1287          * teststreams\\stream_names3.txt:STREAMNAME:$DATA
1288          */
1289         sname = talloc_asprintf(tctx, "%s:StreamName", fname);
1290         torture_assert_not_null(tctx, sname, __location__);
1291         snamel = strlower_talloc(tctx, sname);
1292         torture_assert_not_null(tctx, snamel, __location__);
1293         snameu = strupper_talloc(tctx, sname);
1294         torture_assert_not_null(tctx, snameu, __location__);
1295
1296         sdname = talloc_asprintf(tctx, "%s:$dAtA", sname);
1297         torture_assert_not_null(tctx, sdname, __location__);
1298         sdnamel = strlower_talloc(tctx, sdname);
1299         torture_assert_not_null(tctx, sdnamel, __location__);
1300         sdnameu = strupper_talloc(tctx, sdname);
1301         torture_assert_not_null(tctx, sdnameu, __location__);
1302
1303         torture_comment(tctx, "(%s) testing case insensitive stream names\n",
1304                         __location__);
1305         status = torture_smb2_testfile(tree, fname, &hf);
1306         CHECK_STATUS(status, NT_STATUS_OK);
1307         status = torture_smb2_testfile(tree, sname, &hs);
1308         CHECK_STATUS(status, NT_STATUS_OK);
1309         smb2_util_close(tree, hs);
1310
1311         torture_assert(tctx,
1312                        check_stream_list(tree, tctx, fname,
1313                                          ARRAY_SIZE(streams),
1314                                          streams,
1315                                          hf),
1316                        "streams");
1317
1318         status = torture_smb2_open(tree, sname, SEC_RIGHTS_FILE_ALL, &hs);
1319         CHECK_STATUS(status, NT_STATUS_OK);
1320         status = torture_smb2_open(tree, snamel, SEC_RIGHTS_FILE_ALL, &hsl);
1321         CHECK_STATUS(status, NT_STATUS_OK);
1322         status = torture_smb2_open(tree, snameu, SEC_RIGHTS_FILE_ALL, &hsu);
1323         CHECK_STATUS(status, NT_STATUS_OK);
1324         status = torture_smb2_open(tree, sdname, SEC_RIGHTS_FILE_ALL, &hsd);
1325         CHECK_STATUS(status, NT_STATUS_OK);
1326         status = torture_smb2_open(tree, sdnamel, SEC_RIGHTS_FILE_ALL, &hsdl);
1327         CHECK_STATUS(status, NT_STATUS_OK);
1328         status = torture_smb2_open(tree, sdnameu, SEC_RIGHTS_FILE_ALL, &hsdu);
1329         CHECK_STATUS(status, NT_STATUS_OK);
1330
1331 done:
1332         smb2_util_close(tree, hsdu);
1333         smb2_util_close(tree, hsdl);
1334         smb2_util_close(tree, hsd);
1335         smb2_util_close(tree, hsu);
1336         smb2_util_close(tree, hsl);
1337         smb2_util_close(tree, hs);
1338         smb2_util_close(tree, hf);
1339         smb2_util_close(tree, h);
1340         status = smb2_util_unlink(tree, fname);
1341         smb2_deltree(tree, DNAME);
1342         talloc_free(mem_ctx);
1343
1344         return ret;
1345 }
1346
1347 #define CHECK_CALL_HANDLE(call, rightstatus) do { \
1348         sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1349         sfinfo.generic.in.file.handle = h1; \
1350         status = smb2_setinfo_file(tree, &sfinfo); \
1351         if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1352                 torture_result(tctx, TORTURE_FAIL,                      \
1353                                "(%s) %s - %s (should be %s)\n",         \
1354                                __location__, #call,                     \
1355                                nt_errstr(status), nt_errstr(rightstatus)); \
1356                 ret = false;                                            \
1357         } \
1358         finfo1.generic.level = RAW_FILEINFO_ALL_INFORMATION; \
1359         finfo1.generic.in.file.handle = h1; \
1360         status2 = smb2_getinfo_file(tree, tctx, &finfo1); \
1361         if (!NT_STATUS_IS_OK(status2)) { \
1362                 torture_result(tctx, TORTURE_FAIL,           \
1363                                "(%s) %s pathinfo - %s\n",    \
1364                                __location__, #call, nt_errstr(status)); \
1365                 ret = false; \
1366         }} while (0)
1367
1368 /*
1369   test stream renames
1370 */
1371 static bool test_stream_rename(struct torture_context *tctx,
1372                                struct smb2_tree *tree)
1373 {
1374         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1375         NTSTATUS status, status2;
1376         union smb_open io;
1377         const char *fname = DNAME "\\stream_rename.txt";
1378         const char *sname1, *sname2;
1379         union smb_fileinfo finfo1;
1380         union smb_setfileinfo sfinfo;
1381         bool ret = true;
1382         struct smb2_handle h = {{0}};
1383         struct smb2_handle h1 = {{0}};
1384
1385         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
1386         sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
1387                                  "Second Stream");
1388
1389         smb2_util_unlink(tree, fname);
1390         smb2_deltree(tree, DNAME);
1391
1392         status = torture_smb2_testdir(tree, DNAME, &h);
1393         CHECK_STATUS(status, NT_STATUS_OK);
1394
1395         torture_comment(tctx, "(%s) testing stream renames\n", __location__);
1396         ZERO_STRUCT(io.smb2);
1397         io.smb2.in.create_flags = 0;
1398         io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1399                                       SEC_FILE_WRITE_ATTRIBUTE |
1400                                     SEC_RIGHTS_FILE_ALL;
1401         io.smb2.in.create_options = 0;
1402         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1403         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1404                         NTCREATEX_SHARE_ACCESS_WRITE |
1405                         NTCREATEX_SHARE_ACCESS_DELETE;
1406         io.smb2.in.alloc_size = 0;
1407         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1408         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1409         io.smb2.in.security_flags = 0;
1410         io.smb2.in.fname = sname1;
1411
1412         /* Create two streams. */
1413         status = smb2_create(tree, mem_ctx, &(io.smb2));
1414         CHECK_STATUS(status, NT_STATUS_OK);
1415         h1 = io.smb2.out.file.handle;
1416         smb2_util_close(tree, h1);
1417
1418         io.smb2.in.fname = sname2;
1419         status = smb2_create(tree, mem_ctx, &(io.smb2));
1420         CHECK_STATUS(status, NT_STATUS_OK);
1421         h1 = io.smb2.out.file.handle;
1422
1423         smb2_util_close(tree, h1);
1424
1425         /*
1426          * Open the second stream.
1427          */
1428
1429         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1430         status = smb2_create(tree, mem_ctx, &(io.smb2));
1431         CHECK_STATUS(status, NT_STATUS_OK);
1432         h1 = io.smb2.out.file.handle;
1433
1434         /*
1435          * Now rename the second stream onto the first.
1436          */
1437
1438         ZERO_STRUCT(sfinfo);
1439
1440         sfinfo.rename_information.in.overwrite = 1;
1441         sfinfo.rename_information.in.root_fid  = 0;
1442         sfinfo.rename_information.in.new_name  = ":Stream One";
1443         CHECK_CALL_HANDLE(RENAME_INFORMATION, NT_STATUS_OK);
1444 done:
1445         smb2_util_close(tree, h1);
1446         status = smb2_util_unlink(tree, fname);
1447         smb2_deltree(tree, DNAME);
1448         talloc_free(mem_ctx);
1449
1450         return ret;
1451 }
1452
1453 static bool test_stream_rename2(struct torture_context *tctx,
1454                                 struct smb2_tree *tree)
1455 {
1456         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1457         NTSTATUS status;
1458         union smb_open io;
1459         const char *fname1 = DNAME "\\stream_rename2.txt";
1460         const char *fname2 = DNAME "\\stream2_rename2.txt";
1461         const char *stream_name1 = ":Stream One:$DATA";
1462         const char *stream_name2 = ":Stream Two:$DATA";
1463         const char *stream_name_default = "::$DATA";
1464         const char *sname1;
1465         const char *sname2;
1466         bool ret = true;
1467         struct smb2_handle h, h1;
1468         union smb_setfileinfo sinfo;
1469
1470         ZERO_STRUCT(h);
1471         ZERO_STRUCT(h1);
1472
1473         sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream One");
1474         sname2 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream Two");
1475
1476         smb2_util_unlink(tree, fname1);
1477         smb2_util_unlink(tree, fname2);
1478         smb2_deltree(tree, DNAME);
1479
1480         status = torture_smb2_testdir(tree, DNAME, &h);
1481         CHECK_STATUS(status, NT_STATUS_OK);
1482
1483         ZERO_STRUCT(io.smb2);
1484         io.smb2.in.create_flags = 0;
1485         io.smb2.in.desired_access = SEC_FILE_READ_DATA |
1486                                 SEC_FILE_WRITE_DATA |
1487                                 SEC_STD_DELETE |
1488                                 SEC_FILE_APPEND_DATA |
1489                                 SEC_STD_READ_CONTROL;
1490         io.smb2.in.create_options = 0;
1491         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1492         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1493                                 NTCREATEX_SHARE_ACCESS_WRITE |
1494                                 NTCREATEX_SHARE_ACCESS_DELETE;
1495         io.smb2.in.alloc_size = 0;
1496         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1497         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1498         io.smb2.in.security_flags = 0;
1499         io.smb2.in.fname = sname1;
1500
1501         /* Open/create new stream. */
1502         status = smb2_create(tree, mem_ctx, &(io.smb2));
1503         CHECK_STATUS(status, NT_STATUS_OK);
1504
1505         smb2_util_close(tree, io.smb2.out.file.handle);
1506
1507         /*
1508          * Reopen the stream for SMB2 renames.
1509          */
1510         io.smb2.in.fname = sname1;
1511         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1512         status = smb2_create(tree, mem_ctx, &(io.smb2));
1513         CHECK_STATUS(status, NT_STATUS_OK);
1514         h1 = io.smb2.out.file.handle;
1515
1516         /*
1517          * Check SMB2 rename of a stream using :<stream>.
1518          */
1519         torture_comment(tctx, "(%s) Checking SMB2 rename of a stream using "
1520                         ":<stream>\n", __location__);
1521         ZERO_STRUCT(sinfo);
1522         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION_SMB2;
1523         sinfo.rename_information.in.file.handle = h1;
1524         sinfo.rename_information.in.overwrite = 1;
1525         sinfo.rename_information.in.root_fid = 0;
1526         sinfo.rename_information.in.new_name = stream_name1;
1527         status = smb2_setinfo_file(tree, &sinfo);
1528         CHECK_STATUS(status, NT_STATUS_OK);
1529
1530         /*
1531          * Check SMB2 rename of an overwriting stream using :<stream>.
1532          */
1533         torture_comment(tctx, "(%s) Checking SMB2 rename of an overwriting "
1534                         "stream using :<stream>\n", __location__);
1535
1536         /* Create second stream. */
1537         io.smb2.in.fname = sname2;
1538         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1539         status = smb2_create(tree, mem_ctx, &(io.smb2));
1540         CHECK_STATUS(status, NT_STATUS_OK);
1541         smb2_util_close(tree, io.smb2.out.file.handle);
1542
1543         /* Rename the first stream onto the second. */
1544         sinfo.rename_information.in.file.handle = h1;
1545         sinfo.rename_information.in.new_name = stream_name2;
1546         status = smb2_setinfo_file(tree, &sinfo);
1547         CHECK_STATUS(status, NT_STATUS_OK);
1548
1549         smb2_util_close(tree, h1);
1550
1551         /*
1552          * Reopen the stream with the new name.
1553          */
1554         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1555         io.smb2.in.fname = sname2;
1556         status = smb2_create(tree, mem_ctx, &(io.smb2));
1557         CHECK_STATUS(status, NT_STATUS_OK);
1558         h1 = io.smb2.out.file.handle;
1559
1560         /*
1561          * Check SMB2 rename of a stream using <base>:<stream>.
1562          */
1563         torture_comment(tctx, "(%s) Checking SMB2 rename of a stream using "
1564                         "<base>:<stream>\n", __location__);
1565         sinfo.rename_information.in.file.handle = h1;
1566         sinfo.rename_information.in.new_name = sname1;
1567         status = smb2_setinfo_file(tree, &sinfo);
1568         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
1569
1570         if (!torture_setting_bool(tctx, "samba4", false)) {
1571                 /*
1572                  * Check SMB2 rename to the default stream using :<stream>.
1573                  */
1574                 torture_comment(tctx, "(%s) Checking SMB2 rename to default stream "
1575                                 "using :<stream>\n", __location__);
1576                 sinfo.rename_information.in.file.handle = h1;
1577                 sinfo.rename_information.in.new_name = stream_name_default;
1578                 status = smb2_setinfo_file(tree, &sinfo);
1579                 CHECK_STATUS(status, NT_STATUS_OK);
1580         }
1581
1582         smb2_util_close(tree, h1);
1583
1584  done:
1585         smb2_util_close(tree, h1);
1586         status = smb2_util_unlink(tree, fname1);
1587         status = smb2_util_unlink(tree, fname2);
1588         smb2_deltree(tree, DNAME);
1589         talloc_free(mem_ctx);
1590
1591         return ret;
1592 }
1593
1594 static bool create_file_with_stream(struct torture_context *tctx,
1595                                     struct smb2_tree *tree,
1596                                     TALLOC_CTX *mem_ctx,
1597                                     const char *base_fname,
1598                                     const char *stream)
1599 {
1600         NTSTATUS status;
1601         bool ret = true;
1602         union smb_open io;
1603
1604         /* Create a file with a stream */
1605         ZERO_STRUCT(io.smb2);
1606         io.smb2.in.create_flags = 0;
1607         io.smb2.in.desired_access = SEC_FILE_READ_DATA |
1608                                 SEC_FILE_WRITE_DATA |
1609                                 SEC_FILE_APPEND_DATA |
1610                                 SEC_STD_READ_CONTROL;
1611         io.smb2.in.create_options = 0;
1612         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1613         io.smb2.in.share_access = 0;
1614         io.smb2.in.alloc_size = 0;
1615         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1616         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1617         io.smb2.in.security_flags = 0;
1618         io.smb2.in.fname = stream;
1619
1620         status = smb2_create(tree, mem_ctx, &(io.smb2));
1621         CHECK_STATUS(status, NT_STATUS_OK);
1622
1623  done:
1624         smb2_util_close(tree, io.smb2.out.file.handle);
1625         return ret;
1626 }
1627
1628
1629 /* Test how streams interact with create dispositions */
1630 static bool test_stream_create_disposition(struct torture_context *tctx,
1631                                            struct smb2_tree *tree)
1632 {
1633         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1634         NTSTATUS status;
1635         union smb_open io;
1636         const char *fname = DNAME "\\stream_create_disp.txt";
1637         const char *stream = "Stream One:$DATA";
1638         const char *fname_stream;
1639         const char *default_stream_name = "::$DATA";
1640         const char *stream_list[2];
1641         bool ret = true;
1642         struct smb2_handle h = {{0}};
1643         struct smb2_handle h1 = {{0}};
1644
1645         /* clean slate .. */
1646         smb2_util_unlink(tree, fname);
1647         smb2_deltree(tree, fname);
1648         smb2_deltree(tree, DNAME);
1649
1650         status = torture_smb2_testdir(tree, DNAME, &h);
1651         CHECK_STATUS(status, NT_STATUS_OK);
1652
1653         fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
1654
1655         stream_list[0] = talloc_asprintf(mem_ctx, ":%s", stream);
1656         stream_list[1] = default_stream_name;
1657
1658         if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
1659                                      fname_stream)) {
1660                 goto done;
1661         }
1662
1663         /* Open the base file with OPEN */
1664         ZERO_STRUCT(io.smb2);
1665         io.smb2.in.create_flags = 0;
1666         io.smb2.in.desired_access = SEC_FILE_READ_DATA |
1667                                 SEC_FILE_WRITE_DATA |
1668                                 SEC_FILE_APPEND_DATA |
1669                                 SEC_STD_READ_CONTROL;
1670         io.smb2.in.create_options = 0;
1671         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1672         io.smb2.in.share_access = 0;
1673         io.smb2.in.alloc_size = 0;
1674         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1675         io.smb2.in.security_flags = 0;
1676         io.smb2.in.fname = fname;
1677
1678         /*
1679          * check create open: sanity check
1680          */
1681         torture_comment(tctx, "(%s) Checking create disp: open\n",
1682                         __location__);
1683         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1684         status = smb2_create(tree, mem_ctx, &(io.smb2));
1685         CHECK_STATUS(status, NT_STATUS_OK);
1686         if (!check_stream_list(tree, tctx, fname, 2, stream_list,
1687                                io.smb2.out.file.handle)) {
1688                 goto done;
1689         }
1690         smb2_util_close(tree, io.smb2.out.file.handle);
1691
1692         /*
1693          * check create overwrite
1694          */
1695         torture_comment(tctx, "(%s) Checking create disp: overwrite\n",
1696                         __location__);
1697         io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
1698         status = smb2_create(tree, mem_ctx, &(io.smb2));
1699         CHECK_STATUS(status, NT_STATUS_OK);
1700         if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
1701                                io.smb2.out.file.handle)) {
1702                 goto done;
1703         }
1704         smb2_util_close(tree, io.smb2.out.file.handle);
1705
1706         /*
1707          * check create overwrite_if
1708          */
1709         torture_comment(tctx, "(%s) Checking create disp: overwrite_if\n",
1710                         __location__);
1711         smb2_util_unlink(tree, fname);
1712         if (!create_file_with_stream(tctx, tree, mem_ctx, fname, fname_stream))
1713                 goto done;
1714
1715         io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1716         status = smb2_create(tree, mem_ctx, &(io.smb2));
1717         CHECK_STATUS(status, NT_STATUS_OK);
1718         if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
1719                                io.smb2.out.file.handle)) {
1720                 goto done;
1721         }
1722         smb2_util_close(tree, io.smb2.out.file.handle);
1723
1724         /*
1725          * check create supersede
1726          */
1727         torture_comment(tctx, "(%s) Checking create disp: supersede\n",
1728                         __location__);
1729         smb2_util_unlink(tree, fname);
1730         if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
1731                                      fname_stream)) {
1732                 goto done;
1733         }
1734
1735         io.smb2.in.create_disposition = NTCREATEX_DISP_SUPERSEDE;
1736         status = smb2_create(tree, mem_ctx, &(io.smb2));
1737         CHECK_STATUS(status, NT_STATUS_OK);
1738         if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
1739                                io.smb2.out.file.handle)) {
1740                 goto done;
1741         }
1742         smb2_util_close(tree, io.smb2.out.file.handle);
1743
1744         /*
1745          * check create overwrite_if on a stream.
1746          */
1747         torture_comment(tctx, "(%s) Checking create disp: overwrite_if on "
1748                         "stream\n", __location__);
1749         smb2_util_unlink(tree, fname);
1750         if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
1751                                      fname_stream)) {
1752                 goto done;
1753         }
1754
1755         io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1756         io.smb2.in.fname = fname_stream;
1757         status = smb2_create(tree, mem_ctx, &(io.smb2));
1758         CHECK_STATUS(status, NT_STATUS_OK);
1759         if (!check_stream_list(tree, tctx, fname, 2, stream_list,
1760                                io.smb2.out.file.handle)) {
1761                 goto done;
1762         }
1763         smb2_util_close(tree, io.smb2.out.file.handle);
1764  done:
1765         smb2_util_close(tree, h1);
1766         smb2_util_unlink(tree, fname);
1767         smb2_deltree(tree, DNAME);
1768         talloc_free(mem_ctx);
1769
1770         return ret;
1771 }
1772
1773 static bool open_stream(struct smb2_tree *tree,
1774                         struct torture_context *mem_ctx,
1775                         const char *fname,
1776                         struct smb2_handle *h_out)
1777 {
1778         NTSTATUS status;
1779         union smb_open io;
1780
1781         ZERO_STRUCT(io.smb2);
1782         io.smb2.in.create_flags = 0;
1783         io.smb2.in.desired_access = SEC_FILE_READ_DATA |
1784                                 SEC_FILE_WRITE_DATA |
1785                                 SEC_FILE_APPEND_DATA |
1786                                 SEC_STD_READ_CONTROL |
1787                                 SEC_FILE_WRITE_ATTRIBUTE;
1788         io.smb2.in.create_options = 0;
1789         io.smb2.in.file_attributes = 0;
1790         io.smb2.in.share_access = 0;
1791         io.smb2.in.alloc_size = 0;
1792         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1793         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1794         io.smb2.in.security_flags = 0;
1795         io.smb2.in.fname = fname;
1796
1797         status = smb2_create(tree, mem_ctx, &(io.smb2));
1798         if (!NT_STATUS_IS_OK(status)) {
1799                 return false;
1800         }
1801         *h_out = io.smb2.out.file.handle;
1802         return true;
1803 }
1804
1805
1806 /* Test the effect of setting attributes on a stream. */
1807 static bool test_stream_attributes(struct torture_context *tctx,
1808                                    struct smb2_tree *tree)
1809 {
1810         TALLOC_CTX *mem_ctx = talloc_new(tctx);
1811         bool ret = true;
1812         NTSTATUS status;
1813         union smb_open io;
1814         const char *fname = DNAME "\\stream_attr.txt";
1815         const char *stream = "Stream One:$DATA";
1816         const char *fname_stream;
1817         struct smb2_handle h, h1;
1818         union smb_fileinfo finfo;
1819         union smb_setfileinfo sfinfo;
1820         time_t basetime = (time(NULL) - 86400) & ~1;
1821
1822         ZERO_STRUCT(h);
1823         ZERO_STRUCT(h1);
1824
1825         torture_comment(tctx, "(%s) testing attribute setting on stream\n",
1826                         __location__);
1827
1828         /* clean slate .. */
1829         smb2_util_unlink(tree, fname);
1830         smb2_deltree(tree, fname);
1831         smb2_deltree(tree, DNAME);
1832
1833         status = torture_smb2_testdir(tree, DNAME, &h);
1834         CHECK_STATUS(status, NT_STATUS_OK);
1835
1836         fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
1837
1838         /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1839         ret = create_file_with_stream(tctx, tree, mem_ctx, fname,
1840                                       fname_stream);
1841         if (!ret) {
1842                 goto done;
1843         }
1844
1845         ZERO_STRUCT(io.smb2);
1846         io.smb2.in.fname = fname;
1847         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1848         io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1849         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1850                                  NTCREATEX_SHARE_ACCESS_WRITE |
1851                                  NTCREATEX_SHARE_ACCESS_DELETE;
1852         status = smb2_create(tree, mem_ctx, &(io.smb2));
1853         CHECK_STATUS(status, NT_STATUS_OK);
1854
1855         ZERO_STRUCT(finfo);
1856         finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
1857         finfo.generic.in.file.handle = io.smb2.out.file.handle;
1858         status = smb2_getinfo_file(tree, mem_ctx, &finfo);
1859         CHECK_STATUS(status, NT_STATUS_OK);
1860
1861         if (finfo.basic_info.out.attrib != FILE_ATTRIBUTE_ARCHIVE) {
1862                 torture_comment(tctx, "(%s) Incorrect attrib %x - should be "
1863                     "%x\n", __location__,
1864                     (unsigned int)finfo.basic_info.out.attrib,
1865                     (unsigned int)FILE_ATTRIBUTE_ARCHIVE);
1866                 ret = false;
1867                 goto done;
1868         }
1869
1870         smb2_util_close(tree, io.smb2.out.file.handle);
1871         /* Now open the stream name. */
1872
1873         if (!open_stream(tree, tctx, fname_stream, &h1)) {
1874                 goto done;
1875         }
1876
1877         /* Change the time on the stream. */
1878         ZERO_STRUCT(sfinfo);
1879         unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
1880         sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1881         sfinfo.generic.in.file.handle = h1;
1882         status = smb2_setinfo_file(tree, &sfinfo);
1883         if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1884                 torture_comment(tctx, "(%s) %s - %s (should be %s)\n",
1885                     __location__, "SETATTR",
1886                     nt_errstr(status), nt_errstr(NT_STATUS_OK));
1887                 ret = false;
1888                 goto done;
1889         }
1890
1891         smb2_util_close(tree, h1);
1892
1893         ZERO_STRUCT(io.smb2);
1894         io.smb2.in.fname = fname;
1895         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1896         io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1897         status = smb2_create(tree, mem_ctx, &(io.smb2));
1898         CHECK_STATUS(status, NT_STATUS_OK);
1899         h1 = io.smb2.out.file.handle;
1900
1901         ZERO_STRUCT(finfo);
1902         finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
1903         finfo.generic.in.file.handle = h1;
1904         status = smb2_getinfo_file(tree, mem_ctx, &finfo);
1905         if (!NT_STATUS_IS_OK(status)) {
1906                 torture_comment(tctx, "(%s) %s pathinfo - %s\n",
1907                     __location__, "SETATTRE", nt_errstr(status));
1908                 ret = false;
1909                 goto done;
1910         }
1911
1912         if (nt_time_to_unix(finfo.basic_info.out.write_time) != basetime) {
1913                 torture_comment(tctx, "(%s) time incorrect.\n", __location__);
1914                 ret = false;
1915                 goto done;
1916         }
1917         smb2_util_close(tree, h1);
1918
1919         if (!open_stream(tree, tctx, fname_stream, &h1)) {
1920                 goto done;
1921         }
1922
1923         /* Changing attributes on stream */
1924         ZERO_STRUCT(sfinfo);
1925         sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
1926
1927         sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1928         sfinfo.generic.in.file.handle = h1;
1929         status = smb2_setinfo_file(tree, &sfinfo);
1930         if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1931                 torture_comment(tctx, "(%s) %s - %s (should be %s)\n",
1932                         __location__, "SETATTR",
1933                         nt_errstr(status), nt_errstr(NT_STATUS_OK));
1934                 ret = false;
1935                 goto done;
1936         }
1937
1938         smb2_util_close(tree, h1);
1939
1940         ZERO_STRUCT(io.smb2);
1941         io.smb2.in.fname = fname;
1942         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1943         io.smb2.in.desired_access = SEC_FILE_READ_DATA;
1944         status = smb2_create(tree, mem_ctx, &(io.smb2));
1945         CHECK_STATUS(status, NT_STATUS_OK);
1946         h1 = io.smb2.out.file.handle;
1947
1948         ZERO_STRUCT(finfo);
1949         finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
1950         finfo.generic.in.file.handle = h1;
1951         status = smb2_getinfo_file(tree, mem_ctx, &finfo);
1952         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1953
1954 done:
1955         smb2_util_close(tree, h1);
1956         smb2_util_unlink(tree, fname);
1957         smb2_deltree(tree, DNAME);
1958         talloc_free(mem_ctx);
1959
1960         return ret;
1961 }
1962
1963 static bool test_basefile_rename_with_open_stream(struct torture_context *tctx,
1964                                                   struct smb2_tree *tree)
1965 {
1966         bool ret = true;
1967         NTSTATUS status;
1968         struct smb2_tree *tree2 = NULL;
1969         struct smb2_create create, create2;
1970         struct smb2_handle h1 = {{0}}, h2 = {{0}};
1971         const char *fname = "test_rename_openfile";
1972         const char *sname = "test_rename_openfile:foo";
1973         const char *fname_renamed = "test_rename_openfile_renamed";
1974         union smb_setfileinfo sinfo;
1975         const char *data = "test data";
1976
1977         ret = torture_smb2_connection(tctx, &tree2);
1978         torture_assert_goto(tctx, ret == true, ret, done,
1979                             "torture_smb2_connection failed\n");
1980
1981         torture_comment(tctx, "Creating file with stream\n");
1982
1983         ZERO_STRUCT(create);
1984         create.in.desired_access = SEC_FILE_ALL;
1985         create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
1986         create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1987         create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1988         create.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
1989         create.in.fname = sname;
1990
1991         status = smb2_create(tree, tctx, &create);
1992         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1993                                         "smb2_create failed\n");
1994
1995         h1 = create.out.file.handle;
1996
1997         torture_comment(tctx, "Writing to stream\n");
1998
1999         status = smb2_util_write(tree, h1, data, 0, strlen(data));
2000         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2001                                         "smb2_util_write failed\n");
2002
2003         torture_comment(tctx, "Renaming base file\n");
2004
2005         ZERO_STRUCT(create2);
2006         create2.in.desired_access = SEC_FILE_ALL;
2007         create2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2008         create2.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
2009         create2.in.create_disposition = NTCREATEX_DISP_OPEN;
2010         create2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
2011         create2.in.fname = fname;
2012
2013         status = smb2_create(tree2, tctx, &create2);
2014         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2015                                         "smb2_create failed\n");
2016
2017         h2 = create2.out.file.handle;
2018
2019         ZERO_STRUCT(sinfo);
2020         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
2021         sinfo.rename_information.in.file.handle = h2;
2022         sinfo.rename_information.in.new_name = fname_renamed;
2023
2024         status = smb2_setinfo_file(tree2, &sinfo);
2025         torture_assert_ntstatus_equal_goto(
2026                 tctx, status, NT_STATUS_ACCESS_DENIED, ret, done,
2027                 "smb2_setinfo_file didn't return NT_STATUS_ACCESS_DENIED\n");
2028
2029         smb2_util_close(tree2, h2);
2030
2031 done:
2032         if (!smb2_util_handle_empty(h1)) {
2033                 smb2_util_close(tree, h1);
2034         }
2035         if (!smb2_util_handle_empty(h2)) {
2036                 smb2_util_close(tree2, h2);
2037         }
2038         smb2_util_unlink(tree, fname);
2039         smb2_util_unlink(tree, fname_renamed);
2040
2041         return ret;
2042 }
2043
2044 /*
2045    basic testing of streams calls SMB2
2046 */
2047 struct torture_suite *torture_smb2_streams_init(TALLOC_CTX *ctx)
2048 {
2049         struct torture_suite *suite =
2050                 torture_suite_create(ctx, "streams");
2051
2052         torture_suite_add_1smb2_test(suite, "dir", test_stream_dir);
2053         torture_suite_add_1smb2_test(suite, "io", test_stream_io);
2054         torture_suite_add_1smb2_test(suite, "sharemodes", test_stream_sharemodes);
2055         torture_suite_add_1smb2_test(suite, "names", test_stream_names);
2056         torture_suite_add_1smb2_test(suite, "names2", test_stream_names2);
2057         torture_suite_add_1smb2_test(suite, "names3", test_stream_names3);
2058         torture_suite_add_1smb2_test(suite, "rename", test_stream_rename);
2059         torture_suite_add_1smb2_test(suite, "rename2", test_stream_rename2);
2060         torture_suite_add_1smb2_test(suite, "create-disposition", test_stream_create_disposition);
2061         torture_suite_add_1smb2_test(suite, "attributes", test_stream_attributes);
2062         torture_suite_add_1smb2_test(suite, "delete", test_stream_delete);
2063         torture_suite_add_1smb2_test(suite, "zero-byte", test_zero_byte_stream);
2064         torture_suite_add_1smb2_test(suite, "basefile-rename-with-open-stream",
2065                                         test_basefile_rename_with_open_stream);
2066
2067         suite->description = talloc_strdup(suite, "SMB2-STREAM tests");
2068         return suite;
2069 }