ctdb-scripts: Support storing statd-callout state in cluster filesystem
[samba4-gss.git] / source4 / torture / raw / streams.c
blob90531499df3283519c89d5b2562608a6122afcfe
1 /*
2 Unix SMB/CIFS implementation.
4 test alternate data streams
6 Copyright (C) Andrew Tridgell 2004
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.
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.
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/>.
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"
34 #define BASEDIR "\\teststreams"
36 #define CHECK_STATUS(status, correct) \
37 torture_assert_ntstatus_equal_goto(tctx,status,correct,ret,done,"CHECK_STATUS")
39 #define CHECK_VALUE(v, correct) \
40 torture_assert_int_equal(tctx,v,correct,"CHECK_VALUE")
42 #define CHECK_NTTIME(v, correct) \
43 torture_assert_u64_equal(tctx,v,correct,"CHECK_NTTIME")
45 #define CHECK_STR(v, correct) \
46 torture_assert_str_equal(tctx,v,correct,"CHECK_STR")
49 check that a stream has the right contents
51 static bool check_stream(struct smbcli_state *cli, const char *location,
52 TALLOC_CTX *mem_ctx,
53 const char *fname, const char *sname,
54 const char *value)
56 int fnum;
57 const char *full_name;
58 uint8_t *buf;
59 ssize_t ret;
61 full_name = talloc_asprintf(mem_ctx, "%s:%s", fname, sname);
63 fnum = smbcli_open(cli->tree, full_name, O_RDONLY, DENY_NONE);
65 if (value == NULL) {
66 if (fnum != -1) {
67 printf("(%s) should have failed stream open of %s\n",
68 location, full_name);
69 return false;
71 return true;
74 if (fnum == -1) {
75 printf("(%s) Failed to open stream '%s' - %s\n",
76 location, full_name, smbcli_errstr(cli->tree));
77 return false;
80 buf = talloc_array(mem_ctx, uint8_t, strlen(value)+11);
82 ret = smbcli_read(cli->tree, fnum, buf, 0, strlen(value)+11);
83 if (ret != strlen(value)) {
84 printf("(%s) Failed to read %lu bytes from stream '%s' - got %d\n",
85 location, (long)strlen(value), full_name, (int)ret);
86 return false;
89 if (memcmp(buf, value, strlen(value)) != 0) {
90 printf("(%s) Bad data in stream\n", location);
91 return false;
94 smbcli_close(cli->tree, fnum);
95 return true;
98 static int qsort_string(char * const *s1, char * const *s2)
100 return strcmp(*s1, *s2);
103 static int qsort_stream(const struct stream_struct *s1, const struct stream_struct *s2)
105 return strcmp(s1->stream_name.s, s2->stream_name.s);
108 static bool check_stream_list(struct torture_context *tctx,
109 struct smbcli_state *cli, const char *fname,
110 int num_exp, const char **exp)
112 union smb_fileinfo finfo;
113 NTSTATUS status;
114 int i;
115 TALLOC_CTX *tmp_ctx = talloc_new(cli);
116 char **exp_sort;
117 struct stream_struct *stream_sort;
118 bool ret = false;
119 int fail = -1;
121 finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
122 finfo.generic.in.file.path = fname;
124 status = smb_raw_pathinfo(cli->tree, tmp_ctx, &finfo);
125 CHECK_STATUS(status, NT_STATUS_OK);
127 CHECK_VALUE(finfo.stream_info.out.num_streams, num_exp);
129 if (num_exp == 0) {
130 ret = true;
131 goto done;
134 exp_sort = (char **)talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp));
136 if (exp_sort == NULL) {
137 goto done;
140 TYPESAFE_QSORT(exp_sort, num_exp, qsort_string);
142 stream_sort = (struct stream_struct *)talloc_memdup(tmp_ctx,
143 finfo.stream_info.out.streams,
144 finfo.stream_info.out.num_streams *
145 sizeof(*stream_sort));
147 if (stream_sort == NULL) {
148 goto done;
151 TYPESAFE_QSORT(stream_sort, finfo.stream_info.out.num_streams, qsort_stream);
153 for (i=0; i<num_exp; i++) {
154 if (strcmp(exp_sort[i], stream_sort[i].stream_name.s) != 0) {
155 fail = i;
156 goto show_streams;
160 ret = true;
161 done:
162 talloc_free(tmp_ctx);
163 return ret;
165 show_streams:
166 for (i=0; i<num_exp; i++) {
167 torture_comment(tctx, "stream names '%s' '%s'\n",
168 exp_sort[i], stream_sort[i].stream_name.s);
170 CHECK_STR(stream_sort[fail].stream_name.s, exp_sort[fail]);
171 talloc_free(tmp_ctx);
172 return ret;
176 test behavior of streams on directories
178 static bool test_stream_dir(struct torture_context *tctx,
179 struct smbcli_state *cli)
181 NTSTATUS status;
182 union smb_open io;
183 const char *fname = BASEDIR "\\stream.txt";
184 const char *sname1;
185 bool ret = true;
186 const char *basedir_data;
188 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
190 basedir_data = talloc_asprintf(tctx, "%s::$DATA", BASEDIR);
191 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
193 printf("(%s) opening non-existent directory stream\n", __location__);
194 io.generic.level = RAW_OPEN_NTCREATEX;
195 io.ntcreatex.in.root_fid.fnum = 0;
196 io.ntcreatex.in.flags = 0;
197 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
198 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
199 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
200 io.ntcreatex.in.share_access = 0;
201 io.ntcreatex.in.alloc_size = 0;
202 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
203 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
204 io.ntcreatex.in.security_flags = 0;
205 io.ntcreatex.in.fname = sname1;
206 status = smb_raw_open(cli->tree, tctx, &io);
207 CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
209 printf("(%s) opening basedir stream\n", __location__);
210 io.generic.level = RAW_OPEN_NTCREATEX;
211 io.ntcreatex.in.root_fid.fnum = 0;
212 io.ntcreatex.in.flags = 0;
213 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
214 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
215 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
216 io.ntcreatex.in.share_access = 0;
217 io.ntcreatex.in.alloc_size = 0;
218 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
219 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
220 io.ntcreatex.in.security_flags = 0;
221 io.ntcreatex.in.fname = basedir_data;
222 status = smb_raw_open(cli->tree, tctx, &io);
223 CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
225 printf("(%s) opening basedir ::$DATA stream\n", __location__);
226 io.generic.level = RAW_OPEN_NTCREATEX;
227 io.ntcreatex.in.root_fid.fnum = 0;
228 io.ntcreatex.in.flags = 0x10;
229 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
230 io.ntcreatex.in.create_options = 0;
231 io.ntcreatex.in.file_attr = 0;
232 io.ntcreatex.in.share_access = 0;
233 io.ntcreatex.in.alloc_size = 0;
234 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
235 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
236 io.ntcreatex.in.security_flags = 0;
237 io.ntcreatex.in.fname = basedir_data;
238 status = smb_raw_open(cli->tree, tctx, &io);
239 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
241 printf("(%s) list the streams on the basedir\n", __location__);
242 ret &= check_stream_list(tctx, cli, BASEDIR, 0, NULL);
243 done:
244 smbcli_deltree(cli->tree, BASEDIR);
245 return ret;
249 test basic behavior of streams on directories
251 static bool test_stream_io(struct torture_context *tctx,
252 struct smbcli_state *cli)
254 NTSTATUS status;
255 union smb_open io;
256 const char *fname = BASEDIR "\\stream.txt";
257 const char *sname1, *sname2;
258 bool ret = true;
259 int fnum = -1;
260 ssize_t retsize;
262 const char *one[] = { "::$DATA" };
263 const char *two[] = { "::$DATA", ":Second Stream:$DATA" };
264 const char *three[] = { "::$DATA", ":Stream One:$DATA",
265 ":Second Stream:$DATA" };
267 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
269 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
270 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
272 printf("(%s) creating a stream on a non-existent file\n", __location__);
273 io.generic.level = RAW_OPEN_NTCREATEX;
274 io.ntcreatex.in.root_fid.fnum = 0;
275 io.ntcreatex.in.flags = 0;
276 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
277 io.ntcreatex.in.create_options = 0;
278 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
279 io.ntcreatex.in.share_access = 0;
280 io.ntcreatex.in.alloc_size = 0;
281 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
282 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
283 io.ntcreatex.in.security_flags = 0;
284 io.ntcreatex.in.fname = sname1;
285 status = smb_raw_open(cli->tree, tctx, &io);
286 CHECK_STATUS(status, NT_STATUS_OK);
287 fnum = io.ntcreatex.out.file.fnum;
289 ret &= check_stream(cli, __location__, tctx, fname, "Stream One", NULL);
291 printf("(%s) check that open of base file is allowed\n", __location__);
292 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
293 io.ntcreatex.in.fname = fname;
294 status = smb_raw_open(cli->tree, tctx, &io);
295 CHECK_STATUS(status, NT_STATUS_OK);
296 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
298 printf("(%s) writing to stream\n", __location__);
299 retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
300 CHECK_VALUE(retsize, 9);
302 smbcli_close(cli->tree, fnum);
304 ret &= check_stream(cli, __location__, tctx, fname, "Stream One", "test data");
306 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
307 io.ntcreatex.in.fname = sname1;
308 status = smb_raw_open(cli->tree, tctx, &io);
309 CHECK_STATUS(status, NT_STATUS_OK);
310 fnum = io.ntcreatex.out.file.fnum;
312 printf("(%s) modifying stream\n", __location__);
313 retsize = smbcli_write(cli->tree, fnum, 0, "MORE DATA ", 5, 10);
314 CHECK_VALUE(retsize, 10);
316 smbcli_close(cli->tree, fnum);
318 ret &= check_stream(cli, __location__, tctx, fname, "Stream One:$FOO", NULL);
320 printf("(%s) creating a stream2 on a existing file\n", __location__);
321 io.ntcreatex.in.fname = sname2;
322 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
323 status = smb_raw_open(cli->tree, tctx, &io);
324 CHECK_STATUS(status, NT_STATUS_OK);
325 fnum = io.ntcreatex.out.file.fnum;
327 printf("(%s) modifying stream\n", __location__);
328 retsize = smbcli_write(cli->tree, fnum, 0, "SECOND STREAM", 0, 13);
329 CHECK_VALUE(retsize, 13);
331 smbcli_close(cli->tree, fnum);
333 ret &= check_stream(cli, __location__, tctx, fname, "Stream One", "test MORE DATA ");
334 ret &= check_stream(cli, __location__, tctx, fname, "Stream One:$DATA", "test MORE DATA ");
335 ret &= check_stream(cli, __location__, tctx, fname, "Stream One:", NULL);
336 ret &= check_stream(cli, __location__, tctx, fname, "Second Stream", "SECOND STREAM");
337 ret &= check_stream(cli, __location__, tctx, fname,
338 "SECOND STREAM:$DATA", "SECOND STREAM");
339 ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:$DATA", "SECOND STREAM");
340 ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:", NULL);
341 ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:$FOO", NULL);
343 check_stream_list(tctx, cli, fname, 3, three);
345 printf("(%s) deleting stream\n", __location__);
346 status = smbcli_unlink(cli->tree, sname1);
347 CHECK_STATUS(status, NT_STATUS_OK);
349 check_stream_list(tctx, cli, fname, 2, two);
351 printf("(%s) delete a stream via delete-on-close\n", __location__);
352 io.ntcreatex.in.fname = sname2;
353 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
354 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
355 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
356 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
358 status = smb_raw_open(cli->tree, tctx, &io);
359 CHECK_STATUS(status, NT_STATUS_OK);
360 fnum = io.ntcreatex.out.file.fnum;
362 smbcli_close(cli->tree, fnum);
363 status = smbcli_unlink(cli->tree, sname2);
364 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
366 check_stream_list(tctx, cli, fname, 1, one);
368 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
369 io.ntcreatex.in.fname = sname1;
370 status = smb_raw_open(cli->tree, tctx, &io);
371 CHECK_STATUS(status, NT_STATUS_OK);
372 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
373 io.ntcreatex.in.fname = sname2;
374 status = smb_raw_open(cli->tree, tctx, &io);
375 CHECK_STATUS(status, NT_STATUS_OK);
376 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
378 printf("(%s) deleting file\n", __location__);
379 status = smbcli_unlink(cli->tree, fname);
380 CHECK_STATUS(status, NT_STATUS_OK);
382 done:
383 smbcli_close(cli->tree, fnum);
384 smbcli_deltree(cli->tree, BASEDIR);
385 return ret;
389 test stream sharemodes
391 static bool test_stream_sharemodes(struct torture_context *tctx,
392 struct smbcli_state *cli)
394 NTSTATUS status;
395 union smb_open io;
396 const char *fname = BASEDIR "\\stream.txt";
397 const char *sname1, *sname2;
398 bool ret = true;
399 int fnum1 = -1;
400 int fnum2 = -1;
402 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
404 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
405 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
407 printf("(%s) testing stream share mode conflicts\n", __location__);
408 io.generic.level = RAW_OPEN_NTCREATEX;
409 io.ntcreatex.in.root_fid.fnum = 0;
410 io.ntcreatex.in.flags = 0;
411 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
412 io.ntcreatex.in.create_options = 0;
413 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
414 io.ntcreatex.in.share_access = 0;
415 io.ntcreatex.in.alloc_size = 0;
416 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
417 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
418 io.ntcreatex.in.security_flags = 0;
419 io.ntcreatex.in.fname = sname1;
421 status = smb_raw_open(cli->tree, tctx, &io);
422 CHECK_STATUS(status, NT_STATUS_OK);
423 fnum1 = io.ntcreatex.out.file.fnum;
426 * A different stream does not give a sharing violation
429 io.ntcreatex.in.fname = sname2;
430 status = smb_raw_open(cli->tree, tctx, &io);
431 CHECK_STATUS(status, NT_STATUS_OK);
432 fnum2 = io.ntcreatex.out.file.fnum;
435 * ... whereas the same stream does with unchanged access/share_access
436 * flags
439 io.ntcreatex.in.fname = sname1;
440 io.ntcreatex.in.open_disposition = 0;
441 status = smb_raw_open(cli->tree, tctx, &io);
442 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
444 io.ntcreatex.in.fname = sname2;
445 status = smb_raw_open(cli->tree, tctx, &io);
446 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
448 done:
449 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
450 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
451 status = smbcli_unlink(cli->tree, fname);
452 smbcli_deltree(cli->tree, BASEDIR);
453 return ret;
457 * Test FILE_SHARE_DELETE on streams
459 * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
460 * with SEC_STD_DELETE.
462 * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
463 * be opened with SEC_STD_DELETE.
465 * A stream held open with FILE_SHARE_DELETE allows the file to be
466 * deleted. After the main file is deleted, access to the open file descriptor
467 * still works, but all name-based access to both the main file as well as the
468 * stream is denied with DELETE pending.
470 * This means, an open of the main file with SEC_STD_DELETE should walk all
471 * streams and also open them with SEC_STD_DELETE. If any of these opens gives
472 * SHARING_VIOLATION, the main open fails.
474 * Closing the main file after delete_on_close has been set does not really
475 * unlink it but leaves the corresponding share mode entry with
476 * delete_on_close being set around until all streams are closed.
478 * Opening a stream must also look at the main file's share mode entry, look
479 * at the delete_on_close bit and potentially return DELETE_PENDING.
482 static bool test_stream_delete(struct torture_context *tctx,
483 struct smbcli_state *cli)
485 NTSTATUS status;
486 union smb_open io;
487 const char *fname = BASEDIR "\\stream.txt";
488 const char *sname1;
489 bool ret = true;
490 int fnum = -1;
491 uint8_t buf[9];
492 ssize_t retsize;
493 union smb_fileinfo finfo;
495 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
497 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
499 printf("(%s) opening non-existent file stream\n", __location__);
500 io.generic.level = RAW_OPEN_NTCREATEX;
501 io.ntcreatex.in.root_fid.fnum = 0;
502 io.ntcreatex.in.flags = 0;
503 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
504 io.ntcreatex.in.create_options = 0;
505 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
506 io.ntcreatex.in.share_access = 0;
507 io.ntcreatex.in.alloc_size = 0;
508 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
509 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
510 io.ntcreatex.in.security_flags = 0;
511 io.ntcreatex.in.fname = sname1;
513 status = smb_raw_open(cli->tree, tctx, &io);
514 CHECK_STATUS(status, NT_STATUS_OK);
515 fnum = io.ntcreatex.out.file.fnum;
517 retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
518 CHECK_VALUE(retsize, 9);
521 * One stream opened without FILE_SHARE_DELETE prevents the main file
522 * to be deleted or even opened with DELETE access
525 status = smbcli_unlink(cli->tree, fname);
526 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
528 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
529 io.ntcreatex.in.fname = fname;
530 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
531 status = smb_raw_open(cli->tree, tctx, &io);
532 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
534 smbcli_close(cli->tree, fnum);
537 * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
540 io.ntcreatex.in.fname = sname1;
541 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
542 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
543 status = smb_raw_open(cli->tree, tctx, &io);
544 CHECK_STATUS(status, NT_STATUS_OK);
545 fnum = io.ntcreatex.out.file.fnum;
547 status = smbcli_unlink(cli->tree, fname);
548 CHECK_STATUS(status, NT_STATUS_OK);
551 * file access still works on the stream while the main file is closed
554 retsize = smbcli_read(cli->tree, fnum, buf, 0, 9);
555 CHECK_VALUE(retsize, 9);
557 finfo.generic.level = RAW_FILEINFO_STANDARD;
558 finfo.generic.in.file.path = fname;
561 * name-based access to both the main file and the stream does not
562 * work anymore but gives DELETE_PENDING
565 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
566 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
569 * older S3 doesn't do this
571 finfo.generic.in.file.path = sname1;
572 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
573 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
576 * fd-based qfileinfo on the stream still works, the stream does not
577 * have the delete-on-close bit set. This could mean that open on the
578 * stream first opens the main file
581 finfo.all_info.level = RAW_FILEINFO_ALL_INFO;
582 finfo.all_info.in.file.fnum = fnum;
584 status = smb_raw_fileinfo(cli->tree, tctx, &finfo);
585 CHECK_STATUS(status, NT_STATUS_OK);
587 /* w2k and w2k3 return 0 and w2k8 returns 1 */
588 if (TARGET_IS_WINXP(tctx) || TARGET_IS_W2K3(tctx) ||
589 TARGET_IS_SAMBA3(tctx)) {
590 CHECK_VALUE(finfo.all_info.out.delete_pending, 0);
591 } else {
592 CHECK_VALUE(finfo.all_info.out.delete_pending, 1);
595 smbcli_close(cli->tree, fnum);
598 * After closing the stream the file is really gone.
601 finfo.generic.in.file.path = fname;
602 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
603 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
605 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA
606 |SEC_STD_DELETE;
607 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
608 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
609 status = smb_raw_open(cli->tree, tctx, &io);
610 CHECK_STATUS(status, NT_STATUS_OK);
611 fnum = io.ntcreatex.out.file.fnum;
613 finfo.generic.in.file.path = fname;
614 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
615 CHECK_STATUS(status, NT_STATUS_OK);
617 smbcli_close(cli->tree, fnum);
619 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
620 CHECK_STATUS(status, NT_STATUS_OK);
621 done:
622 smbcli_close(cli->tree, fnum);
623 smbcli_unlink(cli->tree, fname);
624 smbcli_deltree(cli->tree, BASEDIR);
625 return ret;
629 test stream names
631 static bool test_stream_names(struct torture_context *tctx,
632 struct smbcli_state *cli)
634 NTSTATUS status;
635 union smb_open io;
636 union smb_fileinfo info;
637 union smb_fileinfo finfo;
638 union smb_fileinfo stinfo;
639 union smb_setfileinfo sinfo;
640 const char *fname = BASEDIR "\\stream_names.txt";
641 const char *sname1, *sname1b, *sname1c, *sname1d;
642 const char *sname2, *snamew, *snamew2;
643 const char *snamer1;
644 bool ret = true;
645 int fnum1 = -1;
646 int fnum2 = -1;
647 int fnum3 = -1;
648 int i;
649 const char *four[4] = {
650 "::$DATA",
651 ":\x05Stream\n One:$DATA",
652 ":MStream Two:$DATA",
653 ":?Stream*:$DATA"
655 const char *five1[5] = {
656 "::$DATA",
657 ":\x05Stream\n One:$DATA",
658 ":BeforeRename:$DATA",
659 ":MStream Two:$DATA",
660 ":?Stream*:$DATA"
662 const char *five2[5] = {
663 "::$DATA",
664 ":\x05Stream\n One:$DATA",
665 ":AfterRename:$DATA",
666 ":MStream Two:$DATA",
667 ":?Stream*:$DATA"
670 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
672 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "\x05Stream\n One");
673 sname1b = talloc_asprintf(tctx, "%s:", sname1);
674 sname1c = talloc_asprintf(tctx, "%s:$FOO", sname1);
675 sname1d = talloc_asprintf(tctx, "%s:?D*a", sname1);
676 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "MStream Two");
677 snamew = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "?Stream*");
678 snamew2 = talloc_asprintf(tctx, "%s\\stream*:%s:$DATA", BASEDIR, "?Stream*");
679 snamer1 = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "BeforeRename");
681 printf("(%s) testing stream names\n", __location__);
682 io.generic.level = RAW_OPEN_NTCREATEX;
683 io.ntcreatex.in.root_fid.fnum = 0;
684 io.ntcreatex.in.flags = 0;
685 io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
686 io.ntcreatex.in.create_options = 0;
687 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
688 io.ntcreatex.in.share_access =
689 NTCREATEX_SHARE_ACCESS_READ |
690 NTCREATEX_SHARE_ACCESS_WRITE;
691 io.ntcreatex.in.alloc_size = 0;
692 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
693 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
694 io.ntcreatex.in.security_flags = 0;
695 io.ntcreatex.in.fname = fname;
697 status = smb_raw_open(cli->tree, tctx, &io);
698 CHECK_STATUS(status, NT_STATUS_OK);
699 fnum1 = io.ntcreatex.out.file.fnum;
701 torture_comment(tctx, "Adding two EAs to base file\n");
702 ZERO_STRUCT(sinfo);
703 sinfo.generic.level = RAW_SFILEINFO_EA_SET;
704 sinfo.generic.in.file.fnum = fnum1;
705 sinfo.ea_set.in.num_eas = 2;
706 sinfo.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 2);
707 sinfo.ea_set.in.eas[0].flags = 0;
708 sinfo.ea_set.in.eas[0].name.s = "EAONE";
709 sinfo.ea_set.in.eas[0].value = data_blob_string_const("VALUE1");
710 sinfo.ea_set.in.eas[1].flags = 0;
711 sinfo.ea_set.in.eas[1].name.s = "SECONDEA";
712 sinfo.ea_set.in.eas[1].value = data_blob_string_const("ValueTwo");
714 status = smb_raw_setfileinfo(cli->tree, &sinfo);
715 CHECK_STATUS(status, NT_STATUS_OK);
718 * Make sure the create time of the streams are different from the
719 * base file.
721 sleep(2);
722 smbcli_close(cli->tree, fnum1);
724 io.generic.level = RAW_OPEN_NTCREATEX;
725 io.ntcreatex.in.root_fid.fnum = 0;
726 io.ntcreatex.in.flags = 0;
727 io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
728 io.ntcreatex.in.create_options = 0;
729 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
730 io.ntcreatex.in.share_access =
731 NTCREATEX_SHARE_ACCESS_READ |
732 NTCREATEX_SHARE_ACCESS_WRITE;
733 io.ntcreatex.in.alloc_size = 0;
734 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
735 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
736 io.ntcreatex.in.security_flags = 0;
737 io.ntcreatex.in.fname = sname1;
739 status = smb_raw_open(cli->tree, tctx, &io);
740 CHECK_STATUS(status, NT_STATUS_OK);
741 fnum1 = io.ntcreatex.out.file.fnum;
743 torture_comment(tctx, "Adding one EAs to first stream file\n");
744 ZERO_STRUCT(sinfo);
745 sinfo.generic.level = RAW_SFILEINFO_EA_SET;
746 sinfo.generic.in.file.fnum = fnum1;
747 sinfo.ea_set.in.num_eas = 1;
748 sinfo.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 1);
749 sinfo.ea_set.in.eas[0].flags = 0;
750 sinfo.ea_set.in.eas[0].name.s = "STREAMEA";
751 sinfo.ea_set.in.eas[0].value = data_blob_string_const("EA_VALUE1");
753 status = smb_raw_setfileinfo(cli->tree, &sinfo);
754 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
756 status = torture_check_ea(cli, sname1, "STREAMEA", "EA_VALUE1");
757 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
759 ZERO_STRUCT(info);
760 info.generic.level = RAW_FILEINFO_ALL_EAS;
761 info.all_eas.in.file.path = sname1;
763 status = smb_raw_pathinfo(cli->tree, tctx, &info);
764 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
767 * A different stream does not give a sharing violation
770 io.ntcreatex.in.fname = sname2;
771 status = smb_raw_open(cli->tree, tctx, &io);
772 CHECK_STATUS(status, NT_STATUS_OK);
773 fnum2 = io.ntcreatex.out.file.fnum;
776 * ... whereas the same stream does with unchanged access/share_access
777 * flags
780 io.ntcreatex.in.fname = sname1;
781 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
782 status = smb_raw_open(cli->tree, tctx, &io);
783 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
785 io.ntcreatex.in.fname = sname1b;
786 status = smb_raw_open(cli->tree, tctx, &io);
787 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
789 io.ntcreatex.in.fname = sname1c;
790 status = smb_raw_open(cli->tree, tctx, &io);
791 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
792 /* w2k returns INVALID_PARAMETER */
793 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
794 } else {
795 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
798 io.ntcreatex.in.fname = sname1d;
799 status = smb_raw_open(cli->tree, tctx, &io);
800 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
801 /* w2k returns INVALID_PARAMETER */
802 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
803 } else {
804 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
807 io.ntcreatex.in.fname = sname2;
808 status = smb_raw_open(cli->tree, tctx, &io);
809 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
811 io.ntcreatex.in.fname = snamew;
812 status = smb_raw_open(cli->tree, tctx, &io);
813 CHECK_STATUS(status, NT_STATUS_OK);
814 fnum3 = io.ntcreatex.out.file.fnum;
816 io.ntcreatex.in.fname = snamew2;
817 status = smb_raw_open(cli->tree, tctx, &io);
818 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
820 ret &= check_stream_list(tctx, cli, fname, 4, four);
822 smbcli_close(cli->tree, fnum1);
823 smbcli_close(cli->tree, fnum2);
824 smbcli_close(cli->tree, fnum3);
826 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
827 finfo.generic.in.file.path = fname;
828 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
829 CHECK_STATUS(status, NT_STATUS_OK);
831 ret &= check_stream_list(tctx, cli, fname, 4, four);
833 for (i=0; i < 4; i++) {
834 NTTIME write_time;
835 uint64_t stream_size;
836 char *path = talloc_asprintf(tctx, "%s%s",
837 fname, four[i]);
839 char *rpath = talloc_strdup(path, path);
840 char *p = strrchr(rpath, ':');
841 /* eat :$DATA */
842 *p = 0;
843 p--;
844 if (*p == ':') {
845 /* eat ::$DATA */
846 *p = 0;
848 printf("(%s): i[%u][%s]\n", __location__, i, path);
849 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
850 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
851 SEC_FILE_WRITE_ATTRIBUTE |
852 SEC_RIGHTS_FILE_ALL;
853 io.ntcreatex.in.fname = path;
854 status = smb_raw_open(cli->tree, tctx, &io);
855 CHECK_STATUS(status, NT_STATUS_OK);
856 fnum1 = io.ntcreatex.out.file.fnum;
858 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
859 finfo.generic.in.file.path = fname;
860 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
861 CHECK_STATUS(status, NT_STATUS_OK);
863 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
864 stinfo.generic.in.file.fnum = fnum1;
865 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
866 CHECK_STATUS(status, NT_STATUS_OK);
867 if (!torture_setting_bool(tctx, "samba3", false)) {
868 CHECK_NTTIME(stinfo.all_info.out.create_time,
869 finfo.all_info.out.create_time);
870 CHECK_NTTIME(stinfo.all_info.out.access_time,
871 finfo.all_info.out.access_time);
872 CHECK_NTTIME(stinfo.all_info.out.write_time,
873 finfo.all_info.out.write_time);
874 CHECK_NTTIME(stinfo.all_info.out.change_time,
875 finfo.all_info.out.change_time);
877 CHECK_VALUE(stinfo.all_info.out.attrib,
878 finfo.all_info.out.attrib);
879 CHECK_VALUE(stinfo.all_info.out.size,
880 finfo.all_info.out.size);
881 CHECK_VALUE(stinfo.all_info.out.delete_pending,
882 finfo.all_info.out.delete_pending);
883 CHECK_VALUE(stinfo.all_info.out.directory,
884 finfo.all_info.out.directory);
885 CHECK_VALUE(stinfo.all_info.out.ea_size,
886 finfo.all_info.out.ea_size);
888 stinfo.generic.level = RAW_FILEINFO_NAME_INFO;
889 stinfo.generic.in.file.fnum = fnum1;
890 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
891 CHECK_STATUS(status, NT_STATUS_OK);
892 if (!torture_setting_bool(tctx, "samba3", false)) {
893 CHECK_STR(stinfo.name_info.out.fname.s, rpath);
896 write_time = finfo.all_info.out.write_time;
897 write_time += i*1000000;
898 write_time /= 1000000;
899 write_time *= 1000000;
901 ZERO_STRUCT(sinfo);
902 sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
903 sinfo.basic_info.in.file.fnum = fnum1;
904 sinfo.basic_info.in.write_time = write_time;
905 sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
906 status = smb_raw_setfileinfo(cli->tree, &sinfo);
907 CHECK_STATUS(status, NT_STATUS_OK);
909 stream_size = i*8192;
911 ZERO_STRUCT(sinfo);
912 sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFO;
913 sinfo.end_of_file_info.in.file.fnum = fnum1;
914 sinfo.end_of_file_info.in.size = stream_size;
915 status = smb_raw_setfileinfo(cli->tree, &sinfo);
916 CHECK_STATUS(status, NT_STATUS_OK);
918 stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
919 stinfo.generic.in.file.fnum = fnum1;
920 status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
921 CHECK_STATUS(status, NT_STATUS_OK);
922 if (!torture_setting_bool(tctx, "samba3", false)) {
923 CHECK_NTTIME(stinfo.all_info.out.write_time,
924 write_time);
925 CHECK_VALUE(stinfo.all_info.out.attrib,
926 finfo.all_info.out.attrib);
928 CHECK_VALUE(stinfo.all_info.out.size,
929 stream_size);
930 CHECK_VALUE(stinfo.all_info.out.delete_pending,
931 finfo.all_info.out.delete_pending);
932 CHECK_VALUE(stinfo.all_info.out.directory,
933 finfo.all_info.out.directory);
934 CHECK_VALUE(stinfo.all_info.out.ea_size,
935 finfo.all_info.out.ea_size);
937 ret &= check_stream_list(tctx, cli, fname, 4, four);
939 smbcli_close(cli->tree, fnum1);
940 talloc_free(path);
943 printf("(%s): testing stream renames\n", __location__);
944 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
945 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
946 SEC_FILE_WRITE_ATTRIBUTE |
947 SEC_RIGHTS_FILE_ALL;
948 io.ntcreatex.in.fname = snamer1;
949 status = smb_raw_open(cli->tree, tctx, &io);
950 CHECK_STATUS(status, NT_STATUS_OK);
951 fnum1 = io.ntcreatex.out.file.fnum;
953 ret &= check_stream_list(tctx, cli, fname, 5, five1);
955 ZERO_STRUCT(sinfo);
956 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
957 sinfo.rename_information.in.file.fnum = fnum1;
958 sinfo.rename_information.in.overwrite = true;
959 sinfo.rename_information.in.root_fid = 0;
960 sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
961 status = smb_raw_setfileinfo(cli->tree, &sinfo);
962 CHECK_STATUS(status, NT_STATUS_OK);
964 ret &= check_stream_list(tctx, cli, fname, 5, five2);
966 ZERO_STRUCT(sinfo);
967 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
968 sinfo.rename_information.in.file.fnum = fnum1;
969 sinfo.rename_information.in.overwrite = false;
970 sinfo.rename_information.in.root_fid = 0;
971 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
972 status = smb_raw_setfileinfo(cli->tree, &sinfo);
973 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
975 ret &= check_stream_list(tctx, cli, fname, 5, five2);
977 ZERO_STRUCT(sinfo);
978 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
979 sinfo.rename_information.in.file.fnum = fnum1;
980 sinfo.rename_information.in.overwrite = true;
981 sinfo.rename_information.in.root_fid = 0;
982 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
983 status = smb_raw_setfileinfo(cli->tree, &sinfo);
984 if (torture_setting_bool(tctx, "samba4", false) ||
985 torture_setting_bool(tctx, "samba3", false)) {
986 /* why should this rename be considered invalid?? */
987 CHECK_STATUS(status, NT_STATUS_OK);
988 ret &= check_stream_list(tctx, cli, fname, 4, four);
989 } else {
990 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
991 ret &= check_stream_list(tctx, cli, fname, 5, five2);
995 /* TODO: we need to test more rename combinations */
997 done:
998 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
999 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
1000 if (fnum3 != -1) smbcli_close(cli->tree, fnum3);
1001 status = smbcli_unlink(cli->tree, fname);
1002 smbcli_deltree(cli->tree, BASEDIR);
1003 return ret;
1007 test stream names
1009 static bool test_stream_names2(struct torture_context *tctx,
1010 struct smbcli_state *cli)
1012 NTSTATUS status;
1013 union smb_open io;
1014 const char *fname = BASEDIR "\\stream_names2.txt";
1015 bool ret = true;
1016 int fnum1 = -1;
1017 uint8_t i;
1019 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1021 printf("(%s) testing stream names\n", __location__);
1022 io.generic.level = RAW_OPEN_NTCREATEX;
1023 io.ntcreatex.in.root_fid.fnum = 0;
1024 io.ntcreatex.in.flags = 0;
1025 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
1026 io.ntcreatex.in.create_options = 0;
1027 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1028 io.ntcreatex.in.share_access = 0;
1029 io.ntcreatex.in.alloc_size = 0;
1030 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1031 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1032 io.ntcreatex.in.security_flags = 0;
1033 io.ntcreatex.in.fname = fname;
1034 status = smb_raw_open(cli->tree, tctx, &io);
1035 CHECK_STATUS(status, NT_STATUS_OK);
1036 fnum1 = io.ntcreatex.out.file.fnum;
1038 for (i=0x01; i < 0x7F; i++) {
1039 char *path = talloc_asprintf(tctx, "%s:Stream%c0x%02X:$DATA",
1040 fname, i, i);
1041 NTSTATUS expected;
1043 switch (i) {
1044 case '/':/*0x2F*/
1045 case ':':/*0x3A*/
1046 case '\\':/*0x5C*/
1047 expected = NT_STATUS_OBJECT_NAME_INVALID;
1048 break;
1049 default:
1050 expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1051 break;
1055 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1056 io.ntcreatex.in.fname = path;
1057 status = smb_raw_open(cli->tree, tctx, &io);
1058 if (!NT_STATUS_EQUAL(status, expected)) {
1059 printf("(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1060 __location__, fname, isprint(i)?(char)i:' ', i,
1061 isprint(i)?"":" (not printable)",
1062 nt_errstr(expected));
1064 CHECK_STATUS(status, expected);
1066 talloc_free(path);
1069 done:
1070 if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
1071 status = smbcli_unlink(cli->tree, fname);
1072 smbcli_deltree(cli->tree, BASEDIR);
1073 return ret;
1076 #define CHECK_CALL_FNUM(call, rightstatus) do { \
1077 sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1078 sfinfo.generic.in.file.fnum = fnum; \
1079 status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
1080 torture_assert_ntstatus_equal_goto(tctx, status, rightstatus, ret, done, #call); \
1081 finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
1082 finfo1.generic.in.file.fnum = fnum; \
1083 status2 = smb_raw_fileinfo(cli->tree, tctx, &finfo1); \
1084 torture_assert_ntstatus_ok_goto(tctx, status2, ret, done, "ALL_INFO"); \
1085 } while (0)
1088 test stream renames
1090 static bool test_stream_rename(struct torture_context *tctx,
1091 struct smbcli_state *cli)
1093 NTSTATUS status, status2;
1094 union smb_open io;
1095 const char *fname = BASEDIR "\\stream_rename.txt";
1096 const char *sname1, *sname2;
1097 union smb_fileinfo finfo1;
1098 union smb_setfileinfo sfinfo;
1099 bool ret = true;
1100 int fnum = -1;
1102 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1104 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
1105 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
1107 printf("(%s) testing stream renames\n", __location__);
1108 io.generic.level = RAW_OPEN_NTCREATEX;
1109 io.ntcreatex.in.root_fid.fnum = 0;
1110 io.ntcreatex.in.flags = 0;
1111 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1112 SEC_FILE_WRITE_ATTRIBUTE |
1113 SEC_RIGHTS_FILE_ALL;
1114 io.ntcreatex.in.create_options = 0;
1115 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1116 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1117 io.ntcreatex.in.alloc_size = 0;
1118 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1119 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1120 io.ntcreatex.in.security_flags = 0;
1121 io.ntcreatex.in.fname = sname1;
1123 /* Create two streams. */
1124 status = smb_raw_open(cli->tree, tctx, &io);
1125 CHECK_STATUS(status, NT_STATUS_OK);
1126 fnum = io.ntcreatex.out.file.fnum;
1127 if (fnum != -1) smbcli_close(cli->tree, fnum);
1129 io.ntcreatex.in.fname = sname2;
1130 status = smb_raw_open(cli->tree, tctx, &io);
1131 CHECK_STATUS(status, NT_STATUS_OK);
1132 fnum = io.ntcreatex.out.file.fnum;
1134 if (fnum != -1) smbcli_close(cli->tree, fnum);
1137 * Open the second stream.
1140 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1141 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1142 status = smb_raw_open(cli->tree, tctx, &io);
1143 CHECK_STATUS(status, NT_STATUS_OK);
1144 fnum = io.ntcreatex.out.file.fnum;
1147 * Now rename the second stream onto the first.
1150 ZERO_STRUCT(sfinfo);
1152 sfinfo.rename_information.in.overwrite = 1;
1153 sfinfo.rename_information.in.root_fid = 0;
1154 sfinfo.rename_information.in.new_name = ":Stream One";
1155 CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1157 done:
1158 if (fnum != -1) smbcli_close(cli->tree, fnum);
1159 status = smbcli_unlink(cli->tree, fname);
1160 smbcli_deltree(cli->tree, BASEDIR);
1161 return ret;
1164 static bool test_stream_rename2(struct torture_context *tctx,
1165 struct smbcli_state *cli)
1167 NTSTATUS status;
1168 union smb_open io;
1169 const char *fname1 = BASEDIR "\\stream.txt";
1170 const char *fname2 = BASEDIR "\\stream2.txt";
1171 const char *stream_name1 = ":Stream One:$DATA";
1172 const char *stream_name2 = ":Stream Two:$DATA";
1173 const char *stream_name_default = "::$DATA";
1174 const char *sname1;
1175 const char *sname2;
1176 bool ret = true;
1177 int fnum = -1;
1178 union smb_setfileinfo sinfo;
1179 union smb_rename rio;
1181 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1183 sname1 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream One");
1184 sname2 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream Two");
1186 io.generic.level = RAW_OPEN_NTCREATEX;
1187 io.ntcreatex.in.root_fid.fnum = 0;
1188 io.ntcreatex.in.flags = 0;
1189 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1190 SEC_STD_DELETE|SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1191 io.ntcreatex.in.create_options = 0;
1192 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1193 io.ntcreatex.in.share_access = (NTCREATEX_SHARE_ACCESS_READ |
1194 NTCREATEX_SHARE_ACCESS_WRITE |
1195 NTCREATEX_SHARE_ACCESS_DELETE);
1196 io.ntcreatex.in.alloc_size = 0;
1197 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1198 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1199 io.ntcreatex.in.security_flags = 0;
1200 io.ntcreatex.in.fname = sname1;
1202 /* Open/create new stream. */
1203 status = smb_raw_open(cli->tree, tctx, &io);
1204 CHECK_STATUS(status, NT_STATUS_OK);
1206 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1209 * Check raw rename with <base>:<stream>.
1211 printf("(%s) Checking NTRENAME of a stream using <base>:<stream>\n",
1212 __location__);
1213 rio.generic.level = RAW_RENAME_NTRENAME;
1214 rio.ntrename.in.old_name = sname1;
1215 rio.ntrename.in.new_name = sname2;
1216 rio.ntrename.in.attrib = 0;
1217 rio.ntrename.in.cluster_size = 0;
1218 rio.ntrename.in.flags = RENAME_FLAG_RENAME;
1219 status = smb_raw_rename(cli->tree, &rio);
1220 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1223 * Check raw rename to the default stream using :<stream>.
1225 printf("(%s) Checking NTRENAME to default stream using :<stream>\n",
1226 __location__);
1227 rio.ntrename.in.new_name = stream_name_default;
1228 status = smb_raw_rename(cli->tree, &rio);
1229 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
1232 * Check raw rename using :<stream>.
1234 printf("(%s) Checking NTRENAME of a stream using :<stream>\n",
1235 __location__);
1236 rio.ntrename.in.new_name = stream_name2;
1237 status = smb_raw_rename(cli->tree, &rio);
1238 CHECK_STATUS(status, NT_STATUS_OK);
1241 * Check raw rename of a stream to a file.
1243 printf("(%s) Checking NTRENAME of a stream to a file\n",
1244 __location__);
1245 rio.ntrename.in.old_name = sname2;
1246 rio.ntrename.in.new_name = fname2;
1247 status = smb_raw_rename(cli->tree, &rio);
1248 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1251 * Check raw rename of a file to a stream.
1253 printf("(%s) Checking NTRENAME of a file to a stream\n",
1254 __location__);
1256 /* Create the file. */
1257 io.ntcreatex.in.fname = fname2;
1258 status = smb_raw_open(cli->tree, tctx, &io);
1259 CHECK_STATUS(status, NT_STATUS_OK);
1260 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1262 /* Try the rename. */
1263 rio.ntrename.in.old_name = fname2;
1264 rio.ntrename.in.new_name = sname1;
1265 status = smb_raw_rename(cli->tree, &rio);
1266 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
1269 * Reopen the stream for trans2 renames.
1271 io.ntcreatex.in.fname = sname2;
1272 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1273 status = smb_raw_open(cli->tree, tctx, &io);
1274 CHECK_STATUS(status, NT_STATUS_OK);
1275 fnum = io.ntcreatex.out.file.fnum;
1278 * Check trans2 rename of a stream using :<stream>.
1280 printf("(%s) Checking trans2 rename of a stream using :<stream>\n",
1281 __location__);
1282 ZERO_STRUCT(sinfo);
1283 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1284 sinfo.rename_information.in.file.fnum = fnum;
1285 sinfo.rename_information.in.overwrite = 1;
1286 sinfo.rename_information.in.root_fid = 0;
1287 sinfo.rename_information.in.new_name = stream_name1;
1288 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1289 CHECK_STATUS(status, NT_STATUS_OK);
1292 * Check trans2 rename of an overwriting stream using :<stream>.
1294 printf("(%s) Checking trans2 rename of an overwriting stream using "
1295 ":<stream>\n", __location__);
1297 /* Create second stream. */
1298 io.ntcreatex.in.fname = sname2;
1299 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1300 status = smb_raw_open(cli->tree, tctx, &io);
1301 CHECK_STATUS(status, NT_STATUS_OK);
1302 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1304 /* Rename the first stream onto the second. */
1305 sinfo.rename_information.in.file.fnum = fnum;
1306 sinfo.rename_information.in.new_name = stream_name2;
1307 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1308 CHECK_STATUS(status, NT_STATUS_OK);
1310 smbcli_close(cli->tree, fnum);
1313 * Reopen the stream with the new name.
1315 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1316 io.ntcreatex.in.fname = sname2;
1317 status = smb_raw_open(cli->tree, tctx, &io);
1318 CHECK_STATUS(status, NT_STATUS_OK);
1319 fnum = io.ntcreatex.out.file.fnum;
1322 * Check trans2 rename of a stream using <base>:<stream>.
1324 printf("(%s) Checking trans2 rename of a stream using "
1325 "<base>:<stream>\n", __location__);
1326 sinfo.rename_information.in.file.fnum = fnum;
1327 sinfo.rename_information.in.new_name = sname1;
1328 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1329 CHECK_STATUS(status, NT_STATUS_NOT_SUPPORTED);
1332 * Samba3 doesn't currently support renaming a stream to the default
1333 * stream. This test does pass on windows.
1335 if (torture_setting_bool(tctx, "samba3", false) ||
1336 torture_setting_bool(tctx, "samba4", false)) {
1337 goto done;
1341 * Check trans2 rename to the default stream using :<stream>.
1343 printf("(%s) Checking trans2 rename to defaualt stream using "
1344 ":<stream>\n", __location__);
1345 sinfo.rename_information.in.file.fnum = fnum;
1346 sinfo.rename_information.in.new_name = stream_name_default;
1347 status = smb_raw_setfileinfo(cli->tree, &sinfo);
1348 CHECK_STATUS(status, NT_STATUS_OK);
1350 smbcli_close(cli->tree, fnum);
1352 done:
1353 smbcli_close(cli->tree, fnum);
1354 status = smbcli_unlink(cli->tree, fname1);
1355 status = smbcli_unlink(cli->tree, fname2);
1356 smbcli_deltree(cli->tree, BASEDIR);
1357 return ret;
1361 test stream renames
1363 static bool test_stream_rename3(struct torture_context *tctx,
1364 struct smbcli_state *cli)
1366 NTSTATUS status, status2;
1367 union smb_open io;
1368 const char *fname = BASEDIR "\\stream_rename.txt";
1369 const char *sname1, *sname2;
1370 union smb_fileinfo finfo1;
1371 union smb_setfileinfo sfinfo;
1372 bool ret = true;
1373 int fnum = -1;
1374 int fnum2 = -1;
1376 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1378 sname1 = talloc_asprintf(tctx, "%s:%s", fname, "MStream Two:$DATA");
1379 sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
1381 printf("(%s) testing stream renames\n", __location__);
1382 io.generic.level = RAW_OPEN_NTCREATEX;
1383 io.ntcreatex.in.root_fid.fnum = 0;
1384 io.ntcreatex.in.flags = 0;
1385 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
1386 SEC_FILE_WRITE_ATTRIBUTE |
1387 SEC_RIGHTS_FILE_ALL;
1388 io.ntcreatex.in.create_options = 0;
1389 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1390 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1391 NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
1392 io.ntcreatex.in.alloc_size = 0;
1393 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1394 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1395 io.ntcreatex.in.security_flags = 0;
1396 io.ntcreatex.in.fname = sname1;
1398 /* Create two streams. */
1399 status = smb_raw_open(cli->tree, tctx, &io);
1400 CHECK_STATUS(status, NT_STATUS_OK);
1401 fnum = io.ntcreatex.out.file.fnum;
1402 if (fnum != -1) smbcli_close(cli->tree, fnum);
1404 io.ntcreatex.in.fname = sname2;
1405 status = smb_raw_open(cli->tree, tctx, &io);
1406 CHECK_STATUS(status, NT_STATUS_OK);
1407 fnum = io.ntcreatex.out.file.fnum;
1409 if (fnum != -1) smbcli_close(cli->tree, fnum);
1411 /* open the second stream. */
1412 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1413 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1414 status = smb_raw_open(cli->tree, tctx, &io);
1415 CHECK_STATUS(status, NT_STATUS_OK);
1416 fnum = io.ntcreatex.out.file.fnum;
1418 /* Keep a handle to the first stream open. */
1419 io.ntcreatex.in.fname = sname1;
1420 io.ntcreatex.in.access_mask = SEC_STD_DELETE;
1421 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1422 status = smb_raw_open(cli->tree, tctx, &io);
1423 CHECK_STATUS(status, NT_STATUS_OK);
1424 fnum2 = io.ntcreatex.out.file.fnum;
1426 ZERO_STRUCT(sfinfo);
1427 sfinfo.rename_information.in.overwrite = 1;
1428 sfinfo.rename_information.in.root_fid = 0;
1429 sfinfo.rename_information.in.new_name = ":MStream Two:$DATA";
1430 if (torture_setting_bool(tctx, "samba4", false) ||
1431 torture_setting_bool(tctx, "samba3", false)) {
1432 CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
1433 } else {
1434 CHECK_CALL_FNUM(RENAME_INFORMATION,
1435 NT_STATUS_INVALID_PARAMETER);
1439 done:
1440 if (fnum != -1) smbcli_close(cli->tree, fnum);
1441 if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
1442 status = smbcli_unlink(cli->tree, fname);
1443 smbcli_deltree(cli->tree, BASEDIR);
1444 return ret;
1447 static bool create_file_with_stream(struct torture_context *tctx,
1448 struct smbcli_state *cli,
1449 const char *stream)
1451 NTSTATUS status;
1452 bool ret = true;
1453 union smb_open io;
1455 ZERO_STRUCT(io);
1457 /* Create a file with a stream */
1458 io.generic.level = RAW_OPEN_NTCREATEX;
1459 io.ntcreatex.in.root_fid.fnum = 0;
1460 io.ntcreatex.in.flags = 0;
1461 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1462 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1463 io.ntcreatex.in.create_options = 0;
1464 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1465 io.ntcreatex.in.share_access = 0;
1466 io.ntcreatex.in.alloc_size = 0;
1467 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1468 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1469 io.ntcreatex.in.security_flags = 0;
1470 io.ntcreatex.in.fname = stream;
1472 status = smb_raw_open(cli->tree, tctx, &io);
1473 CHECK_STATUS(status, NT_STATUS_OK);
1475 done:
1476 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1477 return ret;
1480 /* Test how streams interact with create dispositions */
1481 static bool test_stream_create_disposition(struct torture_context *tctx,
1482 struct smbcli_state *cli)
1484 NTSTATUS status;
1485 union smb_open io;
1486 const char *fname = BASEDIR "\\stream.txt";
1487 const char *stream = "Stream One:$DATA";
1488 const char *fname_stream;
1489 const char *default_stream_name = "::$DATA";
1490 const char *stream_list[2];
1491 bool ret = false;
1492 int fnum = -1;
1494 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1496 fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1498 stream_list[0] = talloc_asprintf(tctx, ":%s", stream);
1499 stream_list[1] = default_stream_name;
1501 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1502 goto done;
1505 /* Open the base file with OPEN */
1506 io.generic.level = RAW_OPEN_NTCREATEX;
1507 io.ntcreatex.in.root_fid.fnum = 0;
1508 io.ntcreatex.in.flags = 0;
1509 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1510 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
1511 io.ntcreatex.in.create_options = 0;
1512 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1513 io.ntcreatex.in.share_access = 0;
1514 io.ntcreatex.in.alloc_size = 0;
1515 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1516 io.ntcreatex.in.security_flags = 0;
1517 io.ntcreatex.in.fname = fname;
1520 * check ntcreatex open: sanity check
1522 printf("(%s) Checking ntcreatex disp: open\n", __location__);
1523 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1524 status = smb_raw_open(cli->tree, tctx, &io);
1525 CHECK_STATUS(status, NT_STATUS_OK);
1526 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1527 if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
1528 goto done;
1532 * check ntcreatex overwrite
1534 printf("(%s) Checking ntcreatex disp: overwrite\n", __location__);
1535 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
1536 status = smb_raw_open(cli->tree, tctx, &io);
1537 CHECK_STATUS(status, NT_STATUS_OK);
1538 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1539 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1540 goto done;
1544 * check ntcreatex overwrite_if
1546 printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__);
1547 smbcli_unlink(cli->tree, fname);
1548 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1549 goto done;
1552 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1553 status = smb_raw_open(cli->tree, tctx, &io);
1554 CHECK_STATUS(status, NT_STATUS_OK);
1555 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1556 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1557 goto done;
1561 * check ntcreatex supersede
1563 printf("(%s) Checking ntcreatex disp: supersede\n", __location__);
1564 smbcli_unlink(cli->tree, fname);
1565 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1566 goto done;
1569 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
1570 status = smb_raw_open(cli->tree, tctx, &io);
1571 CHECK_STATUS(status, NT_STATUS_OK);
1572 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1573 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1574 goto done;
1578 * check ntcreatex overwrite_if on a stream.
1580 printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
1581 __location__);
1582 smbcli_unlink(cli->tree, fname);
1583 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1584 goto done;
1587 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1588 io.ntcreatex.in.fname = fname_stream;
1589 status = smb_raw_open(cli->tree, tctx, &io);
1590 CHECK_STATUS(status, NT_STATUS_OK);
1591 smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
1592 if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
1593 goto done;
1597 * check openx overwrite_if
1599 printf("(%s) Checking openx disp: overwrite_if\n", __location__);
1600 smbcli_unlink(cli->tree, fname);
1601 if (!create_file_with_stream(tctx, cli, fname_stream)) {
1602 goto done;
1605 io.openx.level = RAW_OPEN_OPENX;
1606 io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
1607 io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPEN_FLAGS_DENY_NONE;
1608 io.openx.in.search_attrs = 0;
1609 io.openx.in.file_attrs = 0;
1610 io.openx.in.write_time = 0;
1611 io.openx.in.size = 1024*1024;
1612 io.openx.in.timeout = 0;
1613 io.openx.in.fname = fname;
1615 io.openx.in.open_func = OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE;
1616 status = smb_raw_open(cli->tree, tctx, &io);
1617 CHECK_STATUS(status, NT_STATUS_OK);
1618 smbcli_close(cli->tree, io.openx.out.file.fnum);
1619 if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
1620 goto done;
1623 ret = true;
1625 done:
1626 smbcli_close(cli->tree, fnum);
1627 smbcli_unlink(cli->tree, fname);
1628 smbcli_deltree(cli->tree, BASEDIR);
1629 return ret;
1632 #if 0
1633 /* Test streaminfo with enough streams on a file to fill up the buffer. */
1634 static bool test_stream_large_streaminfo(struct torture_context *tctx,
1635 struct smbcli_state *cli)
1637 #define LONG_STREAM_SIZE 2
1638 char *lstream_name;
1639 const char *fname = BASEDIR "\\stream.txt";
1640 const char *fname_stream;
1641 NTSTATUS status;
1642 bool ret = true;
1643 int i;
1644 union smb_fileinfo finfo;
1646 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1648 lstream_name = talloc_array(tctx, char, LONG_STREAM_SIZE);
1650 for (i = 0; i < LONG_STREAM_SIZE - 1; i++) {
1651 lstream_name[i] = (char)('a' + i%26);
1653 lstream_name[LONG_STREAM_SIZE - 1] = '\0';
1655 torture_comment(tctx, "(%s) Creating a file with a lot of streams\n", __location__);
1656 for (i = 0; i < 10000; i++) {
1657 fname_stream = talloc_asprintf(tctx, "%s:%s%d", fname,
1658 lstream_name, i);
1659 ret = create_file_with_stream(tctx, cli, fname_stream);
1660 if (!ret) {
1661 goto done;
1665 finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
1666 finfo.generic.in.file.path = fname;
1668 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1669 CHECK_STATUS(status, STATUS_BUFFER_OVERFLOW);
1671 done:
1672 smbcli_unlink(cli->tree, fname);
1673 smbcli_deltree(cli->tree, BASEDIR);
1674 return ret;
1676 #endif
1678 /* Test the effect of setting attributes on a stream. */
1679 static bool test_stream_attributes(struct torture_context *tctx,
1680 struct smbcli_state *cli)
1682 bool ret = true;
1683 NTSTATUS status;
1684 union smb_open io;
1685 const char *fname = BASEDIR "\\stream_attr.txt";
1686 const char *stream = "Stream One:$DATA";
1687 const char *fname_stream;
1688 int fnum = -1;
1689 union smb_fileinfo finfo;
1690 union smb_setfileinfo sfinfo;
1691 time_t basetime = (time(NULL) - 86400) & ~1;
1693 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1695 torture_comment(tctx, "(%s) testing attribute setting on stream\n", __location__);
1697 fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1699 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1700 ret = create_file_with_stream(tctx, cli, fname_stream);
1701 if (!ret) {
1702 goto done;
1705 ZERO_STRUCT(finfo);
1706 finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1707 finfo.generic.in.file.path = fname;
1708 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1709 CHECK_STATUS(status, NT_STATUS_OK);
1711 torture_assert_int_equal_goto(tctx, finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, FILE_ATTRIBUTE_ARCHIVE, ret, done, "attrib incorrect");
1713 /* Now open the stream name. */
1715 io.generic.level = RAW_OPEN_NTCREATEX;
1716 io.ntcreatex.in.root_fid.fnum = 0;
1717 io.ntcreatex.in.flags = 0;
1718 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1719 SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL|SEC_FILE_WRITE_ATTRIBUTE);
1720 io.ntcreatex.in.create_options = 0;
1721 io.ntcreatex.in.file_attr = 0;
1722 io.ntcreatex.in.share_access = 0;
1723 io.ntcreatex.in.alloc_size = 0;
1724 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1725 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1726 io.ntcreatex.in.security_flags = 0;
1727 io.ntcreatex.in.fname = fname_stream;
1729 status = smb_raw_open(cli->tree, tctx, &io);
1730 CHECK_STATUS(status, NT_STATUS_OK);
1732 fnum = io.ntcreatex.out.file.fnum;
1734 /* Change the attributes + time on the stream fnum. */
1735 ZERO_STRUCT(sfinfo);
1736 sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
1737 unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
1739 sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1740 sfinfo.generic.in.file.fnum = fnum;
1741 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
1742 torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "smb_raw_setfileinfo failed");
1744 smbcli_close(cli->tree, fnum);
1745 fnum = -1;
1747 ZERO_STRUCT(finfo);
1748 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
1749 finfo.generic.in.file.path = fname;
1750 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1751 torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "smb_raw_pathinfo failed");
1753 torture_assert_int_equal_goto(tctx, finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, FILE_ATTRIBUTE_READONLY, ret, done, "attrib incorrect");
1755 torture_assert_int_equal_goto(tctx, nt_time_to_unix(finfo.all_info.out.write_time), basetime, ret, done, "time incorrect");
1757 done:
1759 if (fnum != -1) {
1760 smbcli_close(cli->tree, fnum);
1762 smbcli_unlink(cli->tree, fname);
1763 smbcli_deltree(cli->tree, BASEDIR);
1764 return ret;
1768 * A rough approximation of how a windows client creates the streams for use
1769 * in the summary tab.
1771 static bool test_stream_summary_tab(struct torture_context *tctx,
1772 struct smbcli_state *cli)
1774 bool ret = true;
1775 NTSTATUS status;
1776 union smb_open io;
1777 const char *fname = BASEDIR "\\stream_summary.txt";
1778 const char *stream = ":\005SummaryInformation:$DATA";
1779 const char *fname_stream = NULL;
1780 const char *tmp_stream = ":Updt_\005SummaryInformation:$DATA";
1781 const char *fname_tmp_stream = NULL;
1782 int fnum = -1;
1783 union smb_fileinfo finfo;
1784 union smb_rename rio;
1785 ssize_t retsize;
1787 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1789 fname_stream = talloc_asprintf(tctx, "%s%s", fname, stream);
1790 fname_tmp_stream = talloc_asprintf(tctx, "%s%s", fname,
1791 tmp_stream);
1793 /* Create summary info stream */
1794 ret = create_file_with_stream(tctx, cli, fname_stream);
1795 if (!ret) {
1796 goto done;
1799 /* Create summary info tmp update stream */
1800 ret = create_file_with_stream(tctx, cli, fname_tmp_stream);
1801 if (!ret) {
1802 goto done;
1805 /* Open tmp stream and write to it */
1806 io.generic.level = RAW_OPEN_NTCREATEX;
1807 io.ntcreatex.in.root_fid.fnum = 0;
1808 io.ntcreatex.in.flags = 0;
1809 io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
1810 io.ntcreatex.in.create_options = 0;
1811 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1812 io.ntcreatex.in.share_access = 0;
1813 io.ntcreatex.in.alloc_size = 0;
1814 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1815 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1816 io.ntcreatex.in.security_flags = 0;
1817 io.ntcreatex.in.fname = fname_tmp_stream;
1819 status = smb_raw_open(cli->tree, tctx, &io);
1820 CHECK_STATUS(status, NT_STATUS_OK);
1821 fnum = io.ntcreatex.out.file.fnum;
1823 retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
1824 CHECK_VALUE(retsize, 9);
1826 /* close the tmp stream. */
1827 smbcli_close(cli->tree, fnum);
1828 fnum = -1;
1830 /* Delete the current stream */
1831 smbcli_unlink(cli->tree, fname_stream);
1833 /* Do the rename. */
1834 rio.generic.level = RAW_RENAME_RENAME;
1835 rio.rename.in.pattern1 = fname_tmp_stream;
1836 rio.rename.in.pattern2 = stream;
1837 rio.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM |
1838 FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1839 status = smb_raw_rename(cli->tree, &rio);
1840 CHECK_STATUS(status, NT_STATUS_OK);
1842 /* Try to open the tmp stream that we just renamed away. */
1843 status = smb_raw_open(cli->tree, tctx, &io);
1844 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1846 /* Query the base file to make sure it's still there. */
1847 finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1848 finfo.generic.in.file.path = fname;
1850 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1851 CHECK_STATUS(status, NT_STATUS_OK);
1853 done:
1855 if (fnum != -1) {
1856 smbcli_close(cli->tree, fnum);
1858 smbcli_unlink(cli->tree, fname);
1860 smbcli_deltree(cli->tree, BASEDIR);
1861 return ret;
1864 /* Test how streams interact with base file permissions */
1865 /* Regression test for bug:
1866 https://bugzilla.samba.org/show_bug.cgi?id=10229
1867 bug #10229 - No access check verification on stream files.
1869 static bool test_stream_permissions(struct torture_context *tctx,
1870 struct smbcli_state *cli)
1872 NTSTATUS status;
1873 bool ret = true;
1874 union smb_open io;
1875 const char *fname = BASEDIR "\\stream_permissions.txt";
1876 const char *stream = "Stream One:$DATA";
1877 const char *fname_stream;
1878 union smb_fileinfo finfo;
1879 union smb_setfileinfo sfinfo;
1880 int fnum = -1;
1881 union smb_fileinfo q;
1882 union smb_setfileinfo set;
1883 struct security_ace ace = {};
1884 struct security_descriptor *sd;
1886 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
1887 "Failed to setup up test directory: " BASEDIR);
1889 torture_comment(tctx, "(%s) testing permissions on streams\n", __location__);
1891 fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
1893 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1894 ret = create_file_with_stream(tctx, cli, fname_stream);
1895 if (!ret) {
1896 goto done;
1899 ZERO_STRUCT(finfo);
1900 finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
1901 finfo.generic.in.file.path = fname;
1902 status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
1903 CHECK_STATUS(status, NT_STATUS_OK);
1905 torture_assert_int_equal_goto(tctx,
1906 finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED,
1907 FILE_ATTRIBUTE_ARCHIVE, ret, done, "attrib incorrect");
1909 /* Change the attributes on the base file name. */
1910 ZERO_STRUCT(sfinfo);
1911 sfinfo.generic.level = RAW_SFILEINFO_SETATTR;
1912 sfinfo.generic.in.file.path = fname;
1913 sfinfo.setattr.in.attrib = FILE_ATTRIBUTE_READONLY;
1915 status = smb_raw_setpathinfo(cli->tree, &sfinfo);
1916 CHECK_STATUS(status, NT_STATUS_OK);
1918 /* Try and open the stream name for WRITE_DATA. Should
1919 fail with ACCESS_DENIED. */
1921 ZERO_STRUCT(io);
1922 io.generic.level = RAW_OPEN_NTCREATEX;
1923 io.ntcreatex.in.root_fid.fnum = 0;
1924 io.ntcreatex.in.flags = 0;
1925 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
1926 io.ntcreatex.in.create_options = 0;
1927 io.ntcreatex.in.file_attr = 0;
1928 io.ntcreatex.in.share_access = 0;
1929 io.ntcreatex.in.alloc_size = 0;
1930 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1931 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1932 io.ntcreatex.in.security_flags = 0;
1933 io.ntcreatex.in.fname = fname_stream;
1935 status = smb_raw_open(cli->tree, tctx, &io);
1936 CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1938 /* Change the attributes on the base file back. */
1939 ZERO_STRUCT(sfinfo);
1940 sfinfo.generic.level = RAW_SFILEINFO_SETATTR;
1941 sfinfo.generic.in.file.path = fname;
1942 sfinfo.setattr.in.attrib = 0;
1944 status = smb_raw_setpathinfo(cli->tree, &sfinfo);
1945 CHECK_STATUS(status, NT_STATUS_OK);
1947 /* Re-open the file name. */
1949 ZERO_STRUCT(io);
1950 io.generic.level = RAW_OPEN_NTCREATEX;
1951 io.ntcreatex.in.root_fid.fnum = 0;
1952 io.ntcreatex.in.flags = 0;
1953 io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
1954 SEC_STD_READ_CONTROL|SEC_STD_WRITE_DAC|
1955 SEC_FILE_WRITE_ATTRIBUTE);
1956 io.ntcreatex.in.create_options = 0;
1957 io.ntcreatex.in.file_attr = 0;
1958 io.ntcreatex.in.share_access = 0;
1959 io.ntcreatex.in.alloc_size = 0;
1960 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1961 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1962 io.ntcreatex.in.security_flags = 0;
1963 io.ntcreatex.in.fname = fname;
1965 status = smb_raw_open(cli->tree, tctx, &io);
1966 CHECK_STATUS(status, NT_STATUS_OK);
1968 fnum = io.ntcreatex.out.file.fnum;
1970 /* Get the existing security descriptor. */
1971 ZERO_STRUCT(q);
1972 q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
1973 q.query_secdesc.in.file.fnum = fnum;
1974 q.query_secdesc.in.secinfo_flags =
1975 SECINFO_OWNER |
1976 SECINFO_GROUP |
1977 SECINFO_DACL;
1978 status = smb_raw_fileinfo(cli->tree, tctx, &q);
1979 CHECK_STATUS(status, NT_STATUS_OK);
1980 sd = q.query_secdesc.out.sd;
1982 /* Now add a DENY WRITE security descriptor for Everyone. */
1983 torture_comment(tctx, "add a new ACE to the DACL\n");
1985 ace.type = SEC_ACE_TYPE_ACCESS_DENIED;
1986 ace.flags = 0;
1987 ace.access_mask = SEC_FILE_WRITE_DATA;
1988 ace.trustee = global_sid_World;
1990 status = security_descriptor_dacl_add(sd, &ace);
1991 CHECK_STATUS(status, NT_STATUS_OK);
1993 /* security_descriptor_dacl_add adds to the *end* of
1994 the ace array, we need it at the start. Swap.. */
1995 ace = sd->dacl->aces[0];
1996 sd->dacl->aces[0] = sd->dacl->aces[sd->dacl->num_aces-1];
1997 sd->dacl->aces[sd->dacl->num_aces-1] = ace;
1999 ZERO_STRUCT(set);
2000 set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
2001 set.set_secdesc.in.file.fnum = fnum;
2002 set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
2003 set.set_secdesc.in.sd = sd;
2005 status = smb_raw_setfileinfo(cli->tree, &set);
2006 CHECK_STATUS(status, NT_STATUS_OK);
2008 smbcli_close(cli->tree, fnum);
2009 fnum = -1;
2011 /* Try and open the stream name for WRITE_DATA. Should
2012 fail with ACCESS_DENIED. */
2014 ZERO_STRUCT(io);
2015 io.generic.level = RAW_OPEN_NTCREATEX;
2016 io.ntcreatex.in.root_fid.fnum = 0;
2017 io.ntcreatex.in.flags = 0;
2018 io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
2019 io.ntcreatex.in.create_options = 0;
2020 io.ntcreatex.in.file_attr = 0;
2021 io.ntcreatex.in.share_access = 0;
2022 io.ntcreatex.in.alloc_size = 0;
2023 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
2024 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
2025 io.ntcreatex.in.security_flags = 0;
2026 io.ntcreatex.in.fname = fname_stream;
2028 status = smb_raw_open(cli->tree, tctx, &io);
2029 CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
2031 done:
2033 if (fnum != -1) {
2034 smbcli_close(cli->tree, fnum);
2036 smbcli_unlink(cli->tree, fname);
2038 smbcli_deltree(cli->tree, BASEDIR);
2039 return ret;
2043 basic testing of streams calls
2045 struct torture_suite *torture_raw_streams(TALLOC_CTX *tctx)
2047 struct torture_suite *suite = torture_suite_create(tctx, "streams");
2049 torture_suite_add_1smb_test(suite, "dir", test_stream_dir);
2050 torture_suite_add_1smb_test(suite, "io", test_stream_io);
2051 torture_suite_add_1smb_test(suite, "sharemodes", test_stream_sharemodes);
2052 torture_suite_add_1smb_test(suite, "delete", test_stream_delete);
2053 torture_suite_add_1smb_test(suite, "names", test_stream_names);
2054 torture_suite_add_1smb_test(suite, "names2", test_stream_names2);
2055 torture_suite_add_1smb_test(suite, "rename", test_stream_rename);
2056 torture_suite_add_1smb_test(suite, "rename2", test_stream_rename2);
2057 torture_suite_add_1smb_test(suite, "rename3", test_stream_rename3);
2058 torture_suite_add_1smb_test(suite, "createdisp",
2059 test_stream_create_disposition);
2060 torture_suite_add_1smb_test(suite, "attr", test_stream_attributes);
2061 torture_suite_add_1smb_test(suite, "sumtab", test_stream_summary_tab);
2062 torture_suite_add_1smb_test(suite, "perms", test_stream_permissions);
2064 #if 0
2065 torture_suite_add_1smb_test(suite, "LARGESTREAMINFO",
2066 test_stream_large_streaminfo);
2067 #endif
2069 return suite;