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