2 Unix SMB/CIFS implementation.
6 Copyright (C) Andrew Tridgell 2008
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"
25 #include "libcli/smb/smbXcli_base.h"
26 #include "torture/torture.h"
27 #include "torture/util.h"
28 #include "torture/smb2/proto.h"
29 #include "librpc/gen_ndr/ndr_security.h"
30 #include "libcli/security/security.h"
32 #include "system/filesys.h"
33 #include "auth/credentials/credentials.h"
34 #include "lib/cmdline/cmdline.h"
35 #include "librpc/gen_ndr/security.h"
36 #include "lib/events/events.h"
38 #define FNAME "test_create.dat"
39 #define DNAME "smb2_open"
41 #define CHECK_STATUS(status, correct) do { \
42 if (!NT_STATUS_EQUAL(status, correct)) { \
43 torture_result(tctx, TORTURE_FAIL, \
44 "(%s) Incorrect status %s - should be %s\n", \
45 __location__, nt_errstr(status), nt_errstr(correct)); \
49 #define CHECK_EQUAL(v, correct) do { \
51 torture_result(tctx, TORTURE_FAIL, \
52 "(%s) Incorrect value for %s 0x%08llx - " \
53 "should be 0x%08llx\n", \
55 (unsigned long long)v, \
56 (unsigned long long)correct); \
60 #define CHECK_TIME(t, field) do { \
62 finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
63 finfo.all_info.in.file.handle = h1; \
64 status = smb2_getinfo_file(tree, tctx, &finfo); \
65 CHECK_STATUS(status, NT_STATUS_OK); \
67 t2 = nt_time_to_unix(finfo.all_info.out.field) & ~1; \
68 if (abs(t1-t2) > 2) { \
69 torture_result(tctx, TORTURE_FAIL, \
70 "(%s) wrong time for field %s %s - %s\n", \
71 __location__, #field, \
72 timestring(tctx, t1), \
73 timestring(tctx, t2)); \
74 dump_all_info(tctx, &finfo); \
78 #define CHECK_NTTIME(t, field) do { \
80 finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
81 finfo.all_info.in.file.handle = h1; \
82 status = smb2_getinfo_file(tree, tctx, &finfo); \
83 CHECK_STATUS(status, NT_STATUS_OK); \
84 t2 = finfo.all_info.out.field; \
85 if (llabs((int64_t)(t-t2)) > 20000) { \
86 torture_result(tctx, TORTURE_FAIL, \
87 "(%s) wrong time for field %s %s - %s\n", \
88 __location__, #field, \
89 nt_time_string(tctx, t), \
90 nt_time_string(tctx, t2)); \
91 dump_all_info(tctx, &finfo); \
95 #define CHECK_ALL_INFO(v, field) do { \
96 finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
97 finfo.all_info.in.file.handle = h1; \
98 status = smb2_getinfo_file(tree, tctx, &finfo); \
99 CHECK_STATUS(status, NT_STATUS_OK); \
100 if ((v) != (finfo.all_info.out.field)) { \
101 torture_result(tctx, TORTURE_FAIL, \
102 "(%s) wrong value for field %s 0x%x - 0x%x\n", \
103 __location__, #field, (int)v,\
104 (int)(finfo.all_info.out.field)); \
105 dump_all_info(tctx, &finfo); \
109 #define CHECK_VAL(v, correct) do { \
110 if ((v) != (correct)) { \
111 torture_result(tctx, TORTURE_FAIL, \
112 "(%s) wrong value for %s 0x%x - should be 0x%x\n", \
113 __location__, #v, (int)(v), (int)correct); \
117 #define SET_ATTRIB(sattrib, expected_status) do { \
118 union smb_setfileinfo sfinfo; \
119 ZERO_STRUCT(sfinfo.basic_info.in); \
120 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION; \
121 sfinfo.basic_info.in.file.handle = h1; \
122 sfinfo.basic_info.in.attrib = sattrib; \
123 status = smb2_setinfo_file(tree, &sfinfo); \
124 torture_assert_ntstatus_equal(tctx, status, expected_status, \
125 talloc_asprintf(tctx, \
126 "(%s) Failed to set attrib 0x%x on %s\n", \
127 __location__, (unsigned int)(sattrib), fname)); \
131 test some interesting combinations found by gentest
133 static bool test_create_gentest(struct torture_context
*tctx
, struct smb2_tree
*tree
)
135 struct smb2_create io
;
137 uint32_t access_mask
, file_attributes_set
;
138 uint32_t ok_mask
, not_supported_mask
, invalid_parameter_mask
;
139 uint32_t not_a_directory_mask
, unexpected_mask
;
140 union smb_fileinfo q
;
143 io
.in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
;
144 io
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
145 io
.in
.create_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
147 NTCREATEX_SHARE_ACCESS_DELETE
|
148 NTCREATEX_SHARE_ACCESS_READ
|
149 NTCREATEX_SHARE_ACCESS_WRITE
;
150 io
.in
.create_options
= 0;
153 status
= smb2_create(tree
, tctx
, &io
);
154 CHECK_STATUS(status
, NT_STATUS_OK
);
156 status
= smb2_util_close(tree
, io
.out
.file
.handle
);
157 CHECK_STATUS(status
, NT_STATUS_OK
);
159 io
.in
.create_options
= 0xF0000000;
160 status
= smb2_create(tree
, tctx
, &io
);
161 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
163 io
.in
.create_options
= 0;
165 io
.in
.file_attributes
= FILE_ATTRIBUTE_DEVICE
;
166 status
= smb2_create(tree
, tctx
, &io
);
167 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
169 io
.in
.file_attributes
= FILE_ATTRIBUTE_VOLUME
;
170 status
= smb2_create(tree
, tctx
, &io
);
171 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
173 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
174 io
.in
.file_attributes
= FILE_ATTRIBUTE_VOLUME
;
175 status
= smb2_create(tree
, tctx
, &io
);
176 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
178 io
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
179 io
.in
.desired_access
= 0x08000000;
180 status
= smb2_create(tree
, tctx
, &io
);
181 CHECK_STATUS(status
, NT_STATUS_ACCESS_DENIED
);
183 io
.in
.desired_access
= 0x04000000;
184 status
= smb2_create(tree
, tctx
, &io
);
185 CHECK_STATUS(status
, NT_STATUS_ACCESS_DENIED
);
187 io
.in
.file_attributes
= 0;
188 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
189 io
.in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
;
191 not_supported_mask
= 0;
192 invalid_parameter_mask
= 0;
193 not_a_directory_mask
= 0;
198 io
.in
.create_options
= (uint32_t)1<<i
;
199 if (io
.in
.create_options
& NTCREATEX_OPTIONS_DELETE_ON_CLOSE
) {
202 status
= smb2_create(tree
, tctx
, &io
);
203 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
204 not_supported_mask
|= 1<<i
;
205 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
206 invalid_parameter_mask
|= 1<<i
;
207 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
208 not_a_directory_mask
|= 1<<i
;
209 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_OK
)) {
211 status
= smb2_util_close(tree
, io
.out
.file
.handle
);
212 CHECK_STATUS(status
, NT_STATUS_OK
);
214 unexpected_mask
|= 1<<i
;
215 torture_comment(tctx
,
216 "create option 0x%08x returned %s\n",
217 1<<i
, nt_errstr(status
));
221 io
.in
.create_options
= 0;
223 CHECK_EQUAL(ok_mask
, 0x00efcf7e);
224 CHECK_EQUAL(not_a_directory_mask
, 0x00000001);
225 CHECK_EQUAL(not_supported_mask
, 0x00102080);
226 CHECK_EQUAL(invalid_parameter_mask
, 0xff000000);
227 CHECK_EQUAL(unexpected_mask
, 0x00000000);
229 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
230 io
.in
.file_attributes
= 0;
235 io
.in
.desired_access
= (uint32_t)1<<i
;
236 status
= smb2_create(tree
, tctx
, &io
);
237 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) ||
238 NT_STATUS_EQUAL(status
, NT_STATUS_PRIVILEGE_NOT_HELD
)) {
239 access_mask
|= io
.in
.desired_access
;
241 CHECK_STATUS(status
, NT_STATUS_OK
);
242 status
= smb2_util_close(tree
, io
.out
.file
.handle
);
243 CHECK_STATUS(status
, NT_STATUS_OK
);
248 if (TARGET_IS_WIN7(tctx
)) {
249 CHECK_EQUAL(access_mask
, 0x0de0fe00);
250 } else if (torture_setting_bool(tctx
, "samba4", false)) {
251 CHECK_EQUAL(access_mask
, 0x0cf0fe00);
253 CHECK_EQUAL(access_mask
, 0x0df0fe00);
256 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
257 io
.in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
;
258 io
.in
.file_attributes
= 0;
260 invalid_parameter_mask
= 0;
262 file_attributes_set
= 0;
266 io
.in
.file_attributes
= (uint32_t)1<<i
;
267 if (io
.in
.file_attributes
& FILE_ATTRIBUTE_ENCRYPTED
) {
270 smb2_deltree(tree
, FNAME
);
271 status
= smb2_create(tree
, tctx
, &io
);
272 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
273 invalid_parameter_mask
|= 1<<i
;
274 } else if (NT_STATUS_IS_OK(status
)) {
278 expected
= (io
.in
.file_attributes
| FILE_ATTRIBUTE_ARCHIVE
) & 0x00005127;
279 io
.out
.file_attr
&= ~FILE_ATTRIBUTE_NONINDEXED
;
280 CHECK_EQUAL(io
.out
.file_attr
, expected
);
281 file_attributes_set
|= io
.out
.file_attr
;
283 status
= smb2_util_close(tree
, io
.out
.file
.handle
);
284 CHECK_STATUS(status
, NT_STATUS_OK
);
286 unexpected_mask
|= 1<<i
;
287 torture_comment(tctx
,
288 "file attribute 0x%08x returned %s\n",
289 1<<i
, nt_errstr(status
));
294 CHECK_EQUAL(ok_mask
, 0x00003fb7);
295 CHECK_EQUAL(invalid_parameter_mask
, 0xffff8048);
296 CHECK_EQUAL(unexpected_mask
, 0x00000000);
297 CHECK_EQUAL(file_attributes_set
, 0x00001127);
299 smb2_deltree(tree
, FNAME
);
302 * Standalone servers doesn't support encryption
304 io
.in
.file_attributes
= FILE_ATTRIBUTE_ENCRYPTED
;
305 status
= smb2_create(tree
, tctx
, &io
);
306 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
307 torture_comment(tctx
,
308 "FILE_ATTRIBUTE_ENCRYPTED returned %s\n",
311 CHECK_STATUS(status
, NT_STATUS_OK
);
312 CHECK_EQUAL(io
.out
.file_attr
, (FILE_ATTRIBUTE_ENCRYPTED
| FILE_ATTRIBUTE_ARCHIVE
));
313 status
= smb2_util_close(tree
, io
.out
.file
.handle
);
314 CHECK_STATUS(status
, NT_STATUS_OK
);
317 smb2_deltree(tree
, FNAME
);
320 io
.in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
;
321 io
.in
.file_attributes
= 0;
322 io
.in
.create_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
324 NTCREATEX_SHARE_ACCESS_READ
|
325 NTCREATEX_SHARE_ACCESS_WRITE
;
326 io
.in
.create_options
= 0;
327 io
.in
.fname
= FNAME
":stream1";
328 status
= smb2_create(tree
, tctx
, &io
);
329 CHECK_STATUS(status
, NT_STATUS_OK
);
331 status
= smb2_util_close(tree
, io
.out
.file
.handle
);
332 CHECK_STATUS(status
, NT_STATUS_OK
);
335 io
.in
.file_attributes
= 0x8040;
337 NTCREATEX_SHARE_ACCESS_READ
;
338 status
= smb2_create(tree
, tctx
, &io
);
339 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
342 io
.in
.file_attributes
= 0;
343 io
.in
.desired_access
= SEC_FILE_READ_DATA
| SEC_FILE_WRITE_DATA
| SEC_FILE_APPEND_DATA
;
344 io
.in
.query_maximal_access
= true;
345 status
= smb2_create(tree
, tctx
, &io
);
346 CHECK_STATUS(status
, NT_STATUS_OK
);
347 CHECK_EQUAL(io
.out
.maximal_access
, 0x001f01ff);
349 q
.access_information
.level
= RAW_FILEINFO_ACCESS_INFORMATION
;
350 q
.access_information
.in
.file
.handle
= io
.out
.file
.handle
;
351 status
= smb2_getinfo_file(tree
, tctx
, &q
);
352 CHECK_STATUS(status
, NT_STATUS_OK
);
353 CHECK_EQUAL(q
.access_information
.out
.access_flags
, io
.in
.desired_access
);
355 io
.in
.file_attributes
= 0;
356 io
.in
.desired_access
= 0;
357 io
.in
.query_maximal_access
= false;
358 io
.in
.share_access
= 0;
359 status
= smb2_create(tree
, tctx
, &io
);
360 CHECK_STATUS(status
, NT_STATUS_ACCESS_DENIED
);
362 smb2_deltree(tree
, FNAME
);
369 try the various request blobs
371 static bool test_create_blob(struct torture_context
*tctx
, struct smb2_tree
*tree
)
373 struct smb2_create io
;
376 smb2_deltree(tree
, FNAME
);
379 io
.in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
;
380 io
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
381 io
.in
.create_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
383 NTCREATEX_SHARE_ACCESS_DELETE
|
384 NTCREATEX_SHARE_ACCESS_READ
|
385 NTCREATEX_SHARE_ACCESS_WRITE
;
386 io
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
387 NTCREATEX_OPTIONS_ASYNC_ALERT
|
388 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
392 status
= smb2_create(tree
, tctx
, &io
);
393 CHECK_STATUS(status
, NT_STATUS_OK
);
395 status
= smb2_util_close(tree
, io
.out
.file
.handle
);
396 CHECK_STATUS(status
, NT_STATUS_OK
);
398 torture_comment(tctx
, "Testing alloc size\n");
399 /* FIXME We use 1M cause that's the rounded size of Samba.
400 * We should ask the server for the cluster size and calculate it
402 io
.in
.alloc_size
= 0x00100000;
403 status
= smb2_create(tree
, tctx
, &io
);
404 CHECK_STATUS(status
, NT_STATUS_OK
);
405 CHECK_EQUAL(io
.out
.alloc_size
, io
.in
.alloc_size
);
407 status
= smb2_util_close(tree
, io
.out
.file
.handle
);
408 CHECK_STATUS(status
, NT_STATUS_OK
);
410 torture_comment(tctx
, "Testing durable open\n");
411 io
.in
.durable_open
= true;
412 status
= smb2_create(tree
, tctx
, &io
);
413 CHECK_STATUS(status
, NT_STATUS_OK
);
415 status
= smb2_util_close(tree
, io
.out
.file
.handle
);
416 CHECK_STATUS(status
, NT_STATUS_OK
);
418 torture_comment(tctx
, "Testing query maximal access\n");
419 io
.in
.query_maximal_access
= true;
420 status
= smb2_create(tree
, tctx
, &io
);
421 CHECK_STATUS(status
, NT_STATUS_OK
);
422 CHECK_EQUAL(io
.out
.maximal_access
, 0x001f01ff);
424 status
= smb2_util_close(tree
, io
.out
.file
.handle
);
425 CHECK_STATUS(status
, NT_STATUS_OK
);
427 torture_comment(tctx
, "Testing timewarp\n");
428 io
.in
.timewarp
= 10000;
429 status
= smb2_create(tree
, tctx
, &io
);
430 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
433 torture_comment(tctx
, "Testing query_on_disk\n");
434 io
.in
.query_on_disk_id
= true;
435 status
= smb2_create(tree
, tctx
, &io
);
436 CHECK_STATUS(status
, NT_STATUS_OK
);
438 status
= smb2_util_close(tree
, io
.out
.file
.handle
);
439 CHECK_STATUS(status
, NT_STATUS_OK
);
441 torture_comment(tctx
, "Testing unknown tag\n");
442 status
= smb2_create_blob_add(tctx
, &io
.in
.blobs
,
443 "FooO", data_blob(NULL
, 0));
444 CHECK_STATUS(status
, NT_STATUS_OK
);
446 status
= smb2_create(tree
, tctx
, &io
);
447 CHECK_STATUS(status
, NT_STATUS_OK
);
449 status
= smb2_util_close(tree
, io
.out
.file
.handle
);
450 CHECK_STATUS(status
, NT_STATUS_OK
);
452 torture_comment(tctx
, "Testing bad tag length 0\n");
453 ZERO_STRUCT(io
.in
.blobs
);
454 status
= smb2_create_blob_add(tctx
, &io
.in
.blobs
,
455 "x", data_blob(NULL
, 0));
456 CHECK_STATUS(status
, NT_STATUS_OK
);
457 status
= smb2_create(tree
, tctx
, &io
);
458 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
460 torture_comment(tctx
, "Testing bad tag length 1\n");
461 ZERO_STRUCT(io
.in
.blobs
);
462 status
= smb2_create_blob_add(tctx
, &io
.in
.blobs
,
463 "x", data_blob(NULL
, 0));
464 CHECK_STATUS(status
, NT_STATUS_OK
);
465 status
= smb2_create(tree
, tctx
, &io
);
466 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
468 torture_comment(tctx
, "Testing bad tag length 2\n");
469 ZERO_STRUCT(io
.in
.blobs
);
470 status
= smb2_create_blob_add(tctx
, &io
.in
.blobs
,
471 "xx", data_blob(NULL
, 0));
472 CHECK_STATUS(status
, NT_STATUS_OK
);
473 status
= smb2_create(tree
, tctx
, &io
);
474 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
476 torture_comment(tctx
, "Testing bad tag length 3\n");
477 ZERO_STRUCT(io
.in
.blobs
);
478 status
= smb2_create_blob_add(tctx
, &io
.in
.blobs
,
479 "xxx", data_blob(NULL
, 0));
480 CHECK_STATUS(status
, NT_STATUS_OK
);
481 status
= smb2_create(tree
, tctx
, &io
);
482 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
484 torture_comment(tctx
, "Testing tag length 4\n");
485 ZERO_STRUCT(io
.in
.blobs
);
486 status
= smb2_create_blob_add(tctx
, &io
.in
.blobs
,
487 "xxxx", data_blob(NULL
, 0));
488 CHECK_STATUS(status
, NT_STATUS_OK
);
489 status
= smb2_create(tree
, tctx
, &io
);
490 CHECK_STATUS(status
, NT_STATUS_OK
);
492 torture_comment(tctx
, "Testing tag length 5\n");
493 ZERO_STRUCT(io
.in
.blobs
);
494 status
= smb2_create_blob_add(tctx
, &io
.in
.blobs
,
495 "xxxxx", data_blob(NULL
, 0));
496 CHECK_STATUS(status
, NT_STATUS_OK
);
497 status
= smb2_create(tree
, tctx
, &io
);
498 CHECK_STATUS(status
, NT_STATUS_OK
);
500 torture_comment(tctx
, "Testing tag length 6\n");
501 ZERO_STRUCT(io
.in
.blobs
);
502 status
= smb2_create_blob_add(tctx
, &io
.in
.blobs
,
503 "xxxxxx", data_blob(NULL
, 0));
504 CHECK_STATUS(status
, NT_STATUS_OK
);
505 status
= smb2_create(tree
, tctx
, &io
);
506 CHECK_STATUS(status
, NT_STATUS_OK
);
508 torture_comment(tctx
, "Testing tag length 7\n");
509 ZERO_STRUCT(io
.in
.blobs
);
510 status
= smb2_create_blob_add(tctx
, &io
.in
.blobs
,
511 "xxxxxxx", data_blob(NULL
, 0));
512 CHECK_STATUS(status
, NT_STATUS_OK
);
513 status
= smb2_create(tree
, tctx
, &io
);
514 CHECK_STATUS(status
, NT_STATUS_OK
);
516 torture_comment(tctx
, "Testing tag length 8\n");
517 ZERO_STRUCT(io
.in
.blobs
);
518 status
= smb2_create_blob_add(tctx
, &io
.in
.blobs
,
519 "xxxxxxxx", data_blob(NULL
, 0));
520 CHECK_STATUS(status
, NT_STATUS_OK
);
521 status
= smb2_create(tree
, tctx
, &io
);
522 CHECK_STATUS(status
, NT_STATUS_OK
);
524 torture_comment(tctx
, "Testing tag length 16\n");
525 ZERO_STRUCT(io
.in
.blobs
);
526 status
= smb2_create_blob_add(tctx
, &io
.in
.blobs
,
527 "xxxxxxxxxxxxxxxx", data_blob(NULL
, 0));
528 CHECK_STATUS(status
, NT_STATUS_OK
);
529 status
= smb2_create(tree
, tctx
, &io
);
530 CHECK_STATUS(status
, NT_STATUS_OK
);
532 torture_comment(tctx
, "Testing tag length 17\n");
533 ZERO_STRUCT(io
.in
.blobs
);
534 status
= smb2_create_blob_add(tctx
, &io
.in
.blobs
,
535 "xxxxxxxxxxxxxxxxx", data_blob(NULL
, 0));
536 CHECK_STATUS(status
, NT_STATUS_OK
);
537 status
= smb2_create(tree
, tctx
, &io
);
538 CHECK_STATUS(status
, NT_STATUS_OK
);
540 torture_comment(tctx
, "Testing tag length 34\n");
541 ZERO_STRUCT(io
.in
.blobs
);
542 status
= smb2_create_blob_add(tctx
, &io
.in
.blobs
,
543 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
545 CHECK_STATUS(status
, NT_STATUS_OK
);
546 status
= smb2_create(tree
, tctx
, &io
);
547 CHECK_STATUS(status
, NT_STATUS_OK
);
549 smb2_deltree(tree
, FNAME
);
554 #define FAIL_UNLESS(__cond) \
556 if (__cond) {} else { \
557 torture_result(tctx, TORTURE_FAIL, "%s) condition violated: %s\n", \
558 __location__, #__cond); \
559 ret = false; goto done; \
564 try creating with acls
566 static bool test_create_acl_ext(struct torture_context
*tctx
, struct smb2_tree
*tree
, bool test_dir
)
569 struct smb2_create io
;
571 struct security_ace ace
;
572 struct security_descriptor
*sd
;
573 struct dom_sid
*test_sid
;
574 union smb_fileinfo q
= {};
576 FILE_ATTRIBUTE_HIDDEN
|
577 FILE_ATTRIBUTE_SYSTEM
|
578 (test_dir
? FILE_ATTRIBUTE_DIRECTORY
: 0);
579 NTSTATUS (*delete_func
)(struct smb2_tree
*, const char *) =
580 test_dir
? smb2_util_rmdir
: smb2_util_unlink
;
584 smb2_deltree(tree
, FNAME
);
587 io
.in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
;
588 io
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
589 io
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
591 NTCREATEX_SHARE_ACCESS_DELETE
|
592 NTCREATEX_SHARE_ACCESS_READ
|
593 NTCREATEX_SHARE_ACCESS_WRITE
;
594 io
.in
.create_options
= NTCREATEX_OPTIONS_ASYNC_ALERT
| 0x00200000 |
595 (test_dir
? NTCREATEX_OPTIONS_DIRECTORY
:
596 (NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
));
600 torture_comment(tctx
, "basic create\n");
602 status
= smb2_create(tree
, tctx
, &io
);
603 CHECK_STATUS(status
, NT_STATUS_OK
);
605 q
.query_secdesc
.level
= RAW_FILEINFO_SEC_DESC
;
606 q
.query_secdesc
.in
.file
.handle
= io
.out
.file
.handle
;
607 q
.query_secdesc
.in
.secinfo_flags
=
611 status
= smb2_getinfo_file(tree
, tctx
, &q
);
612 CHECK_STATUS(status
, NT_STATUS_OK
);
613 sd
= q
.query_secdesc
.out
.sd
;
615 status
= smb2_util_close(tree
, io
.out
.file
.handle
);
616 CHECK_STATUS(status
, NT_STATUS_OK
);
617 status
= delete_func(tree
, FNAME
);
618 CHECK_STATUS(status
, NT_STATUS_OK
);
620 torture_comment(tctx
, "adding a new ACE\n");
621 test_sid
= dom_sid_parse_talloc(tctx
, SID_NT_AUTHENTICATED_USERS
);
623 ace
.type
= SEC_ACE_TYPE_ACCESS_ALLOWED
;
625 ace
.access_mask
= SEC_STD_ALL
;
626 ace
.trustee
= *test_sid
;
628 status
= security_descriptor_dacl_add(sd
, &ace
);
629 CHECK_STATUS(status
, NT_STATUS_OK
);
631 torture_comment(tctx
, "creating a file with an initial ACL\n");
634 status
= smb2_create(tree
, tctx
, &io
);
635 CHECK_STATUS(status
, NT_STATUS_OK
);
637 FAIL_UNLESS(smb2_util_verify_sd(tctx
, tree
, io
.out
.file
.handle
, sd
));
639 status
= smb2_util_close(tree
, io
.out
.file
.handle
);
640 CHECK_STATUS(status
, NT_STATUS_OK
);
641 status
= delete_func(tree
, FNAME
);
642 CHECK_STATUS(status
, NT_STATUS_OK
);
644 torture_comment(tctx
, "creating with attributes\n");
646 io
.in
.sec_desc
= NULL
;
647 io
.in
.file_attributes
= attrib
;
648 status
= smb2_create(tree
, tctx
, &io
);
649 CHECK_STATUS(status
, NT_STATUS_OK
);
651 FAIL_UNLESS(smb2_util_verify_attrib(tctx
, tree
, io
.out
.file
.handle
, attrib
));
653 status
= smb2_util_close(tree
, io
.out
.file
.handle
);
654 CHECK_STATUS(status
, NT_STATUS_OK
);
655 status
= delete_func(tree
, FNAME
);
656 CHECK_STATUS(status
, NT_STATUS_OK
);
658 torture_comment(tctx
, "creating with attributes and ACL\n");
661 io
.in
.file_attributes
= attrib
;
662 status
= smb2_create(tree
, tctx
, &io
);
663 CHECK_STATUS(status
, NT_STATUS_OK
);
665 FAIL_UNLESS(smb2_util_verify_sd(tctx
, tree
, io
.out
.file
.handle
, sd
));
666 FAIL_UNLESS(smb2_util_verify_attrib(tctx
, tree
, io
.out
.file
.handle
, attrib
));
668 status
= smb2_util_close(tree
, io
.out
.file
.handle
);
669 CHECK_STATUS(status
, NT_STATUS_OK
);
670 status
= delete_func(tree
, FNAME
);
671 CHECK_STATUS(status
, NT_STATUS_OK
);
673 torture_comment(tctx
, "creating with attributes, ACL and owner\n");
674 sd
= security_descriptor_dacl_create(tctx
,
675 0, SID_WORLD
, SID_BUILTIN_USERS
,
677 SEC_ACE_TYPE_ACCESS_ALLOWED
,
678 SEC_RIGHTS_FILE_READ
| SEC_STD_ALL
,
683 io
.in
.file_attributes
= attrib
;
684 status
= smb2_create(tree
, tctx
, &io
);
685 CHECK_STATUS(status
, NT_STATUS_OK
);
687 FAIL_UNLESS(smb2_util_verify_sd(tctx
, tree
, io
.out
.file
.handle
, sd
));
688 FAIL_UNLESS(smb2_util_verify_attrib(tctx
, tree
, io
.out
.file
.handle
, attrib
));
691 status
= smb2_util_close(tree
, io
.out
.file
.handle
);
692 CHECK_STATUS(status
, NT_STATUS_OK
);
693 status
= delete_func(tree
, FNAME
);
694 CHECK_STATUS(status
, NT_STATUS_OK
);
702 static bool test_smb2_open(struct torture_context
*tctx
,
703 struct smb2_tree
*tree
)
706 union smb_fileinfo finfo
;
707 const char *fname
= DNAME
"\\torture_ntcreatex.txt";
708 const char *dname
= DNAME
"\\torture_ntcreatex.dir";
710 struct smb2_handle h
= {{0}};
711 struct smb2_handle h1
= {{0}};
715 uint32_t create_disp
;
717 NTSTATUS correct_status
;
719 { NTCREATEX_DISP_SUPERSEDE
, true, NT_STATUS_OK
},
720 { NTCREATEX_DISP_SUPERSEDE
, false, NT_STATUS_OK
},
721 { NTCREATEX_DISP_OPEN
, true, NT_STATUS_OK
},
722 { NTCREATEX_DISP_OPEN
, false, NT_STATUS_OBJECT_NAME_NOT_FOUND
},
723 { NTCREATEX_DISP_CREATE
, true, NT_STATUS_OBJECT_NAME_COLLISION
},
724 { NTCREATEX_DISP_CREATE
, false, NT_STATUS_OK
},
725 { NTCREATEX_DISP_OPEN_IF
, true, NT_STATUS_OK
},
726 { NTCREATEX_DISP_OPEN_IF
, false, NT_STATUS_OK
},
727 { NTCREATEX_DISP_OVERWRITE
, true, NT_STATUS_OK
},
728 { NTCREATEX_DISP_OVERWRITE
, false, NT_STATUS_OBJECT_NAME_NOT_FOUND
},
729 { NTCREATEX_DISP_OVERWRITE_IF
, true, NT_STATUS_OK
},
730 { NTCREATEX_DISP_OVERWRITE_IF
, false, NT_STATUS_OK
},
731 { 6, true, NT_STATUS_INVALID_PARAMETER
},
732 { 6, false, NT_STATUS_INVALID_PARAMETER
},
735 torture_comment(tctx
, "Checking SMB2 Open\n");
737 smb2_util_unlink(tree
, fname
);
738 smb2_util_rmdir(tree
, dname
);
740 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
741 CHECK_STATUS(status
, NT_STATUS_OK
);
743 ZERO_STRUCT(io
.smb2
);
744 /* reasonable default parameters */
745 io
.generic
.level
= RAW_OPEN_SMB2
;
746 io
.smb2
.in
.create_flags
= NTCREATEX_FLAGS_EXTENDED
;
747 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
748 io
.smb2
.in
.alloc_size
= 1024*1024;
749 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
750 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
751 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
752 io
.smb2
.in
.create_options
= 0;
753 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
754 io
.smb2
.in
.security_flags
= 0;
755 io
.smb2
.in
.fname
= fname
;
757 /* test the create disposition */
758 for (i
=0; i
<ARRAY_SIZE(open_funcs
); i
++) {
759 if (open_funcs
[i
].with_file
) {
760 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
761 status
= smb2_create(tree
, tctx
, &(io
.smb2
));
762 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
763 talloc_asprintf(tctx
,
764 "Failed to create file %s status %s %zu\n",
765 fname
, nt_errstr(status
), i
));
766 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
768 io
.smb2
.in
.create_disposition
= open_funcs
[i
].create_disp
;
769 status
= smb2_create(tree
, tctx
, &(io
.smb2
));
770 torture_assert_ntstatus_equal_goto(tctx
, status
,
771 open_funcs
[i
].correct_status
,
773 talloc_asprintf(tctx
,
774 "(i=%zu with_file=%d open_disp=%d)\n",
775 i
, (int)open_funcs
[i
].with_file
,
776 (int)open_funcs
[i
].create_disp
));
777 if (NT_STATUS_IS_OK(status
) || open_funcs
[i
].with_file
) {
778 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
779 smb2_util_unlink(tree
, fname
);
783 /* basic field testing */
784 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
786 status
= smb2_create(tree
, tctx
, &(io
.smb2
));
787 CHECK_STATUS(status
, NT_STATUS_OK
);
788 h1
= io
.smb2
.out
.file
.handle
;
790 CHECK_VAL(io
.smb2
.out
.oplock_level
, 0);
791 CHECK_VAL(io
.smb2
.out
.create_action
, NTCREATEX_ACTION_CREATED
);
792 CHECK_NTTIME(io
.smb2
.out
.create_time
, create_time
);
793 CHECK_NTTIME(io
.smb2
.out
.access_time
, access_time
);
794 CHECK_NTTIME(io
.smb2
.out
.write_time
, write_time
);
795 CHECK_NTTIME(io
.smb2
.out
.change_time
, change_time
);
796 CHECK_ALL_INFO(io
.smb2
.out
.file_attr
, attrib
);
797 CHECK_ALL_INFO(io
.smb2
.out
.alloc_size
, alloc_size
);
798 CHECK_ALL_INFO(io
.smb2
.out
.size
, size
);
800 /* check fields when the file already existed */
801 smb2_util_close(tree
, h1
);
802 smb2_util_unlink(tree
, fname
);
804 status
= smb2_create_complex_file(tctx
, tree
, fname
, &h1
);
805 CHECK_STATUS(status
, NT_STATUS_OK
);
807 smb2_util_close(tree
, h1
);
809 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
810 status
= smb2_create(tree
, tctx
, &(io
.smb2
));
811 CHECK_STATUS(status
, NT_STATUS_OK
);
812 h1
= io
.smb2
.out
.file
.handle
;
814 CHECK_VAL(io
.smb2
.out
.oplock_level
, 0);
815 CHECK_VAL(io
.smb2
.out
.create_action
, NTCREATEX_ACTION_EXISTED
);
816 CHECK_NTTIME(io
.smb2
.out
.create_time
, create_time
);
817 CHECK_NTTIME(io
.smb2
.out
.access_time
, access_time
);
818 CHECK_NTTIME(io
.smb2
.out
.write_time
, write_time
);
819 CHECK_NTTIME(io
.smb2
.out
.change_time
, change_time
);
820 CHECK_ALL_INFO(io
.smb2
.out
.file_attr
, attrib
);
821 CHECK_ALL_INFO(io
.smb2
.out
.alloc_size
, alloc_size
);
822 CHECK_ALL_INFO(io
.smb2
.out
.size
, size
);
823 smb2_util_close(tree
, h1
);
824 smb2_util_unlink(tree
, fname
);
826 /* create a directory */
827 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
828 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
829 io
.smb2
.in
.alloc_size
= 0;
830 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
831 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
832 io
.smb2
.in
.create_options
= 0;
833 io
.smb2
.in
.fname
= dname
;
836 smb2_util_rmdir(tree
, fname
);
837 smb2_util_unlink(tree
, fname
);
839 io
.smb2
.in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
;
840 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
841 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
842 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
843 NTCREATEX_SHARE_ACCESS_WRITE
;
844 status
= smb2_create(tree
, tctx
, &(io
.smb2
));
845 CHECK_STATUS(status
, NT_STATUS_OK
);
846 h1
= io
.smb2
.out
.file
.handle
;
848 CHECK_VAL(io
.smb2
.out
.oplock_level
, 0);
849 CHECK_VAL(io
.smb2
.out
.create_action
, NTCREATEX_ACTION_CREATED
);
850 CHECK_NTTIME(io
.smb2
.out
.create_time
, create_time
);
851 CHECK_NTTIME(io
.smb2
.out
.access_time
, access_time
);
852 CHECK_NTTIME(io
.smb2
.out
.write_time
, write_time
);
853 CHECK_NTTIME(io
.smb2
.out
.change_time
, change_time
);
854 CHECK_ALL_INFO(io
.smb2
.out
.file_attr
, attrib
);
855 CHECK_VAL(io
.smb2
.out
.file_attr
& ~FILE_ATTRIBUTE_NONINDEXED
,
856 FILE_ATTRIBUTE_DIRECTORY
);
857 CHECK_ALL_INFO(io
.smb2
.out
.alloc_size
, alloc_size
);
858 CHECK_ALL_INFO(io
.smb2
.out
.size
, size
);
859 CHECK_VAL(io
.smb2
.out
.size
, 0);
860 smb2_util_unlink(tree
, fname
);
863 smb2_util_close(tree
, h1
);
864 smb2_util_unlink(tree
, fname
);
865 smb2_deltree(tree
, DNAME
);
870 test with an already opened and byte range locked file
873 static bool test_smb2_open_brlocked(struct torture_context
*tctx
,
874 struct smb2_tree
*tree
)
876 union smb_open io
, io1
;
878 struct smb2_lock_element lock
[1];
879 const char *fname
= DNAME
"\\torture_ntcreatex.txt";
882 struct smb2_handle h
;
885 torture_comment(tctx
,
886 "Testing SMB2 open with a byte range locked file\n");
888 smb2_util_unlink(tree
, fname
);
890 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
891 CHECK_STATUS(status
, NT_STATUS_OK
);
893 ZERO_STRUCT(io
.smb2
);
894 io
.generic
.level
= RAW_OPEN_SMB2
;
895 io
.smb2
.in
.create_flags
= NTCREATEX_FLAGS_EXTENDED
;
896 io
.smb2
.in
.desired_access
= 0x2019f;
897 io
.smb2
.in
.alloc_size
= 0;
898 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
899 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
900 NTCREATEX_SHARE_ACCESS_WRITE
;
901 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
902 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
903 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_IMPERSONATION
;
904 io
.smb2
.in
.security_flags
= SMB2_SECURITY_DYNAMIC_TRACKING
;
905 io
.smb2
.in
.fname
= fname
;
907 status
= smb2_create(tree
, tctx
, &(io
.smb2
));
908 CHECK_STATUS(status
, NT_STATUS_OK
);
910 status
= smb2_util_write(tree
, io
.smb2
.out
.file
.handle
, &b
, 0, 1);
911 CHECK_STATUS(status
, NT_STATUS_OK
);
913 ZERO_STRUCT(io2
.smb2
);
914 io2
.smb2
.level
= RAW_LOCK_SMB2
;
915 io2
.smb2
.in
.file
.handle
= io
.smb2
.out
.file
.handle
;
916 io2
.smb2
.in
.lock_count
= 1;
921 lock
[0].flags
= SMB2_LOCK_FLAG_EXCLUSIVE
|
922 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
;
923 io2
.smb2
.in
.locks
= &lock
[0];
924 status
= smb2_lock(tree
, &(io2
.smb2
));
925 CHECK_STATUS(status
, NT_STATUS_OK
);
927 ZERO_STRUCT(io1
.smb2
);
928 io1
.smb2
.in
.create_flags
= NTCREATEX_FLAGS_EXTENDED
;
929 io1
.smb2
.in
.desired_access
= 0x20196;
930 io1
.smb2
.in
.alloc_size
= 0;
931 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
932 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
933 NTCREATEX_SHARE_ACCESS_WRITE
;
934 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
935 io1
.smb2
.in
.create_options
= 0;
936 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_IMPERSONATION
;
937 io1
.smb2
.in
.security_flags
= SMB2_SECURITY_DYNAMIC_TRACKING
;
938 io1
.smb2
.in
.fname
= fname
;
940 status
= smb2_create(tree
, tctx
, &(io1
.smb2
));
941 CHECK_STATUS(status
, NT_STATUS_OK
);
943 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
944 smb2_util_close(tree
, io1
.smb2
.out
.file
.handle
);
945 smb2_util_unlink(tree
, fname
);
946 smb2_deltree(tree
, DNAME
);
951 /* A little torture test to expose a race condition in Samba 3.0.20 ... :-) */
953 static bool test_smb2_open_multi(struct torture_context
*tctx
,
954 struct smb2_tree
*tree
)
956 const char *fname
= "test_oplock.dat";
960 struct smb2_tree
**trees
;
961 struct smb2_request
**requests
;
963 int i
, num_files
= 3;
965 int num_collision
= 0;
967 torture_comment(tctx
,
968 "Testing SMB2 Open with multiple connections\n");
969 trees
= talloc_array(tctx
, struct smb2_tree
*, num_files
);
970 requests
= talloc_array(tctx
, struct smb2_request
*, num_files
);
971 ios
= talloc_array(tctx
, union smb_open
, num_files
);
972 if ((tctx
->ev
== NULL
) || (trees
== NULL
) || (requests
== NULL
) ||
974 torture_comment(tctx
, ("talloc failed\n"));
979 tree
->session
->transport
->options
.request_timeout
= 60;
981 for (i
=0; i
<num_files
; i
++) {
982 if (!torture_smb2_connection(tctx
, &(trees
[i
]))) {
983 torture_comment(tctx
,
984 "Could not open %d'th connection\n", i
);
985 torture_assert_goto(tctx
, false, ret
, done
, __location__
);
987 trees
[i
]->session
->transport
->options
.request_timeout
= 60;
991 smb2_util_unlink(tree
, fname
);
996 ZERO_STRUCT(io
.smb2
);
997 io
.generic
.level
= RAW_OPEN_SMB2
;
998 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
999 io
.smb2
.in
.alloc_size
= 0;
1000 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1001 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1002 NTCREATEX_SHARE_ACCESS_WRITE
|
1003 NTCREATEX_SHARE_ACCESS_DELETE
;
1004 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1005 io
.smb2
.in
.create_options
= 0;
1006 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1007 io
.smb2
.in
.security_flags
= 0;
1008 io
.smb2
.in
.fname
= fname
;
1009 io
.smb2
.in
.create_flags
= 0;
1011 for (i
=0; i
<num_files
; i
++) {
1013 requests
[i
] = smb2_create_send(trees
[i
], &(ios
[i
].smb2
));
1014 if (requests
[i
] == NULL
) {
1015 torture_comment(tctx
,
1016 "could not send %d'th request\n", i
);
1017 torture_assert_goto(tctx
, false, ret
, done
, __location__
);
1021 torture_comment(tctx
, "waiting for replies\n");
1023 bool unreplied
= false;
1024 for (i
=0; i
<num_files
; i
++) {
1025 if (requests
[i
] == NULL
) {
1028 if (requests
[i
]->state
< SMB2_REQUEST_DONE
) {
1032 status
= smb2_create_recv(requests
[i
], tctx
,
1035 torture_comment(tctx
,
1036 "File %d returned status %s\n", i
,
1039 if (NT_STATUS_IS_OK(status
)) {
1043 if (NT_STATUS_EQUAL(status
,
1044 NT_STATUS_OBJECT_NAME_COLLISION
)) {
1054 if (tevent_loop_once(tctx
->ev
) != 0) {
1055 torture_comment(tctx
, "tevent_loop_once failed\n");
1056 torture_assert_goto(tctx
, false, ret
, done
, __location__
);
1060 if ((num_ok
!= 1) || (num_ok
+ num_collision
!= num_files
)) {
1061 torture_assert_goto(tctx
, false, ret
, done
, __location__
);
1064 smb2_deltree(tree
, fname
);
1070 test opening for delete on a read-only attribute file.
1073 static bool test_smb2_open_for_delete(struct torture_context
*tctx
,
1074 struct smb2_tree
*tree
)
1077 union smb_fileinfo finfo
;
1078 const char *fname
= DNAME
"\\torture_open_for_delete.txt";
1080 struct smb2_handle h
, h1
;
1083 torture_comment(tctx
,
1084 "Checking SMB2_OPEN for delete on a readonly file.\n");
1085 smb2_util_unlink(tree
, fname
);
1086 smb2_deltree(tree
, fname
);
1088 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
1089 CHECK_STATUS(status
, NT_STATUS_OK
);
1091 /* reasonable default parameters */
1092 ZERO_STRUCT(io
.smb2
);
1093 io
.generic
.level
= RAW_OPEN_SMB2
;
1094 io
.smb2
.in
.create_flags
= NTCREATEX_FLAGS_EXTENDED
;
1095 io
.smb2
.in
.alloc_size
= 0;
1096 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1097 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_READONLY
;
1098 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
1099 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1100 io
.smb2
.in
.create_options
= 0;
1101 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1102 io
.smb2
.in
.security_flags
= 0;
1103 io
.smb2
.in
.fname
= fname
;
1105 /* Create the readonly file. */
1107 status
= smb2_create(tree
, tctx
, &(io
.smb2
));
1108 CHECK_STATUS(status
, NT_STATUS_OK
);
1109 h1
= io
.smb2
.out
.file
.handle
;
1111 CHECK_VAL(io
.smb2
.out
.oplock_level
, 0);
1112 io
.smb2
.in
.create_options
= 0;
1113 CHECK_VAL(io
.smb2
.out
.create_action
, NTCREATEX_ACTION_CREATED
);
1114 CHECK_ALL_INFO(io
.smb2
.out
.file_attr
, attrib
);
1115 smb2_util_close(tree
, h1
);
1117 /* Now try and open for delete only - should succeed. */
1118 io
.smb2
.in
.desired_access
= SEC_STD_DELETE
;
1119 io
.smb2
.in
.file_attributes
= 0;
1120 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1121 NTCREATEX_SHARE_ACCESS_WRITE
|
1122 NTCREATEX_SHARE_ACCESS_DELETE
;
1123 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1124 status
= smb2_create(tree
, tctx
, &(io
.smb2
));
1125 CHECK_STATUS(status
, NT_STATUS_OK
);
1126 smb2_util_close(tree
, io
.smb2
.out
.file
.handle
);
1128 /* Clear readonly flag to allow file deletion */
1129 io
.smb2
.in
.desired_access
= SEC_FILE_READ_ATTRIBUTE
|
1130 SEC_FILE_WRITE_ATTRIBUTE
;
1131 status
= smb2_create(tree
, tctx
, &(io
.smb2
));
1132 CHECK_STATUS(status
, NT_STATUS_OK
);
1133 h1
= io
.smb2
.out
.file
.handle
;
1134 SET_ATTRIB(FILE_ATTRIBUTE_ARCHIVE
, NT_STATUS_OK
);
1135 smb2_util_close(tree
, h1
);
1137 smb2_util_close(tree
, h
);
1138 smb2_util_unlink(tree
, fname
);
1139 smb2_deltree(tree
, DNAME
);
1145 test SMB2 open with a leading slash on the path.
1146 Trying to create a directory with a leading slash
1147 should give NT_STATUS_INVALID_PARAMETER error
1149 static bool test_smb2_leading_slash(struct torture_context
*tctx
,
1150 struct smb2_tree
*tree
)
1153 const char *dnameslash
= "\\"DNAME
;
1157 torture_comment(tctx
,
1158 "Trying to create a directory with leading slash on path\n");
1159 smb2_deltree(tree
, dnameslash
);
1161 ZERO_STRUCT(io
.smb2
);
1162 io
.generic
.level
= RAW_OPEN_SMB2
;
1163 io
.smb2
.in
.oplock_level
= 0;
1164 io
.smb2
.in
.desired_access
= SEC_RIGHTS_DIR_ALL
;
1165 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
1166 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1167 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1168 NTCREATEX_SHARE_ACCESS_WRITE
|
1169 NTCREATEX_SHARE_ACCESS_DELETE
;
1170 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1171 io
.smb2
.in
.fname
= dnameslash
;
1173 status
= smb2_create(tree
, tree
, &(io
.smb2
));
1174 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1176 smb2_deltree(tree
, dnameslash
);
1181 test SMB2 open with an invalid impersonation level.
1182 Should give NT_STATUS_BAD_IMPERSONATION_LEVEL error
1184 static bool test_smb2_impersonation_level(struct torture_context
*tctx
,
1185 struct smb2_tree
*tree
)
1188 const char *fname
= DNAME
"\\torture_invalid_impersonation_level.txt";
1190 struct smb2_handle h
;
1193 torture_comment(tctx
,
1194 "Testing SMB2 open with an invalid impersonation level.\n");
1196 smb2_util_unlink(tree
, fname
);
1197 smb2_util_rmdir(tree
, DNAME
);
1199 status
= torture_smb2_testdir(tree
, DNAME
, &h
);
1200 CHECK_STATUS(status
, NT_STATUS_OK
);
1202 ZERO_STRUCT(io
.smb2
);
1203 io
.generic
.level
= RAW_OPEN_SMB2
;
1204 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1205 io
.smb2
.in
.alloc_size
= 0;
1206 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1207 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1208 NTCREATEX_SHARE_ACCESS_WRITE
|
1209 NTCREATEX_SHARE_ACCESS_DELETE
;
1210 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1211 io
.smb2
.in
.create_options
= 0;
1212 io
.smb2
.in
.impersonation_level
= 0x12345678;
1213 io
.smb2
.in
.security_flags
= 0;
1214 io
.smb2
.in
.fname
= fname
;
1215 io
.smb2
.in
.create_flags
= 0;
1217 status
= smb2_create(tree
, tree
, &(io
.smb2
));
1218 CHECK_STATUS(status
, NT_STATUS_BAD_IMPERSONATION_LEVEL
);
1220 smb2_util_close(tree
, h
);
1221 smb2_util_unlink(tree
, fname
);
1222 smb2_deltree(tree
, DNAME
);
1226 static bool test_create_acl_file(struct torture_context
*tctx
,
1227 struct smb2_tree
*tree
)
1229 torture_comment(tctx
, "Testing nttrans create with sec_desc on files\n");
1231 return test_create_acl_ext(tctx
, tree
, false);
1234 static bool test_create_acl_dir(struct torture_context
*tctx
,
1235 struct smb2_tree
*tree
)
1237 torture_comment(tctx
, "Testing nttrans create with sec_desc on directories\n");
1239 return test_create_acl_ext(tctx
, tree
, true);
1242 #define CHECK_ACCESS_FLAGS(_fh, flags) do { \
1243 union smb_fileinfo _q; \
1244 _q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION; \
1245 _q.access_information.in.file.handle = (_fh); \
1246 status = smb2_getinfo_file(tree, tctx, &_q); \
1247 CHECK_STATUS(status, NT_STATUS_OK); \
1248 if (_q.access_information.out.access_flags != (flags)) { \
1249 torture_result(tctx, TORTURE_FAIL, "(%s) Incorrect access_flags 0x%08x - should be 0x%08x\n", \
1250 __location__, _q.access_information.out.access_flags, (flags)); \
1257 * Test creating a file with a NULL DACL.
1259 static bool test_create_null_dacl(struct torture_context
*tctx
,
1260 struct smb2_tree
*tree
)
1263 struct smb2_create io
;
1264 const char *fname
= "nulldacl.txt";
1266 struct smb2_handle handle
;
1267 union smb_fileinfo q
;
1268 union smb_setfileinfo s
;
1269 struct security_descriptor
*sd
= security_descriptor_initialise(tctx
);
1270 struct security_acl dacl
;
1272 torture_comment(tctx
, "TESTING SEC_DESC WITH A NULL DACL\n");
1274 smb2_util_unlink(tree
, fname
);
1277 io
.level
= RAW_OPEN_SMB2
;
1278 io
.in
.create_flags
= 0;
1279 io
.in
.desired_access
= SEC_STD_READ_CONTROL
| SEC_STD_WRITE_DAC
1280 | SEC_STD_WRITE_OWNER
;
1281 io
.in
.create_options
= 0;
1282 io
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1283 io
.in
.share_access
=
1284 NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
1285 io
.in
.alloc_size
= 0;
1286 io
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1287 io
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1288 io
.in
.security_flags
= 0;
1289 io
.in
.fname
= fname
;
1290 io
.in
.sec_desc
= sd
;
1291 /* XXX create_options ? */
1292 io
.in
.create_options
= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY
|
1293 NTCREATEX_OPTIONS_ASYNC_ALERT
|
1294 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
|
1297 torture_comment(tctx
, "creating a file with a empty sd\n");
1298 status
= smb2_create(tree
, tctx
, &io
);
1299 CHECK_STATUS(status
, NT_STATUS_OK
);
1300 handle
= io
.out
.file
.handle
;
1302 torture_comment(tctx
, "get the original sd\n");
1303 q
.query_secdesc
.level
= RAW_FILEINFO_SEC_DESC
;
1304 q
.query_secdesc
.in
.file
.handle
= handle
;
1305 q
.query_secdesc
.in
.secinfo_flags
=
1309 status
= smb2_getinfo_file(tree
, tctx
, &q
);
1310 CHECK_STATUS(status
, NT_STATUS_OK
);
1313 * Testing the created DACL,
1314 * the server should add the inherited DACL
1315 * when SEC_DESC_DACL_PRESENT isn't specified
1317 if (!(q
.query_secdesc
.out
.sd
->type
& SEC_DESC_DACL_PRESENT
)) {
1319 torture_fail_goto(tctx
, done
, "DACL_PRESENT flag not set by the server!\n");
1321 if (q
.query_secdesc
.out
.sd
->dacl
== NULL
) {
1323 torture_fail_goto(tctx
, done
, "no DACL has been created on the server!\n");
1326 torture_comment(tctx
, "set NULL DACL\n");
1327 sd
->type
|= SEC_DESC_DACL_PRESENT
;
1329 s
.set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
1330 s
.set_secdesc
.in
.file
.handle
= handle
;
1331 s
.set_secdesc
.in
.secinfo_flags
= SECINFO_DACL
;
1332 s
.set_secdesc
.in
.sd
= sd
;
1333 status
= smb2_setinfo_file(tree
, &s
);
1334 CHECK_STATUS(status
, NT_STATUS_OK
);
1336 torture_comment(tctx
, "get the sd\n");
1337 q
.query_secdesc
.level
= RAW_FILEINFO_SEC_DESC
;
1338 q
.query_secdesc
.in
.file
.handle
= handle
;
1339 q
.query_secdesc
.in
.secinfo_flags
=
1343 status
= smb2_getinfo_file(tree
, tctx
, &q
);
1344 CHECK_STATUS(status
, NT_STATUS_OK
);
1346 /* Testing the modified DACL */
1347 if (!(q
.query_secdesc
.out
.sd
->type
& SEC_DESC_DACL_PRESENT
)) {
1349 torture_fail_goto(tctx
, done
, "DACL_PRESENT flag not set by the server!\n");
1351 if (q
.query_secdesc
.out
.sd
->dacl
!= NULL
) {
1353 torture_fail_goto(tctx
, done
, "DACL has been created on the server!\n");
1356 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1358 torture_comment(tctx
, "try open for read control\n");
1359 io
.in
.desired_access
= SEC_STD_READ_CONTROL
;
1360 status
= smb2_create(tree
, tctx
, &io
);
1361 CHECK_STATUS(status
, NT_STATUS_OK
);
1362 CHECK_ACCESS_FLAGS(io
.out
.file
.handle
,
1363 SEC_STD_READ_CONTROL
);
1364 smb2_util_close(tree
, io
.out
.file
.handle
);
1366 torture_comment(tctx
, "try open for write\n");
1367 io
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
1368 status
= smb2_create(tree
, tctx
, &io
);
1369 CHECK_STATUS(status
, NT_STATUS_OK
);
1370 CHECK_ACCESS_FLAGS(io
.out
.file
.handle
,
1371 SEC_FILE_WRITE_DATA
);
1372 smb2_util_close(tree
, io
.out
.file
.handle
);
1374 torture_comment(tctx
, "try open for read\n");
1375 io
.in
.desired_access
= SEC_FILE_READ_DATA
;
1376 status
= smb2_create(tree
, tctx
, &io
);
1377 CHECK_STATUS(status
, NT_STATUS_OK
);
1378 CHECK_ACCESS_FLAGS(io
.out
.file
.handle
,
1379 SEC_FILE_READ_DATA
);
1380 smb2_util_close(tree
, io
.out
.file
.handle
);
1382 torture_comment(tctx
, "try open for generic write\n");
1383 io
.in
.desired_access
= SEC_GENERIC_WRITE
;
1384 status
= smb2_create(tree
, tctx
, &io
);
1385 CHECK_STATUS(status
, NT_STATUS_OK
);
1386 CHECK_ACCESS_FLAGS(io
.out
.file
.handle
,
1387 SEC_RIGHTS_FILE_WRITE
);
1388 smb2_util_close(tree
, io
.out
.file
.handle
);
1390 torture_comment(tctx
, "try open for generic read\n");
1391 io
.in
.desired_access
= SEC_GENERIC_READ
;
1392 status
= smb2_create(tree
, tctx
, &io
);
1393 CHECK_STATUS(status
, NT_STATUS_OK
);
1394 CHECK_ACCESS_FLAGS(io
.out
.file
.handle
,
1395 SEC_RIGHTS_FILE_READ
);
1396 smb2_util_close(tree
, io
.out
.file
.handle
);
1398 torture_comment(tctx
, "set DACL with 0 aces\n");
1400 dacl
.revision
= SECURITY_ACL_REVISION_NT4
;
1404 s
.set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
1405 s
.set_secdesc
.in
.file
.handle
= handle
;
1406 s
.set_secdesc
.in
.secinfo_flags
= SECINFO_DACL
;
1407 s
.set_secdesc
.in
.sd
= sd
;
1408 status
= smb2_setinfo_file(tree
, &s
);
1409 CHECK_STATUS(status
, NT_STATUS_OK
);
1411 torture_comment(tctx
, "get the sd\n");
1412 q
.query_secdesc
.level
= RAW_FILEINFO_SEC_DESC
;
1413 q
.query_secdesc
.in
.file
.handle
= handle
;
1414 q
.query_secdesc
.in
.secinfo_flags
=
1418 status
= smb2_getinfo_file(tree
, tctx
, &q
);
1419 CHECK_STATUS(status
, NT_STATUS_OK
);
1421 /* Testing the modified DACL */
1422 if (!(q
.query_secdesc
.out
.sd
->type
& SEC_DESC_DACL_PRESENT
)) {
1424 torture_fail_goto(tctx
, done
, "DACL_PRESENT flag not set by the server!\n");
1426 if (q
.query_secdesc
.out
.sd
->dacl
== NULL
) {
1428 torture_fail_goto(tctx
, done
, "no DACL has been created on the server!\n");
1430 if (q
.query_secdesc
.out
.sd
->dacl
->num_aces
!= 0) {
1431 torture_result(tctx
, TORTURE_FAIL
, "DACL has %u aces!\n",
1432 q
.query_secdesc
.out
.sd
->dacl
->num_aces
);
1437 torture_comment(tctx
, "try open for read control\n");
1438 io
.in
.desired_access
= SEC_STD_READ_CONTROL
;
1439 status
= smb2_create(tree
, tctx
, &io
);
1440 CHECK_STATUS(status
, NT_STATUS_OK
);
1441 CHECK_ACCESS_FLAGS(io
.out
.file
.handle
,
1442 SEC_STD_READ_CONTROL
);
1443 smb2_util_close(tree
, io
.out
.file
.handle
);
1445 torture_comment(tctx
, "try open for write => access_denied\n");
1446 io
.in
.desired_access
= SEC_FILE_WRITE_DATA
;
1447 status
= smb2_create(tree
, tctx
, &io
);
1448 if (torture_setting_bool(tctx
, "hide_on_access_denied", false)) {
1449 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
1451 CHECK_STATUS(status
, NT_STATUS_ACCESS_DENIED
);
1454 torture_comment(tctx
, "try open for read => access_denied\n");
1455 io
.in
.desired_access
= SEC_FILE_READ_DATA
;
1456 status
= smb2_create(tree
, tctx
, &io
);
1457 if (torture_setting_bool(tctx
, "hide_on_access_denied", false)) {
1458 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
1460 CHECK_STATUS(status
, NT_STATUS_ACCESS_DENIED
);
1463 torture_comment(tctx
, "try open for generic write => access_denied\n");
1464 io
.in
.desired_access
= SEC_GENERIC_WRITE
;
1465 status
= smb2_create(tree
, tctx
, &io
);
1466 if (torture_setting_bool(tctx
, "hide_on_access_denied", false)) {
1467 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
1469 CHECK_STATUS(status
, NT_STATUS_ACCESS_DENIED
);
1472 torture_comment(tctx
, "try open for generic read => access_denied\n");
1473 io
.in
.desired_access
= SEC_GENERIC_READ
;
1474 status
= smb2_create(tree
, tctx
, &io
);
1475 if (torture_setting_bool(tctx
, "hide_on_access_denied", false)) {
1476 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
1478 CHECK_STATUS(status
, NT_STATUS_ACCESS_DENIED
);
1481 torture_comment(tctx
, "set empty sd\n");
1482 sd
->type
&= ~SEC_DESC_DACL_PRESENT
;
1485 s
.set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
1486 s
.set_secdesc
.in
.file
.handle
= handle
;
1487 s
.set_secdesc
.in
.secinfo_flags
= SECINFO_DACL
;
1488 s
.set_secdesc
.in
.sd
= sd
;
1489 status
= smb2_setinfo_file(tree
, &s
);
1490 CHECK_STATUS(status
, NT_STATUS_OK
);
1492 torture_comment(tctx
, "get the sd\n");
1493 q
.query_secdesc
.level
= RAW_FILEINFO_SEC_DESC
;
1494 q
.query_secdesc
.in
.file
.handle
= handle
;
1495 q
.query_secdesc
.in
.secinfo_flags
=
1499 status
= smb2_getinfo_file(tree
, tctx
, &q
);
1500 CHECK_STATUS(status
, NT_STATUS_OK
);
1502 /* Testing the modified DACL */
1503 if (!(q
.query_secdesc
.out
.sd
->type
& SEC_DESC_DACL_PRESENT
)) {
1505 torture_fail_goto(tctx
, done
, "DACL_PRESENT flag not set by the server!\n");
1507 if (q
.query_secdesc
.out
.sd
->dacl
!= NULL
) {
1509 torture_fail_goto(tctx
, done
, "DACL has been created on the server!\n");
1512 smb2_util_close(tree
, handle
);
1513 smb2_util_unlink(tree
, fname
);
1515 smb2_logoff(tree
->session
);
1520 test SMB2 mkdir with OPEN_IF on the same name twice.
1521 Must use 2 connections to hit the race.
1524 static bool test_mkdir_dup(struct torture_context
*tctx
,
1525 struct smb2_tree
*tree
)
1527 const char *fname
= "mkdir_dup";
1531 struct smb2_tree
**trees
;
1532 struct smb2_request
**requests
;
1533 union smb_open
*ios
;
1534 int i
, num_files
= 2;
1536 int num_created
= 0;
1537 int num_existed
= 0;
1539 torture_comment(tctx
,
1540 "Testing SMB2 Create Directory with multiple connections\n");
1541 trees
= talloc_array(tctx
, struct smb2_tree
*, num_files
);
1542 requests
= talloc_array(tctx
, struct smb2_request
*, num_files
);
1543 ios
= talloc_array(tctx
, union smb_open
, num_files
);
1544 if ((tctx
->ev
== NULL
) || (trees
== NULL
) || (requests
== NULL
) ||
1546 torture_fail(tctx
, ("talloc failed\n"));
1551 tree
->session
->transport
->options
.request_timeout
= 60;
1553 for (i
=0; i
<num_files
; i
++) {
1554 if (!torture_smb2_connection(tctx
, &(trees
[i
]))) {
1556 talloc_asprintf(tctx
,
1557 "Could not open %d'th connection\n", i
));
1561 trees
[i
]->session
->transport
->options
.request_timeout
= 60;
1565 smb2_util_unlink(tree
, fname
);
1566 smb2_util_rmdir(tree
, fname
);
1569 base ntcreatex parms
1571 ZERO_STRUCT(io
.smb2
);
1572 io
.generic
.level
= RAW_OPEN_SMB2
;
1573 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1574 io
.smb2
.in
.alloc_size
= 0;
1575 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1576 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1577 NTCREATEX_SHARE_ACCESS_WRITE
|
1578 NTCREATEX_SHARE_ACCESS_DELETE
;
1579 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1580 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1581 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1582 io
.smb2
.in
.security_flags
= 0;
1583 io
.smb2
.in
.fname
= fname
;
1584 io
.smb2
.in
.create_flags
= 0;
1586 for (i
=0; i
<num_files
; i
++) {
1588 requests
[i
] = smb2_create_send(trees
[i
], &(ios
[i
].smb2
));
1589 if (requests
[i
] == NULL
) {
1591 talloc_asprintf(tctx
,
1592 "could not send %d'th request\n", i
));
1598 torture_comment(tctx
, "waiting for replies\n");
1600 bool unreplied
= false;
1601 for (i
=0; i
<num_files
; i
++) {
1602 if (requests
[i
] == NULL
) {
1605 if (requests
[i
]->state
< SMB2_REQUEST_DONE
) {
1609 status
= smb2_create_recv(requests
[i
], tctx
,
1612 if (NT_STATUS_IS_OK(status
)) {
1615 if (ios
[i
].smb2
.out
.create_action
==
1616 NTCREATEX_ACTION_CREATED
) {
1619 if (ios
[i
].smb2
.out
.create_action
==
1620 NTCREATEX_ACTION_EXISTED
) {
1625 talloc_asprintf(tctx
,
1626 "File %d returned status %s\n", i
,
1627 nt_errstr(status
)));
1637 if (tevent_loop_once(tctx
->ev
) != 0) {
1638 torture_fail(tctx
, "tevent_loop_once failed\n");
1646 talloc_asprintf(tctx
,
1647 "num_ok == %d\n", num_ok
));
1650 if (num_created
!= 1) {
1652 talloc_asprintf(tctx
,
1653 "num_created == %d\n", num_created
));
1656 if (num_existed
!= 1) {
1658 talloc_asprintf(tctx
,
1659 "num_existed == %d\n", num_existed
));
1663 smb2_deltree(tree
, fname
);
1669 test SMB2 mkdir with OPEN_IF on the same name twice.
1670 Must use 2 connections to hit the race.
1673 struct test_mkdir_visible_open
;
1675 struct test_mkdir_visible_state
{
1676 struct torture_context
*tctx
;
1677 size_t loops_running
;
1681 struct test_mkdir_visible_open
{
1682 struct test_mkdir_visible_state
*state
;
1683 struct smb2_tree
*tree
;
1685 struct smbXcli_conn
*conn
;
1686 uint32_t timeout_msec
;
1687 struct smbXcli_session
*session
;
1688 struct smbXcli_tcon
*tcon
;
1689 const char *filename
;
1690 uint8_t oplock_level
;
1691 uint32_t impersonation_level
;
1692 uint32_t desired_access
;
1693 uint32_t file_attributes
;
1694 uint32_t share_access
;
1695 uint32_t create_disposition
;
1696 uint32_t create_options
;
1697 struct tevent_req
*subreq
;
1699 uint64_t fid_persistent
;
1700 uint64_t fid_volatile
;
1701 struct smb_create_returns cr
;
1705 static void test_mkdir_visible_open_retry(struct tevent_req
*subreq
)
1707 struct test_mkdir_visible_open
*op
=
1708 tevent_req_callback_data(subreq
,
1709 struct test_mkdir_visible_open
);
1710 struct test_mkdir_visible_state
*state
= op
->state
;
1711 struct torture_context
*tctx
= state
->tctx
;
1717 torture_assert_goto(tctx
, op
->subreq
== subreq
,
1718 state
->ok
, done
, "subreq");
1721 op
->status
= smb2cli_create_recv(subreq
,
1722 &op
->fid_persistent
,
1728 TALLOC_FREE(subreq
);
1729 torture_comment(tctx
, "%s:%s: try[%"PRIu64
"] %s\n",
1730 __func__
, op
->filename
, op
->try,
1731 nt_errstr(op
->status
));
1732 if (NT_STATUS_EQUAL(op
->status
, NT_STATUS_ACCESS_DENIED
)) {
1735 torture_assert_ntstatus_equal_goto(tctx
,
1736 op
->status
, NT_STATUS_OBJECT_PATH_NOT_FOUND
,
1737 state
->ok
, done
, "smb2cli_create_recv");
1740 torture_comment(tctx
, "%s:%s: try[%"PRIu64
"] starting\n",
1741 __func__
, op
->filename
, op
->try);
1742 subreq
= smb2cli_create_send(op
,
1750 op
->impersonation_level
,
1752 op
->file_attributes
,
1754 op
->create_disposition
,
1757 torture_assert_not_null_goto(tctx
, subreq
,
1759 "smb2cli_create_send");
1760 tevent_req_set_callback(subreq
,
1761 test_mkdir_visible_open_retry
,
1763 op
->subreq
= subreq
;
1768 state
->loops_running
-= 1;
1771 static void test_mkdir_visible_open_done(struct tevent_req
*subreq
)
1773 struct test_mkdir_visible_open
*op
=
1774 tevent_req_callback_data(subreq
,
1775 struct test_mkdir_visible_open
);
1776 struct test_mkdir_visible_state
*state
= op
->state
;
1777 struct torture_context
*tctx
= state
->tctx
;
1783 torture_assert_goto(tctx
, op
->subreq
== subreq
,
1784 state
->ok
, done
, "subreq");
1787 op
->status
= smb2cli_create_recv(subreq
,
1788 &op
->fid_persistent
,
1794 TALLOC_FREE(subreq
);
1795 torture_comment(tctx
, "%s:%s: %s\n",
1796 __func__
, op
->filename
,
1797 nt_errstr(op
->status
));
1798 torture_assert_ntstatus_ok_goto(tctx
, op
->status
,
1799 state
->ok
, done
, "smb2cli_create_recv");
1805 static bool test_mkdir_visible(struct torture_context
*tctx
,
1806 struct smb2_tree
*tree
)
1808 struct test_mkdir_visible_state
*state
= NULL
;
1809 struct test_mkdir_visible_open templ
= {
1812 struct test_mkdir_visible_open
*dop
= NULL
;
1813 size_t num_loops
= 50;
1814 struct test_mkdir_visible_open
**loops
= NULL
;
1815 const char *base_dname
= "mkdir_visible";
1816 const char *file_ok
= NULL
;
1817 const char *file_fail
= NULL
;
1818 struct smb2_handle bdh
= {{}};
1819 struct smb2_handle h
= {{}};
1820 union smb_fileinfo q
= {};
1821 union smb_setfileinfo setinfo
= {};
1822 struct security_descriptor
*sd
= NULL
;
1823 struct security_ace
*ace
= NULL
;
1828 smb2_keepalive(tree
->session
->transport
);
1829 smb2_deltree(tree
, base_dname
);
1830 smb2_keepalive(tree
->session
->transport
);
1832 torture_comment(tctx
,
1833 "Testing SMB2 Create Directory is visible with multiple connections\n");
1835 state
= talloc_zero(tctx
, struct test_mkdir_visible_state
);
1836 torture_assert_not_null_goto(tctx
, state
, ret
, done
, "talloc_zero");
1841 * We create a base directory that has an inheritiable
1842 * ACE to deny SEC_DIR_ADD_FILE.
1845 status
= torture_smb2_testdir(tree
, base_dname
, &bdh
);
1846 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1847 "torture_smb2_testdir");
1849 file_ok
= talloc_asprintf(state
, "%s\\file_ok", base_dname
);
1850 torture_assert_not_null_goto(tctx
, file_ok
, ret
, done
,
1852 file_fail
= talloc_asprintf(state
, "%s\\file_fail", base_dname
);
1853 torture_assert_not_null_goto(tctx
, file_fail
, ret
, done
,
1856 status
= torture_smb2_testfile(tree
, file_ok
, &h
);
1857 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1858 "torture_smb2_testfile(file_ok)");
1859 status
= smb2_util_close(tree
, h
);
1860 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1861 "smb2_util_close(file_ok)");
1863 q
.query_secdesc
.level
= RAW_FILEINFO_SEC_DESC
;
1864 q
.query_secdesc
.in
.file
.handle
= bdh
;
1865 q
.query_secdesc
.in
.secinfo_flags
= SECINFO_DACL
;
1866 status
= smb2_getinfo_file(tree
, state
, &q
);
1867 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1868 "RAW_FILEINFO_SEC_DESC");
1869 sd
= q
.query_secdesc
.out
.sd
;
1870 torture_assert_not_null_goto(tctx
, sd
, ret
, done
,
1871 "q.query_secdesc.out.sd");
1872 torture_assert_not_null_goto(tctx
, sd
->dacl
, ret
, done
,
1873 "q.query_secdesc.out.sd->dacl");
1875 sd
= security_descriptor_copy(state
, sd
);
1876 torture_assert_not_null_goto(tctx
, sd
, ret
, done
,
1877 "security_descriptor_copy");
1878 ace
= security_ace_create(sd
,
1880 SEC_ACE_TYPE_ACCESS_DENIED
,
1882 SEC_ACE_FLAG_CONTAINER_INHERIT
);
1883 torture_assert_not_null_goto(tctx
, ace
, ret
, done
,
1884 "security_ace_create");
1885 status
= security_descriptor_dacl_insert(sd
, ace
, 0);
1886 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1887 "security_descriptor_dacl_insert");
1889 setinfo
.set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
1890 setinfo
.set_secdesc
.in
.file
.handle
= bdh
;
1891 setinfo
.set_secdesc
.in
.secinfo_flags
= SECINFO_DACL
;
1892 setinfo
.set_secdesc
.in
.sd
= sd
;
1893 status
= smb2_setinfo_file(tree
, &setinfo
);
1894 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1895 "RAW_SFILEINFO_SEC_DESC");
1898 * Make sure the new deny ACE works
1900 status
= torture_smb2_testfile(tree
, file_fail
, &h
);
1901 torture_assert_ntstatus_equal_goto(tctx
, status
,
1902 NT_STATUS_ACCESS_DENIED
,
1904 "torture_smb2_testfile(file_ok)");
1906 status
= smb2_util_close(tree
, bdh
);
1907 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1908 "smb2_util_close(base_dname)");
1910 templ
.state
= state
;
1911 templ
.timeout_msec
= 30000;
1912 templ
.oplock_level
= SMB2_OPLOCK_LEVEL_NONE
;
1913 templ
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1914 templ
.desired_access
= SEC_FILE_READ_ATTRIBUTE
;
1915 templ
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1916 templ
.share_access
= FILE_SHARE_READ
|
1919 templ
.create_disposition
= FILE_CREATE
;
1920 templ
.create_options
= FILE_NON_DIRECTORY_FILE
;
1921 templ
.status
= NT_STATUS_REQUEST_OUT_OF_SEQUENCE
;
1923 dop
= talloc_zero(state
, struct test_mkdir_visible_open
);
1924 torture_assert_not_null_goto(tctx
, dop
, ret
, done
, "talloc_zero");
1926 dop
->filename
= talloc_asprintf(dop
, "%s\\visible_dir", base_dname
);
1927 torture_assert_not_null_goto(tctx
, dop
->filename
, ret
, done
,
1929 dop
->desired_access
|= SEC_STD_READ_CONTROL
;
1930 dop
->file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
1931 dop
->create_options
= FILE_DIRECTORY_FILE
;
1933 dop
->conn
= tree
->session
->transport
->conn
;
1934 dop
->session
= tree
->session
->smbXcli
;
1935 dop
->tcon
= tree
->smbXcli
;
1937 loops
= talloc_zero_array(state
,
1938 struct test_mkdir_visible_open
*,
1940 torture_assert_not_null_goto(tctx
, loops
, ret
, done
,
1941 "talloc_zero_array");
1943 for (i
= 0; i
< num_loops
; i
++) {
1944 struct test_mkdir_visible_open
*op
= NULL
;
1946 op
= talloc_zero(loops
, struct test_mkdir_visible_open
);
1947 torture_assert_not_null_goto(tctx
, op
, ret
, done
, "talloc_zero");
1950 op
->filename
= talloc_asprintf(op
, "%s\\visible_dir\\file_%zu",
1952 torture_assert_not_null_goto(tctx
, op
->filename
, ret
, done
,
1955 ret
= torture_smb2_connection(tctx
, &op
->tree
);
1956 torture_assert_goto(tctx
, ret
, ret
, done
,
1957 "torture_smb2_connection");
1959 op
->conn
= op
->tree
->session
->transport
->conn
;
1960 op
->session
= op
->tree
->session
->smbXcli
;
1961 op
->tcon
= op
->tree
->smbXcli
;
1966 for (i
= 0; i
< num_loops
; i
++) {
1967 struct test_mkdir_visible_open
*op
= loops
[i
];
1970 torture_comment(tctx
, "%s:%s: try[%"PRIu64
"] starting\n",
1971 __func__
, op
->filename
, op
->try);
1972 op
->subreq
= smb2cli_create_send(op
,
1980 op
->impersonation_level
,
1982 op
->file_attributes
,
1984 op
->create_disposition
,
1987 torture_assert_not_null_goto(tctx
, op
->subreq
,
1989 "smb2cli_create_send");
1990 tevent_req_set_callback(op
->subreq
,
1991 test_mkdir_visible_open_retry
,
1993 state
->loops_running
+= 1;
1996 torture_comment(tctx
, "%s:%s: starting\n",
1997 __func__
, dop
->filename
);
1998 dop
->subreq
= smb2cli_create_send(dop
,
2006 dop
->impersonation_level
,
2007 dop
->desired_access
,
2008 dop
->file_attributes
,
2010 dop
->create_disposition
,
2011 dop
->create_options
,
2013 torture_assert_not_null_goto(tctx
, dop
->subreq
,
2015 "smb2cli_create_send");
2016 tevent_req_set_callback(dop
->subreq
,
2017 test_mkdir_visible_open_done
,
2020 ret
= tevent_req_poll(dop
->subreq
, tctx
->ev
);
2021 torture_assert_goto(tctx
, ret
, ret
, done
, "tevent_req_poll(dop)");
2022 torture_assert_goto(tctx
, dop
->done
, ret
, done
, "dop->done after dop");
2024 torture_assert_goto(tctx
, state
->ok
, ret
, done
, "state->ok after dop");
2026 while (state
->ok
&& state
->loops_running
> 0) {
2027 int lret
= tevent_loop_once(tctx
->ev
);
2028 torture_assert_int_equal_goto(tctx
, lret
, 0,
2030 "tevent_loop_once()");
2033 torture_assert_goto(tctx
, state
->ok
, ret
, done
, "state->ok after loop");
2034 torture_assert_int_equal_goto(tctx
, state
->loops_running
, 0,
2036 "state->loops_running after loop");
2038 for (i
= 0; i
< num_loops
; i
++) {
2039 struct test_mkdir_visible_open
*op
= loops
[i
];
2041 torture_assert_goto(tctx
, op
->done
, ret
, done
,
2042 "op->done after loop");
2044 torture_comment(tctx
, "%s:%s: try[%"PRIu64
"] checking...\n",
2045 __func__
, op
->filename
, op
->try);
2047 torture_assert_ntstatus_equal_goto(tctx
,
2048 op
->status
, NT_STATUS_ACCESS_DENIED
,
2049 ret
, done
, "smb2cli_create_recv");
2054 smb2_keepalive(tree
->session
->transport
);
2055 smb2_deltree(tree
, base_dname
);
2056 smb2_keepalive(tree
->session
->transport
);
2062 test directory creation with an initial allocation size > 0
2064 static bool test_dir_alloc_size(struct torture_context
*tctx
,
2065 struct smb2_tree
*tree
)
2068 const char *dname
= DNAME
"\\torture_alloc_size.dir";
2070 struct smb2_create c
;
2071 struct smb2_handle h1
= {{0}}, h2
;
2073 torture_comment(tctx
, "Checking initial allocation size on directories\n");
2075 smb2_deltree(tree
, dname
);
2077 status
= torture_smb2_testdir(tree
, DNAME
, &h1
);
2078 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "torture_smb2_testdir failed");
2081 c
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2082 c
.in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
;
2083 c
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
2084 c
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
2085 c
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2088 * An insanely large value so we can check the value is
2089 * ignored: Samba either returns 0 (current behaviour), or,
2090 * once vfswrap_get_alloc_size() is fixed to allow retrieving
2091 * the allocated size for directories, returns
2092 * smb_roundup(..., stat.st_size) which would be 1 MB by
2095 * Windows returns 0 for empty directories, once directories
2096 * have a few entries it starts replying with values > 0.
2098 c
.in
.alloc_size
= 1024*1024*1024;
2100 status
= smb2_create(tree
, tctx
, &c
);
2101 h2
= c
.out
.file
.handle
;
2102 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2103 "dir create with initial alloc size failed");
2105 smb2_util_close(tree
, h2
);
2107 torture_comment(tctx
, "Got directory alloc size: %ju\n", (uintmax_t)c
.out
.alloc_size
);
2110 * See above for the rational for this test
2112 if (c
.out
.alloc_size
> 1024*1024) {
2113 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "bad alloc size: %ju",
2114 (uintmax_t)c
.out
.alloc_size
));
2118 if (!smb2_util_handle_empty(h1
)) {
2119 smb2_util_close(tree
, h1
);
2121 smb2_deltree(tree
, DNAME
);
2125 static bool test_twrp_write(struct torture_context
*tctx
, struct smb2_tree
*tree
)
2127 struct smb2_create io
;
2128 struct smb2_handle h1
= {{0}};
2135 const char *file
= NULL
;
2136 const char *snapshot
= NULL
;
2137 uint32_t expected_access
;
2138 union smb_fileinfo getinfo
;
2139 union smb_setfileinfo setinfo
;
2140 struct security_descriptor
*sd
= NULL
, *sd_orig
= NULL
;
2141 const char *owner_sid
= NULL
;
2142 struct create_disps_tests
{
2144 uint32_t create_disposition
;
2145 uint32_t create_options
;
2146 NTSTATUS expected_status
;
2148 struct create_disps_tests
*cd_test
= NULL
;
2150 file
= torture_setting_string(tctx
, "twrp_file", NULL
);
2152 torture_skip(tctx
, "missing 'twrp_file' option\n");
2155 snapshot
= torture_setting_string(tctx
, "twrp_snapshot", NULL
);
2156 if (snapshot
== NULL
) {
2157 torture_skip(tctx
, "missing 'twrp_snapshot' option\n");
2160 torture_comment(tctx
, "Testing timewarp (%s) (%s)\n", file
, snapshot
);
2162 setenv("TZ", "GMT", 1);
2164 /* strptime does not set tm.tm_isdst but mktime assumes DST is in
2165 * effect if it is greater than 1. */
2168 p
= strptime(snapshot
, "@GMT-%Y.%m.%d-%H.%M.%S", &tm
);
2169 torture_assert_goto(tctx
, p
!= NULL
, ret
, done
, "strptime\n");
2170 torture_assert_goto(tctx
, *p
== '\0', ret
, done
, "strptime\n");
2173 unix_to_nt_time(&nttime
, t
);
2175 io
= (struct smb2_create
) {
2176 .in
.desired_access
= SEC_FILE_READ_DATA
,
2177 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
2178 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
2179 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
2181 .in
.query_maximal_access
= true,
2182 .in
.timewarp
= nttime
,
2185 status
= smb2_create(tree
, tctx
, &io
);
2186 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2188 smb2_util_close(tree
, io
.out
.file
.handle
);
2190 expected_access
= SEC_RIGHTS_FILE_ALL
&
2191 ~(SEC_FILE_EXECUTE
| SEC_DIR_DELETE_CHILD
);
2193 torture_assert_int_equal_goto(tctx
,
2194 io
.out
.maximal_access
& expected_access
,
2196 ret
, done
, "Bad access\n");
2200 * Test create dispositions
2202 struct create_disps_tests cd_tests
[] = {
2205 .create_disposition
= NTCREATEX_DISP_OPEN
,
2206 .expected_status
= NT_STATUS_OK
,
2210 .create_disposition
= NTCREATEX_DISP_OPEN_IF
,
2211 .expected_status
= NT_STATUS_OK
,
2215 .create_disposition
= NTCREATEX_DISP_OVERWRITE
,
2216 .expected_status
= NT_STATUS_MEDIA_WRITE_PROTECTED
,
2220 .create_disposition
= NTCREATEX_DISP_OVERWRITE_IF
,
2221 .expected_status
= NT_STATUS_MEDIA_WRITE_PROTECTED
,
2225 .create_disposition
= NTCREATEX_DISP_SUPERSEDE
,
2226 .expected_status
= NT_STATUS_MEDIA_WRITE_PROTECTED
,
2230 .create_disposition
= NTCREATEX_DISP_OPEN_IF
,
2231 .expected_status
= NT_STATUS_MEDIA_WRITE_PROTECTED
,
2235 .create_disposition
= NTCREATEX_DISP_OVERWRITE_IF
,
2236 .expected_status
= NT_STATUS_MEDIA_WRITE_PROTECTED
,
2240 .create_disposition
= NTCREATEX_DISP_CREATE
,
2241 .expected_status
= NT_STATUS_MEDIA_WRITE_PROTECTED
,
2245 .create_disposition
= NTCREATEX_DISP_SUPERSEDE
,
2246 .expected_status
= NT_STATUS_MEDIA_WRITE_PROTECTED
,
2250 .create_disposition
= NTCREATEX_DISP_OPEN_IF
,
2251 .create_options
= NTCREATEX_OPTIONS_DIRECTORY
,
2252 .expected_status
= NT_STATUS_MEDIA_WRITE_PROTECTED
,
2256 .create_disposition
= NTCREATEX_DISP_CREATE
,
2257 .create_options
= NTCREATEX_OPTIONS_DIRECTORY
,
2258 .expected_status
= NT_STATUS_MEDIA_WRITE_PROTECTED
,
2265 for (cd_test
= &cd_tests
[0]; cd_test
->file
!= NULL
; cd_test
++) {
2266 io
= (struct smb2_create
) {
2267 .in
.fname
= cd_test
->file
,
2268 .in
.create_disposition
= cd_test
->create_disposition
,
2269 .in
.create_options
= cd_test
->create_options
,
2271 .in
.desired_access
= SEC_FILE_READ_DATA
,
2272 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
2273 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
2274 .in
.timewarp
= nttime
,
2277 status
= smb2_create(tree
, tctx
, &io
);
2278 torture_assert_ntstatus_equal_goto(
2279 tctx
, status
, cd_test
->expected_status
, ret
, done
,
2284 io
= (struct smb2_create
) {
2285 .in
.desired_access
= expected_access
,
2286 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
2287 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
2288 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
2290 .in
.timewarp
= nttime
,
2293 status
= smb2_create(tree
, tctx
, &io
);
2294 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2296 h1
= io
.out
.file
.handle
;
2298 status
= smb2_util_write(tree
, h1
, "123", 0, 3);
2299 torture_assert_ntstatus_equal_goto(tctx
, status
,
2300 NT_STATUS_MEDIA_WRITE_PROTECTED
,
2301 ret
, done
, "smb2_create\n");
2304 * Verify access mask
2307 ZERO_STRUCT(getinfo
);
2308 getinfo
.generic
.level
= RAW_FILEINFO_ACCESS_INFORMATION
;
2309 getinfo
.generic
.in
.file
.handle
= h1
;
2311 status
= smb2_getinfo_file(tree
, tree
, &getinfo
);
2312 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2313 "smb2_getinfo_file\n");
2315 torture_assert_int_equal_goto(
2317 getinfo
.access_information
.out
.access_flags
,
2320 "Bad access mask\n");
2323 * Check we can't set various things
2326 ZERO_STRUCT(getinfo
);
2327 getinfo
.query_secdesc
.level
= RAW_FILEINFO_SEC_DESC
;
2328 getinfo
.query_secdesc
.in
.file
.handle
= h1
;
2329 getinfo
.query_secdesc
.in
.secinfo_flags
= SECINFO_DACL
| SECINFO_OWNER
;
2331 status
= smb2_getinfo_file(tree
, tctx
, &getinfo
);
2332 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2333 "smb2_getinfo_file\n");
2335 sd_orig
= getinfo
.query_secdesc
.out
.sd
;
2336 owner_sid
= dom_sid_string(tctx
, sd_orig
->owner_sid
);
2338 sd
= security_descriptor_dacl_create(tctx
,
2341 SEC_ACE_TYPE_ACCESS_ALLOWED
,
2342 SEC_FILE_WRITE_DATA
,
2346 /* Try to set ACL */
2348 ZERO_STRUCT(setinfo
);
2349 setinfo
.set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
2350 setinfo
.set_secdesc
.in
.file
.handle
= h1
;
2351 setinfo
.set_secdesc
.in
.secinfo_flags
= SECINFO_DACL
;
2352 setinfo
.set_secdesc
.in
.sd
= sd
;
2354 status
= smb2_setinfo_file(tree
, &setinfo
);
2355 torture_assert_ntstatus_equal_goto(
2358 NT_STATUS_MEDIA_WRITE_PROTECTED
,
2360 "smb2_setinfo_file\n");
2364 ZERO_STRUCT(setinfo
);
2365 setinfo
.generic
.level
= RAW_SFILEINFO_DISPOSITION_INFORMATION
;
2366 setinfo
.disposition_info
.in
.delete_on_close
= 1;
2367 setinfo
.generic
.in
.file
.handle
= h1
;
2369 status
= smb2_setinfo_file(tree
, &setinfo
);
2370 torture_assert_ntstatus_equal_goto(
2373 NT_STATUS_MEDIA_WRITE_PROTECTED
,
2375 "smb2_setinfo_file\n");
2377 ZERO_STRUCT(setinfo
);
2378 setinfo
.basic_info
.in
.attrib
= FILE_ATTRIBUTE_HIDDEN
;
2379 setinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
2380 setinfo
.generic
.in
.file
.handle
= h1
;
2382 status
= smb2_setinfo_file(tree
, &setinfo
);
2383 torture_assert_ntstatus_equal_goto(
2386 NT_STATUS_MEDIA_WRITE_PROTECTED
,
2388 "smb2_setinfo_file\n");
2390 /* Try to truncate */
2392 ZERO_STRUCT(setinfo
);
2393 setinfo
.generic
.level
= SMB_SFILEINFO_END_OF_FILE_INFORMATION
;
2394 setinfo
.generic
.in
.file
.handle
= h1
;
2395 setinfo
.end_of_file_info
.in
.size
= 0x100000;
2397 status
= smb2_setinfo_file(tree
, &setinfo
);
2398 torture_assert_ntstatus_equal_goto(
2401 NT_STATUS_MEDIA_WRITE_PROTECTED
,
2403 "smb2_setinfo_file\n");
2405 /* Try to set a hardlink */
2407 ZERO_STRUCT(setinfo
);
2408 setinfo
.generic
.level
= RAW_SFILEINFO_LINK_INFORMATION
;
2409 setinfo
.generic
.in
.file
.handle
= h1
;
2410 setinfo
.link_information
.in
.new_name
= "hardlink";
2412 status
= smb2_setinfo_file(tree
, &setinfo
);
2413 torture_assert_ntstatus_equal_goto(
2416 NT_STATUS_NOT_SAME_DEVICE
,
2418 "smb2_setinfo_file\n");
2422 ZERO_STRUCT(setinfo
);
2423 setinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
2424 setinfo
.rename_information
.in
.file
.handle
= h1
;
2425 setinfo
.rename_information
.in
.new_name
= "renamed";
2427 status
= smb2_setinfo_file(tree
, &setinfo
);
2428 torture_assert_ntstatus_equal_goto(
2431 NT_STATUS_NOT_SAME_DEVICE
,
2433 "smb2_setinfo_file\n");
2435 smb2_util_close(tree
, h1
);
2439 if (!smb2_util_handle_empty(h1
)) {
2440 smb2_util_close(tree
, h1
);
2445 static bool test_twrp_stream(struct torture_context
*tctx
,
2446 struct smb2_tree
*tree
)
2448 struct smb2_create io
;
2455 const char *file
= NULL
;
2456 const char *stream
= NULL
;
2457 const char *snapshot
= NULL
;
2460 uint8_t *buf
= NULL
;
2461 struct smb2_handle h1
= {{0}};
2464 file
= torture_setting_string(tctx
, "twrp_file", NULL
);
2466 torture_skip(tctx
, "missing 'twrp_file' option\n");
2469 stream
= torture_setting_string(tctx
, "twrp_stream", NULL
);
2470 if (stream
== NULL
) {
2471 torture_skip(tctx
, "missing 'twrp_stream' option\n");
2474 snapshot
= torture_setting_string(tctx
, "twrp_snapshot", NULL
);
2475 if (snapshot
== NULL
) {
2476 torture_skip(tctx
, "missing 'twrp_snapshot' option\n");
2479 stream_size
= torture_setting_int(tctx
, "twrp_stream_size", 0);
2480 if (stream_size
== 0) {
2481 torture_skip(tctx
, "missing 'twrp_stream_size' option\n");
2484 torture_comment(tctx
, "Testing timewarp on stream (%s) (%s)\n",
2487 path
= talloc_asprintf(tree
, "%s:%s", file
, stream
);
2488 torture_assert_not_null_goto(tctx
, path
, ret
, done
, "path\n");
2490 buf
= talloc_zero_array(tree
, uint8_t, stream_size
);
2491 torture_assert_not_null_goto(tctx
, buf
, ret
, done
, "buf\n");
2493 setenv("TZ", "GMT", 1);
2495 /* strptime does not set tm.tm_isdst but mktime assumes DST is in
2496 * effect if it is greater than 1. */
2499 p
= strptime(snapshot
, "@GMT-%Y.%m.%d-%H.%M.%S", &tm
);
2500 torture_assert_goto(tctx
, p
!= NULL
, ret
, done
, "strptime\n");
2501 torture_assert_goto(tctx
, *p
== '\0', ret
, done
, "strptime\n");
2504 unix_to_nt_time(&nttime
, t
);
2506 io
= (struct smb2_create
) {
2507 .in
.desired_access
= SEC_FILE_READ_DATA
,
2508 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
2509 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
2510 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
2512 .in
.timewarp
= nttime
,
2515 status
= smb2_create(tree
, tctx
, &io
);
2516 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2518 h1
= io
.out
.file
.handle
;
2520 r
= (struct smb2_read
) {
2521 .in
.file
.handle
= h1
,
2522 .in
.length
= stream_size
,
2526 status
= smb2_read(tree
, tree
, &r
);
2527 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2530 smb2_util_close(tree
, h1
);
2536 static bool test_twrp_openroot(struct torture_context
*tctx
, struct smb2_tree
*tree
)
2538 struct smb2_create io
;
2545 const char *snapshot
= NULL
;
2547 snapshot
= torture_setting_string(tctx
, "twrp_snapshot", NULL
);
2548 if (snapshot
== NULL
) {
2549 torture_skip(tctx
, "missing 'twrp_snapshot' option\n");
2552 torture_comment(tctx
, "Testing open of root of "
2553 "share with timewarp (%s)\n",
2556 setenv("TZ", "GMT", 1);
2558 /* strptime does not set tm.tm_isdst but mktime assumes DST is in
2559 * effect if it is greater than 1. */
2562 p
= strptime(snapshot
, "@GMT-%Y.%m.%d-%H.%M.%S", &tm
);
2563 torture_assert_goto(tctx
, p
!= NULL
, ret
, done
, "strptime\n");
2564 torture_assert_goto(tctx
, *p
== '\0', ret
, done
, "strptime\n");
2567 unix_to_nt_time(&nttime
, t
);
2569 io
= (struct smb2_create
) {
2570 .in
.desired_access
= SEC_FILE_READ_DATA
,
2571 .in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
,
2572 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
2573 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
2575 .in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
,
2576 .in
.timewarp
= nttime
,
2579 status
= smb2_create(tree
, tctx
, &io
);
2580 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2582 smb2_util_close(tree
, io
.out
.file
.handle
);
2588 static bool test_twrp_listdir(struct torture_context
*tctx
,
2589 struct smb2_tree
*tree
)
2591 struct smb2_create create
;
2592 struct smb2_handle h
= {{0}};
2593 struct smb2_find find
;
2595 union smb_search_data
*d
;
2600 const char *snapshot
= NULL
;
2601 uint64_t normal_fileid
;
2602 uint64_t snapshot_fileid
;
2606 snapshot
= torture_setting_string(tctx
, "twrp_snapshot", NULL
);
2607 if (snapshot
== NULL
) {
2608 torture_fail(tctx
, "missing 'twrp_snapshot' option\n");
2611 torture_comment(tctx
, "Testing File-Ids of directory listing "
2612 "with timewarp (%s)\n",
2615 setenv("TZ", "GMT", 1);
2617 /* strptime does not set tm.tm_isdst but mktime assumes DST is in
2618 * effect if it is greater than 1. */
2621 p
= strptime(snapshot
, "@GMT-%Y.%m.%d-%H.%M.%S", &tm
);
2622 torture_assert_goto(tctx
, p
!= NULL
, ret
, done
, "strptime\n");
2623 torture_assert_goto(tctx
, *p
== '\0', ret
, done
, "strptime\n");
2626 unix_to_nt_time(&nttime
, t
);
2629 * 1: Query the file's File-Id
2631 create
= (struct smb2_create
) {
2632 .in
.desired_access
= SEC_FILE_READ_DATA
,
2633 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
2634 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
2635 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
2636 .in
.fname
= "subdir/hardlink",
2637 .in
.query_on_disk_id
= true,
2640 status
= smb2_create(tree
, tctx
, &create
);
2641 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2642 "test file could not be created\n");
2643 smb2_util_close(tree
, create
.out
.file
.handle
);
2644 normal_fileid
= BVAL(&create
.out
.on_disk_id
, 0);
2647 * 2: check directory listing of the file returns same File-Id
2650 create
= (struct smb2_create
) {
2651 .in
.desired_access
= SEC_DIR_LIST
,
2652 .in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
,
2653 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
2654 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
2655 .in
.fname
= "subdir",
2656 .in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
,
2659 status
= smb2_create(tree
, tctx
, &create
);
2660 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2662 h
= create
.out
.file
.handle
;
2664 find
= (struct smb2_find
) {
2665 .in
.file
.handle
= h
,
2667 .in
.max_response_size
= 0x1000,
2668 .in
.level
= SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
2671 status
= smb2_find_level(tree
, tree
, &find
, &count
, &d
);
2672 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2673 "smb2_find_level failed\n");
2675 smb2_util_close(tree
, h
);
2677 torture_assert_int_equal_goto(tctx
, count
, 3, ret
, done
, "Bad count\n");
2678 torture_assert_str_equal_goto(tctx
,
2679 d
[2].id_both_directory_info
.name
.s
,
2681 ret
, done
, "bad name");
2682 torture_assert_u64_equal_goto(tctx
,
2683 d
[2].id_both_directory_info
.file_id
,
2685 ret
, done
, "bad fileid\n");
2688 * 3: Query File-Id of snapshot of the file and check the File-Id is
2689 * different compared to the basefile
2692 create
= (struct smb2_create
) {
2693 .in
.desired_access
= SEC_FILE_READ_DATA
,
2694 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
2695 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
2696 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
2697 .in
.fname
= "subdir/hardlink",
2698 .in
.query_on_disk_id
= true,
2699 .in
.timewarp
= nttime
,
2702 status
= smb2_create(tree
, tctx
, &create
);
2703 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2704 "test file could not be created\n");
2705 smb2_util_close(tree
, create
.out
.file
.handle
);
2707 snapshot_fileid
= BVAL(&create
.out
.on_disk_id
, 0);
2710 * 4: List directory of the snapshot and check the File-Id returned here
2711 * is the same as in 3.
2714 create
= (struct smb2_create
) {
2715 .in
.desired_access
= SEC_DIR_LIST
,
2716 .in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
,
2717 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
2718 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
2719 .in
.fname
= "subdir",
2720 .in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
,
2721 .in
.timewarp
= nttime
,
2724 status
= smb2_create(tree
, tctx
, &create
);
2725 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2727 h
= create
.out
.file
.handle
;
2729 find
= (struct smb2_find
) {
2730 .in
.file
.handle
= h
,
2732 .in
.max_response_size
= 0x1000,
2733 .in
.level
= SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
2736 status
= smb2_find_level(tree
, tree
, &find
, &count
, &d
);
2737 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2738 "smb2_find_level failed\n");
2739 smb2_util_close(tree
, h
);
2741 torture_assert_int_equal_goto(tctx
, count
, 3, ret
, done
, "Bad count\n");
2742 torture_assert_str_equal_goto(tctx
,
2743 d
[2].id_both_directory_info
.name
.s
,
2745 ret
, done
, "bad name");
2746 torture_assert_u64_equal_goto(tctx
,
2748 d
[2].id_both_directory_info
.file_id
,
2749 ret
, done
, "bad fileid\n");
2755 static bool test_fileid(struct torture_context
*tctx
,
2756 struct smb2_tree
*tree
)
2758 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
2759 const char *fname
= DNAME
"\\foo";
2760 const char *sname
= DNAME
"\\foo:bar";
2761 struct smb2_handle testdirh
;
2762 struct smb2_handle h1
;
2763 struct smb2_create create
;
2764 union smb_fileinfo finfo
;
2765 union smb_setfileinfo sinfo
;
2768 union smb_search_data
*d
;
2769 uint64_t expected_fileid
;
2770 uint64_t returned_fileid
;
2774 smb2_deltree(tree
, DNAME
);
2776 status
= torture_smb2_testdir(tree
, DNAME
, &testdirh
);
2777 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2778 "torture_smb2_testdir failed\n");
2781 * Initial create with QFID
2783 create
= (struct smb2_create
) {
2784 .in
.desired_access
= SEC_FILE_ALL
,
2785 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
2786 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
2787 .in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
,
2789 .in
.query_on_disk_id
= true,
2792 status
= smb2_create(tree
, tctx
, &create
);
2793 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2794 "test file could not be created\n");
2795 h1
= create
.out
.file
.handle
;
2796 expected_fileid
= BVAL(&create
.out
.on_disk_id
, 0);
2799 * Getinfo the File-ID on the just opened handle
2801 finfo
= (union smb_fileinfo
) {
2802 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
2803 .generic
.in
.file
.handle
= h1
,
2806 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
2807 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2808 "torture_smb2_testdir\n");
2809 smb2_util_close(tree
, h1
);
2810 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
2812 ret
, done
, "bad fileid\n");
2815 * Open existing with QFID
2817 create
= (struct smb2_create
) {
2818 .in
.desired_access
= SEC_FILE_ALL
,
2819 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
2820 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
2821 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
2823 .in
.query_on_disk_id
= true,
2826 status
= smb2_create(tree
, tctx
, &create
);
2827 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2828 "test file could not be created\n");
2829 h1
= create
.out
.file
.handle
;
2830 returned_fileid
= BVAL(&create
.out
.on_disk_id
, 0);
2831 torture_assert_u64_equal_goto(tctx
, returned_fileid
, expected_fileid
,
2832 ret
, done
, "bad fileid\n");
2835 * Getinfo the File-ID on the just opened handle
2837 finfo
= (union smb_fileinfo
) {
2838 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
2839 .generic
.in
.file
.handle
= h1
,
2842 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
2843 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2844 "torture_smb2_testdir\n");
2845 smb2_util_close(tree
, h1
);
2846 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
2848 ret
, done
, "bad fileid\n");
2851 * Overwrite with QFID
2853 create
= (struct smb2_create
) {
2854 .in
.desired_access
= SEC_FILE_ALL
,
2855 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
2856 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
2857 .in
.create_disposition
= NTCREATEX_DISP_OVERWRITE
,
2859 .in
.query_on_disk_id
= true,
2862 status
= smb2_create(tree
, tctx
, &create
);
2863 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2864 "test file could not be created\n");
2865 h1
= create
.out
.file
.handle
;
2866 returned_fileid
= BVAL(&create
.out
.on_disk_id
, 0);
2867 torture_assert_u64_equal_goto(tctx
, returned_fileid
, expected_fileid
,
2868 ret
, done
, "bad fileid\n");
2871 * Getinfo the File-ID on the open with overwrite handle
2873 finfo
= (union smb_fileinfo
) {
2874 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
2875 .generic
.in
.file
.handle
= h1
,
2878 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
2879 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2880 "torture_smb2_testdir\n");
2881 smb2_util_close(tree
, h1
);
2882 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
2884 ret
, done
, "bad fileid\n");
2887 * Do some modifications on the basefile (IO, setinfo), verifying
2888 * File-ID after each step.
2890 create
= (struct smb2_create
) {
2891 .in
.desired_access
= SEC_FILE_ALL
,
2892 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
2893 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
2894 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
2896 .in
.query_on_disk_id
= true,
2899 status
= smb2_create(tree
, tctx
, &create
);
2900 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2901 "test file could not be created\n");
2902 h1
= create
.out
.file
.handle
;
2904 status
= smb2_util_write(tree
, h1
, "foo", 0, strlen("foo"));
2905 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2906 "smb2_util_write failed\n");
2908 finfo
= (union smb_fileinfo
) {
2909 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
2910 .generic
.in
.file
.handle
= h1
,
2912 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
2913 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2914 "smb2_getinfo_file failed\n");
2915 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
2917 ret
, done
, "bad fileid\n");
2919 sinfo
= (union smb_setfileinfo
) {
2920 .basic_info
.level
= RAW_SFILEINFO_BASIC_INFORMATION
,
2921 .basic_info
.in
.file
.handle
= h1
,
2923 unix_to_nt_time(&sinfo
.basic_info
.in
.write_time
, time(NULL
));
2925 status
= smb2_setinfo_file(tree
, &sinfo
);
2926 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2927 "smb2_setinfo_file failed\n");
2929 finfo
= (union smb_fileinfo
) {
2930 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
2931 .generic
.in
.file
.handle
= h1
,
2933 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
2934 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2935 "smb2_getinfo_file failed\n");
2936 smb2_util_close(tree
, h1
);
2937 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
2939 ret
, done
, "bad fileid\n");
2942 * Create stream, check the stream's File-ID, should be the same as the
2943 * base file (sic!, tested against Windows).
2945 create
= (struct smb2_create
) {
2946 .in
.desired_access
= SEC_FILE_ALL
,
2947 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
2948 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
2949 .in
.create_disposition
= NTCREATEX_DISP_CREATE
,
2951 .in
.query_on_disk_id
= true,
2954 status
= smb2_create(tree
, tctx
, &create
);
2955 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2956 "test file could not be created\n");
2957 h1
= create
.out
.file
.handle
;
2958 returned_fileid
= BVAL(&create
.out
.on_disk_id
, 0);
2959 torture_assert_u64_equal_goto(tctx
, returned_fileid
, expected_fileid
,
2960 ret
, done
, "bad fileid\n");
2963 * Getinfo the File-ID on the created stream
2965 finfo
= (union smb_fileinfo
) {
2966 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
2967 .generic
.in
.file
.handle
= h1
,
2970 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
2971 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2972 "smb2_getinfo_file failed\n");
2973 smb2_util_close(tree
, h1
);
2974 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
2976 ret
, done
, "bad fileid\n");
2979 * Open stream, check the stream's File-ID, should be the same as the
2980 * base file (sic!, tested against Windows).
2982 create
= (struct smb2_create
) {
2983 .in
.desired_access
= SEC_FILE_ALL
,
2984 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
2985 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
2986 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
2988 .in
.query_on_disk_id
= true,
2991 status
= smb2_create(tree
, tctx
, &create
);
2992 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2993 "test file could not be created\n");
2994 h1
= create
.out
.file
.handle
;
2995 returned_fileid
= BVAL(&create
.out
.on_disk_id
, 0);
2996 torture_assert_u64_equal_goto(tctx
, returned_fileid
, expected_fileid
,
2997 ret
, done
, "bad fileid\n");
3000 * Getinfo the File-ID on the opened stream
3002 finfo
= (union smb_fileinfo
) {
3003 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
3004 .generic
.in
.file
.handle
= h1
,
3007 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
3008 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3009 "smb2_getinfo_file failed\n");
3010 smb2_util_close(tree
, h1
);
3011 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
3013 ret
, done
, "bad fileid\n");
3016 * Overwrite stream, check the stream's File-ID, should be the same as
3017 * the base file (sic!, tested against Windows).
3019 create
= (struct smb2_create
) {
3020 .in
.desired_access
= SEC_FILE_ALL
,
3021 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
3022 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
3023 .in
.create_disposition
= NTCREATEX_DISP_OVERWRITE
,
3025 .in
.query_on_disk_id
= true,
3028 status
= smb2_create(tree
, tctx
, &create
);
3029 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3030 "test file could not be created\n");
3031 h1
= create
.out
.file
.handle
;
3032 returned_fileid
= BVAL(&create
.out
.on_disk_id
, 0);
3033 torture_assert_u64_equal_goto(tctx
, returned_fileid
, expected_fileid
,
3034 ret
, done
, "bad fileid\n");
3037 * Getinfo the File-ID on the overwritten stream
3039 finfo
= (union smb_fileinfo
) {
3040 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
3041 .generic
.in
.file
.handle
= h1
,
3044 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
3045 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3046 "smb2_getinfo_file failed\n");
3047 smb2_util_close(tree
, h1
);
3048 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
3050 ret
, done
, "bad fileid\n");
3053 * Do some modifications on the stream (IO, setinfo), verifying File-ID
3056 create
= (struct smb2_create
) {
3057 .in
.desired_access
= SEC_FILE_ALL
,
3058 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
3059 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
3060 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
3062 .in
.query_on_disk_id
= true,
3065 status
= smb2_create(tree
, tctx
, &create
);
3066 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3067 "test file could not be created\n");
3068 h1
= create
.out
.file
.handle
;
3070 status
= smb2_util_write(tree
, h1
, "foo", 0, strlen("foo"));
3071 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3072 "smb2_util_write failed\n");
3074 finfo
= (union smb_fileinfo
) {
3075 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
3076 .generic
.in
.file
.handle
= h1
,
3078 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
3079 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3080 "smb2_getinfo_file failed\n");
3081 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
3083 ret
, done
, "bad fileid\n");
3085 sinfo
= (union smb_setfileinfo
) {
3086 .basic_info
.level
= RAW_SFILEINFO_BASIC_INFORMATION
,
3087 .basic_info
.in
.file
.handle
= h1
,
3089 unix_to_nt_time(&sinfo
.basic_info
.in
.write_time
, time(NULL
));
3091 status
= smb2_setinfo_file(tree
, &sinfo
);
3092 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3093 "smb2_setinfo_file failed\n");
3095 finfo
= (union smb_fileinfo
) {
3096 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
3097 .generic
.in
.file
.handle
= h1
,
3099 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
3100 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3101 "smb2_getinfo_file failed\n");
3102 smb2_util_close(tree
, h1
);
3103 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
3105 ret
, done
, "bad fileid\n");
3108 * Final open of the basefile with QFID
3110 create
= (struct smb2_create
) {
3111 .in
.desired_access
= SEC_FILE_ALL
,
3112 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
3113 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
3114 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
3116 .in
.query_on_disk_id
= true,
3119 status
= smb2_create(tree
, tctx
, &create
);
3120 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3121 "test file could not be created\n");
3122 h1
= create
.out
.file
.handle
;
3123 returned_fileid
= BVAL(&create
.out
.on_disk_id
, 0);
3124 torture_assert_u64_equal_goto(tctx
, returned_fileid
, expected_fileid
,
3125 ret
, done
, "bad fileid\n");
3128 * Final Getinfo checking File-ID
3130 finfo
= (union smb_fileinfo
) {
3131 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
3132 .generic
.in
.file
.handle
= h1
,
3135 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
3136 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3137 "torture_smb2_testdir\n");
3138 smb2_util_close(tree
, h1
);
3139 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
3141 ret
, done
, "bad fileid\n");
3144 * Final list directory, verifying the operations on basefile and stream
3145 * didn't modify the base file metadata.
3147 f
= (struct smb2_find
) {
3148 .in
.file
.handle
= testdirh
,
3149 .in
.pattern
= "foo",
3150 .in
.max_response_size
= 0x1000,
3151 .in
.level
= SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
3152 .in
.continue_flags
= SMB2_CONTINUE_FLAG_RESTART
,
3155 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
3156 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3157 "smb2_find_level failed\n");
3158 torture_assert_u64_equal_goto(tctx
,
3159 d
->id_both_directory_info
.file_id
,
3161 ret
, done
, "bad fileid\n");
3164 smb2_util_close(tree
, testdirh
);
3165 smb2_deltree(tree
, DNAME
);
3166 talloc_free(mem_ctx
);
3170 static bool test_fileid_dir(struct torture_context
*tctx
,
3171 struct smb2_tree
*tree
)
3173 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
3174 const char *dname
= DNAME
"\\foo";
3175 const char *sname
= DNAME
"\\foo:bar";
3176 struct smb2_handle testdirh
;
3177 struct smb2_handle h1
;
3178 struct smb2_create create
;
3179 union smb_fileinfo finfo
;
3180 union smb_setfileinfo sinfo
;
3183 union smb_search_data
*d
;
3184 uint64_t expected_fileid
;
3185 uint64_t returned_fileid
;
3189 smb2_deltree(tree
, DNAME
);
3191 status
= torture_smb2_testdir(tree
, DNAME
, &testdirh
);
3192 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3193 "torture_smb2_testdir failed\n");
3196 * Initial directory create with QFID
3198 create
= (struct smb2_create
) {
3199 .in
.desired_access
= SEC_FILE_ALL
,
3200 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
3201 .in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
,
3202 .in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
,
3203 .in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
,
3205 .in
.query_on_disk_id
= true,
3208 status
= smb2_create(tree
, tctx
, &create
);
3209 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3210 "test file could not be created\n");
3211 h1
= create
.out
.file
.handle
;
3212 expected_fileid
= BVAL(&create
.out
.on_disk_id
, 0);
3215 * Getinfo the File-ID on the just opened handle
3217 finfo
= (union smb_fileinfo
) {
3218 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
3219 .generic
.in
.file
.handle
= h1
,
3222 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
3223 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3224 "torture_smb2_testdir\n");
3225 smb2_util_close(tree
, h1
);
3226 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
3228 ret
, done
, "bad fileid\n");
3231 * Open existing directory with QFID
3233 create
= (struct smb2_create
) {
3234 .in
.desired_access
= SEC_FILE_ALL
,
3235 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
3236 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
3237 .in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
,
3238 .in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
,
3240 .in
.query_on_disk_id
= true,
3243 status
= smb2_create(tree
, tctx
, &create
);
3244 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3245 "test file could not be created\n");
3246 h1
= create
.out
.file
.handle
;
3247 returned_fileid
= BVAL(&create
.out
.on_disk_id
, 0);
3248 torture_assert_u64_equal_goto(tctx
, returned_fileid
, expected_fileid
,
3249 ret
, done
, "bad fileid\n");
3252 * Getinfo the File-ID on the just opened handle
3254 finfo
= (union smb_fileinfo
) {
3255 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
3256 .generic
.in
.file
.handle
= h1
,
3259 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
3260 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3261 "torture_smb2_testdir\n");
3262 smb2_util_close(tree
, h1
);
3263 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
3265 ret
, done
, "bad fileid\n");
3268 * Create stream, check the stream's File-ID, should be the same as the
3269 * base file (sic!, tested against Windows).
3271 create
= (struct smb2_create
) {
3272 .in
.desired_access
= SEC_FILE_ALL
,
3273 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
3274 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
3275 .in
.create_disposition
= NTCREATEX_DISP_CREATE
,
3277 .in
.query_on_disk_id
= true,
3280 status
= smb2_create(tree
, tctx
, &create
);
3281 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3282 "test file could not be created\n");
3283 h1
= create
.out
.file
.handle
;
3284 returned_fileid
= BVAL(&create
.out
.on_disk_id
, 0);
3285 torture_assert_u64_equal_goto(tctx
, returned_fileid
, expected_fileid
,
3286 ret
, done
, "bad fileid\n");
3289 * Getinfo the File-ID on the created stream
3291 finfo
= (union smb_fileinfo
) {
3292 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
3293 .generic
.in
.file
.handle
= h1
,
3296 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
3297 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3298 "smb2_getinfo_file failed\n");
3299 smb2_util_close(tree
, h1
);
3300 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
3302 ret
, done
, "bad fileid\n");
3305 * Open stream, check the stream's File-ID, should be the same as the
3306 * base file (sic!, tested against Windows).
3308 create
= (struct smb2_create
) {
3309 .in
.desired_access
= SEC_FILE_ALL
,
3310 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
3311 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
3312 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
3314 .in
.query_on_disk_id
= true,
3317 status
= smb2_create(tree
, tctx
, &create
);
3318 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3319 "test file could not be created\n");
3320 h1
= create
.out
.file
.handle
;
3321 returned_fileid
= BVAL(&create
.out
.on_disk_id
, 0);
3322 torture_assert_u64_equal_goto(tctx
, returned_fileid
, expected_fileid
,
3323 ret
, done
, "bad fileid\n");
3326 * Getinfo the File-ID on the opened stream
3328 finfo
= (union smb_fileinfo
) {
3329 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
3330 .generic
.in
.file
.handle
= h1
,
3333 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
3334 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3335 "smb2_getinfo_file failed\n");
3336 smb2_util_close(tree
, h1
);
3337 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
3339 ret
, done
, "bad fileid\n");
3342 * Overwrite stream, check the stream's File-ID, should be the same as
3343 * the base file (sic!, tested against Windows).
3345 create
= (struct smb2_create
) {
3346 .in
.desired_access
= SEC_FILE_ALL
,
3347 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
3348 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
3349 .in
.create_disposition
= NTCREATEX_DISP_OVERWRITE
,
3351 .in
.query_on_disk_id
= true,
3354 status
= smb2_create(tree
, tctx
, &create
);
3355 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3356 "test file could not be created\n");
3357 h1
= create
.out
.file
.handle
;
3358 returned_fileid
= BVAL(&create
.out
.on_disk_id
, 0);
3359 torture_assert_u64_equal_goto(tctx
, returned_fileid
, expected_fileid
,
3360 ret
, done
, "bad fileid\n");
3363 * Getinfo the File-ID on the overwritten stream
3365 finfo
= (union smb_fileinfo
) {
3366 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
3367 .generic
.in
.file
.handle
= h1
,
3370 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
3371 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3372 "smb2_getinfo_file failed\n");
3373 smb2_util_close(tree
, h1
);
3374 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
3376 ret
, done
, "bad fileid\n");
3379 * Do some modifications on the stream (IO, setinfo), verifying File-ID
3382 create
= (struct smb2_create
) {
3383 .in
.desired_access
= SEC_FILE_ALL
,
3384 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
3385 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
3386 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
3388 .in
.query_on_disk_id
= true,
3391 status
= smb2_create(tree
, tctx
, &create
);
3392 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3393 "test file could not be created\n");
3394 h1
= create
.out
.file
.handle
;
3396 status
= smb2_util_write(tree
, h1
, "foo", 0, strlen("foo"));
3397 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3398 "smb2_util_write failed\n");
3400 finfo
= (union smb_fileinfo
) {
3401 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
3402 .generic
.in
.file
.handle
= h1
,
3404 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
3405 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3406 "smb2_getinfo_file failed\n");
3407 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
3409 ret
, done
, "bad fileid\n");
3411 sinfo
= (union smb_setfileinfo
) {
3412 .basic_info
.level
= RAW_SFILEINFO_BASIC_INFORMATION
,
3413 .basic_info
.in
.file
.handle
= h1
,
3415 unix_to_nt_time(&sinfo
.basic_info
.in
.write_time
, time(NULL
));
3417 status
= smb2_setinfo_file(tree
, &sinfo
);
3418 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3419 "smb2_setinfo_file failed\n");
3421 finfo
= (union smb_fileinfo
) {
3422 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
3423 .generic
.in
.file
.handle
= h1
,
3425 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
3426 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3427 "smb2_getinfo_file failed\n");
3428 smb2_util_close(tree
, h1
);
3429 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
3431 ret
, done
, "bad fileid\n");
3434 * Final open of the directory with QFID
3436 create
= (struct smb2_create
) {
3437 .in
.desired_access
= SEC_FILE_ALL
,
3438 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
3439 .in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
,
3440 .in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
,
3441 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
3443 .in
.query_on_disk_id
= true,
3446 status
= smb2_create(tree
, tctx
, &create
);
3447 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3448 "test file could not be created\n");
3449 h1
= create
.out
.file
.handle
;
3450 returned_fileid
= BVAL(&create
.out
.on_disk_id
, 0);
3451 torture_assert_u64_equal_goto(tctx
, returned_fileid
, expected_fileid
,
3452 ret
, done
, "bad fileid\n");
3455 * Final Getinfo checking File-ID
3457 finfo
= (union smb_fileinfo
) {
3458 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
3459 .generic
.in
.file
.handle
= h1
,
3462 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
3463 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3464 "torture_smb2_testdir\n");
3465 smb2_util_close(tree
, h1
);
3466 torture_assert_u64_equal_goto(tctx
, finfo
.all_info2
.out
.file_id
,
3468 ret
, done
, "bad fileid\n");
3471 * Final list directory, verifying the operations on basefile and stream
3472 * didn't modify the base file metadata.
3474 f
= (struct smb2_find
) {
3475 .in
.file
.handle
= testdirh
,
3476 .in
.pattern
= "foo",
3477 .in
.max_response_size
= 0x1000,
3478 .in
.level
= SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
3479 .in
.continue_flags
= SMB2_CONTINUE_FLAG_RESTART
,
3482 status
= smb2_find_level(tree
, tree
, &f
, &count
, &d
);
3483 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3484 "smb2_find_level failed\n");
3485 torture_assert_u64_equal_goto(tctx
,
3486 d
->id_both_directory_info
.file_id
,
3488 ret
, done
, "bad fileid\n");
3491 smb2_util_close(tree
, testdirh
);
3492 smb2_deltree(tree
, DNAME
);
3493 talloc_free(mem_ctx
);
3497 static bool test_fileid_unique_object(
3498 struct torture_context
*tctx
,
3499 struct smb2_tree
*tree
,
3500 unsigned int num_objs
,
3503 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
3505 struct smb2_handle testdirh
;
3506 struct smb2_handle h1
;
3507 struct smb2_create create
;
3509 uint64_t fileid_array
[num_objs
];
3513 smb2_deltree(tree
, DNAME
);
3515 status
= torture_smb2_testdir(tree
, DNAME
, &testdirh
);
3516 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3517 "test_fileid_unique failed\n");
3518 smb2_util_close(tree
, testdirh
);
3520 /* Create num_obj files as rapidly as we can. */
3521 for (i
= 0; i
< num_objs
; i
++) {
3522 fname
= talloc_asprintf(mem_ctx
,
3526 torture_assert_goto(tctx
,
3532 create
= (struct smb2_create
) {
3533 .in
.desired_access
= SEC_FILE_READ_ATTRIBUTE
,
3534 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
3535 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
3536 .in
.create_disposition
= NTCREATEX_DISP_CREATE
,
3541 create
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
3542 create
.in
.create_options
= FILE_DIRECTORY_FILE
;
3545 status
= smb2_create(tree
, tctx
, &create
);
3546 if (!NT_STATUS_IS_OK(status
)) {
3548 talloc_asprintf(tctx
,
3549 "test file %s could not be created\n",
3556 h1
= create
.out
.file
.handle
;
3557 smb2_util_close(tree
, h1
);
3564 for (i
= 0; i
< num_objs
; i
++) {
3565 union smb_fileinfo finfo
;
3567 fname
= talloc_asprintf(mem_ctx
,
3571 torture_assert_goto(tctx
,
3577 create
= (struct smb2_create
) {
3578 .in
.desired_access
= SEC_FILE_READ_ATTRIBUTE
,
3579 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
3580 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
3581 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
3586 create
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
3587 create
.in
.create_options
= FILE_DIRECTORY_FILE
;
3590 status
= smb2_create(tree
, tctx
, &create
);
3591 if (!NT_STATUS_IS_OK(status
)) {
3593 talloc_asprintf(tctx
,
3594 "test file %s could not "
3597 nt_errstr(status
)));
3603 h1
= create
.out
.file
.handle
;
3605 finfo
= (union smb_fileinfo
) {
3606 .generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
,
3607 .generic
.in
.file
.handle
= h1
,
3610 status
= smb2_getinfo_file(tree
, tctx
, &finfo
);
3611 if (!NT_STATUS_IS_OK(status
)) {
3613 talloc_asprintf(tctx
,
3614 "failed to get fileid for "
3615 "test file %s: %s\n",
3617 nt_errstr(status
)));
3622 smb2_util_close(tree
, h1
);
3624 fileid_array
[i
] = finfo
.all_info2
.out
.file_id
;
3628 /* All returned fileids must be unique. 100 is small so brute force. */
3629 for (i
= 0; i
< num_objs
- 1; i
++) {
3631 for (j
= i
+ 1; j
< num_objs
; j
++) {
3632 if (fileid_array
[i
] == fileid_array
[j
]) {
3634 talloc_asprintf(tctx
,
3635 "fileid %u == fileid %u (0x%"PRIu64
")\n",
3647 smb2_util_close(tree
, testdirh
);
3648 smb2_deltree(tree
, DNAME
);
3649 talloc_free(mem_ctx
);
3653 static bool test_fileid_unique(
3654 struct torture_context
*tctx
,
3655 struct smb2_tree
*tree
)
3657 return test_fileid_unique_object(tctx
, tree
, 100, false);
3660 static bool test_fileid_unique_dir(
3661 struct torture_context
*tctx
,
3662 struct smb2_tree
*tree
)
3664 return test_fileid_unique_object(tctx
, tree
, 100, true);
3667 static bool test_dosattr_tmp_dir(struct torture_context
*tctx
,
3668 struct smb2_tree
*tree
)
3672 struct smb2_create c
;
3673 struct smb2_handle h1
= {{0}};
3674 const char *fname
= DNAME
;
3676 smb2_deltree(tree
, fname
);
3677 smb2_util_rmdir(tree
, fname
);
3679 c
= (struct smb2_create
) {
3680 .in
.desired_access
= SEC_RIGHTS_DIR_ALL
,
3681 .in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
,
3682 .in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
,
3683 .in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
3684 NTCREATEX_SHARE_ACCESS_WRITE
|
3685 NTCREATEX_SHARE_ACCESS_DELETE
,
3686 .in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
,
3690 status
= smb2_create(tree
, tctx
, &c
);
3691 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3693 h1
= c
.out
.file
.handle
;
3695 /* Try to set temporary attribute on directory */
3696 SET_ATTRIB(FILE_ATTRIBUTE_TEMPORARY
, NT_STATUS_INVALID_PARAMETER
);
3699 if (!smb2_util_handle_empty(h1
)) {
3700 smb2_util_close(tree
, h1
);
3702 smb2_util_unlink(tree
, fname
);
3703 smb2_deltree(tree
, fname
);
3709 test opening quota fakefile handle and returned attributes
3711 static bool test_smb2_open_quota_fake_file(struct torture_context
*tctx
,
3712 struct smb2_tree
*tree
)
3714 const char *fname
= "$Extend\\$Quota:$Q:$INDEX_ALLOCATION";
3715 struct smb2_create create
;
3716 struct smb2_handle h
= {{0}};
3720 create
= (struct smb2_create
) {
3721 .in
.desired_access
= SEC_RIGHTS_FILE_READ
,
3722 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
3723 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
3724 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
3725 .in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
,
3729 status
= smb2_create(tree
, tree
, &create
);
3730 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
3731 "smb2_create failed\n");
3732 h
= create
.out
.file
.handle
;
3734 torture_assert_u64_equal_goto(tctx
,
3735 create
.out
.file_attr
,
3736 FILE_ATTRIBUTE_HIDDEN
3737 | FILE_ATTRIBUTE_SYSTEM
3738 | FILE_ATTRIBUTE_DIRECTORY
3739 | FILE_ATTRIBUTE_ARCHIVE
,
3742 "Wrong attributes\n");
3744 torture_assert_u64_equal_goto(tctx
,
3745 create
.out
.create_time
, 0,
3748 "create_time is not 0\n");
3749 torture_assert_u64_equal_goto(tctx
,
3750 create
.out
.access_time
, 0,
3753 "access_time is not 0\n");
3754 torture_assert_u64_equal_goto(tctx
,
3755 create
.out
.write_time
, 0,
3758 "write_time is not 0\n");
3759 torture_assert_u64_equal_goto(tctx
,
3760 create
.out
.change_time
, 0,
3763 "change_time is not 0\n");
3766 smb2_util_close(tree
, h
);
3771 Find Maximum Path Length
3773 static bool generate_path(const size_t len
,
3775 const size_t buf_len
)
3779 if (len
>= buf_len
) {
3783 for (i
= 0; i
< len
; i
++) {
3784 buffer
[i
] = (char)(i
% 10) + 48;
3790 static bool test_path_length_test(struct torture_context
*tctx
,
3791 struct smb2_tree
*tree
)
3793 const size_t max_name
= 2048;
3794 char *name
= talloc_array(tctx
, char, max_name
);
3795 struct smb2_handle fh
= {{0}};
3796 size_t length
= 128;
3797 size_t max_file_name
= 0;
3798 size_t max_path_length
= 0;
3799 char *path_ok
= NULL
;
3800 char *path_next
= NULL
;
3801 char *topdir
= NULL
;
3802 bool is_interactive
= torture_setting_bool(tctx
, "interactive", false);
3806 if (!is_interactive
) {
3807 torture_result(tctx
, TORTURE_SKIP
,
3808 "Interactive Test: Skipping... "
3809 "(enable with --interactive)\n");
3813 torture_comment(tctx
, "Testing filename and path lengths\n");
3815 /* Find Longest File Name */
3816 for (length
= 128; length
< max_name
; length
++) {
3817 if (!generate_path(length
, name
, max_name
)) {
3818 torture_result(tctx
, TORTURE_FAIL
,
3819 "Failed to generate path.");
3823 status
= torture_smb2_testfile(tree
, name
, &fh
);
3824 if (!NT_STATUS_IS_OK(status
)) {
3828 smb2_util_close(tree
, fh
);
3829 smb2_util_unlink(tree
, name
);
3831 max_file_name
= length
;
3834 torture_assert_int_not_equal_goto(tctx
, length
, max_name
, ret
, done
,
3837 torture_comment(tctx
, "Max file name length: %zu\n", max_file_name
);
3839 /* Remove one char that caused the failure above */
3840 name
[max_file_name
] = '\0';
3842 path_ok
= talloc_strdup(tree
, name
);
3843 torture_assert_not_null_goto(tctx
, path_ok
, ret
, done
,
3844 "talloc_strdup failed\n");
3846 topdir
= talloc_strdup(tree
, name
);
3847 torture_assert_not_null_goto(tctx
, topdir
, ret
, done
,
3848 "talloc_strdup failed\n");
3850 status
= smb2_util_mkdir(tree
, path_ok
);
3851 if (!NT_STATUS_IS_OK(status
)) {
3852 torture_comment(tctx
, "mkdir [%s] failed: %s\n",
3853 path_ok
, nt_errstr(status
));
3854 torture_result(tctx
, TORTURE_FAIL
, "Initial mkdir failed");
3859 path_next
= talloc_asprintf(tctx
, "%s\\%s", path_ok
, name
);
3860 torture_assert_not_null_goto(tctx
, path_next
, ret
, done
,
3861 "talloc_asprintf failed\n");
3863 status
= smb2_util_mkdir(tree
, path_next
);
3864 if (!NT_STATUS_IS_OK(status
)) {
3868 path_ok
= path_next
;
3871 for (length
= 1; length
< max_name
; length
++) {
3872 if (!generate_path(length
, name
, max_name
)) {
3873 torture_result(tctx
, TORTURE_FAIL
,
3874 "Failed to generate path.");
3878 path_next
= talloc_asprintf(tctx
, "%s\\%s", path_ok
, name
);
3879 torture_assert_not_null_goto(tctx
, path_next
, ret
, done
,
3880 "talloc_asprintf failed\n");
3882 status
= torture_smb2_testfile(tree
, path_next
, &fh
);
3883 if (!NT_STATUS_IS_OK(status
)) {
3886 smb2_util_close(tree
, fh
);
3887 path_ok
= path_next
;
3890 max_path_length
= talloc_array_length(path_ok
);
3892 torture_comment(tctx
, "Max path name length: %zu\n", max_path_length
);
3899 basic testing of SMB2 read
3901 struct torture_suite
*torture_smb2_create_init(TALLOC_CTX
*ctx
)
3903 struct torture_suite
*suite
= torture_suite_create(ctx
, "create");
3905 torture_suite_add_1smb2_test(suite
, "gentest", test_create_gentest
);
3906 torture_suite_add_1smb2_test(suite
, "blob", test_create_blob
);
3907 torture_suite_add_1smb2_test(suite
, "open", test_smb2_open
);
3908 torture_suite_add_1smb2_test(suite
, "brlocked", test_smb2_open_brlocked
);
3909 torture_suite_add_1smb2_test(suite
, "multi", test_smb2_open_multi
);
3910 torture_suite_add_1smb2_test(suite
, "delete", test_smb2_open_for_delete
);
3911 torture_suite_add_1smb2_test(suite
, "leading-slash", test_smb2_leading_slash
);
3912 torture_suite_add_1smb2_test(suite
, "impersonation", test_smb2_impersonation_level
);
3913 torture_suite_add_1smb2_test(suite
, "aclfile", test_create_acl_file
);
3914 torture_suite_add_1smb2_test(suite
, "acldir", test_create_acl_dir
);
3915 torture_suite_add_1smb2_test(suite
, "nulldacl", test_create_null_dacl
);
3916 torture_suite_add_1smb2_test(suite
, "mkdir-dup", test_mkdir_dup
);
3917 torture_suite_add_1smb2_test(suite
, "mkdir-visible", test_mkdir_visible
);
3918 torture_suite_add_1smb2_test(suite
, "dir-alloc-size", test_dir_alloc_size
);
3919 torture_suite_add_1smb2_test(suite
, "dosattr_tmp_dir", test_dosattr_tmp_dir
);
3920 torture_suite_add_1smb2_test(suite
, "quota-fake-file", test_smb2_open_quota_fake_file
);
3921 torture_suite_add_1smb2_test(suite
, "path-length", test_path_length_test
);
3922 torture_suite_add_1smb2_test(suite
, "bench-path-contention-shared", test_smb2_bench_path_contention_shared
);
3924 suite
->description
= talloc_strdup(suite
, "SMB2-CREATE tests");
3929 struct torture_suite
*torture_smb2_twrp_init(TALLOC_CTX
*ctx
)
3931 struct torture_suite
*suite
= torture_suite_create(ctx
, "twrp");
3933 torture_suite_add_1smb2_test(suite
, "write", test_twrp_write
);
3934 torture_suite_add_1smb2_test(suite
, "stream", test_twrp_stream
);
3935 torture_suite_add_1smb2_test(suite
, "openroot", test_twrp_openroot
);
3936 torture_suite_add_1smb2_test(suite
, "listdir", test_twrp_listdir
);
3938 suite
->description
= talloc_strdup(suite
, "SMB2-TWRP tests");
3944 basic testing of SMB2 File-IDs
3946 struct torture_suite
*torture_smb2_fileid_init(TALLOC_CTX
*ctx
)
3948 struct torture_suite
*suite
= torture_suite_create(ctx
, "fileid");
3950 torture_suite_add_1smb2_test(suite
, "fileid", test_fileid
);
3951 torture_suite_add_1smb2_test(suite
, "fileid-dir", test_fileid_dir
);
3952 torture_suite_add_1smb2_test(suite
, "unique", test_fileid_unique
);
3953 torture_suite_add_1smb2_test(suite
, "unique-dir", test_fileid_unique_dir
);
3955 suite
->description
= talloc_strdup(suite
, "SMB2-FILEID tests");
3960 static bool test_no_stream(struct torture_context
*tctx
,
3961 struct smb2_tree
*tree
)
3963 struct smb2_create c
;
3966 const char *names
[] = {
3967 "test_no_stream::$DATA",
3968 "test_no_stream::foooooooooooo",
3969 "test_no_stream:stream",
3970 "test_no_stream:stream:$DATA",
3975 for (i
= 0; names
[i
] != NULL
; i
++) {
3976 c
= (struct smb2_create
) {
3977 .in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
,
3978 .in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
,
3979 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
3980 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
3981 .in
.fname
= names
[i
],
3984 status
= smb2_create(tree
, tctx
, &c
);
3985 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_INVALID
)) {
3987 tctx
, "Expected NT_STATUS_OBJECT_NAME_INVALID, "
3988 "got %s, name: '%s'\n",
3989 nt_errstr(status
), names
[i
]);
3990 torture_fail_goto(tctx
, done
, "Bad create result\n");
3997 struct torture_suite
*torture_smb2_create_no_streams_init(TALLOC_CTX
*ctx
)
3999 struct torture_suite
*suite
= torture_suite_create(ctx
, "create_no_streams");
4001 torture_suite_add_1smb2_test(suite
, "no_stream", test_no_stream
);
4003 suite
->description
= talloc_strdup(suite
, "SMB2-CREATE stream test on share without streams support");