ctdb-scripts: Support storing statd-callout state in cluster filesystem
[samba4-gss.git] / source4 / torture / smb2 / streams.c
blobbfdb41a3a38cf8a679e892da94b4aa93c803478c
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 "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
26 #include "smb_constants.h"
27 #include "torture/torture.h"
28 #include "torture/smb2/proto.h"
30 #include "system/filesys.h"
31 #include "system/locale.h"
32 #include "lib/util/tsort.h"
33 #include "libcli/security/security_descriptor.h"
35 #define DNAME "teststreams"
37 #define CHECK_STATUS(status, correct) \
38 torture_assert_ntstatus_equal_goto(tctx, status, correct, ret, done, "CHECK_STATUS")
40 #define CHECK_VALUE(v, correct) \
41 torture_assert_u64_equal_goto(tctx, v, correct, ret, done, "CHECK_VALUE")
43 #define CHECK_NTTIME(v, correct) \
44 torture_assert_nttime_equal_goto(tctx, v, correct, ret, done, "CHECK_NTTIME")
46 #define CHECK_STR(v, correct) \
47 torture_assert_str_equal_goto(tctx, v, correct, ret, done, "CHECK_STR")
49 static int qsort_string(char * const *s1, char * const *s2)
51 return strcmp(*s1, *s2);
54 static int qsort_stream(const struct stream_struct * s1, const struct stream_struct *s2)
56 return strcmp(s1->stream_name.s, s2->stream_name.s);
59 static bool check_stream(struct torture_context *tctx,
60 struct smb2_tree *tree,
61 const char *location,
62 TALLOC_CTX *mem_ctx,
63 const char *fname,
64 const char *sname,
65 const char *value)
67 struct smb2_handle handle;
68 struct smb2_create create;
69 struct smb2_read r;
70 NTSTATUS status;
71 const char *full_name;
73 full_name = talloc_asprintf(mem_ctx, "%s:%s", fname, sname);
75 ZERO_STRUCT(create);
76 create.in.desired_access = SEC_RIGHTS_FILE_ALL;
77 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
78 create.in.create_disposition = NTCREATEX_DISP_OPEN;
79 create.in.fname = full_name;
81 status = smb2_create(tree, mem_ctx, &create);
82 if (!NT_STATUS_IS_OK(status)) {
83 if (value == NULL) {
84 return true;
85 } else {
86 torture_comment(tctx, "Unable to open stream %s\n",
87 full_name);
88 return false;
92 handle = create.out.file.handle;
93 if (value == NULL) {
94 return true;
98 ZERO_STRUCT(r);
99 r.in.file.handle = handle;
100 r.in.length = strlen(value)+11;
101 r.in.offset = 0;
103 status = smb2_read(tree, tree, &r);
105 if (!NT_STATUS_IS_OK(status)) {
106 torture_comment(tctx, "(%s) Failed to read %lu bytes from "
107 "stream '%s'\n", location, (long)strlen(value), full_name);
108 return false;
111 if (memcmp(r.out.data.data, value, strlen(value)) != 0) {
112 torture_comment(tctx, "(%s) Bad data in stream\n", location);
113 return false;
116 smb2_util_close(tree, handle);
117 return true;
120 static bool check_stream_list(struct smb2_tree *tree,
121 struct torture_context *tctx,
122 const char *fname,
123 unsigned int num_exp,
124 const char **exp,
125 struct smb2_handle h)
127 union smb_fileinfo finfo;
128 NTSTATUS status;
129 unsigned int i;
130 TALLOC_CTX *tmp_ctx = talloc_new(tctx);
131 char **exp_sort;
132 struct stream_struct *stream_sort;
133 bool ret = false;
135 finfo.generic.level = RAW_FILEINFO_STREAM_INFORMATION;
136 finfo.generic.in.file.handle = h;
138 status = smb2_getinfo_file(tree, tctx, &finfo);
139 if (!NT_STATUS_IS_OK(status)) {
140 torture_comment(tctx, "(%s) smb_raw_pathinfo failed: %s\n",
141 __location__, nt_errstr(status));
142 goto fail;
145 if (finfo.stream_info.out.num_streams != num_exp) {
146 torture_comment(tctx, "(%s) expected %d streams, got %d\n",
147 __location__, num_exp, finfo.stream_info.out.num_streams);
148 goto fail;
151 if (num_exp == 0) {
152 ret = true;
153 goto fail;
156 exp_sort = talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp));
158 if (exp_sort == NULL) {
159 goto fail;
162 TYPESAFE_QSORT(exp_sort, num_exp, qsort_string);
164 stream_sort = talloc_memdup(tmp_ctx, finfo.stream_info.out.streams,
165 finfo.stream_info.out.num_streams *
166 sizeof(*stream_sort));
168 if (stream_sort == NULL) {
169 goto fail;
172 TYPESAFE_QSORT(stream_sort, finfo.stream_info.out.num_streams, qsort_stream);
174 for (i=0; i<num_exp; i++) {
175 if (strcmp(exp_sort[i], stream_sort[i].stream_name.s) != 0) {
176 torture_comment(tctx,
177 "(%s) expected stream name %s, got %s\n",
178 __location__, exp_sort[i],
179 stream_sort[i].stream_name.s);
180 goto fail;
184 ret = true;
185 fail:
186 talloc_free(tmp_ctx);
187 return ret;
191 static bool test_stream_dir(struct torture_context *tctx,
192 struct smb2_tree *tree)
194 TALLOC_CTX *mem_ctx = talloc_new(tctx);
195 NTSTATUS status;
196 union smb_open io;
197 const char *fname = DNAME "\\stream.txt";
198 const char *sname1;
199 bool ret = true;
200 const char *basedir_data;
201 struct smb2_handle h;
203 smb2_util_unlink(tree, fname);
204 smb2_deltree(tree, DNAME);
206 status = torture_smb2_testdir(tree, DNAME, &h);
207 CHECK_STATUS(status, NT_STATUS_OK);
209 basedir_data = talloc_asprintf(mem_ctx, "%s::$DATA", DNAME);
210 sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
211 torture_comment(tctx, "%s\n", sname1);
213 torture_comment(tctx, "(%s) opening non-existent directory stream\n",
214 __location__);
215 ZERO_STRUCT(io.smb2);
216 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
217 io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
218 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
219 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
220 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
221 io.smb2.in.share_access = 0;
222 io.smb2.in.alloc_size = 0;
223 io.smb2.in.security_flags = 0;
224 io.smb2.in.fname = sname1;
225 io.smb2.in.create_flags = 0;
226 status = smb2_create(tree, mem_ctx, &(io.smb2));
227 CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
229 torture_comment(tctx, "(%s) opening basedir stream\n", __location__);
230 ZERO_STRUCT(io.smb2);
231 io.smb2.in.create_flags = 0;
232 io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
233 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
234 io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
235 io.smb2.in.share_access = 0;
236 io.smb2.in.alloc_size = 0;
237 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
238 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
239 io.smb2.in.security_flags = 0;
240 io.smb2.in.fname = basedir_data;
241 status = smb2_create(tree, mem_ctx, &(io.smb2));
242 CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
244 torture_comment(tctx, "(%s) opening basedir ::$DATA stream\n",
245 __location__);
246 ZERO_STRUCT(io.smb2);
247 io.smb2.in.create_flags = 0x10;
248 io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
249 io.smb2.in.create_options = 0;
250 io.smb2.in.file_attributes = 0;
251 io.smb2.in.share_access = 0;
252 io.smb2.in.alloc_size = 0;
253 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
254 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
255 io.smb2.in.security_flags = 0;
256 io.smb2.in.fname = basedir_data;
257 status = smb2_create(tree, mem_ctx, &(io.smb2));
258 CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
260 torture_comment(tctx, "(%s) list the streams on the basedir\n",
261 __location__);
262 ret &= check_stream_list(tree, mem_ctx, DNAME, 0, NULL, h);
263 done:
264 smb2_util_unlink(tree, fname);
265 smb2_deltree(tree, DNAME);
266 talloc_free(mem_ctx);
268 return ret;
271 static bool test_stream_io(struct torture_context *tctx,
272 struct smb2_tree *tree)
274 TALLOC_CTX *mem_ctx = talloc_new(tctx);
275 NTSTATUS status;
276 union smb_open io;
277 const char *fname = DNAME "\\stream.txt";
278 const char *sname1, *sname2;
279 bool ret = true;
280 struct smb2_handle h, h2;
282 const char *one[] = { "::$DATA" };
283 const char *two[] = { "::$DATA", ":Second Stream:$DATA" };
284 const char *three[] = { "::$DATA", ":Stream One:$DATA",
285 ":Second Stream:$DATA" };
287 ZERO_STRUCT(h);
288 ZERO_STRUCT(h2);
290 sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
291 sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
292 "Second Stream");
294 smb2_util_unlink(tree, fname);
295 smb2_deltree(tree, DNAME);
297 status = torture_smb2_testdir(tree, DNAME, &h);
298 CHECK_STATUS(status, NT_STATUS_OK);
300 torture_comment(tctx, "(%s) creating a stream on a non-existent file\n",
301 __location__);
303 ZERO_STRUCT(io.smb2);
304 io.smb2.in.create_flags = 0;
305 io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
306 io.smb2.in.create_options = 0;
307 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
308 io.smb2.in.share_access = 0;
309 io.smb2.in.alloc_size = 0;
310 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
311 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
312 io.smb2.in.security_flags = 0;
313 io.smb2.in.fname = sname1;
314 status = smb2_create(tree, mem_ctx, &(io.smb2));
315 CHECK_STATUS(status, NT_STATUS_OK);
316 h2 = io.smb2.out.file.handle;
318 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
319 "Stream One", NULL);
321 torture_comment(tctx, "(%s) check that open of base file is allowed\n", __location__);
322 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
323 io.smb2.in.fname = fname;
324 status = smb2_create(tree, mem_ctx, &(io.smb2));
325 CHECK_STATUS(status, NT_STATUS_OK);
326 smb2_util_close(tree, io.smb2.out.file.handle);
328 torture_comment(tctx, "(%s) writing to stream\n", __location__);
329 status = smb2_util_write(tree, h2, "test data", 0, 9);
330 CHECK_STATUS(status, NT_STATUS_OK);
332 smb2_util_close(tree, h2);
334 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
335 "Stream One", "test data");
337 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
338 io.smb2.in.fname = sname1;
339 status = smb2_create(tree, mem_ctx, &(io.smb2));
340 CHECK_STATUS(status, NT_STATUS_OK);
341 h2 = io.smb2.out.file.handle;
343 torture_comment(tctx, "(%s) modifying stream\n", __location__);
344 status = smb2_util_write(tree, h2, "MORE DATA ", 5, 10);
345 CHECK_STATUS(status, NT_STATUS_OK);
347 smb2_util_close(tree, h2);
349 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
350 "Stream One:$FOO", NULL);
352 torture_comment(tctx, "(%s) creating a stream2 on a existing file\n",
353 __location__);
354 io.smb2.in.fname = sname2;
355 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
356 status = smb2_create(tree, mem_ctx, &(io.smb2));
357 CHECK_STATUS(status, NT_STATUS_OK);
358 h2 = io.smb2.out.file.handle;
360 torture_comment(tctx, "(%s) modifying stream\n", __location__);
361 status= smb2_util_write(tree, h2, "SECOND STREAM", 0, 13);
362 CHECK_STATUS(status, NT_STATUS_OK);
363 smb2_util_close(tree, h2);
365 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
366 "Stream One", "test MORE DATA ");
368 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
369 "Stream One:$DATA", "test MORE DATA ");
371 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
372 "Stream One:", NULL);
374 if (!ret) {
375 torture_result(tctx, TORTURE_FAIL,
376 "check_stream(\"Stream One:*\") failed\n");
377 goto done;
380 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
381 "Second Stream", "SECOND STREAM");
383 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
384 "SECOND STREAM:$DATA", "SECOND STREAM");
385 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
386 "Second Stream:$DATA", "SECOND STREAM");
388 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
389 "Second Stream:", NULL);
391 ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
392 "Second Stream:$FOO", NULL);
394 if (!ret) {
395 torture_result(tctx, TORTURE_FAIL,
396 "check_stream(\"Second Stream:*\") failed\n");
397 goto done;
400 io.smb2.in.fname = sname2;
401 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
402 status = smb2_create(tree, mem_ctx, &(io.smb2));
403 CHECK_STATUS(status, NT_STATUS_OK);
404 h2 = io.smb2.out.file.handle;
405 check_stream_list(tree, tctx, fname, 3, three, h2);
407 smb2_util_close(tree, h2);
409 torture_comment(tctx, "(%s) deleting stream\n", __location__);
410 status = smb2_util_unlink(tree, sname1);
411 CHECK_STATUS(status, NT_STATUS_OK);
413 io.smb2.in.fname = sname2;
414 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
415 status = smb2_create(tree, mem_ctx, &(io.smb2));
416 CHECK_STATUS(status, NT_STATUS_OK);
417 h2 = io.smb2.out.file.handle;
418 check_stream_list(tree, tctx, fname, 2, two, h2);
419 smb2_util_close(tree, h2);
421 torture_comment(tctx, "(%s) delete a stream via delete-on-close\n",
422 __location__);
423 io.smb2.in.fname = sname2;
424 io.smb2.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
425 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
426 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
427 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
429 status = smb2_create(tree, mem_ctx, &(io.smb2));
430 CHECK_STATUS(status, NT_STATUS_OK);
431 h2 = io.smb2.out.file.handle;
433 smb2_util_close(tree, h2);
434 status = smb2_util_unlink(tree, sname2);
435 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
437 io.smb2.in.fname = fname;
438 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
439 status = smb2_create(tree, mem_ctx, &(io.smb2));
440 h2 = io.smb2.out.file.handle;
441 check_stream_list(tree,tctx, fname, 1, one, h2);
442 smb2_util_close(tree, h2);
444 if (!torture_setting_bool(tctx, "samba4", false)) {
445 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
446 io.smb2.in.fname = sname1;
447 status = smb2_create(tree, mem_ctx, &(io.smb2));
448 CHECK_STATUS(status, NT_STATUS_OK);
449 smb2_util_close(tree, io.ntcreatex.out.file.handle);
450 io.smb2.in.fname = sname2;
451 status = smb2_create(tree, mem_ctx, &(io.smb2));
452 CHECK_STATUS(status, NT_STATUS_OK);
453 smb2_util_close(tree, io.ntcreatex.out.file.handle);
454 torture_comment(tctx, "(%s) deleting file\n", __location__);
455 status = smb2_util_unlink(tree, fname);
456 CHECK_STATUS(status, NT_STATUS_OK);
460 done:
461 smb2_util_close(tree, h2);
462 smb2_deltree(tree, DNAME);
463 talloc_free(mem_ctx);
465 return ret;
468 static bool test_zero_byte_stream(struct torture_context *tctx,
469 struct smb2_tree *tree)
471 TALLOC_CTX *mem_ctx = talloc_new(tctx);
472 NTSTATUS status;
473 union smb_open io;
474 const char *fname = DNAME "\\stream.txt";
475 const char *sname;
476 bool ret = true;
477 struct smb2_handle h, bh;
478 const char *streams[] = { "::$DATA", ":foo:$DATA" };
480 sname = talloc_asprintf(mem_ctx, "%s:%s", fname, "foo");
482 smb2_util_unlink(tree, fname);
483 smb2_deltree(tree, DNAME);
485 status = torture_smb2_testdir(tree, DNAME, &h);
486 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "testdir");
487 smb2_util_close(tree, h);
489 torture_comment(tctx, "(%s) Check 0 byte named stream\n",
490 __location__);
492 /* Create basefile */
493 ZERO_STRUCT(io);
494 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
495 io.smb2.in.fname = fname;
496 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
497 SEC_FILE_WRITE_ATTRIBUTE |
498 SEC_FILE_READ_DATA |
499 SEC_FILE_WRITE_DATA;
500 status = smb2_create(tree, mem_ctx, &(io.smb2));
501 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "create");
502 smb2_util_close(tree, io.smb2.out.file.handle);
504 /* Create named stream and close it */
505 ZERO_STRUCT(io);
506 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
507 io.smb2.in.fname = sname;
508 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
509 SEC_FILE_WRITE_ATTRIBUTE |
510 SEC_FILE_READ_DATA |
511 SEC_FILE_WRITE_DATA;
512 status = smb2_create(tree, mem_ctx, &(io.smb2));
513 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "create");
514 smb2_util_close(tree, io.smb2.out.file.handle);
517 * Check stream list, the 0 byte stream MUST be returned by
518 * the server.
520 ZERO_STRUCT(io);
521 io.smb2.in.fname = fname;
522 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
523 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
524 SEC_FILE_WRITE_ATTRIBUTE |
525 SEC_FILE_READ_DATA |
526 SEC_FILE_WRITE_DATA;
527 status = smb2_create(tree, mem_ctx, &(io.smb2));
528 bh = io.smb2.out.file.handle;
530 ret = check_stream_list(tree,tctx, fname, 2, streams, bh);
531 torture_assert_goto(tctx, ret == true, ret, done, "smb2_create");
532 smb2_util_close(tree, bh);
534 done:
535 smb2_deltree(tree, DNAME);
536 talloc_free(mem_ctx);
538 return ret;
542 test stream sharemodes
544 static bool test_stream_sharemodes(struct torture_context *tctx,
545 struct smb2_tree *tree)
547 TALLOC_CTX *mem_ctx = talloc_new(tctx);
548 NTSTATUS status;
549 union smb_open io;
550 const char *fname = DNAME "\\stream_share.txt";
551 const char *sname1, *sname2;
552 bool ret = true;
553 struct smb2_handle h, h1, h2;
555 ZERO_STRUCT(h);
556 ZERO_STRUCT(h1);
557 ZERO_STRUCT(h2);
559 sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
560 sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
561 "Second Stream");
563 smb2_util_unlink(tree, fname);
564 smb2_deltree(tree, DNAME);
566 status = torture_smb2_testdir(tree, DNAME, &h);
567 CHECK_STATUS(status, NT_STATUS_OK);
569 torture_comment(tctx, "(%s) Testing stream share mode conflicts\n",
570 __location__);
571 ZERO_STRUCT(io.smb2);
572 io.generic.level = RAW_OPEN_SMB2;
573 io.smb2.in.create_flags = 0;
574 io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
575 io.smb2.in.create_options = 0;
576 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
577 io.smb2.in.share_access = 0;
578 io.smb2.in.alloc_size = 0;
579 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
580 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
581 io.smb2.in.security_flags = 0;
582 io.smb2.in.fname = sname1;
584 status = smb2_create(tree, mem_ctx, &(io.smb2));
585 CHECK_STATUS(status, NT_STATUS_OK);
586 h1 = io.smb2.out.file.handle;
589 * A different stream does not give a sharing violation
592 io.smb2.in.fname = sname2;
593 status = smb2_create(tree, mem_ctx, &(io.smb2));
594 CHECK_STATUS(status, NT_STATUS_OK);
595 h2 = io.smb2.out.file.handle;
598 * ... whereas the same stream does with unchanged access/share_access
599 * flags
602 io.smb2.in.fname = sname1;
603 io.smb2.in.create_disposition = 0;
604 status = smb2_create(tree, mem_ctx, &(io.smb2));
605 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
607 io.smb2.in.fname = sname2;
608 status = smb2_create(tree, mem_ctx, &(io.smb2));
609 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
611 done:
612 smb2_util_close(tree, h1);
613 smb2_util_close(tree, h2);
614 status = smb2_util_unlink(tree, fname);
615 smb2_deltree(tree, DNAME);
616 talloc_free(mem_ctx);
618 return ret;
622 * Test FILE_SHARE_DELETE on streams
624 * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
625 * with SEC_STD_DELETE.
627 * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
628 * be opened with SEC_STD_DELETE.
630 * A stream held open with FILE_SHARE_DELETE allows the file to be
631 * deleted. After the main file is deleted, access to the open file descriptor
632 * still works, but all name-based access to both the main file as well as the
633 * stream is denied with DELETE pending.
635 * This means, an open of the main file with SEC_STD_DELETE should walk all
636 * streams and also open them with SEC_STD_DELETE. If any of these opens gives
637 * SHARING_VIOLATION, the main open fails.
639 * Closing the main file after delete_on_close has been set does not really
640 * unlink it but leaves the corresponding share mode entry with
641 * delete_on_close being set around until all streams are closed.
643 * Opening a stream must also look at the main file's share mode entry, look
644 * at the delete_on_close bit and potentially return DELETE_PENDING.
647 static bool test_stream_delete(struct torture_context *tctx,
648 struct smb2_tree *tree)
650 TALLOC_CTX *mem_ctx = talloc_new(tctx);
651 NTSTATUS status;
652 union smb_open io;
653 const char *fname = DNAME "\\stream_delete.txt";
654 const char *sname1;
655 bool ret = true;
656 struct smb2_handle h = {{0}};
657 struct smb2_handle h1 = {{0}};
658 struct smb2_read r;
660 if (torture_setting_bool(tctx, "samba4", false)) {
661 torture_comment(tctx, "Skipping test as samba4 is enabled\n");
662 goto done;
665 ZERO_STRUCT(h);
666 ZERO_STRUCT(h1);
668 sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
670 /* clean slate .. */
671 smb2_util_unlink(tree, fname);
672 smb2_deltree(tree, fname);
673 smb2_deltree(tree, DNAME);
675 status = torture_smb2_testdir(tree, DNAME, &h);
676 CHECK_STATUS(status, NT_STATUS_OK);
678 torture_comment(tctx, "(%s) opening non-existent file stream\n",
679 __location__);
680 ZERO_STRUCT(io.smb2);
681 io.smb2.in.create_flags = 0;
682 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
683 io.smb2.in.create_options = 0;
684 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
685 io.smb2.in.share_access = 0;
686 io.smb2.in.alloc_size = 0;
687 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
688 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
689 io.smb2.in.security_flags = 0;
690 io.smb2.in.fname = sname1;
692 status = smb2_create(tree, mem_ctx, &(io.smb2));
693 CHECK_STATUS(status, NT_STATUS_OK);
694 h1 = io.smb2.out.file.handle;
696 status = smb2_util_write(tree, h1, "test data", 0, 9);
697 CHECK_STATUS(status, NT_STATUS_OK);
700 * One stream opened without FILE_SHARE_DELETE prevents the main file
701 * to be deleted or even opened with DELETE access
704 status = smb2_util_unlink(tree, fname);
705 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
707 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
708 io.smb2.in.fname = fname;
709 io.smb2.in.desired_access = SEC_STD_DELETE;
710 status = smb2_create(tree, mem_ctx, &(io.smb2));
711 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
713 smb2_util_close(tree, h1);
716 * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
719 io.smb2.in.fname = sname1;
720 io.smb2.in.desired_access = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
721 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
722 NTCREATEX_SHARE_ACCESS_READ |
723 NTCREATEX_SHARE_ACCESS_WRITE;
724 status = smb2_create(tree, mem_ctx, &(io.smb2));
725 CHECK_STATUS(status, NT_STATUS_OK);
726 h1 = io.smb2.out.file.handle;
728 status = smb2_util_unlink(tree, fname);
729 CHECK_STATUS(status, NT_STATUS_OK);
732 * file access still works on the stream while the main file is closed
734 ZERO_STRUCT(r);
735 r.in.file.handle = h1;
736 r.in.length = 9;
737 r.in.offset = 0;
739 status = smb2_read(tree, tree, &r);
740 CHECK_STATUS(status, NT_STATUS_OK);
743 * name-based access to both the main file and the stream does not
744 * work anymore but gives DELETE_PENDING
747 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
748 io.smb2.in.fname = fname;
749 status = smb2_create(tree, mem_ctx, &(io.smb2));
750 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
753 * older S3 doesn't do this
756 io.smb2.in.fname = sname1;
757 status = smb2_create(tree, mem_ctx, &(io.smb2));
758 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
760 smb2_util_close(tree, h1);
761 ZERO_STRUCT(h1);
764 * After closing the stream the file is really gone.
767 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
768 io.smb2.in.fname = fname;
769 status = smb2_create(tree, mem_ctx, &(io.smb2));
770 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
772 done:
773 if (!smb2_util_handle_empty(h1)) {
774 smb2_util_close(tree, h1);
776 smb2_util_unlink(tree, fname);
777 smb2_deltree(tree, DNAME);
778 talloc_free(mem_ctx);
780 return ret;
784 test stream names
786 static bool test_stream_names(struct torture_context *tctx,
787 struct smb2_tree *tree)
789 TALLOC_CTX *mem_ctx = talloc_new(tctx);
790 NTSTATUS status;
791 union smb_open io;
792 union smb_fileinfo finfo;
793 union smb_fileinfo stinfo;
794 union smb_setfileinfo sinfo;
795 const char *fname = DNAME "\\stream_names.txt";
796 const char *sname1, *sname1b, *sname1c, *sname1d;
797 const char *sname2, *snamew, *snamew2;
798 const char *snamer1;
799 bool ret = true;
800 struct smb2_handle h, h1, h2, h3;
801 int i;
802 const char *four[4] = {
803 "::$DATA",
804 ":\x05Stream\n One:$DATA",
805 ":MStream Two:$DATA",
806 ":?Stream*:$DATA"
808 const char *five1[5] = {
809 "::$DATA",
810 ":\x05Stream\n One:$DATA",
811 ":BeforeRename:$DATA",
812 ":MStream Two:$DATA",
813 ":?Stream*:$DATA"
815 const char *five2[5] = {
816 "::$DATA",
817 ":\x05Stream\n One:$DATA",
818 ":AfterRename:$DATA",
819 ":MStream Two:$DATA",
820 ":?Stream*:$DATA"
823 ZERO_STRUCT(h);
824 ZERO_STRUCT(h1);
825 ZERO_STRUCT(h2);
826 ZERO_STRUCT(h3);
828 sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "\x05Stream\n One");
829 sname1b = talloc_asprintf(mem_ctx, "%s:", sname1);
830 sname1c = talloc_asprintf(mem_ctx, "%s:$FOO", sname1);
831 sname1d = talloc_asprintf(mem_ctx, "%s:?D*a", sname1);
832 sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "MStream Two");
833 snamew = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname, "?Stream*");
834 snamew2 = talloc_asprintf(mem_ctx, "%s\\stream*:%s:$DATA", DNAME,
835 "?Stream*");
836 snamer1 = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname,
837 "BeforeRename");
839 /* clean slate ...*/
840 smb2_util_unlink(tree, fname);
841 smb2_deltree(tree, fname);
842 smb2_deltree(tree, DNAME);
844 status = torture_smb2_testdir(tree, DNAME, &h);
845 CHECK_STATUS(status, NT_STATUS_OK);
847 torture_comment(tctx, "(%s) testing stream names\n", __location__);
848 ZERO_STRUCT(io.smb2);
849 io.smb2.in.create_flags = 0;
850 io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
851 io.smb2.in.create_options = 0;
852 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
853 io.smb2.in.share_access = 0;
854 io.smb2.in.alloc_size = 0;
855 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
856 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
857 io.smb2.in.security_flags = 0;
858 io.smb2.in.fname = sname1;
860 status = smb2_create(tree, mem_ctx, &(io.smb2));
861 CHECK_STATUS(status, NT_STATUS_OK);
862 h1 = io.smb2.out.file.handle;
865 * A different stream does not give a sharing violation
868 io.smb2.in.fname = sname2;
869 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
870 status = smb2_create(tree, mem_ctx, &(io.smb2));
871 CHECK_STATUS(status, NT_STATUS_OK);
872 h2 = io.smb2.out.file.handle;
875 * ... whereas the same stream does with unchanged access/share_access
876 * flags
879 io.smb2.in.fname = sname1;
880 io.smb2.in.create_disposition = NTCREATEX_DISP_SUPERSEDE;
881 status = smb2_create(tree, mem_ctx, &(io.smb2));
882 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
884 io.smb2.in.fname = sname1b;
885 status = smb2_create(tree, mem_ctx, &(io.smb2));
886 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
888 io.smb2.in.fname = sname1c;
889 status = smb2_create(tree, mem_ctx, &(io.smb2));
890 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
891 /* w2k returns INVALID_PARAMETER */
892 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
893 } else {
894 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
897 io.smb2.in.fname = sname1d;
898 status = smb2_create(tree, mem_ctx, &(io.smb2));
899 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
900 /* w2k returns INVALID_PARAMETER */
901 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
902 } else {
903 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
906 io.smb2.in.fname = sname2;
907 status = smb2_create(tree, mem_ctx, &(io.smb2));
908 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
910 io.smb2.in.fname = snamew;
911 status = smb2_create(tree, mem_ctx, &(io.smb2));
912 CHECK_STATUS(status, NT_STATUS_OK);
913 h3 = io.smb2.out.file.handle;
915 io.smb2.in.fname = snamew2;
916 status = smb2_create(tree, mem_ctx, &(io.smb2));
917 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
919 io.smb2.in.fname = fname;
920 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
921 status = smb2_create(tree, mem_ctx, &(io.smb2));
922 CHECK_STATUS(status, NT_STATUS_OK);
923 ret &= check_stream_list(tree, tctx, fname, 4, four,
924 io.smb2.out.file.handle);
925 CHECK_VALUE(ret, true);
926 smb2_util_close(tree, h1);
927 smb2_util_close(tree, h2);
928 smb2_util_close(tree, h3);
930 if (torture_setting_bool(tctx, "samba4", true)) {
931 goto done;
934 finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
935 finfo.generic.in.file.handle = io.smb2.out.file.handle;
936 status = smb2_getinfo_file(tree, mem_ctx, &finfo);
937 CHECK_STATUS(status, NT_STATUS_OK);
938 ret &= check_stream_list(tree, tctx, fname, 4, four,
939 io.smb2.out.file.handle);
941 CHECK_VALUE(ret, true);
942 for (i=0; i < 4; i++) {
943 NTTIME write_time;
944 uint64_t stream_size;
945 char *path = talloc_asprintf(tctx, "%s%s",
946 fname, four[i]);
948 char *rpath = talloc_strdup(path, path);
949 char *p = strrchr(rpath, ':');
950 /* eat :$DATA */
951 *p = 0;
952 p--;
953 if (*p == ':') {
954 /* eat ::$DATA */
955 *p = 0;
957 torture_comment(tctx, "(%s): i[%u][%s]\n",
958 __location__, i,path);
959 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
960 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
961 SEC_FILE_WRITE_ATTRIBUTE |
962 SEC_RIGHTS_FILE_ALL;
963 io.smb2.in.fname = path;
964 status = smb2_create(tree, mem_ctx, &(io.smb2));
965 CHECK_STATUS(status, NT_STATUS_OK);
966 h1 = io.smb2.out.file.handle;
968 finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
969 finfo.generic.in.file.path = fname;
970 status = smb2_getinfo_file(tree, mem_ctx, &finfo);
971 CHECK_STATUS(status, NT_STATUS_OK);
973 stinfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
974 stinfo.generic.in.file.handle = h1;
975 status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
976 CHECK_STATUS(status, NT_STATUS_OK);
977 if (!torture_setting_bool(tctx, "samba3", false)) {
978 CHECK_NTTIME(stinfo.all_info.out.create_time,
979 finfo.all_info.out.create_time);
980 CHECK_NTTIME(stinfo.all_info.out.access_time,
981 finfo.all_info.out.access_time);
982 CHECK_NTTIME(stinfo.all_info.out.write_time,
983 finfo.all_info.out.write_time);
984 CHECK_NTTIME(stinfo.all_info.out.change_time,
985 finfo.all_info.out.change_time);
987 CHECK_VALUE(stinfo.all_info.out.attrib,
988 finfo.all_info.out.attrib);
989 CHECK_VALUE(stinfo.all_info.out.size,
990 finfo.all_info.out.size);
991 CHECK_VALUE(stinfo.all_info.out.delete_pending,
992 finfo.all_info.out.delete_pending);
993 CHECK_VALUE(stinfo.all_info.out.directory,
994 finfo.all_info.out.directory);
995 CHECK_VALUE(stinfo.all_info.out.ea_size,
996 finfo.all_info.out.ea_size);
998 stinfo.generic.level = RAW_FILEINFO_NAME_INFORMATION;
999 stinfo.generic.in.file.handle = h1;
1000 status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
1001 CHECK_STATUS(status, NT_STATUS_OK);
1002 if (!torture_setting_bool(tctx, "samba3", false)) {
1003 CHECK_STR(rpath, stinfo.name_info.out.fname.s);
1006 write_time = finfo.all_info.out.write_time;
1007 write_time += i*1000000;
1008 write_time /= 1000000;
1009 write_time *= 1000000;
1011 ZERO_STRUCT(sinfo);
1012 sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
1013 sinfo.basic_info.in.file.handle = h1;
1014 sinfo.basic_info.in.write_time = write_time;
1015 sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
1016 status = smb2_setinfo_file(tree, &sinfo);
1017 CHECK_STATUS(status, NT_STATUS_OK);
1019 stream_size = i*8192;
1021 ZERO_STRUCT(sinfo);
1022 sinfo.end_of_file_info.level =
1023 RAW_SFILEINFO_END_OF_FILE_INFORMATION;
1024 sinfo.end_of_file_info.in.file.handle = h1;
1025 sinfo.end_of_file_info.in.size = stream_size;
1026 status = smb2_setinfo_file(tree, &sinfo);
1027 CHECK_STATUS(status, NT_STATUS_OK);
1029 stinfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
1030 stinfo.generic.in.file.handle = h1;
1031 status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
1032 CHECK_STATUS(status, NT_STATUS_OK);
1033 if (!torture_setting_bool(tctx, "samba3", false)) {
1034 CHECK_NTTIME(stinfo.all_info.out.write_time,
1035 write_time);
1036 CHECK_VALUE(stinfo.all_info.out.attrib,
1037 finfo.all_info.out.attrib);
1039 CHECK_VALUE(stinfo.all_info.out.size,
1040 stream_size);
1041 CHECK_VALUE(stinfo.all_info.out.delete_pending,
1042 finfo.all_info.out.delete_pending);
1043 CHECK_VALUE(stinfo.all_info.out.directory,
1044 finfo.all_info.out.directory);
1045 CHECK_VALUE(stinfo.all_info.out.ea_size,
1046 finfo.all_info.out.ea_size);
1048 io.smb2.in.fname = fname;
1049 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1050 status = smb2_create(tree, mem_ctx, &(io.smb2));
1051 CHECK_STATUS(status, NT_STATUS_OK);
1052 ret &= check_stream_list(tree, tctx, fname, 4, four,
1053 io.smb2.out.file.handle);
1055 smb2_util_close(tree, h1);
1056 talloc_free(path);
1059 torture_comment(tctx, "(%s): testing stream renames\n", __location__);
1060 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1061 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1062 SEC_FILE_WRITE_ATTRIBUTE |
1063 SEC_RIGHTS_FILE_ALL;
1064 io.smb2.in.fname = snamer1;
1065 status = smb2_create(tree, mem_ctx, &(io.smb2));
1066 CHECK_STATUS(status, NT_STATUS_OK);
1067 h1 = io.smb2.out.file.handle;
1068 ret &= check_stream_list(tree,tctx, fname, 5, five1,
1069 io.smb2.out.file.handle);
1071 ZERO_STRUCT(sinfo);
1072 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1073 sinfo.rename_information.in.file.handle = h1;
1074 sinfo.rename_information.in.overwrite = true;
1075 sinfo.rename_information.in.root_fid = 0;
1076 sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
1077 status = smb2_setinfo_file(tree, &sinfo);
1078 CHECK_STATUS(status, NT_STATUS_OK);
1080 ret &= check_stream_list(tree,tctx, fname, 5, five2,
1081 io.smb2.out.file.handle);
1083 CHECK_VALUE(ret, true);
1084 ZERO_STRUCT(sinfo);
1085 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1086 sinfo.rename_information.in.file.handle = h1;
1087 sinfo.rename_information.in.overwrite = false;
1088 sinfo.rename_information.in.root_fid = 0;
1089 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
1090 status = smb2_setinfo_file(tree, &sinfo);
1091 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
1093 ret &= check_stream_list(tree,tctx, fname, 5, five2,
1094 io.smb2.out.file.handle);
1096 ZERO_STRUCT(sinfo);
1097 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1098 sinfo.rename_information.in.file.handle = h1;
1099 sinfo.rename_information.in.overwrite = true;
1100 sinfo.rename_information.in.root_fid = 0;
1101 sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
1102 status = smb2_setinfo_file(tree, &sinfo);
1103 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1105 ret &= check_stream_list(tree,tctx, fname, 5, five2,
1106 io.smb2.out.file.handle);
1108 CHECK_VALUE(ret, true);
1109 /* TODO: we need to test more rename combinations */
1111 done:
1112 smb2_util_close(tree, h1);
1113 status = smb2_util_unlink(tree, fname);
1114 smb2_deltree(tree, DNAME);
1115 talloc_free(mem_ctx);
1117 return ret;
1121 test stream names
1123 static bool test_stream_names2(struct torture_context *tctx,
1124 struct smb2_tree *tree)
1126 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1127 NTSTATUS status;
1128 union smb_open io;
1129 const char *fname = DNAME "\\stream_names2.txt";
1130 bool ret = true;
1131 struct smb2_handle h = {{0}};
1132 struct smb2_handle h1 = {{0}};
1133 uint8_t i;
1135 smb2_util_unlink(tree, fname);
1136 smb2_deltree(tree, DNAME);
1138 status = torture_smb2_testdir(tree, DNAME, &h);
1139 CHECK_STATUS(status, NT_STATUS_OK);
1141 torture_comment(tctx, "(%s) testing stream names\n", __location__);
1142 ZERO_STRUCT(io.smb2);
1143 io.smb2.in.create_flags = 0;
1144 io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
1145 io.smb2.in.create_options = 0;
1146 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1147 io.smb2.in.share_access = 0;
1148 io.smb2.in.alloc_size = 0;
1149 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1150 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1151 io.smb2.in.security_flags = 0;
1152 io.smb2.in.fname = fname;
1153 status = smb2_create(tree, mem_ctx, &(io.smb2));
1154 CHECK_STATUS(status, NT_STATUS_OK);
1155 h1 = io.smb2.out.file.handle;
1157 for (i=0x01; i < 0x7F; i++) {
1158 char *path = talloc_asprintf(mem_ctx, "%s:Stream%c0x%02X:$DATA",
1159 fname, i, i);
1160 NTSTATUS expected;
1162 switch (i) {
1163 case '/':/*0x2F*/
1164 case ':':/*0x3A*/
1165 case '\\':/*0x5C*/
1166 expected = NT_STATUS_OBJECT_NAME_INVALID;
1167 break;
1168 default:
1169 expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1170 break;
1174 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1175 io.smb2.in.fname = path;
1176 status = smb2_create(tree, mem_ctx, &(io.smb2));
1177 if (!NT_STATUS_EQUAL(status, expected)) {
1178 torture_comment(tctx,
1179 "(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
1180 __location__, fname, isprint(i)?(char)i:' ', i,
1181 isprint(i)?"":" (not printable)",
1182 nt_errstr(expected));
1184 CHECK_STATUS(status, expected);
1186 talloc_free(path);
1189 done:
1190 smb2_util_close(tree, h1);
1191 status = smb2_util_unlink(tree, fname);
1192 smb2_deltree(tree, DNAME);
1193 talloc_free(mem_ctx);
1195 return ret;
1199 test case insensitive stream names
1201 static bool test_stream_names3(struct torture_context *tctx,
1202 struct smb2_tree *tree)
1204 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1205 NTSTATUS status;
1206 union smb_fsinfo info;
1207 const char *fname = DNAME "\\stream_names3.txt";
1208 const char *sname = NULL;
1209 const char *snamel = NULL;
1210 const char *snameu = NULL;
1211 const char *sdname = NULL;
1212 const char *sdnamel = NULL;
1213 const char *sdnameu = NULL;
1214 bool ret = true;
1215 struct smb2_handle h = {{0}};
1216 struct smb2_handle hf = {{0}};
1217 struct smb2_handle hs = {{0}};
1218 struct smb2_handle hsl = {{0}};
1219 struct smb2_handle hsu = {{0}};
1220 struct smb2_handle hsd = {{0}};
1221 struct smb2_handle hsdl = {{0}};
1222 struct smb2_handle hsdu = {{0}};
1223 const char *streams[] = { "::$DATA", ":StreamName:$DATA", };
1225 smb2_deltree(tree, DNAME);
1226 status = torture_smb2_testdir(tree, DNAME, &h);
1227 CHECK_STATUS(status, NT_STATUS_OK);
1229 ZERO_STRUCT(info);
1230 info.generic.level = RAW_QFS_ATTRIBUTE_INFORMATION;
1231 info.generic.handle = h;
1232 status = smb2_getinfo_fs(tree, tree, &info);
1233 CHECK_STATUS(status, NT_STATUS_OK);
1234 if (!(info.attribute_info.out.fs_attr & FILE_CASE_SENSITIVE_SEARCH)) {
1235 torture_skip(tctx, "No FILE_CASE_SENSITIVE_SEARCH supported");
1239 * We create the following file:
1241 * teststreams\\stream_names3.txt
1243 * and add a stream named 'StreamName'
1245 * Then we try to open the stream using the following names:
1247 * teststreams\\stream_names3.txt:StreamName
1248 * teststreams\\stream_names3.txt:streamname
1249 * teststreams\\stream_names3.txt:STREAMNAME
1250 * teststreams\\stream_names3.txt:StreamName:$dAtA
1251 * teststreams\\stream_names3.txt:streamname:$data
1252 * teststreams\\stream_names3.txt:STREAMNAME:$DATA
1254 sname = talloc_asprintf(tctx, "%s:StreamName", fname);
1255 torture_assert_not_null(tctx, sname, __location__);
1256 snamel = strlower_talloc(tctx, sname);
1257 torture_assert_not_null(tctx, snamel, __location__);
1258 snameu = strupper_talloc(tctx, sname);
1259 torture_assert_not_null(tctx, snameu, __location__);
1261 sdname = talloc_asprintf(tctx, "%s:$dAtA", sname);
1262 torture_assert_not_null(tctx, sdname, __location__);
1263 sdnamel = strlower_talloc(tctx, sdname);
1264 torture_assert_not_null(tctx, sdnamel, __location__);
1265 sdnameu = strupper_talloc(tctx, sdname);
1266 torture_assert_not_null(tctx, sdnameu, __location__);
1268 torture_comment(tctx, "(%s) testing case insensitive stream names\n",
1269 __location__);
1270 status = torture_smb2_testfile(tree, fname, &hf);
1271 CHECK_STATUS(status, NT_STATUS_OK);
1272 status = torture_smb2_testfile(tree, sname, &hs);
1273 CHECK_STATUS(status, NT_STATUS_OK);
1274 smb2_util_close(tree, hs);
1276 torture_assert(tctx,
1277 check_stream_list(tree, tctx, fname,
1278 ARRAY_SIZE(streams),
1279 streams,
1280 hf),
1281 "streams");
1283 status = torture_smb2_open(tree, sname, SEC_RIGHTS_FILE_ALL, &hs);
1284 CHECK_STATUS(status, NT_STATUS_OK);
1285 status = torture_smb2_open(tree, snamel, SEC_RIGHTS_FILE_ALL, &hsl);
1286 CHECK_STATUS(status, NT_STATUS_OK);
1287 status = torture_smb2_open(tree, snameu, SEC_RIGHTS_FILE_ALL, &hsu);
1288 CHECK_STATUS(status, NT_STATUS_OK);
1289 status = torture_smb2_open(tree, sdname, SEC_RIGHTS_FILE_ALL, &hsd);
1290 CHECK_STATUS(status, NT_STATUS_OK);
1291 status = torture_smb2_open(tree, sdnamel, SEC_RIGHTS_FILE_ALL, &hsdl);
1292 CHECK_STATUS(status, NT_STATUS_OK);
1293 status = torture_smb2_open(tree, sdnameu, SEC_RIGHTS_FILE_ALL, &hsdu);
1294 CHECK_STATUS(status, NT_STATUS_OK);
1296 done:
1297 smb2_util_close(tree, hsdu);
1298 smb2_util_close(tree, hsdl);
1299 smb2_util_close(tree, hsd);
1300 smb2_util_close(tree, hsu);
1301 smb2_util_close(tree, hsl);
1302 smb2_util_close(tree, hs);
1303 smb2_util_close(tree, hf);
1304 smb2_util_close(tree, h);
1305 status = smb2_util_unlink(tree, fname);
1306 smb2_deltree(tree, DNAME);
1307 talloc_free(mem_ctx);
1309 return ret;
1312 #define CHECK_CALL_HANDLE(call, rightstatus) do { \
1313 sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
1314 sfinfo.generic.in.file.handle = h1; \
1315 status = smb2_setinfo_file(tree, &sfinfo); \
1316 torture_assert_ntstatus_equal_goto(tctx, status, rightstatus, ret, done, #call); \
1317 finfo1.generic.level = RAW_FILEINFO_ALL_INFORMATION; \
1318 finfo1.generic.in.file.handle = h1; \
1319 status2 = smb2_getinfo_file(tree, tctx, &finfo1); \
1320 torture_assert_ntstatus_ok_goto(tctx, status2, ret, done, "ALL_INFO"); \
1321 } while (0)
1324 test stream renames
1326 static bool test_stream_rename(struct torture_context *tctx,
1327 struct smb2_tree *tree)
1329 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1330 NTSTATUS status, status2;
1331 union smb_open io;
1332 const char *fname = DNAME "\\stream_rename.txt";
1333 const char *sname1, *sname2;
1334 union smb_fileinfo finfo1;
1335 union smb_setfileinfo sfinfo;
1336 bool ret = true;
1337 struct smb2_handle h = {{0}};
1338 struct smb2_handle h1 = {{0}};
1340 sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
1341 sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
1342 "Second Stream");
1344 smb2_util_unlink(tree, fname);
1345 smb2_deltree(tree, DNAME);
1347 status = torture_smb2_testdir(tree, DNAME, &h);
1348 CHECK_STATUS(status, NT_STATUS_OK);
1350 torture_comment(tctx, "(%s) testing stream renames\n", __location__);
1351 ZERO_STRUCT(io.smb2);
1352 io.smb2.in.create_flags = 0;
1353 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1354 SEC_FILE_WRITE_ATTRIBUTE |
1355 SEC_RIGHTS_FILE_ALL;
1356 io.smb2.in.create_options = 0;
1357 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1358 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1359 NTCREATEX_SHARE_ACCESS_WRITE |
1360 NTCREATEX_SHARE_ACCESS_DELETE;
1361 io.smb2.in.alloc_size = 0;
1362 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1363 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1364 io.smb2.in.security_flags = 0;
1365 io.smb2.in.fname = sname1;
1367 /* Create two streams. */
1368 status = smb2_create(tree, mem_ctx, &(io.smb2));
1369 CHECK_STATUS(status, NT_STATUS_OK);
1370 h1 = io.smb2.out.file.handle;
1371 smb2_util_close(tree, h1);
1373 io.smb2.in.fname = sname2;
1374 status = smb2_create(tree, mem_ctx, &(io.smb2));
1375 CHECK_STATUS(status, NT_STATUS_OK);
1376 h1 = io.smb2.out.file.handle;
1378 smb2_util_close(tree, h1);
1381 * Open the second stream.
1384 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1385 status = smb2_create(tree, mem_ctx, &(io.smb2));
1386 CHECK_STATUS(status, NT_STATUS_OK);
1387 h1 = io.smb2.out.file.handle;
1390 * Now rename the second stream onto the first.
1393 ZERO_STRUCT(sfinfo);
1395 sfinfo.rename_information.in.overwrite = 1;
1396 sfinfo.rename_information.in.root_fid = 0;
1397 sfinfo.rename_information.in.new_name = ":Stream One";
1398 CHECK_CALL_HANDLE(RENAME_INFORMATION, NT_STATUS_OK);
1399 done:
1400 smb2_util_close(tree, h1);
1401 status = smb2_util_unlink(tree, fname);
1402 smb2_deltree(tree, DNAME);
1403 talloc_free(mem_ctx);
1405 return ret;
1408 static bool test_stream_rename2(struct torture_context *tctx,
1409 struct smb2_tree *tree)
1411 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1412 NTSTATUS status;
1413 union smb_open io;
1414 const char *fname1 = DNAME "\\stream_rename2.txt";
1415 const char *fname2 = DNAME "\\stream2_rename2.txt";
1416 const char *stream_name1 = ":Stream One:$DATA";
1417 const char *stream_name2 = ":Stream Two:$DATA";
1418 const char *stream_name_default = "::$DATA";
1419 const char *sname1;
1420 const char *sname2;
1421 bool ret = true;
1422 struct smb2_handle h, h1;
1423 union smb_setfileinfo sinfo;
1425 ZERO_STRUCT(h);
1426 ZERO_STRUCT(h1);
1428 sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream One");
1429 sname2 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream Two");
1431 smb2_util_unlink(tree, fname1);
1432 smb2_util_unlink(tree, fname2);
1433 smb2_deltree(tree, DNAME);
1435 status = torture_smb2_testdir(tree, DNAME, &h);
1436 CHECK_STATUS(status, NT_STATUS_OK);
1438 ZERO_STRUCT(io.smb2);
1439 io.smb2.in.create_flags = 0;
1440 io.smb2.in.desired_access = SEC_FILE_READ_DATA |
1441 SEC_FILE_WRITE_DATA |
1442 SEC_STD_DELETE |
1443 SEC_FILE_APPEND_DATA |
1444 SEC_STD_READ_CONTROL;
1445 io.smb2.in.create_options = 0;
1446 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1447 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1448 NTCREATEX_SHARE_ACCESS_WRITE |
1449 NTCREATEX_SHARE_ACCESS_DELETE;
1450 io.smb2.in.alloc_size = 0;
1451 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1452 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1453 io.smb2.in.security_flags = 0;
1454 io.smb2.in.fname = sname1;
1456 /* Open/create new stream. */
1457 status = smb2_create(tree, mem_ctx, &(io.smb2));
1458 CHECK_STATUS(status, NT_STATUS_OK);
1460 smb2_util_close(tree, io.smb2.out.file.handle);
1463 * Reopen the stream for SMB2 renames.
1465 io.smb2.in.fname = sname1;
1466 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1467 status = smb2_create(tree, mem_ctx, &(io.smb2));
1468 CHECK_STATUS(status, NT_STATUS_OK);
1469 h1 = io.smb2.out.file.handle;
1472 * Check SMB2 rename of a stream using :<stream>.
1474 torture_comment(tctx, "(%s) Checking SMB2 rename of a stream using "
1475 ":<stream>\n", __location__);
1476 ZERO_STRUCT(sinfo);
1477 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION_SMB2;
1478 sinfo.rename_information.in.file.handle = h1;
1479 sinfo.rename_information.in.overwrite = 1;
1480 sinfo.rename_information.in.root_fid = 0;
1481 sinfo.rename_information.in.new_name = stream_name1;
1482 status = smb2_setinfo_file(tree, &sinfo);
1483 CHECK_STATUS(status, NT_STATUS_OK);
1486 * Check SMB2 rename of an overwriting stream using :<stream>.
1488 torture_comment(tctx, "(%s) Checking SMB2 rename of an overwriting "
1489 "stream using :<stream>\n", __location__);
1491 /* Create second stream. */
1492 io.smb2.in.fname = sname2;
1493 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1494 status = smb2_create(tree, mem_ctx, &(io.smb2));
1495 CHECK_STATUS(status, NT_STATUS_OK);
1496 smb2_util_close(tree, io.smb2.out.file.handle);
1498 /* Rename the first stream onto the second. */
1499 sinfo.rename_information.in.file.handle = h1;
1500 sinfo.rename_information.in.new_name = stream_name2;
1501 status = smb2_setinfo_file(tree, &sinfo);
1502 CHECK_STATUS(status, NT_STATUS_OK);
1504 smb2_util_close(tree, h1);
1507 * Reopen the stream with the new name.
1509 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1510 io.smb2.in.fname = sname2;
1511 status = smb2_create(tree, mem_ctx, &(io.smb2));
1512 CHECK_STATUS(status, NT_STATUS_OK);
1513 h1 = io.smb2.out.file.handle;
1516 * Check SMB2 rename of a stream using <base>:<stream>.
1518 torture_comment(tctx, "(%s) Checking SMB2 rename of a stream using "
1519 "<base>:<stream>\n", __location__);
1520 sinfo.rename_information.in.file.handle = h1;
1521 sinfo.rename_information.in.new_name = sname1;
1522 status = smb2_setinfo_file(tree, &sinfo);
1523 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
1525 if (!torture_setting_bool(tctx, "samba4", false)) {
1527 * Check SMB2 rename to the default stream using :<stream>.
1529 torture_comment(tctx, "(%s) Checking SMB2 rename to default stream "
1530 "using :<stream>\n", __location__);
1531 sinfo.rename_information.in.file.handle = h1;
1532 sinfo.rename_information.in.new_name = stream_name_default;
1533 status = smb2_setinfo_file(tree, &sinfo);
1534 CHECK_STATUS(status, NT_STATUS_OK);
1537 smb2_util_close(tree, h1);
1539 done:
1540 smb2_util_close(tree, h1);
1541 status = smb2_util_unlink(tree, fname1);
1542 status = smb2_util_unlink(tree, fname2);
1543 smb2_deltree(tree, DNAME);
1544 talloc_free(mem_ctx);
1546 return ret;
1549 static bool create_file_with_stream(struct torture_context *tctx,
1550 struct smb2_tree *tree,
1551 TALLOC_CTX *mem_ctx,
1552 const char *base_fname,
1553 const char *stream)
1555 NTSTATUS status;
1556 bool ret = true;
1557 union smb_open io;
1559 /* Create a file with a stream */
1560 ZERO_STRUCT(io.smb2);
1561 io.smb2.in.create_flags = 0;
1562 io.smb2.in.desired_access = SEC_FILE_READ_DATA |
1563 SEC_FILE_WRITE_DATA |
1564 SEC_FILE_APPEND_DATA |
1565 SEC_STD_READ_CONTROL;
1566 io.smb2.in.create_options = 0;
1567 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1568 io.smb2.in.share_access = 0;
1569 io.smb2.in.alloc_size = 0;
1570 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1571 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1572 io.smb2.in.security_flags = 0;
1573 io.smb2.in.fname = stream;
1575 status = smb2_create(tree, mem_ctx, &(io.smb2));
1576 CHECK_STATUS(status, NT_STATUS_OK);
1578 done:
1579 smb2_util_close(tree, io.smb2.out.file.handle);
1580 return ret;
1584 /* Test how streams interact with create dispositions */
1585 static bool test_stream_create_disposition(struct torture_context *tctx,
1586 struct smb2_tree *tree)
1588 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1589 NTSTATUS status;
1590 union smb_open io;
1591 const char *fname = DNAME "\\stream_create_disp.txt";
1592 const char *stream = "Stream One:$DATA";
1593 const char *fname_stream;
1594 const char *default_stream_name = "::$DATA";
1595 const char *stream_list[2];
1596 bool ret = true;
1597 struct smb2_handle h = {{0}};
1598 struct smb2_handle h1 = {{0}};
1600 /* clean slate .. */
1601 smb2_util_unlink(tree, fname);
1602 smb2_deltree(tree, fname);
1603 smb2_deltree(tree, DNAME);
1605 status = torture_smb2_testdir(tree, DNAME, &h);
1606 CHECK_STATUS(status, NT_STATUS_OK);
1608 fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
1610 stream_list[0] = talloc_asprintf(mem_ctx, ":%s", stream);
1611 stream_list[1] = default_stream_name;
1613 if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
1614 fname_stream)) {
1615 goto done;
1618 /* Open the base file with OPEN */
1619 ZERO_STRUCT(io.smb2);
1620 io.smb2.in.create_flags = 0;
1621 io.smb2.in.desired_access = SEC_FILE_READ_DATA |
1622 SEC_FILE_WRITE_DATA |
1623 SEC_FILE_APPEND_DATA |
1624 SEC_STD_READ_CONTROL;
1625 io.smb2.in.create_options = 0;
1626 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1627 io.smb2.in.share_access = 0;
1628 io.smb2.in.alloc_size = 0;
1629 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1630 io.smb2.in.security_flags = 0;
1631 io.smb2.in.fname = fname;
1634 * check create open: sanity check
1636 torture_comment(tctx, "(%s) Checking create disp: open\n",
1637 __location__);
1638 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1639 status = smb2_create(tree, mem_ctx, &(io.smb2));
1640 CHECK_STATUS(status, NT_STATUS_OK);
1641 if (!check_stream_list(tree, tctx, fname, 2, stream_list,
1642 io.smb2.out.file.handle)) {
1643 goto done;
1645 smb2_util_close(tree, io.smb2.out.file.handle);
1648 * check create overwrite
1650 torture_comment(tctx, "(%s) Checking create disp: overwrite\n",
1651 __location__);
1652 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
1653 status = smb2_create(tree, mem_ctx, &(io.smb2));
1654 CHECK_STATUS(status, NT_STATUS_OK);
1655 if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
1656 io.smb2.out.file.handle)) {
1657 goto done;
1659 smb2_util_close(tree, io.smb2.out.file.handle);
1662 * check create overwrite_if
1664 torture_comment(tctx, "(%s) Checking create disp: overwrite_if\n",
1665 __location__);
1666 smb2_util_unlink(tree, fname);
1667 if (!create_file_with_stream(tctx, tree, mem_ctx, fname, fname_stream))
1668 goto done;
1670 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1671 status = smb2_create(tree, mem_ctx, &(io.smb2));
1672 CHECK_STATUS(status, NT_STATUS_OK);
1673 if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
1674 io.smb2.out.file.handle)) {
1675 goto done;
1677 smb2_util_close(tree, io.smb2.out.file.handle);
1680 * check create supersede
1682 torture_comment(tctx, "(%s) Checking create disp: supersede\n",
1683 __location__);
1684 smb2_util_unlink(tree, fname);
1685 if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
1686 fname_stream)) {
1687 goto done;
1690 io.smb2.in.create_disposition = NTCREATEX_DISP_SUPERSEDE;
1691 status = smb2_create(tree, mem_ctx, &(io.smb2));
1692 CHECK_STATUS(status, NT_STATUS_OK);
1693 if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
1694 io.smb2.out.file.handle)) {
1695 goto done;
1697 smb2_util_close(tree, io.smb2.out.file.handle);
1700 * check create overwrite_if on a stream.
1702 torture_comment(tctx, "(%s) Checking create disp: overwrite_if on "
1703 "stream\n", __location__);
1704 smb2_util_unlink(tree, fname);
1705 if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
1706 fname_stream)) {
1707 goto done;
1710 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
1711 io.smb2.in.fname = fname_stream;
1712 status = smb2_create(tree, mem_ctx, &(io.smb2));
1713 CHECK_STATUS(status, NT_STATUS_OK);
1714 if (!check_stream_list(tree, tctx, fname, 2, stream_list,
1715 io.smb2.out.file.handle)) {
1716 goto done;
1718 smb2_util_close(tree, io.smb2.out.file.handle);
1719 done:
1720 smb2_util_close(tree, h1);
1721 smb2_util_unlink(tree, fname);
1722 smb2_deltree(tree, DNAME);
1723 talloc_free(mem_ctx);
1725 return ret;
1728 static bool open_stream(struct smb2_tree *tree,
1729 struct torture_context *mem_ctx,
1730 const char *fname,
1731 struct smb2_handle *h_out)
1733 NTSTATUS status;
1734 union smb_open io;
1736 ZERO_STRUCT(io.smb2);
1737 io.smb2.in.create_flags = 0;
1738 io.smb2.in.desired_access = SEC_FILE_READ_DATA |
1739 SEC_FILE_WRITE_DATA |
1740 SEC_FILE_APPEND_DATA |
1741 SEC_STD_READ_CONTROL |
1742 SEC_FILE_WRITE_ATTRIBUTE;
1743 io.smb2.in.create_options = 0;
1744 io.smb2.in.file_attributes = 0;
1745 io.smb2.in.share_access = 0;
1746 io.smb2.in.alloc_size = 0;
1747 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1748 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1749 io.smb2.in.security_flags = 0;
1750 io.smb2.in.fname = fname;
1752 status = smb2_create(tree, mem_ctx, &(io.smb2));
1753 if (!NT_STATUS_IS_OK(status)) {
1754 return false;
1756 *h_out = io.smb2.out.file.handle;
1757 return true;
1761 /* Test the effect of setting attributes on a stream. */
1762 static bool test_stream_attributes1(struct torture_context *tctx,
1763 struct smb2_tree *tree)
1765 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1766 bool ret = true;
1767 NTSTATUS status;
1768 union smb_open io;
1769 const char *fname = DNAME "\\stream_attr.txt";
1770 const char *stream = "Stream One:$DATA";
1771 const char *fname_stream;
1772 struct smb2_handle h, h1;
1773 union smb_fileinfo finfo;
1774 union smb_setfileinfo sfinfo;
1775 time_t basetime = (time(NULL) - 86400) & ~1;
1777 ZERO_STRUCT(h);
1778 ZERO_STRUCT(h1);
1780 torture_comment(tctx, "(%s) testing attribute setting on stream\n",
1781 __location__);
1783 /* clean slate .. */
1784 smb2_util_unlink(tree, fname);
1785 smb2_deltree(tree, fname);
1786 smb2_deltree(tree, DNAME);
1788 status = torture_smb2_testdir(tree, DNAME, &h);
1789 CHECK_STATUS(status, NT_STATUS_OK);
1791 fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
1793 /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
1794 ret = create_file_with_stream(tctx, tree, mem_ctx, fname,
1795 fname_stream);
1796 if (!ret) {
1797 goto done;
1800 ZERO_STRUCT(io.smb2);
1801 io.smb2.in.fname = fname;
1802 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1803 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1804 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1805 NTCREATEX_SHARE_ACCESS_WRITE |
1806 NTCREATEX_SHARE_ACCESS_DELETE;
1807 status = smb2_create(tree, mem_ctx, &(io.smb2));
1808 CHECK_STATUS(status, NT_STATUS_OK);
1810 ZERO_STRUCT(finfo);
1811 finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
1812 finfo.generic.in.file.handle = io.smb2.out.file.handle;
1813 status = smb2_getinfo_file(tree, mem_ctx, &finfo);
1814 CHECK_STATUS(status, NT_STATUS_OK);
1816 if (finfo.basic_info.out.attrib != FILE_ATTRIBUTE_ARCHIVE) {
1817 torture_comment(tctx, "(%s) Incorrect attrib %x - should be "
1818 "%x\n", __location__,
1819 (unsigned int)finfo.basic_info.out.attrib,
1820 (unsigned int)FILE_ATTRIBUTE_ARCHIVE);
1821 ret = false;
1822 goto done;
1825 smb2_util_close(tree, io.smb2.out.file.handle);
1826 /* Now open the stream name. */
1828 if (!open_stream(tree, tctx, fname_stream, &h1)) {
1829 goto done;
1832 /* Change the time on the stream. */
1833 ZERO_STRUCT(sfinfo);
1834 unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
1835 sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1836 sfinfo.generic.in.file.handle = h1;
1837 status = smb2_setinfo_file(tree, &sfinfo);
1838 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1839 torture_comment(tctx, "(%s) %s - %s (should be %s)\n",
1840 __location__, "SETATTR",
1841 nt_errstr(status), nt_errstr(NT_STATUS_OK));
1842 ret = false;
1843 goto done;
1846 smb2_util_close(tree, h1);
1848 ZERO_STRUCT(io.smb2);
1849 io.smb2.in.fname = fname;
1850 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1851 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1852 status = smb2_create(tree, mem_ctx, &(io.smb2));
1853 CHECK_STATUS(status, NT_STATUS_OK);
1854 h1 = io.smb2.out.file.handle;
1856 ZERO_STRUCT(finfo);
1857 finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
1858 finfo.generic.in.file.handle = h1;
1859 status = smb2_getinfo_file(tree, mem_ctx, &finfo);
1860 if (!NT_STATUS_IS_OK(status)) {
1861 torture_comment(tctx, "(%s) %s pathinfo - %s\n",
1862 __location__, "SETATTRE", nt_errstr(status));
1863 ret = false;
1864 goto done;
1867 if (nt_time_to_unix(finfo.basic_info.out.write_time) != basetime) {
1868 torture_comment(tctx, "(%s) time incorrect.\n", __location__);
1869 ret = false;
1870 goto done;
1872 smb2_util_close(tree, h1);
1874 if (!open_stream(tree, tctx, fname_stream, &h1)) {
1875 goto done;
1878 /* Changing attributes on stream */
1879 ZERO_STRUCT(sfinfo);
1880 sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
1882 sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1883 sfinfo.generic.in.file.handle = h1;
1884 status = smb2_setinfo_file(tree, &sfinfo);
1885 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1886 torture_comment(tctx, "(%s) %s - %s (should be %s)\n",
1887 __location__, "SETATTR",
1888 nt_errstr(status), nt_errstr(NT_STATUS_OK));
1889 ret = false;
1890 goto done;
1893 smb2_util_close(tree, h1);
1895 ZERO_STRUCT(io.smb2);
1896 io.smb2.in.fname = fname;
1897 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1898 io.smb2.in.desired_access = SEC_FILE_READ_DATA;
1899 status = smb2_create(tree, mem_ctx, &(io.smb2));
1900 CHECK_STATUS(status, NT_STATUS_OK);
1901 h1 = io.smb2.out.file.handle;
1903 ZERO_STRUCT(finfo);
1904 finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
1905 finfo.generic.in.file.handle = h1;
1906 status = smb2_getinfo_file(tree, mem_ctx, &finfo);
1907 CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1909 done:
1910 smb2_util_close(tree, h1);
1911 smb2_util_unlink(tree, fname);
1912 smb2_deltree(tree, DNAME);
1913 talloc_free(mem_ctx);
1915 return ret;
1918 static bool check_metadata(struct torture_context *tctx,
1919 struct smb2_tree *tree,
1920 const char *path,
1921 struct smb2_handle _h,
1922 NTTIME expected_btime,
1923 uint32_t expected_attribs)
1925 struct smb2_handle h = _h;
1926 union smb_fileinfo getinfo;
1927 NTSTATUS status;
1928 bool ret = true;
1930 if (smb2_util_handle_empty(h)) {
1931 struct smb2_create c;
1933 c = (struct smb2_create) {
1934 .in.desired_access = SEC_FILE_ALL,
1935 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
1936 .in.file_attributes = FILE_ATTRIBUTE_HIDDEN,
1937 .in.create_disposition = NTCREATEX_DISP_OPEN,
1938 .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
1939 .in.fname = path,
1941 status = smb2_create(tree, tctx, &c);
1942 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1943 "smb2_create failed\n");
1945 h = c.out.file.handle;
1948 getinfo = (union smb_fileinfo) {
1949 .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
1950 .generic.in.file.handle = h,
1953 status = smb2_getinfo_file(tree, tctx, &getinfo);
1954 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1955 "smb2_getinfo_file failed\n");
1957 torture_assert_u64_equal_goto(tctx,
1958 expected_btime,
1959 getinfo.basic_info.out.create_time,
1960 ret, done,
1961 "btime was updated\n");
1963 torture_assert_u32_equal_goto(tctx,
1964 expected_attribs,
1965 getinfo.basic_info.out.attrib,
1966 ret, done,
1967 "btime was updated\n");
1969 done:
1970 if (smb2_util_handle_empty(_h)) {
1971 smb2_util_close(tree, h);
1974 return ret;
1977 static bool test_stream_attributes2(struct torture_context *tctx,
1978 struct smb2_tree *tree)
1980 NTSTATUS status;
1981 struct smb2_create c1;
1982 struct smb2_handle h1 = {{0}};
1983 const char *fname = DNAME "\\test_stream_btime";
1984 const char *sname = DNAME "\\test_stream_btime:stream";
1985 union smb_fileinfo getinfo;
1986 union smb_setfileinfo setinfo;
1987 const char *data = "test data";
1988 struct timespec ts;
1989 NTTIME btime;
1990 uint32_t attrib = FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_ARCHIVE;
1991 bool ret;
1993 smb2_deltree(tree, DNAME);
1995 status = torture_smb2_testdir(tree, DNAME, &h1);
1996 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1997 "torture_smb2_testdir failed\n");
1998 smb2_util_close(tree, h1);
2000 torture_comment(tctx, "Let's dance!\n");
2003 * Step 1: create file and get creation date
2006 c1 = (struct smb2_create) {
2007 .in.desired_access = SEC_FILE_ALL,
2008 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2009 .in.file_attributes = FILE_ATTRIBUTE_HIDDEN,
2010 .in.create_disposition = NTCREATEX_DISP_CREATE,
2011 .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
2012 .in.fname = fname,
2014 status = smb2_create(tree, tctx, &c1);
2015 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2016 "smb2_create failed\n");
2017 h1 = c1.out.file.handle;
2019 getinfo = (union smb_fileinfo) {
2020 .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
2021 .generic.in.file.handle = h1,
2023 status = smb2_getinfo_file(tree, tctx, &getinfo);
2024 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2025 "smb2_getinfo_file failed\n");
2027 btime = getinfo.basic_info.out.create_time;
2029 status = smb2_util_close(tree, h1);
2030 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2031 "smb2_util_close failed\n");
2032 ZERO_STRUCT(h1);
2035 * Step X: write to file, assert btime was not updated
2038 c1 = (struct smb2_create) {
2039 .in.desired_access = SEC_FILE_ALL,
2040 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2041 .in.file_attributes = attrib,
2042 .in.create_disposition = NTCREATEX_DISP_OPEN,
2043 .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
2044 .in.fname = fname,
2046 status = smb2_create(tree, tctx, &c1);
2047 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2048 "smb2_create failed\n");
2049 h1 = c1.out.file.handle;
2051 status = smb2_util_write(tree, h1, data, 0, strlen(data));
2052 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2053 "smb2_util_write failed\n");
2055 ret = check_metadata(tctx, tree, NULL, h1, btime, attrib);
2056 torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
2058 status = smb2_util_close(tree, h1);
2059 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2060 "smb2_util_close failed\n");
2061 ZERO_STRUCT(h1);
2063 ret = check_metadata(tctx, tree, fname, (struct smb2_handle){{0}},
2064 btime, attrib);
2065 torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
2068 * Step X: create stream, assert creation date is the same
2069 * as the one on the basefile
2072 c1 = (struct smb2_create) {
2073 .in.desired_access = SEC_FILE_ALL,
2074 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2075 .in.file_attributes = attrib,
2076 .in.create_disposition = NTCREATEX_DISP_CREATE,
2077 .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
2078 .in.fname = sname,
2080 status = smb2_create(tree, tctx, &c1);
2081 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2082 "smb2_create failed\n");
2083 h1 = c1.out.file.handle;
2085 status = smb2_util_close(tree, h1);
2086 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2087 "smb2_util_close failed\n");
2088 ZERO_STRUCT(h1);
2090 ret = check_metadata(tctx, tree, sname, (struct smb2_handle){{0}},
2091 btime, attrib);
2092 torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
2095 * Step X: set btime on stream, verify basefile has the same btime.
2098 c1 = (struct smb2_create) {
2099 .in.desired_access = SEC_FILE_ALL,
2100 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2101 .in.file_attributes = attrib,
2102 .in.create_disposition = NTCREATEX_DISP_OPEN,
2103 .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
2104 .in.fname = sname,
2106 status = smb2_create(tree, tctx, &c1);
2107 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2108 "smb2_create failed\n");
2109 h1 = c1.out.file.handle;
2111 setinfo = (union smb_setfileinfo) {
2112 .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
2113 .basic_info.in.file.handle = h1,
2115 clock_gettime_mono(&ts);
2116 btime = setinfo.basic_info.in.create_time = full_timespec_to_nt_time(&ts);
2118 status = smb2_setinfo_file(tree, &setinfo);
2119 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2120 "smb2_setinfo_file failed\n");
2122 ret = check_metadata(tctx, tree, NULL, h1, btime, attrib);
2123 torture_assert_goto(tctx, ret, ret, done, "Bad time on stream\n");
2125 status = smb2_util_close(tree, h1);
2126 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2127 "smb2_util_close failed\n");
2128 ZERO_STRUCT(h1);
2130 ret = check_metadata(tctx, tree, fname, (struct smb2_handle){{0}},
2131 btime, attrib);
2132 torture_assert_goto(tctx, ret, ret, done, "Bad time on basefile\n");
2134 ret = check_metadata(tctx, tree, sname, (struct smb2_handle){{0}},
2135 btime, attrib);
2136 torture_assert_goto(tctx, ret, ret, done, "Bad time on stream\n");
2139 * Step X: write to stream, assert btime was not updated
2142 c1 = (struct smb2_create) {
2143 .in.desired_access = SEC_FILE_ALL,
2144 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2145 .in.file_attributes = attrib,
2146 .in.create_disposition = NTCREATEX_DISP_OPEN,
2147 .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
2148 .in.fname = sname,
2150 status = smb2_create(tree, tctx, &c1);
2151 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2152 "smb2_create failed\n");
2153 h1 = c1.out.file.handle;
2155 status = smb2_util_write(tree, h1, data, 0, strlen(data));
2156 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2157 "smb2_util_write failed\n");
2159 ret = check_metadata(tctx, tree, NULL, h1, btime, attrib);
2160 torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
2162 status = smb2_util_close(tree, h1);
2163 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2164 "smb2_util_close failed\n");
2165 ZERO_STRUCT(h1);
2167 ret = check_metadata(tctx, tree, fname, (struct smb2_handle){{0}},
2168 btime, attrib);
2169 torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
2171 ret = check_metadata(tctx, tree, sname, (struct smb2_handle){{0}},
2172 btime, attrib);
2173 torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
2176 * Step X: modify attributes via stream, verify it's "also" set on the
2177 * basefile.
2180 c1 = (struct smb2_create) {
2181 .in.desired_access = SEC_FILE_ALL,
2182 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2183 .in.file_attributes = attrib,
2184 .in.create_disposition = NTCREATEX_DISP_OPEN,
2185 .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
2186 .in.fname = sname,
2188 status = smb2_create(tree, tctx, &c1);
2189 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2190 "smb2_create failed\n");
2191 h1 = c1.out.file.handle;
2193 attrib = FILE_ATTRIBUTE_NORMAL;
2195 setinfo = (union smb_setfileinfo) {
2196 .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
2197 .basic_info.in.file.handle = h1,
2198 .basic_info.in.attrib = attrib,
2201 status = smb2_setinfo_file(tree, &setinfo);
2202 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2203 "smb2_setinfo_file failed\n");
2205 status = smb2_util_close(tree, h1);
2206 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2207 "smb2_util_close failed\n");
2208 ZERO_STRUCT(h1);
2210 ret = check_metadata(tctx, tree, fname, (struct smb2_handle){{0}},
2211 btime, attrib);
2212 torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
2214 ret = check_metadata(tctx, tree, sname, (struct smb2_handle){{0}},
2215 btime, attrib);
2216 torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
2219 * Step X: modify attributes via basefile, verify it's "also" set on the
2220 * stream.
2223 c1 = (struct smb2_create) {
2224 .in.desired_access = SEC_FILE_ALL,
2225 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2226 .in.file_attributes = attrib,
2227 .in.create_disposition = NTCREATEX_DISP_OPEN,
2228 .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
2229 .in.fname = fname,
2231 status = smb2_create(tree, tctx, &c1);
2232 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2233 "smb2_create failed\n");
2234 h1 = c1.out.file.handle;
2236 attrib = FILE_ATTRIBUTE_HIDDEN;
2238 setinfo = (union smb_setfileinfo) {
2239 .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
2240 .basic_info.in.file.handle = h1,
2241 .basic_info.in.attrib = attrib,
2244 status = smb2_setinfo_file(tree, &setinfo);
2245 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2246 "smb2_setinfo_file failed\n");
2248 status = smb2_util_close(tree, h1);
2249 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2250 "smb2_util_close failed\n");
2251 ZERO_STRUCT(h1);
2253 ret = check_metadata(tctx, tree, fname, (struct smb2_handle){{0}},
2254 btime, attrib);
2255 torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
2257 ret = check_metadata(tctx, tree, sname, (struct smb2_handle){{0}},
2258 btime, attrib);
2259 torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
2261 done:
2262 if (!smb2_util_handle_empty(h1)) {
2263 smb2_util_close(tree, h1);
2266 smb2_deltree(tree, DNAME);
2268 return ret;
2271 static bool test_basefile_rename_with_open_stream(struct torture_context *tctx,
2272 struct smb2_tree *tree)
2274 bool ret = true;
2275 NTSTATUS status;
2276 struct smb2_tree *tree2 = NULL;
2277 struct smb2_create create, create2;
2278 struct smb2_handle h1 = {{0}}, h2 = {{0}};
2279 const char *fname = "test_rename_openfile";
2280 const char *sname = "test_rename_openfile:foo";
2281 const char *fname_renamed = "test_rename_openfile_renamed";
2282 union smb_setfileinfo sinfo;
2283 const char *data = "test data";
2285 ret = torture_smb2_connection(tctx, &tree2);
2286 torture_assert_goto(tctx, ret == true, ret, done,
2287 "torture_smb2_connection failed\n");
2289 torture_comment(tctx, "Creating file with stream\n");
2291 ZERO_STRUCT(create);
2292 create.in.desired_access = SEC_FILE_ALL;
2293 create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
2294 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2295 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2296 create.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
2297 create.in.fname = sname;
2299 status = smb2_create(tree, tctx, &create);
2300 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2301 "smb2_create failed\n");
2303 h1 = create.out.file.handle;
2305 torture_comment(tctx, "Writing to stream\n");
2307 status = smb2_util_write(tree, h1, data, 0, strlen(data));
2308 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2309 "smb2_util_write failed\n");
2311 torture_comment(tctx, "Renaming base file\n");
2313 ZERO_STRUCT(create2);
2314 create2.in.desired_access = SEC_FILE_ALL;
2315 create2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2316 create2.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
2317 create2.in.create_disposition = NTCREATEX_DISP_OPEN;
2318 create2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
2319 create2.in.fname = fname;
2321 status = smb2_create(tree2, tctx, &create2);
2322 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2323 "smb2_create failed\n");
2325 h2 = create2.out.file.handle;
2327 ZERO_STRUCT(sinfo);
2328 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
2329 sinfo.rename_information.in.file.handle = h2;
2330 sinfo.rename_information.in.new_name = fname_renamed;
2332 status = smb2_setinfo_file(tree2, &sinfo);
2333 torture_assert_ntstatus_equal_goto(
2334 tctx, status, NT_STATUS_ACCESS_DENIED, ret, done,
2335 "smb2_setinfo_file didn't return NT_STATUS_ACCESS_DENIED\n");
2337 smb2_util_close(tree2, h2);
2339 done:
2340 if (!smb2_util_handle_empty(h1)) {
2341 smb2_util_close(tree, h1);
2343 if (!smb2_util_handle_empty(h2)) {
2344 smb2_util_close(tree2, h2);
2346 smb2_util_unlink(tree, fname);
2347 smb2_util_unlink(tree, fname_renamed);
2349 return ret;
2353 * Simple test creating a stream on a share with "inherit permissions"
2354 * enabled. This tests specifically bug 15695.
2356 bool test_stream_inherit_perms(struct torture_context *tctx,
2357 struct smb2_tree *tree)
2359 NTSTATUS status;
2360 struct smb2_handle h = {};
2361 union smb_fileinfo q = {};
2362 union smb_setfileinfo setinfo = {};
2363 struct security_descriptor *sd = NULL;
2364 struct security_ace ace = {};
2365 const char *fname = DNAME "\\test_stream_inherit_perms:stream";
2366 bool ret = true;
2368 smb2_deltree(tree, DNAME);
2370 status = torture_smb2_testdir(tree, DNAME, &h);
2371 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2372 "torture_smb2_testdir failed\n");
2374 torture_comment(tctx, "getting original sd\n");
2376 q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
2377 q.query_secdesc.in.file.handle = h;
2378 q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
2380 status = smb2_getinfo_file(tree, tctx, &q);
2381 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2382 "smb2_getinfo_file failed\n");
2384 sd = q.query_secdesc.out.sd;
2387 * Add one explicit non-inheriting ACE which will be stored
2388 * as a non-inheriting POSIX ACE. These are the ACEs that
2389 * "inherit permissions" will want to inherit.
2391 ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
2392 ace.access_mask = SEC_STD_ALL;
2393 ace.trustee = *(sd->owner_sid);
2395 status = security_descriptor_dacl_add(sd, &ace);
2396 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2397 "security_descriptor_dacl_add failed\n");
2399 setinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
2400 setinfo.set_secdesc.in.file.handle = h;
2401 setinfo.set_secdesc.in.secinfo_flags = SECINFO_DACL;
2402 setinfo.set_secdesc.in.sd = sd;
2404 status = smb2_setinfo_file(tree, &setinfo);
2405 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2406 "smb2_setinfo_file failed");
2408 smb2_util_close(tree, h);
2409 ZERO_STRUCT(h);
2411 /* This triggers the crash */
2412 status = torture_smb2_testfile(tree, fname, &h);
2413 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2414 "torture_smb2_testfile failed");
2416 done:
2417 if (!smb2_util_handle_empty(h)) {
2418 smb2_util_close(tree, h);
2420 smb2_deltree(tree, DNAME);
2421 return ret;
2425 basic testing of streams calls SMB2
2427 struct torture_suite *torture_smb2_streams_init(TALLOC_CTX *ctx)
2429 struct torture_suite *suite =
2430 torture_suite_create(ctx, "streams");
2432 torture_suite_add_1smb2_test(suite, "dir", test_stream_dir);
2433 torture_suite_add_1smb2_test(suite, "io", test_stream_io);
2434 torture_suite_add_1smb2_test(suite, "sharemodes", test_stream_sharemodes);
2435 torture_suite_add_1smb2_test(suite, "names", test_stream_names);
2436 torture_suite_add_1smb2_test(suite, "names2", test_stream_names2);
2437 torture_suite_add_1smb2_test(suite, "names3", test_stream_names3);
2438 torture_suite_add_1smb2_test(suite, "rename", test_stream_rename);
2439 torture_suite_add_1smb2_test(suite, "rename2", test_stream_rename2);
2440 torture_suite_add_1smb2_test(suite, "create-disposition", test_stream_create_disposition);
2441 torture_suite_add_1smb2_test(suite, "attributes1", test_stream_attributes1);
2442 torture_suite_add_1smb2_test(suite, "attributes2", test_stream_attributes2);
2443 torture_suite_add_1smb2_test(suite, "delete", test_stream_delete);
2444 torture_suite_add_1smb2_test(suite, "zero-byte", test_zero_byte_stream);
2445 torture_suite_add_1smb2_test(suite, "basefile-rename-with-open-stream",
2446 test_basefile_rename_with_open_stream);
2448 suite->description = talloc_strdup(suite, "SMB2-STREAM tests");
2449 return suite;