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