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 "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
,
67 struct smb2_handle handle
;
68 struct smb2_create create
;
71 const char *full_name
;
73 full_name
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, sname
);
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
)) {
86 torture_comment(tctx
, "Unable to open stream %s\n",
92 handle
= create
.out
.file
.handle
;
99 r
.in
.file
.handle
= handle
;
100 r
.in
.length
= strlen(value
)+11;
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
);
111 if (memcmp(r
.out
.data
.data
, value
, strlen(value
)) != 0) {
112 torture_comment(tctx
, "(%s) Bad data in stream\n", location
);
116 smb2_util_close(tree
, handle
);
120 static bool check_stream_list(struct smb2_tree
*tree
,
121 struct torture_context
*tctx
,
123 unsigned int num_exp
,
125 struct smb2_handle h
)
127 union smb_fileinfo finfo
;
130 TALLOC_CTX
*tmp_ctx
= talloc_new(tctx
);
132 struct stream_struct
*stream_sort
;
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
));
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
);
156 exp_sort
= talloc_memdup(tmp_ctx
, exp
, num_exp
* sizeof(*exp
));
158 if (exp_sort
== NULL
) {
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
) {
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
);
186 talloc_free(tmp_ctx
);
191 static bool test_stream_dir(struct torture_context
*tctx
,
192 struct smb2_tree
*tree
)
194 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
197 const char *fname
= DNAME
"\\stream.txt";
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",
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",
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",
262 ret
&= check_stream_list(tree
, mem_ctx
, DNAME
, 0, NULL
, h
);
264 smb2_util_unlink(tree
, fname
);
265 smb2_deltree(tree
, DNAME
);
266 talloc_free(mem_ctx
);
271 static bool test_stream_io(struct torture_context
*tctx
,
272 struct smb2_tree
*tree
)
274 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
277 const char *fname
= DNAME
"\\stream.txt";
278 const char *sname1
, *sname2
;
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" };
290 sname1
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, "Stream One");
291 sname2
= talloc_asprintf(mem_ctx
, "%s:%s:$DaTa", fname
,
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",
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
,
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",
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
);
375 torture_result(tctx
, TORTURE_FAIL
,
376 "check_stream(\"Stream One:*\") failed\n");
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
);
395 torture_result(tctx
, TORTURE_FAIL
,
396 "check_stream(\"Second Stream:*\") failed\n");
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",
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
);
461 smb2_util_close(tree
, h2
);
462 smb2_deltree(tree
, DNAME
);
463 talloc_free(mem_ctx
);
468 static bool test_zero_byte_stream(struct torture_context
*tctx
,
469 struct smb2_tree
*tree
)
471 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
474 const char *fname
= DNAME
"\\stream.txt";
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",
492 /* Create basefile */
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
|
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 */
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
|
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
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
|
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
);
535 smb2_deltree(tree
, DNAME
);
536 talloc_free(mem_ctx
);
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
);
550 const char *fname
= DNAME
"\\stream_share.txt";
551 const char *sname1
, *sname2
;
553 struct smb2_handle h
, h1
, h2
;
559 sname1
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, "Stream One");
560 sname2
= talloc_asprintf(mem_ctx
, "%s:%s:$DaTa", fname
,
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",
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
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
);
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
);
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
);
653 const char *fname
= DNAME
"\\stream_delete.txt";
656 struct smb2_handle h
= {{0}};
657 struct smb2_handle h1
= {{0}};
660 if (torture_setting_bool(tctx
, "samba4", false)) {
661 torture_comment(tctx
, "Skipping test as samba4 is enabled\n");
668 sname1
= talloc_asprintf(mem_ctx
, "%s:%s", fname
, "Stream One");
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",
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
735 r
.in
.file
.handle
= h1
;
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
);
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
);
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
);
786 static bool test_stream_names(struct torture_context
*tctx
,
787 struct smb2_tree
*tree
)
789 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
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
;
800 struct smb2_handle h
, h1
, h2
, h3
;
802 const char *four
[4] = {
804 ":\x05Stream\n One:$DATA",
805 ":MStream Two:$DATA",
808 const char *five1
[5] = {
810 ":\x05Stream\n One:$DATA",
811 ":BeforeRename:$DATA",
812 ":MStream Two:$DATA",
815 const char *five2
[5] = {
817 ":\x05Stream\n One:$DATA",
818 ":AfterRename:$DATA",
819 ":MStream Two:$DATA",
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
,
836 snamer1
= talloc_asprintf(mem_ctx
, "%s:%s:$DATA", fname
,
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
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
);
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
);
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)) {
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
++) {
944 uint64_t stream_size
;
945 char *path
= talloc_asprintf(tctx
, "%s%s",
948 char *rpath
= talloc_strdup(path
, path
);
949 char *p
= strrchr(rpath
, ':');
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
|
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;
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;
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
,
1036 CHECK_VALUE(stinfo
.all_info
.out
.attrib
,
1037 finfo
.all_info
.out
.attrib
);
1039 CHECK_VALUE(stinfo
.all_info
.out
.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
);
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
);
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);
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
);
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 */
1112 smb2_util_close(tree
, h1
);
1113 status
= smb2_util_unlink(tree
, fname
);
1114 smb2_deltree(tree
, DNAME
);
1115 talloc_free(mem_ctx
);
1123 static bool test_stream_names2(struct torture_context
*tctx
,
1124 struct smb2_tree
*tree
)
1126 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
1129 const char *fname
= DNAME
"\\stream_names2.txt";
1131 struct smb2_handle h
= {{0}};
1132 struct smb2_handle h1
= {{0}};
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",
1166 expected
= NT_STATUS_OBJECT_NAME_INVALID
;
1169 expected
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
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
);
1190 smb2_util_close(tree
, h1
);
1191 status
= smb2_util_unlink(tree
, fname
);
1192 smb2_deltree(tree
, DNAME
);
1193 talloc_free(mem_ctx
);
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
);
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
;
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
);
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",
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
),
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
);
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
);
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"); \
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
;
1332 const char *fname
= DNAME
"\\stream_rename.txt";
1333 const char *sname1
, *sname2
;
1334 union smb_fileinfo finfo1
;
1335 union smb_setfileinfo sfinfo
;
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
,
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
);
1400 smb2_util_close(tree
, h1
);
1401 status
= smb2_util_unlink(tree
, fname
);
1402 smb2_deltree(tree
, DNAME
);
1403 talloc_free(mem_ctx
);
1408 static bool test_stream_rename2(struct torture_context
*tctx
,
1409 struct smb2_tree
*tree
)
1411 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
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";
1422 struct smb2_handle h
, h1
;
1423 union smb_setfileinfo sinfo
;
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
|
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__
);
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
);
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
);
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
,
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
);
1579 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
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
);
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];
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
,
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",
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
)) {
1645 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1648 * check create overwrite
1650 torture_comment(tctx
, "(%s) Checking create disp: overwrite\n",
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
)) {
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",
1666 smb2_util_unlink(tree
, fname
);
1667 if (!create_file_with_stream(tctx
, tree
, mem_ctx
, fname
, fname_stream
))
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
)) {
1677 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1680 * check create supersede
1682 torture_comment(tctx
, "(%s) Checking create disp: supersede\n",
1684 smb2_util_unlink(tree
, fname
);
1685 if (!create_file_with_stream(tctx
, tree
, mem_ctx
, fname
,
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
)) {
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
,
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
)) {
1718 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1720 smb2_util_close(tree
, h1
);
1721 smb2_util_unlink(tree
, fname
);
1722 smb2_deltree(tree
, DNAME
);
1723 talloc_free(mem_ctx
);
1728 static bool open_stream(struct smb2_tree
*tree
,
1729 struct torture_context
*mem_ctx
,
1731 struct smb2_handle
*h_out
)
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
)) {
1756 *h_out
= io
.smb2
.out
.file
.handle
;
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
);
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;
1780 torture_comment(tctx
, "(%s) testing attribute setting on stream\n",
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
,
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
);
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
);
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
)) {
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
));
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
;
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
));
1867 if (nt_time_to_unix(finfo
.basic_info
.out
.write_time
) != basetime
) {
1868 torture_comment(tctx
, "(%s) time incorrect.\n", __location__
);
1872 smb2_util_close(tree
, h1
);
1874 if (!open_stream(tree
, tctx
, fname_stream
, &h1
)) {
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
));
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
;
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
);
1910 smb2_util_close(tree
, h1
);
1911 smb2_util_unlink(tree
, fname
);
1912 smb2_deltree(tree
, DNAME
);
1913 talloc_free(mem_ctx
);
1918 static bool check_metadata(struct torture_context
*tctx
,
1919 struct smb2_tree
*tree
,
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
;
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
,
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
,
1959 getinfo
.basic_info
.out
.create_time
,
1961 "btime was updated\n");
1963 torture_assert_u32_equal_goto(tctx
,
1965 getinfo
.basic_info
.out
.attrib
,
1967 "btime was updated\n");
1970 if (smb2_util_handle_empty(_h
)) {
1971 smb2_util_close(tree
, h
);
1977 static bool test_stream_attributes2(struct torture_context
*tctx
,
1978 struct smb2_tree
*tree
)
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";
1990 uint32_t attrib
= FILE_ATTRIBUTE_HIDDEN
|FILE_ATTRIBUTE_ARCHIVE
;
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
,
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");
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
,
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");
2063 ret
= check_metadata(tctx
, tree
, fname
, (struct smb2_handle
){{0}},
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
,
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");
2090 ret
= check_metadata(tctx
, tree
, sname
, (struct smb2_handle
){{0}},
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
,
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");
2130 ret
= check_metadata(tctx
, tree
, fname
, (struct smb2_handle
){{0}},
2132 torture_assert_goto(tctx
, ret
, ret
, done
, "Bad time on basefile\n");
2134 ret
= check_metadata(tctx
, tree
, sname
, (struct smb2_handle
){{0}},
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
,
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");
2167 ret
= check_metadata(tctx
, tree
, fname
, (struct smb2_handle
){{0}},
2169 torture_assert_goto(tctx
, ret
, ret
, done
, "Bad metadata\n");
2171 ret
= check_metadata(tctx
, tree
, sname
, (struct smb2_handle
){{0}},
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
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
,
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");
2210 ret
= check_metadata(tctx
, tree
, fname
, (struct smb2_handle
){{0}},
2212 torture_assert_goto(tctx
, ret
, ret
, done
, "Bad metadata\n");
2214 ret
= check_metadata(tctx
, tree
, sname
, (struct smb2_handle
){{0}},
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
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
,
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");
2253 ret
= check_metadata(tctx
, tree
, fname
, (struct smb2_handle
){{0}},
2255 torture_assert_goto(tctx
, ret
, ret
, done
, "Bad metadata\n");
2257 ret
= check_metadata(tctx
, tree
, sname
, (struct smb2_handle
){{0}},
2259 torture_assert_goto(tctx
, ret
, ret
, done
, "Bad metadata\n");
2262 if (!smb2_util_handle_empty(h1
)) {
2263 smb2_util_close(tree
, h1
);
2266 smb2_deltree(tree
, DNAME
);
2271 static bool test_basefile_rename_with_open_stream(struct torture_context
*tctx
,
2272 struct smb2_tree
*tree
)
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
;
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
);
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
);
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
)
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";
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
);
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");
2417 if (!smb2_util_handle_empty(h
)) {
2418 smb2_util_close(tree
, h
);
2420 smb2_deltree(tree
, DNAME
);
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");