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/>.
23 #include "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
26 #include "torture/torture.h"
27 #include "torture/smb2/proto.h"
29 #include "system/filesys.h"
30 #include "system/locale.h"
31 #include "lib/util/tsort.h"
33 #define DNAME "teststreams"
35 #define CHECK_STATUS(status, correct) do { \
36 if (!NT_STATUS_EQUAL(status, correct)) { \
37 torture_result(tctx, TORTURE_FAIL, \
38 "(%s) Incorrect status %s - should be %s\n", \
39 __location__, nt_errstr(status), nt_errstr(correct)); \
44 #define CHECK_VALUE(v, correct) do { \
45 if ((v) != (correct)) { \
46 torture_result(tctx, TORTURE_FAIL, \
47 "(%s) Incorrect value %s=%d - should be %d\n", \
48 __location__, #v, (int)v, (int)correct); \
52 #define CHECK_NTTIME(v, correct) do { \
53 if ((v) != (correct)) { \
54 torture_result(tctx, TORTURE_FAIL, \
55 "(%s) Incorrect value %s=%llu - should be %llu\n", \
56 __location__, #v, (unsigned long long)v, \
57 (unsigned long long)correct); \
61 #define CHECK_STR(v, correct) do { \
63 if ((v) && !(correct)) { \
65 } else if (!(v) && (correct)) { \
67 } else if (!(v) && !(correct)) { \
69 } else if (strcmp((v), (correct)) == 0) { \
75 torture_result(tctx, TORTURE_FAIL, \
76 "(%s) Incorrect value %s='%s' - " \
78 __location__, #v, (v)?(v):"NULL", \
79 (correct)?(correct):"NULL"); \
84 static int qsort_string(char * const *s1, char * const *s2)
86 return strcmp(*s1, *s2);
89 static int qsort_stream(const struct stream_struct * s1, const struct stream_struct *s2)
91 return strcmp(s1->stream_name.s, s2->stream_name.s);
94 static bool check_stream(struct torture_context *tctx,
95 struct smb2_tree *tree,
102 struct smb2_handle handle;
103 struct smb2_create create;
106 const char *full_name;
108 full_name = talloc_asprintf(mem_ctx, "%s:%s", fname, sname);
111 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
112 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
113 create.in.create_disposition = NTCREATEX_DISP_OPEN;
114 create.in.fname = full_name;
116 status = smb2_create(tree, mem_ctx, &create);
117 if (!NT_STATUS_IS_OK(status)) {
121 torture_comment(tctx, "Unable to open stream %s\n",
127 handle = create.out.file.handle;
134 r.in.file.handle = handle;
135 r.in.length = strlen(value)+11;
138 status = smb2_read(tree, tree, &r);
140 if (!NT_STATUS_IS_OK(status)) {
141 torture_comment(tctx, "(%s) Failed to read %lu bytes from "
142 "stream '%s'\n", location, (long)strlen(value), full_name);
146 if (memcmp(r.out.data.data, value, strlen(value)) != 0) {
147 torture_comment(tctx, "(%s) Bad data in stream\n", location);
151 smb2_util_close(tree, handle);
155 static bool check_stream_list(struct smb2_tree *tree,
156 struct torture_context *tctx,
160 struct smb2_handle h)
162 union smb_fileinfo finfo;
165 TALLOC_CTX *tmp_ctx = talloc_new(tctx);
167 struct stream_struct *stream_sort;
170 finfo.generic.level = RAW_FILEINFO_STREAM_INFORMATION;
171 finfo.generic.in.file.handle = h;
173 status = smb2_getinfo_file(tree, tctx, &finfo);
174 if (!NT_STATUS_IS_OK(status)) {
175 torture_comment(tctx, "(%s) smb_raw_pathinfo failed: %s\n",
176 __location__, nt_errstr(status));
180 if (finfo.stream_info.out.num_streams != num_exp) {
181 torture_comment(tctx, "(%s) expected %d streams, got %d\n",
182 __location__, num_exp, finfo.stream_info.out.num_streams);
191 exp_sort = talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp));
193 if (exp_sort == NULL) {
197 TYPESAFE_QSORT(exp_sort, num_exp, qsort_string);
199 stream_sort = talloc_memdup(tmp_ctx, finfo.stream_info.out.streams,
200 finfo.stream_info.out.num_streams *
201 sizeof(*stream_sort));
203 if (stream_sort == NULL) {
207 TYPESAFE_QSORT(stream_sort, finfo.stream_info.out.num_streams, qsort_stream);
209 for (i=0; i<num_exp; i++) {
210 if (strcmp(exp_sort[i], stream_sort[i].stream_name.s) != 0) {
211 torture_comment(tctx,
212 "(%s) expected stream name %s, got %s\n",
213 __location__, exp_sort[i],
214 stream_sort[i].stream_name.s);
221 talloc_free(tmp_ctx);
226 static bool test_stream_dir(struct torture_context *tctx,
227 struct smb2_tree *tree)
229 TALLOC_CTX *mem_ctx = talloc_new(tctx);
232 const char *fname = DNAME "\\stream.txt";
235 const char *basedir_data;
236 struct smb2_handle h;
238 smb2_util_unlink(tree, fname);
239 smb2_deltree(tree, DNAME);
241 status = torture_smb2_testdir(tree, DNAME, &h);
242 CHECK_STATUS(status, NT_STATUS_OK);
244 basedir_data = talloc_asprintf(mem_ctx, "%s::$DATA", DNAME);
245 sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
246 torture_comment(tctx, "%s\n", sname1);
248 torture_comment(tctx, "(%s) opening non-existent directory stream\n",
250 ZERO_STRUCT(io.smb2);
251 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
252 io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
253 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
254 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
255 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
256 io.smb2.in.share_access = 0;
257 io.smb2.in.alloc_size = 0;
258 io.smb2.in.security_flags = 0;
259 io.smb2.in.fname = sname1;
260 io.smb2.in.create_flags = 0;
261 status = smb2_create(tree, mem_ctx, &(io.smb2));
262 CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
264 torture_comment(tctx, "(%s) opening basedir stream\n", __location__);
265 ZERO_STRUCT(io.smb2);
266 io.smb2.in.create_flags = 0;
267 io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
268 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
269 io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
270 io.smb2.in.share_access = 0;
271 io.smb2.in.alloc_size = 0;
272 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
273 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
274 io.smb2.in.security_flags = 0;
275 io.smb2.in.fname = basedir_data;
276 status = smb2_create(tree, mem_ctx, &(io.smb2));
277 CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
279 torture_comment(tctx, "(%s) opening basedir ::$DATA stream\n",
281 ZERO_STRUCT(io.smb2);
282 io.smb2.in.create_flags = 0x10;
283 io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
284 io.smb2.in.create_options = 0;
285 io.smb2.in.file_attributes = 0;
286 io.smb2.in.share_access = 0;
287 io.smb2.in.alloc_size = 0;
288 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
289 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
290 io.smb2.in.security_flags = 0;
291 io.smb2.in.fname = basedir_data;
292 status = smb2_create(tree, mem_ctx, &(io.smb2));
293 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
295 torture_comment(tctx, "(%s) list the streams on the basedir\n",
297 ret &= check_stream_list(tree, mem_ctx, DNAME, 0, NULL, h);
299 smb2_util_unlink(tree, fname);
300 smb2_deltree(tree, DNAME);
301 talloc_free(mem_ctx);
306 static bool test_stream_io(struct torture_context *tctx,
307 struct smb2_tree *tree)
309 TALLOC_CTX *mem_ctx = talloc_new(tctx);
312 const char *fname = DNAME "\\stream.txt";
313 const char *sname1, *sname2;
315 struct smb2_handle h, h2;
317 const char *one[] = { "::$DATA" };
318 const char *two[] = { "::$DATA", ":Second Stream:$DATA" };
319 const char *three[] = { "::$DATA", ":Stream One:$DATA",
320 ":Second Stream:$DATA" };
325 sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
326 sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
329 smb2_util_unlink(tree, fname);
330 smb2_deltree(tree, DNAME);
332 status = torture_smb2_testdir(tree, DNAME, &h);
333 CHECK_STATUS(status, NT_STATUS_OK);
335 torture_comment(tctx, "(%s) creating a stream on a non-existent file\n",
338 ZERO_STRUCT(io.smb2);
339 io.smb2.in.create_flags = 0;
340 io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
341 io.smb2.in.create_options = 0;
342 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
343 io.smb2.in.share_access = 0;
344 io.smb2.in.alloc_size = 0;
345 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
346 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
347 io.smb2.in.security_flags = 0;
348 io.smb2.in.fname = sname1;
349 status = smb2_create(tree, mem_ctx, &(io.smb2));
350 CHECK_STATUS(status, NT_STATUS_OK);
351 h2 = io.smb2.out.file.handle;
353 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
356 torture_comment(tctx, "(%s) check that open of base file is allowed\n", __location__);
357 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
358 io.smb2.in.fname = fname;
359 status = smb2_create(tree, mem_ctx, &(io.smb2));
360 CHECK_STATUS(status, NT_STATUS_OK);
361 smb2_util_close(tree, io.smb2.out.file.handle);
363 torture_comment(tctx, "(%s) writing to stream\n", __location__);
364 status = smb2_util_write(tree, h2, "test data", 0, 9);
365 CHECK_STATUS(status, NT_STATUS_OK);
367 smb2_util_close(tree, h2);
369 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
370 "Stream One", "test data");
372 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
373 io.smb2.in.fname = sname1;
374 status = smb2_create(tree, mem_ctx, &(io.smb2));
375 CHECK_STATUS(status, NT_STATUS_OK);
376 h2 = io.smb2.out.file.handle;
378 torture_comment(tctx, "(%s) modifying stream\n", __location__);
379 status = smb2_util_write(tree, h2, "MORE DATA ", 5, 10);
380 CHECK_STATUS(status, NT_STATUS_OK);
382 smb2_util_close(tree, h2);
384 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
385 "Stream One:$FOO", NULL);
387 torture_comment(tctx, "(%s) creating a stream2 on a existing file\n",
389 io.smb2.in.fname = sname2;
390 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
391 status = smb2_create(tree, mem_ctx, &(io.smb2));
392 CHECK_STATUS(status, NT_STATUS_OK);
393 h2 = io.smb2.out.file.handle;
395 torture_comment(tctx, "(%s) modifying stream\n", __location__);
396 status= smb2_util_write(tree, h2, "SECOND STREAM", 0, 13);
397 CHECK_STATUS(status, NT_STATUS_OK);
398 smb2_util_close(tree, h2);
400 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
401 "Stream One", "test MORE DATA ");
403 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
404 "Stream One:$DATA", "test MORE DATA ");
406 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
407 "Stream One:", NULL);
410 torture_result(tctx, TORTURE_FAIL,
411 "check_stream(\"Stream One:*\") failed\n");
415 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
416 "Second Stream", "SECOND STREAM");
418 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
419 "SECOND STREAM:$DATA", "SECOND STREAM");
420 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
421 "Second Stream:$DATA", "SECOND STREAM");
423 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
424 "Second Stream:", NULL);
426 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
427 "Second Stream:$FOO", NULL);
430 torture_result(tctx, TORTURE_FAIL,
431 "check_stream(\"Second Stream:*\") failed\n");
435 io.smb2.in.fname = sname2;
436 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
437 status = smb2_create(tree, mem_ctx, &(io.smb2));
438 CHECK_STATUS(status, NT_STATUS_OK);
439 h2 = io.smb2.out.file.handle;
440 check_stream_list(tree, tctx, fname, 3, three, h2);
442 smb2_util_close(tree, h2);
444 torture_comment(tctx, "(%s) deleting stream\n", __location__);
445 status = smb2_util_unlink(tree, sname1);
446 CHECK_STATUS(status, NT_STATUS_OK);
448 io.smb2.in.fname = sname2;
449 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
450 status = smb2_create(tree, mem_ctx, &(io.smb2));
451 CHECK_STATUS(status, NT_STATUS_OK);
452 h2 = io.smb2.out.file.handle;
453 check_stream_list(tree, tctx, fname, 2, two, h2);
454 smb2_util_close(tree, h2);
456 torture_comment(tctx, "(%s) delete a stream via delete-on-close\n",
458 io.smb2.in.fname = sname2;
459 io.smb2.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
460 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
461 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
462 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
464 status = smb2_create(tree, mem_ctx, &(io.smb2));
465 CHECK_STATUS(status, NT_STATUS_OK);
466 h2 = io.smb2.out.file.handle;
468 smb2_util_close(tree, h2);
469 status = smb2_util_unlink(tree, sname2);
470 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
472 io.smb2.in.fname = fname;
473 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
474 status = smb2_create(tree, mem_ctx, &(io.smb2));
475 h2 = io.smb2.out.file.handle;
476 check_stream_list(tree,tctx, fname, 1, one, h2);
477 smb2_util_close(tree, h2);
479 if (!torture_setting_bool(tctx, "samba4", false)) {
480 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
481 io.smb2.in.fname = sname1;
482 status = smb2_create(tree, mem_ctx, &(io.smb2));
483 CHECK_STATUS(status, NT_STATUS_OK);
484 smb2_util_close(tree, io.ntcreatex.out.file.handle);
485 io.smb2.in.fname = sname2;
486 status = smb2_create(tree, mem_ctx, &(io.smb2));
487 CHECK_STATUS(status, NT_STATUS_OK);
488 smb2_util_close(tree, io.ntcreatex.out.file.handle);
489 torture_comment(tctx, "(%s) deleting file\n", __location__);
490 status = smb2_util_unlink(tree, fname);
491 CHECK_STATUS(status, NT_STATUS_OK);
496 smb2_util_close(tree, h2);
497 smb2_deltree(tree, DNAME);
498 talloc_free(mem_ctx);
503 static bool test_zero_byte_stream(struct torture_context *tctx,
504 struct smb2_tree *tree)
506 TALLOC_CTX *mem_ctx = talloc_new(tctx);
509 const char *fname = DNAME "\\stream.txt";
512 struct smb2_handle h, bh;
513 const char *streams[] = { "::$DATA", ":foo:$DATA" };
515 sname = talloc_asprintf(mem_ctx, "%s:%s", fname, "foo");
517 smb2_util_unlink(tree, fname);
518 smb2_deltree(tree, DNAME);
520 status = torture_smb2_testdir(tree, DNAME, &h);
521 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "testdir");
522 smb2_util_close(tree, h);
524 torture_comment(tctx, "(%s) Check 0 byte named stream\n",
527 /* Create basefile */
529 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
530 io.smb2.in.fname = fname;
531 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
532 SEC_FILE_WRITE_ATTRIBUTE |
535 status = smb2_create(tree, mem_ctx, &(io.smb2));
536 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "create");
537 smb2_util_close(tree, io.smb2.out.file.handle);
539 /* Create named stream and close it */
541 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
542 io.smb2.in.fname = sname;
543 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
544 SEC_FILE_WRITE_ATTRIBUTE |
547 status = smb2_create(tree, mem_ctx, &(io.smb2));
548 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "create");
549 smb2_util_close(tree, io.smb2.out.file.handle);
552 * Check stream list, the 0 byte stream MUST be returned by
556 io.smb2.in.fname = fname;
557 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
558 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
559 SEC_FILE_WRITE_ATTRIBUTE |
562 status = smb2_create(tree, mem_ctx, &(io.smb2));
563 bh = io.smb2.out.file.handle;
565 ret = check_stream_list(tree,tctx, fname, 2, streams, bh);
566 torture_assert_goto(tctx, ret == true, ret, done, "smb2_create");
567 smb2_util_close(tree, bh);
570 smb2_deltree(tree, DNAME);
571 talloc_free(mem_ctx);
577 test stream sharemodes
579 static bool test_stream_sharemodes(struct torture_context *tctx,
580 struct smb2_tree *tree)
582 TALLOC_CTX *mem_ctx = talloc_new(tctx);
585 const char *fname = DNAME "\\stream_share.txt";
586 const char *sname1, *sname2;
588 struct smb2_handle h, h1, h2;
594 sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
595 sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
598 smb2_util_unlink(tree, fname);
599 smb2_deltree(tree, DNAME);
601 status = torture_smb2_testdir(tree, DNAME, &h);
602 CHECK_STATUS(status, NT_STATUS_OK);
604 torture_comment(tctx, "(%s) Testing stream share mode conflicts\n",
606 ZERO_STRUCT(io.smb2);
607 io.generic.level = RAW_OPEN_SMB2;
608 io.smb2.in.create_flags = 0;
609 io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
610 io.smb2.in.create_options = 0;
611 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
612 io.smb2.in.share_access = 0;
613 io.smb2.in.alloc_size = 0;
614 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
615 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
616 io.smb2.in.security_flags = 0;
617 io.smb2.in.fname = sname1;
619 status = smb2_create(tree, mem_ctx, &(io.smb2));
620 CHECK_STATUS(status, NT_STATUS_OK);
621 h1 = io.smb2.out.file.handle;
624 * A different stream does not give a sharing violation
627 io.smb2.in.fname = sname2;
628 status = smb2_create(tree, mem_ctx, &(io.smb2));
629 CHECK_STATUS(status, NT_STATUS_OK);
630 h2 = io.smb2.out.file.handle;
633 * ... whereas the same stream does with unchanged access/share_access
637 io.smb2.in.fname = sname1;
638 io.smb2.in.create_disposition = 0;
639 status = smb2_create(tree, mem_ctx, &(io.smb2));
640 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
642 io.smb2.in.fname = sname2;
643 status = smb2_create(tree, mem_ctx, &(io.smb2));
644 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
647 smb2_util_close(tree, h1);
648 smb2_util_close(tree, h2);
649 status = smb2_util_unlink(tree, fname);
650 smb2_deltree(tree, DNAME);
651 talloc_free(mem_ctx);
657 * Test FILE_SHARE_DELETE on streams
659 * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
660 * with SEC_STD_DELETE.
662 * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
663 * be opened with SEC_STD_DELETE.
665 * A stream held open with FILE_SHARE_DELETE allows the file to be
666 * deleted. After the main file is deleted, access to the open file descriptor
667 * still works, but all name-based access to both the main file as well as the
668 * stream is denied with DELETE pending.
670 * This means, an open of the main file with SEC_STD_DELETE should walk all
671 * streams and also open them with SEC_STD_DELETE. If any of these opens gives
672 * SHARING_VIOLATION, the main open fails.
674 * Closing the main file after delete_on_close has been set does not really
675 * unlink it but leaves the corresponding share mode entry with
676 * delete_on_close being set around until all streams are closed.
678 * Opening a stream must also look at the main file's share mode entry, look
679 * at the delete_on_close bit and potentially return DELETE_PENDING.
682 static bool test_stream_delete(struct torture_context *tctx,
683 struct smb2_tree *tree)
685 TALLOC_CTX *mem_ctx = talloc_new(tctx);
688 const char *fname = DNAME "\\stream_delete.txt";
691 struct smb2_handle h = {{0}};
692 struct smb2_handle h1 = {{0}};
695 if (torture_setting_bool(tctx, "samba4", false)) {
696 torture_comment(tctx, "Skipping test as samba4 is enabled\n");
703 sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
706 smb2_util_unlink(tree, fname);
707 smb2_deltree(tree, fname);
708 smb2_deltree(tree, DNAME);
710 status = torture_smb2_testdir(tree, DNAME, &h);
711 CHECK_STATUS(status, NT_STATUS_OK);
713 torture_comment(tctx, "(%s) opening non-existent file stream\n",
715 ZERO_STRUCT(io.smb2);
716 io.smb2.in.create_flags = 0;
717 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
718 io.smb2.in.create_options = 0;
719 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
720 io.smb2.in.share_access = 0;
721 io.smb2.in.alloc_size = 0;
722 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
723 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
724 io.smb2.in.security_flags = 0;
725 io.smb2.in.fname = sname1;
727 status = smb2_create(tree, mem_ctx, &(io.smb2));
728 CHECK_STATUS(status, NT_STATUS_OK);
729 h1 = io.smb2.out.file.handle;
731 status = smb2_util_write(tree, h1, "test data", 0, 9);
732 CHECK_STATUS(status, NT_STATUS_OK);
735 * One stream opened without FILE_SHARE_DELETE prevents the main file
736 * to be deleted or even opened with DELETE access
739 status = smb2_util_unlink(tree, fname);
740 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
742 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
743 io.smb2.in.fname = fname;
744 io.smb2.in.desired_access = SEC_STD_DELETE;
745 status = smb2_create(tree, mem_ctx, &(io.smb2));
746 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
748 smb2_util_close(tree, h1);
751 * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
754 io.smb2.in.fname = sname1;
755 io.smb2.in.desired_access = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
756 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
757 NTCREATEX_SHARE_ACCESS_READ |
758 NTCREATEX_SHARE_ACCESS_WRITE;
759 status = smb2_create(tree, mem_ctx, &(io.smb2));
760 CHECK_STATUS(status, NT_STATUS_OK);
761 h1 = io.smb2.out.file.handle;
763 status = smb2_util_unlink(tree, fname);
764 CHECK_STATUS(status, NT_STATUS_OK);
767 * file access still works on the stream while the main file is closed
770 r.in.file.handle = h1;
774 status = smb2_read(tree, tree, &r);
775 CHECK_STATUS(status, NT_STATUS_OK);
778 * name-based access to both the main file and the stream does not
779 * work anymore but gives DELETE_PENDING
782 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
783 io.smb2.in.fname = fname;
784 status = smb2_create(tree, mem_ctx, &(io.smb2));
785 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
788 * older S3 doesn't do this
791 io.smb2.in.fname = sname1;
792 status = smb2_create(tree, mem_ctx, &(io.smb2));
793 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
795 smb2_util_close(tree, h1);
799 * After closing the stream the file is really gone.
802 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
803 io.smb2.in.fname = fname;
804 status = smb2_create(tree, mem_ctx, &(io.smb2));
805 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
808 if (!smb2_util_handle_empty(h1)) {
809 smb2_util_close(tree, h1);
811 smb2_util_unlink(tree, fname);
812 smb2_deltree(tree, DNAME);
813 talloc_free(mem_ctx);
821 static bool test_stream_names(struct torture_context *tctx,
822 struct smb2_tree *tree)
824 TALLOC_CTX *mem_ctx = talloc_new(tctx);
827 union smb_fileinfo finfo;
828 union smb_fileinfo stinfo;
829 union smb_setfileinfo sinfo;
830 const char *fname = DNAME "\\stream_names.txt";
831 const char *sname1, *sname1b, *sname1c, *sname1d;
832 const char *sname2, *snamew, *snamew2;
835 struct smb2_handle h, h1, h2, h3;
837 const char *four[4] = {
839 ":\x05Stream\n One:$DATA",
840 ":MStream Two:$DATA",
843 const char *five1[5] = {
845 ":\x05Stream\n One:$DATA",
846 ":BeforeRename:$DATA",
847 ":MStream Two:$DATA",
850 const char *five2[5] = {
852 ":\x05Stream\n One:$DATA",
853 ":AfterRename:$DATA",
854 ":MStream Two:$DATA",
863 sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "\x05Stream\n One");
864 sname1b = talloc_asprintf(mem_ctx, "%s:", sname1);
865 sname1c = talloc_asprintf(mem_ctx, "%s:$FOO", sname1);
866 sname1d = talloc_asprintf(mem_ctx, "%s:?D*a", sname1);
867 sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "MStream Two");
868 snamew = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname, "?Stream*");
869 snamew2 = talloc_asprintf(mem_ctx, "%s\\stream*:%s:$DATA", DNAME,
871 snamer1 = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname,
875 smb2_util_unlink(tree, fname);
876 smb2_deltree(tree, fname);
877 smb2_deltree(tree, DNAME);
879 status = torture_smb2_testdir(tree, DNAME, &h);
880 CHECK_STATUS(status, NT_STATUS_OK);
882 torture_comment(tctx, "(%s) testing stream names\n", __location__);
883 ZERO_STRUCT(io.smb2);
884 io.smb2.in.create_flags = 0;
885 io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
886 io.smb2.in.create_options = 0;
887 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
888 io.smb2.in.share_access = 0;
889 io.smb2.in.alloc_size = 0;
890 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
891 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
892 io.smb2.in.security_flags = 0;
893 io.smb2.in.fname = sname1;
895 status = smb2_create(tree, mem_ctx, &(io.smb2));
896 CHECK_STATUS(status, NT_STATUS_OK);
897 h1 = io.smb2.out.file.handle;
900 * A different stream does not give a sharing violation
903 io.smb2.in.fname = sname2;
904 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
905 status = smb2_create(tree, mem_ctx, &(io.smb2));
906 CHECK_STATUS(status, NT_STATUS_OK);
907 h2 = io.smb2.out.file.handle;
910 * ... whereas the same stream does with unchanged access/share_access
914 io.smb2.in.fname = sname1;
915 io.smb2.in.create_disposition = NTCREATEX_DISP_SUPERSEDE;
916 status = smb2_create(tree, mem_ctx, &(io.smb2));
917 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
919 io.smb2.in.fname = sname1b;
920 status = smb2_create(tree, mem_ctx, &(io.smb2));
921 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
923 io.smb2.in.fname = sname1c;
924 status = smb2_create(tree, mem_ctx, &(io.smb2));
925 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
926 /* w2k returns INVALID_PARAMETER */
927 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
929 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
932 io.smb2.in.fname = sname1d;
933 status = smb2_create(tree, mem_ctx, &(io.smb2));
934 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
935 /* w2k returns INVALID_PARAMETER */
936 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
938 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
941 io.smb2.in.fname = sname2;
942 status = smb2_create(tree, mem_ctx, &(io.smb2));
943 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
945 io.smb2.in.fname = snamew;
946 status = smb2_create(tree, mem_ctx, &(io.smb2));
947 CHECK_STATUS(status, NT_STATUS_OK);
948 h3 = io.smb2.out.file.handle;
950 io.smb2.in.fname = snamew2;
951 status = smb2_create(tree, mem_ctx, &(io.smb2));
952 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
954 io.smb2.in.fname = fname;
955 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
956 status = smb2_create(tree, mem_ctx, &(io.smb2));
957 CHECK_STATUS(status, NT_STATUS_OK);
958 ret &= check_stream_list(tree, tctx, fname, 4, four,
959 io.smb2.out.file.handle);
960 CHECK_VALUE(ret, true);
961 smb2_util_close(tree, h1);
962 smb2_util_close(tree, h2);
963 smb2_util_close(tree, h3);
965 if (torture_setting_bool(tctx, "samba4", true)) {
969 finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
970 finfo.generic.in.file.handle = io.smb2.out.file.handle;
971 status = smb2_getinfo_file(tree, mem_ctx, &finfo);
972 CHECK_STATUS(status, NT_STATUS_OK);
973 ret &= check_stream_list(tree, tctx, fname, 4, four,
974 io.smb2.out.file.handle);
976 CHECK_VALUE(ret, true);
977 for (i=0; i < 4; i++) {
979 uint64_t stream_size;
980 char *path = talloc_asprintf(tctx, "%s%s",
983 char *rpath = talloc_strdup(path, path);
984 char *p = strrchr(rpath, ':');
992 torture_comment(tctx, "(%s): i[%u][%s]\n",
993 __location__, i,path);
994 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
995 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
996 SEC_FILE_WRITE_ATTRIBUTE |
998 io.smb2.in.fname = path;
999 status = smb2_create(tree, mem_ctx, &(io.smb2));
1000 CHECK_STATUS(status, NT_STATUS_OK);
1001 h1 = io.smb2.out.file.handle;
1003 finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
1004 finfo.generic.in.file.path = fname;
1005 status = smb2_getinfo_file(tree, mem_ctx, &finfo);
1006 CHECK_STATUS(status, NT_STATUS_OK);
1008 stinfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
1009 stinfo.generic.in.file.handle = h1;
1010 status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
1011 CHECK_STATUS(status, NT_STATUS_OK);
1012 if (!torture_setting_bool(tctx, "samba3", false)) {
1013 CHECK_NTTIME(stinfo.all_info.out.create_time,
1014 finfo.all_info.out.create_time);
1015 CHECK_NTTIME(stinfo.all_info.out.access_time,
1016 finfo.all_info.out.access_time);
1017 CHECK_NTTIME(stinfo.all_info.out.write_time,
1018 finfo.all_info.out.write_time);
1019 CHECK_NTTIME(stinfo.all_info.out.change_time,
1020 finfo.all_info.out.change_time);
1022 CHECK_VALUE(stinfo.all_info.out.attrib,
1023 finfo.all_info.out.attrib);
1024 CHECK_VALUE(stinfo.all_info.out.size,
1025 finfo.all_info.out.size);
1026 CHECK_VALUE(stinfo.all_info.out.delete_pending,
1027 finfo.all_info.out.delete_pending);
1028 CHECK_VALUE(stinfo.all_info.out.directory,
1029 finfo.all_info.out.directory);
1030 CHECK_VALUE(stinfo.all_info.out.ea_size,
1031 finfo.all_info.out.ea_size);
1033 stinfo.generic.level = RAW_FILEINFO_NAME_INFORMATION;
1034 stinfo.generic.in.file.handle = h1;
1035 status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
1036 CHECK_STATUS(status, NT_STATUS_OK);
1037 if (!torture_setting_bool(tctx, "samba3", false)) {
1038 CHECK_STR(rpath, stinfo.name_info.out.fname.s);
1041 write_time = finfo.all_info.out.write_time;
1042 write_time += i*1000000;
1043 write_time /= 1000000;
1044 write_time *= 1000000;
1047 sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
1048 sinfo.basic_info.in.file.handle = h1;
1049 sinfo.basic_info.in.write_time = write_time;
1050 sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
1051 status = smb2_setinfo_file(tree, &sinfo);
1052 CHECK_STATUS(status, NT_STATUS_OK);
1054 stream_size = i*8192;
1057 sinfo.end_of_file_info.level =
1058 RAW_SFILEINFO_END_OF_FILE_INFORMATION;
1059 sinfo.end_of_file_info.in.file.handle = h1;
1060 sinfo.end_of_file_info.in.size = stream_size;
1061 status = smb2_setinfo_file(tree, &sinfo);
1062 CHECK_STATUS(status, NT_STATUS_OK);
1064 stinfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
1065 stinfo.generic.in.file.handle = h1;
1066 status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
1067 CHECK_STATUS(status, NT_STATUS_OK);
1068 if (!torture_setting_bool(tctx, "samba3", false)) {
1069 CHECK_NTTIME(stinfo.all_info.out.write_time,
1071 CHECK_VALUE(stinfo.all_info.out.attrib,
1072 finfo.all_info.out.attrib);
1074 CHECK_VALUE(stinfo.all_info.out.size,
1076 CHECK_VALUE(stinfo.all_info.out.delete_pending,
1077 finfo.all_info.out.delete_pending);
1078 CHECK_VALUE(stinfo.all_info.out.directory,
1079 finfo.all_info.out.directory);
1080 CHECK_VALUE(stinfo.all_info.out.ea_size,
1081 finfo.all_info.out.ea_size);
1083 io.smb2.in.fname = fname;
1084 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1085 status = smb2_create(tree, mem_ctx, &(io.smb2));
1086 CHECK_STATUS(status, NT_STATUS_OK);
1087 ret &= check_stream_list(tree, tctx, fname, 4, four,
1088 io.smb2.out.file.handle);
1090 smb2_util_close(tree, h1);
1094 torture_comment(tctx, "(%s): testing stream renames\n", __location__);
1095 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1096 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1097 SEC_FILE_WRITE_ATTRIBUTE |
1098 SEC_RIGHTS_FILE_ALL;
1099 io.smb2.in.fname = snamer1;
1100 status = smb2_create(tree, mem_ctx, &(io.smb2));
1101 CHECK_STATUS(status, NT_STATUS_OK);
1102 h1 = io.smb2.out.file.handle;
1103 ret &= check_stream_list(tree,tctx, fname, 5, five1,
1104 io.smb2.out.file.handle);
1107 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1108 sinfo.rename_information.in.file.handle = h1;
1109 sinfo.rename_information.in.overwrite = true;
1110 sinfo.rename_information.in.root_fid = 0;
1111 sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
1112 status = smb2_setinfo_file(tree, &sinfo);
1113 CHECK_STATUS(status, NT_STATUS_OK);
1115 ret &= check_stream_list(tree,tctx, fname, 5, five2,
1116 io.smb2.out.file.handle);
1118 CHECK_VALUE(ret, true);
1120 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1121 sinfo.rename_information.in.file.handle = h1;
1122 sinfo.rename_information.in.overwrite = false;
1123 sinfo.rename_information.in.root_fid = 0;
1124 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
1125 status = smb2_setinfo_file(tree, &sinfo);
1126 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
1128 ret &= check_stream_list(tree,tctx, fname, 5, five2,
1129 io.smb2.out.file.handle);
1132 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1133 sinfo.rename_information.in.file.handle = h1;
1134 sinfo.rename_information.in.overwrite = true;
1135 sinfo.rename_information.in.root_fid = 0;
1136 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
1137 status = smb2_setinfo_file(tree, &sinfo);
1138 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1140 ret &= check_stream_list(tree,tctx, fname, 5, five2,
1141 io.smb2.out.file.handle);
1143 CHECK_VALUE(ret, true);
1144 /* TODO: we need to test more rename combinations */
1147 smb2_util_close(tree, h1);
1148 status = smb2_util_unlink(tree, fname);
1149 smb2_deltree(tree, DNAME);
1150 talloc_free(mem_ctx);
1158 static bool test_stream_names2(struct torture_context *tctx,
1159 struct smb2_tree *tree)
1161 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1164 const char *fname = DNAME "\\stream_names2.txt";
1166 struct smb2_handle h = {{0}};
1167 struct smb2_handle h1 = {{0}};
1170 smb2_util_unlink(tree, fname);
1171 smb2_deltree(tree, DNAME);
1173 status = torture_smb2_testdir(tree, DNAME, &h);
1174 CHECK_STATUS(status, NT_STATUS_OK);
1176 torture_comment(tctx, "(%s) testing stream names\n", __location__);
1177 ZERO_STRUCT(io.smb2);
1178 io.smb2.in.create_flags = 0;
1179 io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
1180 io.smb2.in.create_options = 0;
1181 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1182 io.smb2.in.share_access = 0;
1183 io.smb2.in.alloc_size = 0;
1184 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1185 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1186 io.smb2.in.security_flags = 0;
1187 io.smb2.in.fname = fname;
1188 status = smb2_create(tree, mem_ctx, &(io.smb2));
1189 CHECK_STATUS(status, NT_STATUS_OK);
1190 h1 = io.smb2.out.file.handle;
1192 for (i=0x01; i < 0x7F; i++) {
1193 char *path = talloc_asprintf(mem_ctx, "%s:Stream%c0x%02X:$DATA",
1201 expected = NT_STATUS_OBJECT_NAME_INVALID;
1204 expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1209 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1210 io.smb2.in.fname = path;
1211 status = smb2_create(tree, mem_ctx, &(io.smb2));
1212 if (!NT_STATUS_EQUAL(status, expected)) {
1213 torture_comment(tctx,
1214 "(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1215 __location__, fname, isprint(i)?(char)i:' ', i,
1216 isprint(i)?"":" (not printable)",
1217 nt_errstr(expected));
1219 CHECK_STATUS(status, expected);
1225 smb2_util_close(tree, h1);
1226 status = smb2_util_unlink(tree, fname);
1227 smb2_deltree(tree, DNAME);
1228 talloc_free(mem_ctx);
1234 test case insensitive stream names
1236 static bool test_stream_names3(struct torture_context *tctx,
1237 struct smb2_tree *tree)
1239 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1241 union smb_fsinfo info;
1242 const char *fname = DNAME "\\stream_names3.txt";
1243 const char *sname = NULL;
1244 const char *snamel = NULL;
1245 const char *snameu = NULL;
1246 const char *sdname = NULL;
1247 const char *sdnamel = NULL;
1248 const char *sdnameu = NULL;
1250 struct smb2_handle h = {{0}};
1251 struct smb2_handle hf = {{0}};
1252 struct smb2_handle hs = {{0}};
1253 struct smb2_handle hsl = {{0}};
1254 struct smb2_handle hsu = {{0}};
1255 struct smb2_handle hsd = {{0}};
1256 struct smb2_handle hsdl = {{0}};
1257 struct smb2_handle hsdu = {{0}};
1258 const char *streams[] = { "::$DATA", ":StreamName:$DATA", };
1260 smb2_deltree(tree, DNAME);
1261 status = torture_smb2_testdir(tree, DNAME, &h);
1262 CHECK_STATUS(status, NT_STATUS_OK);
1265 info.generic.level = RAW_QFS_ATTRIBUTE_INFORMATION;
1266 info.generic.handle = h;
1267 status = smb2_getinfo_fs(tree, tree, &info);
1268 CHECK_STATUS(status, NT_STATUS_OK);
1269 if (!(info.attribute_info.out.fs_attr & FILE_CASE_SENSITIVE_SEARCH)) {
1270 torture_skip(tctx, "No FILE_CASE_SENSITIVE_SEARCH supported");
1274 * We create the following file:
1276 * teststreams\\stream_names3.txt
1278 * and add a stream named 'StreamName'
1280 * Then we try to open the stream using the following names:
1282 * teststreams\\stream_names3.txt:StreamName
1283 * teststreams\\stream_names3.txt:streamname
1284 * teststreams\\stream_names3.txt:STREAMNAME
1285 * teststreams\\stream_names3.txt:StreamName:$dAtA
1286 * teststreams\\stream_names3.txt:streamname:$data
1287 * teststreams\\stream_names3.txt:STREAMNAME:$DATA
1289 sname = talloc_asprintf(tctx, "%s:StreamName", fname);
1290 torture_assert_not_null(tctx, sname, __location__);
1291 snamel = strlower_talloc(tctx, sname);
1292 torture_assert_not_null(tctx, snamel, __location__);
1293 snameu = strupper_talloc(tctx, sname);
1294 torture_assert_not_null(tctx, snameu, __location__);
1296 sdname = talloc_asprintf(tctx, "%s:$dAtA", sname);
1297 torture_assert_not_null(tctx, sdname, __location__);
1298 sdnamel = strlower_talloc(tctx, sdname);
1299 torture_assert_not_null(tctx, sdnamel, __location__);
1300 sdnameu = strupper_talloc(tctx, sdname);
1301 torture_assert_not_null(tctx, sdnameu, __location__);
1303 torture_comment(tctx, "(%s) testing case insensitive stream names\n",
1305 status = torture_smb2_testfile(tree, fname, &hf);
1306 CHECK_STATUS(status, NT_STATUS_OK);
1307 status = torture_smb2_testfile(tree, sname, &hs);
1308 CHECK_STATUS(status, NT_STATUS_OK);
1309 smb2_util_close(tree, hs);
1311 torture_assert(tctx,
1312 check_stream_list(tree, tctx, fname,
1313 ARRAY_SIZE(streams),
1318 status = torture_smb2_open(tree, sname, SEC_RIGHTS_FILE_ALL, &hs);
1319 CHECK_STATUS(status, NT_STATUS_OK);
1320 status = torture_smb2_open(tree, snamel, SEC_RIGHTS_FILE_ALL, &hsl);
1321 CHECK_STATUS(status, NT_STATUS_OK);
1322 status = torture_smb2_open(tree, snameu, SEC_RIGHTS_FILE_ALL, &hsu);
1323 CHECK_STATUS(status, NT_STATUS_OK);
1324 status = torture_smb2_open(tree, sdname, SEC_RIGHTS_FILE_ALL, &hsd);
1325 CHECK_STATUS(status, NT_STATUS_OK);
1326 status = torture_smb2_open(tree, sdnamel, SEC_RIGHTS_FILE_ALL, &hsdl);
1327 CHECK_STATUS(status, NT_STATUS_OK);
1328 status = torture_smb2_open(tree, sdnameu, SEC_RIGHTS_FILE_ALL, &hsdu);
1329 CHECK_STATUS(status, NT_STATUS_OK);
1332 smb2_util_close(tree, hsdu);
1333 smb2_util_close(tree, hsdl);
1334 smb2_util_close(tree, hsd);
1335 smb2_util_close(tree, hsu);
1336 smb2_util_close(tree, hsl);
1337 smb2_util_close(tree, hs);
1338 smb2_util_close(tree, hf);
1339 smb2_util_close(tree, h);
1340 status = smb2_util_unlink(tree, fname);
1341 smb2_deltree(tree, DNAME);
1342 talloc_free(mem_ctx);
1347 #define CHECK_CALL_HANDLE(call, rightstatus) do { \
1348 sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1349 sfinfo.generic.in.file.handle = h1; \
1350 status = smb2_setinfo_file(tree, &sfinfo); \
1351 if (!NT_STATUS_EQUAL(status, rightstatus)) { \
1352 torture_result(tctx, TORTURE_FAIL, \
1353 "(%s) %s - %s (should be %s)\n", \
1354 __location__, #call, \
1355 nt_errstr(status), nt_errstr(rightstatus)); \
1358 finfo1.generic.level = RAW_FILEINFO_ALL_INFORMATION; \
1359 finfo1.generic.in.file.handle = h1; \
1360 status2 = smb2_getinfo_file(tree, tctx, &finfo1); \
1361 if (!NT_STATUS_IS_OK(status2)) { \
1362 torture_result(tctx, TORTURE_FAIL, \
1363 "(%s) %s pathinfo - %s\n", \
1364 __location__, #call, nt_errstr(status)); \
1371 static bool test_stream_rename(struct torture_context *tctx,
1372 struct smb2_tree *tree)
1374 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1375 NTSTATUS status, status2;
1377 const char *fname = DNAME "\\stream_rename.txt";
1378 const char *sname1, *sname2;
1379 union smb_fileinfo finfo1;
1380 union smb_setfileinfo sfinfo;
1382 struct smb2_handle h = {{0}};
1383 struct smb2_handle h1 = {{0}};
1385 sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
1386 sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
1389 smb2_util_unlink(tree, fname);
1390 smb2_deltree(tree, DNAME);
1392 status = torture_smb2_testdir(tree, DNAME, &h);
1393 CHECK_STATUS(status, NT_STATUS_OK);
1395 torture_comment(tctx, "(%s) testing stream renames\n", __location__);
1396 ZERO_STRUCT(io.smb2);
1397 io.smb2.in.create_flags = 0;
1398 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1399 SEC_FILE_WRITE_ATTRIBUTE |
1400 SEC_RIGHTS_FILE_ALL;
1401 io.smb2.in.create_options = 0;
1402 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1403 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1404 NTCREATEX_SHARE_ACCESS_WRITE |
1405 NTCREATEX_SHARE_ACCESS_DELETE;
1406 io.smb2.in.alloc_size = 0;
1407 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1408 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1409 io.smb2.in.security_flags = 0;
1410 io.smb2.in.fname = sname1;
1412 /* Create two streams. */
1413 status = smb2_create(tree, mem_ctx, &(io.smb2));
1414 CHECK_STATUS(status, NT_STATUS_OK);
1415 h1 = io.smb2.out.file.handle;
1416 smb2_util_close(tree, h1);
1418 io.smb2.in.fname = sname2;
1419 status = smb2_create(tree, mem_ctx, &(io.smb2));
1420 CHECK_STATUS(status, NT_STATUS_OK);
1421 h1 = io.smb2.out.file.handle;
1423 smb2_util_close(tree, h1);
1426 * Open the second stream.
1429 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1430 status = smb2_create(tree, mem_ctx, &(io.smb2));
1431 CHECK_STATUS(status, NT_STATUS_OK);
1432 h1 = io.smb2.out.file.handle;
1435 * Now rename the second stream onto the first.
1438 ZERO_STRUCT(sfinfo);
1440 sfinfo.rename_information.in.overwrite = 1;
1441 sfinfo.rename_information.in.root_fid = 0;
1442 sfinfo.rename_information.in.new_name = ":Stream One";
1443 CHECK_CALL_HANDLE(RENAME_INFORMATION, NT_STATUS_OK);
1445 smb2_util_close(tree, h1);
1446 status = smb2_util_unlink(tree, fname);
1447 smb2_deltree(tree, DNAME);
1448 talloc_free(mem_ctx);
1453 static bool test_stream_rename2(struct torture_context *tctx,
1454 struct smb2_tree *tree)
1456 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1459 const char *fname1 = DNAME "\\stream_rename2.txt";
1460 const char *fname2 = DNAME "\\stream2_rename2.txt";
1461 const char *stream_name1 = ":Stream One:$DATA";
1462 const char *stream_name2 = ":Stream Two:$DATA";
1463 const char *stream_name_default = "::$DATA";
1467 struct smb2_handle h, h1;
1468 union smb_setfileinfo sinfo;
1473 sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream One");
1474 sname2 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream Two");
1476 smb2_util_unlink(tree, fname1);
1477 smb2_util_unlink(tree, fname2);
1478 smb2_deltree(tree, DNAME);
1480 status = torture_smb2_testdir(tree, DNAME, &h);
1481 CHECK_STATUS(status, NT_STATUS_OK);
1483 ZERO_STRUCT(io.smb2);
1484 io.smb2.in.create_flags = 0;
1485 io.smb2.in.desired_access = SEC_FILE_READ_DATA |
1486 SEC_FILE_WRITE_DATA |
1488 SEC_FILE_APPEND_DATA |
1489 SEC_STD_READ_CONTROL;
1490 io.smb2.in.create_options = 0;
1491 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1492 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1493 NTCREATEX_SHARE_ACCESS_WRITE |
1494 NTCREATEX_SHARE_ACCESS_DELETE;
1495 io.smb2.in.alloc_size = 0;
1496 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1497 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1498 io.smb2.in.security_flags = 0;
1499 io.smb2.in.fname = sname1;
1501 /* Open/create new stream. */
1502 status = smb2_create(tree, mem_ctx, &(io.smb2));
1503 CHECK_STATUS(status, NT_STATUS_OK);
1505 smb2_util_close(tree, io.smb2.out.file.handle);
1508 * Reopen the stream for SMB2 renames.
1510 io.smb2.in.fname = sname1;
1511 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1512 status = smb2_create(tree, mem_ctx, &(io.smb2));
1513 CHECK_STATUS(status, NT_STATUS_OK);
1514 h1 = io.smb2.out.file.handle;
1517 * Check SMB2 rename of a stream using :<stream>.
1519 torture_comment(tctx, "(%s) Checking SMB2 rename of a stream using "
1520 ":<stream>\n", __location__);
1522 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION_SMB2;
1523 sinfo.rename_information.in.file.handle = h1;
1524 sinfo.rename_information.in.overwrite = 1;
1525 sinfo.rename_information.in.root_fid = 0;
1526 sinfo.rename_information.in.new_name = stream_name1;
1527 status = smb2_setinfo_file(tree, &sinfo);
1528 CHECK_STATUS(status, NT_STATUS_OK);
1531 * Check SMB2 rename of an overwriting stream using :<stream>.
1533 torture_comment(tctx, "(%s) Checking SMB2 rename of an overwriting "
1534 "stream using :<stream>\n", __location__);
1536 /* Create second stream. */
1537 io.smb2.in.fname = sname2;
1538 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1539 status = smb2_create(tree, mem_ctx, &(io.smb2));
1540 CHECK_STATUS(status, NT_STATUS_OK);
1541 smb2_util_close(tree, io.smb2.out.file.handle);
1543 /* Rename the first stream onto the second. */
1544 sinfo.rename_information.in.file.handle = h1;
1545 sinfo.rename_information.in.new_name = stream_name2;
1546 status = smb2_setinfo_file(tree, &sinfo);
1547 CHECK_STATUS(status, NT_STATUS_OK);
1549 smb2_util_close(tree, h1);
1552 * Reopen the stream with the new name.
1554 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1555 io.smb2.in.fname = sname2;
1556 status = smb2_create(tree, mem_ctx, &(io.smb2));
1557 CHECK_STATUS(status, NT_STATUS_OK);
1558 h1 = io.smb2.out.file.handle;
1561 * Check SMB2 rename of a stream using <base>:<stream>.
1563 torture_comment(tctx, "(%s) Checking SMB2 rename of a stream using "
1564 "<base>:<stream>\n", __location__);
1565 sinfo.rename_information.in.file.handle = h1;
1566 sinfo.rename_information.in.new_name = sname1;
1567 status = smb2_setinfo_file(tree, &sinfo);
1568 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
1570 if (!torture_setting_bool(tctx, "samba4", false)) {
1572 * Check SMB2 rename to the default stream using :<stream>.
1574 torture_comment(tctx, "(%s) Checking SMB2 rename to default stream "
1575 "using :<stream>\n", __location__);
1576 sinfo.rename_information.in.file.handle = h1;
1577 sinfo.rename_information.in.new_name = stream_name_default;
1578 status = smb2_setinfo_file(tree, &sinfo);
1579 CHECK_STATUS(status, NT_STATUS_OK);
1582 smb2_util_close(tree, h1);
1585 smb2_util_close(tree, h1);
1586 status = smb2_util_unlink(tree, fname1);
1587 status = smb2_util_unlink(tree, fname2);
1588 smb2_deltree(tree, DNAME);
1589 talloc_free(mem_ctx);
1594 static bool create_file_with_stream(struct torture_context *tctx,
1595 struct smb2_tree *tree,
1596 TALLOC_CTX *mem_ctx,
1597 const char *base_fname,
1604 /* Create a file with a stream */
1605 ZERO_STRUCT(io.smb2);
1606 io.smb2.in.create_flags = 0;
1607 io.smb2.in.desired_access = SEC_FILE_READ_DATA |
1608 SEC_FILE_WRITE_DATA |
1609 SEC_FILE_APPEND_DATA |
1610 SEC_STD_READ_CONTROL;
1611 io.smb2.in.create_options = 0;
1612 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1613 io.smb2.in.share_access = 0;
1614 io.smb2.in.alloc_size = 0;
1615 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1616 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1617 io.smb2.in.security_flags = 0;
1618 io.smb2.in.fname = stream;
1620 status = smb2_create(tree, mem_ctx, &(io.smb2));
1621 CHECK_STATUS(status, NT_STATUS_OK);
1624 smb2_util_close(tree, io.smb2.out.file.handle);
1629 /* Test how streams interact with create dispositions */
1630 static bool test_stream_create_disposition(struct torture_context *tctx,
1631 struct smb2_tree *tree)
1633 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1636 const char *fname = DNAME "\\stream_create_disp.txt";
1637 const char *stream = "Stream One:$DATA";
1638 const char *fname_stream;
1639 const char *default_stream_name = "::$DATA";
1640 const char *stream_list[2];
1642 struct smb2_handle h = {{0}};
1643 struct smb2_handle h1 = {{0}};
1645 /* clean slate .. */
1646 smb2_util_unlink(tree, fname);
1647 smb2_deltree(tree, fname);
1648 smb2_deltree(tree, DNAME);
1650 status = torture_smb2_testdir(tree, DNAME, &h);
1651 CHECK_STATUS(status, NT_STATUS_OK);
1653 fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
1655 stream_list[0] = talloc_asprintf(mem_ctx, ":%s", stream);
1656 stream_list[1] = default_stream_name;
1658 if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
1663 /* Open the base file with OPEN */
1664 ZERO_STRUCT(io.smb2);
1665 io.smb2.in.create_flags = 0;
1666 io.smb2.in.desired_access = SEC_FILE_READ_DATA |
1667 SEC_FILE_WRITE_DATA |
1668 SEC_FILE_APPEND_DATA |
1669 SEC_STD_READ_CONTROL;
1670 io.smb2.in.create_options = 0;
1671 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1672 io.smb2.in.share_access = 0;
1673 io.smb2.in.alloc_size = 0;
1674 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1675 io.smb2.in.security_flags = 0;
1676 io.smb2.in.fname = fname;
1679 * check create open: sanity check
1681 torture_comment(tctx, "(%s) Checking create disp: open\n",
1683 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1684 status = smb2_create(tree, mem_ctx, &(io.smb2));
1685 CHECK_STATUS(status, NT_STATUS_OK);
1686 if (!check_stream_list(tree, tctx, fname, 2, stream_list,
1687 io.smb2.out.file.handle)) {
1690 smb2_util_close(tree, io.smb2.out.file.handle);
1693 * check create overwrite
1695 torture_comment(tctx, "(%s) Checking create disp: overwrite\n",
1697 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
1698 status = smb2_create(tree, mem_ctx, &(io.smb2));
1699 CHECK_STATUS(status, NT_STATUS_OK);
1700 if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
1701 io.smb2.out.file.handle)) {
1704 smb2_util_close(tree, io.smb2.out.file.handle);
1707 * check create overwrite_if
1709 torture_comment(tctx, "(%s) Checking create disp: overwrite_if\n",
1711 smb2_util_unlink(tree, fname);
1712 if (!create_file_with_stream(tctx, tree, mem_ctx, fname, fname_stream))
1715 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1716 status = smb2_create(tree, mem_ctx, &(io.smb2));
1717 CHECK_STATUS(status, NT_STATUS_OK);
1718 if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
1719 io.smb2.out.file.handle)) {
1722 smb2_util_close(tree, io.smb2.out.file.handle);
1725 * check create supersede
1727 torture_comment(tctx, "(%s) Checking create disp: supersede\n",
1729 smb2_util_unlink(tree, fname);
1730 if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
1735 io.smb2.in.create_disposition = NTCREATEX_DISP_SUPERSEDE;
1736 status = smb2_create(tree, mem_ctx, &(io.smb2));
1737 CHECK_STATUS(status, NT_STATUS_OK);
1738 if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
1739 io.smb2.out.file.handle)) {
1742 smb2_util_close(tree, io.smb2.out.file.handle);
1745 * check create overwrite_if on a stream.
1747 torture_comment(tctx, "(%s) Checking create disp: overwrite_if on "
1748 "stream\n", __location__);
1749 smb2_util_unlink(tree, fname);
1750 if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
1755 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1756 io.smb2.in.fname = fname_stream;
1757 status = smb2_create(tree, mem_ctx, &(io.smb2));
1758 CHECK_STATUS(status, NT_STATUS_OK);
1759 if (!check_stream_list(tree, tctx, fname, 2, stream_list,
1760 io.smb2.out.file.handle)) {
1763 smb2_util_close(tree, io.smb2.out.file.handle);
1765 smb2_util_close(tree, h1);
1766 smb2_util_unlink(tree, fname);
1767 smb2_deltree(tree, DNAME);
1768 talloc_free(mem_ctx);
1773 static bool open_stream(struct smb2_tree *tree,
1774 struct torture_context *mem_ctx,
1776 struct smb2_handle *h_out)
1781 ZERO_STRUCT(io.smb2);
1782 io.smb2.in.create_flags = 0;
1783 io.smb2.in.desired_access = SEC_FILE_READ_DATA |
1784 SEC_FILE_WRITE_DATA |
1785 SEC_FILE_APPEND_DATA |
1786 SEC_STD_READ_CONTROL |
1787 SEC_FILE_WRITE_ATTRIBUTE;
1788 io.smb2.in.create_options = 0;
1789 io.smb2.in.file_attributes = 0;
1790 io.smb2.in.share_access = 0;
1791 io.smb2.in.alloc_size = 0;
1792 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1793 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1794 io.smb2.in.security_flags = 0;
1795 io.smb2.in.fname = fname;
1797 status = smb2_create(tree, mem_ctx, &(io.smb2));
1798 if (!NT_STATUS_IS_OK(status)) {
1801 *h_out = io.smb2.out.file.handle;
1806 /* Test the effect of setting attributes on a stream. */
1807 static bool test_stream_attributes(struct torture_context *tctx,
1808 struct smb2_tree *tree)
1810 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1814 const char *fname = DNAME "\\stream_attr.txt";
1815 const char *stream = "Stream One:$DATA";
1816 const char *fname_stream;
1817 struct smb2_handle h, h1;
1818 union smb_fileinfo finfo;
1819 union smb_setfileinfo sfinfo;
1820 time_t basetime = (time(NULL) - 86400) & ~1;
1825 torture_comment(tctx, "(%s) testing attribute setting on stream\n",
1828 /* clean slate .. */
1829 smb2_util_unlink(tree, fname);
1830 smb2_deltree(tree, fname);
1831 smb2_deltree(tree, DNAME);
1833 status = torture_smb2_testdir(tree, DNAME, &h);
1834 CHECK_STATUS(status, NT_STATUS_OK);
1836 fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
1838 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1839 ret = create_file_with_stream(tctx, tree, mem_ctx, fname,
1845 ZERO_STRUCT(io.smb2);
1846 io.smb2.in.fname = fname;
1847 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1848 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1849 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1850 NTCREATEX_SHARE_ACCESS_WRITE |
1851 NTCREATEX_SHARE_ACCESS_DELETE;
1852 status = smb2_create(tree, mem_ctx, &(io.smb2));
1853 CHECK_STATUS(status, NT_STATUS_OK);
1856 finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
1857 finfo.generic.in.file.handle = io.smb2.out.file.handle;
1858 status = smb2_getinfo_file(tree, mem_ctx, &finfo);
1859 CHECK_STATUS(status, NT_STATUS_OK);
1861 if (finfo.basic_info.out.attrib != FILE_ATTRIBUTE_ARCHIVE) {
1862 torture_comment(tctx, "(%s) Incorrect attrib %x - should be "
1863 "%x\n", __location__,
1864 (unsigned int)finfo.basic_info.out.attrib,
1865 (unsigned int)FILE_ATTRIBUTE_ARCHIVE);
1870 smb2_util_close(tree, io.smb2.out.file.handle);
1871 /* Now open the stream name. */
1873 if (!open_stream(tree, tctx, fname_stream, &h1)) {
1877 /* Change the time on the stream. */
1878 ZERO_STRUCT(sfinfo);
1879 unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
1880 sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1881 sfinfo.generic.in.file.handle = h1;
1882 status = smb2_setinfo_file(tree, &sfinfo);
1883 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1884 torture_comment(tctx, "(%s) %s - %s (should be %s)\n",
1885 __location__, "SETATTR",
1886 nt_errstr(status), nt_errstr(NT_STATUS_OK));
1891 smb2_util_close(tree, h1);
1893 ZERO_STRUCT(io.smb2);
1894 io.smb2.in.fname = fname;
1895 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1896 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1897 status = smb2_create(tree, mem_ctx, &(io.smb2));
1898 CHECK_STATUS(status, NT_STATUS_OK);
1899 h1 = io.smb2.out.file.handle;
1902 finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
1903 finfo.generic.in.file.handle = h1;
1904 status = smb2_getinfo_file(tree, mem_ctx, &finfo);
1905 if (!NT_STATUS_IS_OK(status)) {
1906 torture_comment(tctx, "(%s) %s pathinfo - %s\n",
1907 __location__, "SETATTRE", nt_errstr(status));
1912 if (nt_time_to_unix(finfo.basic_info.out.write_time) != basetime) {
1913 torture_comment(tctx, "(%s) time incorrect.\n", __location__);
1917 smb2_util_close(tree, h1);
1919 if (!open_stream(tree, tctx, fname_stream, &h1)) {
1923 /* Changing attributes on stream */
1924 ZERO_STRUCT(sfinfo);
1925 sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
1927 sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1928 sfinfo.generic.in.file.handle = h1;
1929 status = smb2_setinfo_file(tree, &sfinfo);
1930 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1931 torture_comment(tctx, "(%s) %s - %s (should be %s)\n",
1932 __location__, "SETATTR",
1933 nt_errstr(status), nt_errstr(NT_STATUS_OK));
1938 smb2_util_close(tree, h1);
1940 ZERO_STRUCT(io.smb2);
1941 io.smb2.in.fname = fname;
1942 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1943 io.smb2.in.desired_access = SEC_FILE_READ_DATA;
1944 status = smb2_create(tree, mem_ctx, &(io.smb2));
1945 CHECK_STATUS(status, NT_STATUS_OK);
1946 h1 = io.smb2.out.file.handle;
1949 finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
1950 finfo.generic.in.file.handle = h1;
1951 status = smb2_getinfo_file(tree, mem_ctx, &finfo);
1952 CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1955 smb2_util_close(tree, h1);
1956 smb2_util_unlink(tree, fname);
1957 smb2_deltree(tree, DNAME);
1958 talloc_free(mem_ctx);
1963 static bool test_basefile_rename_with_open_stream(struct torture_context *tctx,
1964 struct smb2_tree *tree)
1968 struct smb2_tree *tree2 = NULL;
1969 struct smb2_create create, create2;
1970 struct smb2_handle h1 = {{0}}, h2 = {{0}};
1971 const char *fname = "test_rename_openfile";
1972 const char *sname = "test_rename_openfile:foo";
1973 const char *fname_renamed = "test_rename_openfile_renamed";
1974 union smb_setfileinfo sinfo;
1975 const char *data = "test data";
1977 ret = torture_smb2_connection(tctx, &tree2);
1978 torture_assert_goto(tctx, ret == true, ret, done,
1979 "torture_smb2_connection failed\n");
1981 torture_comment(tctx, "Creating file with stream\n");
1983 ZERO_STRUCT(create);
1984 create.in.desired_access = SEC_FILE_ALL;
1985 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
1986 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1987 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1988 create.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
1989 create.in.fname = sname;
1991 status = smb2_create(tree, tctx, &create);
1992 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1993 "smb2_create failed\n");
1995 h1 = create.out.file.handle;
1997 torture_comment(tctx, "Writing to stream\n");
1999 status = smb2_util_write(tree, h1, data, 0, strlen(data));
2000 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2001 "smb2_util_write failed\n");
2003 torture_comment(tctx, "Renaming base file\n");
2005 ZERO_STRUCT(create2);
2006 create2.in.desired_access = SEC_FILE_ALL;
2007 create2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2008 create2.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
2009 create2.in.create_disposition = NTCREATEX_DISP_OPEN;
2010 create2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
2011 create2.in.fname = fname;
2013 status = smb2_create(tree2, tctx, &create2);
2014 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2015 "smb2_create failed\n");
2017 h2 = create2.out.file.handle;
2020 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
2021 sinfo.rename_information.in.file.handle = h2;
2022 sinfo.rename_information.in.new_name = fname_renamed;
2024 status = smb2_setinfo_file(tree2, &sinfo);
2025 torture_assert_ntstatus_equal_goto(
2026 tctx, status, NT_STATUS_ACCESS_DENIED, ret, done,
2027 "smb2_setinfo_file didn't return NT_STATUS_ACCESS_DENIED\n");
2029 smb2_util_close(tree2, h2);
2032 if (!smb2_util_handle_empty(h1)) {
2033 smb2_util_close(tree, h1);
2035 if (!smb2_util_handle_empty(h2)) {
2036 smb2_util_close(tree2, h2);
2038 smb2_util_unlink(tree, fname);
2039 smb2_util_unlink(tree, fname_renamed);
2045 basic testing of streams calls SMB2
2047 struct torture_suite *torture_smb2_streams_init(TALLOC_CTX *ctx)
2049 struct torture_suite *suite =
2050 torture_suite_create(ctx, "streams");
2052 torture_suite_add_1smb2_test(suite, "dir", test_stream_dir);
2053 torture_suite_add_1smb2_test(suite, "io", test_stream_io);
2054 torture_suite_add_1smb2_test(suite, "sharemodes", test_stream_sharemodes);
2055 torture_suite_add_1smb2_test(suite, "names", test_stream_names);
2056 torture_suite_add_1smb2_test(suite, "names2", test_stream_names2);
2057 torture_suite_add_1smb2_test(suite, "names3", test_stream_names3);
2058 torture_suite_add_1smb2_test(suite, "rename", test_stream_rename);
2059 torture_suite_add_1smb2_test(suite, "rename2", test_stream_rename2);
2060 torture_suite_add_1smb2_test(suite, "create-disposition", test_stream_create_disposition);
2061 torture_suite_add_1smb2_test(suite, "attributes", test_stream_attributes);
2062 torture_suite_add_1smb2_test(suite, "delete", test_stream_delete);
2063 torture_suite_add_1smb2_test(suite, "zero-byte", test_zero_byte_stream);
2064 torture_suite_add_1smb2_test(suite, "basefile-rename-with-open-stream",
2065 test_basefile_rename_with_open_stream);
2067 suite->description = talloc_strdup(suite, "SMB2-STREAM tests");