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