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