libcli/auth: let netlogon_creds_copy() make use of ndr_deepcopy_struct()
[samba4-gss.git] / source4 / torture / smb2 / create.c
blob756256dc4f5d96d9792d35982002f791e2e25e8f
1 /*
2 Unix SMB/CIFS implementation.
4 SMB2 create test suite
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/>.
22 #include "includes.h"
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)); \
46 return false; \
47 }} while (0)
49 #define CHECK_EQUAL(v, correct) do { \
50 if (v != correct) { \
51 torture_result(tctx, TORTURE_FAIL, \
52 "(%s) Incorrect value for %s 0x%08llx - " \
53 "should be 0x%08llx\n", \
54 __location__, #v, \
55 (unsigned long long)v, \
56 (unsigned long long)correct); \
57 return false; \
58 }} while (0)
60 #define CHECK_TIME(t, field) do { \
61 time_t t1, t2; \
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); \
66 t1 = t & ~1; \
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); \
75 ret = false; \
76 }} while (0)
78 #define CHECK_NTTIME(t, field) do { \
79 NTTIME t2; \
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); \
92 ret = false; \
93 }} while (0)
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); \
106 ret = false; \
107 }} while (0)
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); \
114 ret = false; \
115 }} while (0)
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)); \
128 } while (0)
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;
136 NTSTATUS status;
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;
142 ZERO_STRUCT(io);
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;
146 io.in.share_access =
147 NTCREATEX_SHARE_ACCESS_DELETE|
148 NTCREATEX_SHARE_ACCESS_READ|
149 NTCREATEX_SHARE_ACCESS_WRITE;
150 io.in.create_options = 0;
151 io.in.fname = FNAME;
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;
190 ok_mask = 0;
191 not_supported_mask = 0;
192 invalid_parameter_mask = 0;
193 not_a_directory_mask = 0;
194 unexpected_mask = 0;
196 int i;
197 for (i=0;i<32;i++) {
198 io.in.create_options = (uint32_t)1<<i;
199 if (io.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
200 continue;
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)) {
210 ok_mask |= 1<<i;
211 status = smb2_util_close(tree, io.out.file.handle);
212 CHECK_STATUS(status, NT_STATUS_OK);
213 } else {
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;
231 access_mask = 0;
233 int i;
234 for (i=0;i<32;i++) {
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;
240 } else {
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);
252 } else {
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;
259 ok_mask = 0;
260 invalid_parameter_mask = 0;
261 unexpected_mask = 0;
262 file_attributes_set = 0;
264 int i;
265 for (i=0;i<32;i++) {
266 io.in.file_attributes = (uint32_t)1<<i;
267 if (io.in.file_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
268 continue;
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)) {
275 uint32_t expected;
276 ok_mask |= 1<<i;
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);
285 } else {
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",
309 nt_errstr(status));
310 } else {
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);
319 ZERO_STRUCT(io);
320 io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
321 io.in.file_attributes = 0;
322 io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
323 io.in.share_access =
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);
334 io.in.fname = FNAME;
335 io.in.file_attributes = 0x8040;
336 io.in.share_access =
337 NTCREATEX_SHARE_ACCESS_READ;
338 status = smb2_create(tree, tctx, &io);
339 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
341 io.in.fname = FNAME;
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);
364 return true;
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;
374 NTSTATUS status;
376 smb2_deltree(tree, FNAME);
378 ZERO_STRUCT(io);
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;
382 io.in.share_access =
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 |
389 0x00200000;
390 io.in.fname = FNAME;
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
401 * correctly. */
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);
431 io.in.timewarp = 0;
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",
544 data_blob(NULL, 0));
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);
551 return true;
554 #define FAIL_UNLESS(__cond) \
555 do { \
556 if (__cond) {} else { \
557 torture_result(tctx, TORTURE_FAIL, "%s) condition violated: %s\n", \
558 __location__, #__cond); \
559 ret = false; goto done; \
561 } while(0)
564 try creating with acls
566 static bool test_create_acl_ext(struct torture_context *tctx, struct smb2_tree *tree, bool test_dir)
568 bool ret = true;
569 struct smb2_create io;
570 NTSTATUS status;
571 struct security_ace ace;
572 struct security_descriptor *sd;
573 struct dom_sid *test_sid;
574 union smb_fileinfo q = {};
575 uint32_t attrib =
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;
582 ZERO_STRUCT(ace);
584 smb2_deltree(tree, FNAME);
586 ZERO_STRUCT(io);
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;
590 io.in.share_access =
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));
598 io.in.fname = FNAME;
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 =
608 SECINFO_OWNER |
609 SECINFO_GROUP |
610 SECINFO_DACL;
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;
624 ace.flags = 0;
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");
633 io.in.sec_desc = sd;
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");
660 io.in.sec_desc = sd;
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,
676 SID_WORLD,
677 SEC_ACE_TYPE_ACCESS_ALLOWED,
678 SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
680 NULL);
682 io.in.sec_desc = sd;
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));
690 done:
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);
696 return ret;
700 test SMB2 open
702 static bool test_smb2_open(struct torture_context *tctx,
703 struct smb2_tree *tree)
705 union smb_open io;
706 union smb_fileinfo finfo;
707 const char *fname = DNAME "\\torture_ntcreatex.txt";
708 const char *dname = DNAME "\\torture_ntcreatex.dir";
709 NTSTATUS status;
710 struct smb2_handle h = {{0}};
711 struct smb2_handle h1 = {{0}};
712 bool ret = true;
713 size_t i;
714 struct {
715 uint32_t create_disp;
716 bool with_file;
717 NTSTATUS correct_status;
718 } open_funcs[] = {
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,
772 ret, done,
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;
834 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);
862 done:
863 smb2_util_close(tree, h1);
864 smb2_util_unlink(tree, fname);
865 smb2_deltree(tree, DNAME);
866 return ret;
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;
877 union smb_lock io2;
878 struct smb2_lock_element lock[1];
879 const char *fname = DNAME "\\torture_ntcreatex.txt";
880 NTSTATUS status;
881 bool ret = true;
882 struct smb2_handle h;
883 char b = 42;
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;
918 ZERO_STRUCT(lock);
919 lock[0].offset = 0;
920 lock[0].length = 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);
948 return ret;
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";
957 NTSTATUS status;
958 bool ret = true;
959 union smb_open io;
960 struct smb2_tree **trees;
961 struct smb2_request **requests;
962 union smb_open *ios;
963 int i, num_files = 3;
964 int num_ok = 0;
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) ||
973 (ios == NULL)) {
974 torture_comment(tctx, ("talloc failed\n"));
975 ret = false;
976 goto done;
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;
990 /* cleanup */
991 smb2_util_unlink(tree, fname);
994 base ntcreatex parms
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++) {
1012 ios[i] = io;
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");
1022 while (1) {
1023 bool unreplied = false;
1024 for (i=0; i<num_files; i++) {
1025 if (requests[i] == NULL) {
1026 continue;
1028 if (requests[i]->state < SMB2_REQUEST_DONE) {
1029 unreplied = true;
1030 break;
1032 status = smb2_create_recv(requests[i], tctx,
1033 &(ios[i].smb2));
1035 torture_comment(tctx,
1036 "File %d returned status %s\n", i,
1037 nt_errstr(status));
1039 if (NT_STATUS_IS_OK(status)) {
1040 num_ok += 1;
1043 if (NT_STATUS_EQUAL(status,
1044 NT_STATUS_OBJECT_NAME_COLLISION)) {
1045 num_collision += 1;
1048 requests[i] = NULL;
1050 if (!unreplied) {
1051 break;
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__);
1063 done:
1064 smb2_deltree(tree, fname);
1066 return ret;
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)
1076 union smb_open io;
1077 union smb_fileinfo finfo;
1078 const char *fname = DNAME "\\torture_open_for_delete.txt";
1079 NTSTATUS status;
1080 struct smb2_handle h, h1;
1081 bool ret = true;
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);
1141 return ret;
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)
1152 union smb_open io;
1153 const char *dnameslash = "\\"DNAME;
1154 NTSTATUS status;
1155 bool ret = true;
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);
1177 return ret;
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)
1187 union smb_open io;
1188 const char *fname = DNAME "\\torture_invalid_impersonation_level.txt";
1189 NTSTATUS status;
1190 struct smb2_handle h;
1191 bool ret = true;
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);
1223 return ret;
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)); \
1251 ret = false; \
1252 goto done; \
1254 } while (0)
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)
1262 NTSTATUS status;
1263 struct smb2_create io;
1264 const char *fname = "nulldacl.txt";
1265 bool ret = true;
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);
1276 ZERO_STRUCT(io);
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 |
1295 0x00200000;
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 =
1306 SECINFO_OWNER |
1307 SECINFO_GROUP |
1308 SECINFO_DACL;
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)) {
1318 ret = false;
1319 torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
1321 if (q.query_secdesc.out.sd->dacl == NULL) {
1322 ret = false;
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 =
1340 SECINFO_OWNER |
1341 SECINFO_GROUP |
1342 SECINFO_DACL;
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)) {
1348 ret = false;
1349 torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
1351 if (q.query_secdesc.out.sd->dacl != NULL) {
1352 ret = false;
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");
1399 ZERO_STRUCT(dacl);
1400 dacl.revision = SECURITY_ACL_REVISION_NT4;
1401 dacl.num_aces = 0;
1402 sd->dacl = &dacl;
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 =
1415 SECINFO_OWNER |
1416 SECINFO_GROUP |
1417 SECINFO_DACL;
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)) {
1423 ret = false;
1424 torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
1426 if (q.query_secdesc.out.sd->dacl == NULL) {
1427 ret = false;
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);
1433 ret = false;
1434 goto done;
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);
1450 } else {
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);
1459 } else {
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);
1468 } else {
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);
1477 } else {
1478 CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1481 torture_comment(tctx, "set empty sd\n");
1482 sd->type &= ~SEC_DESC_DACL_PRESENT;
1483 sd->dacl = NULL;
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 =
1496 SECINFO_OWNER |
1497 SECINFO_GROUP |
1498 SECINFO_DACL;
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)) {
1504 ret = false;
1505 torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
1507 if (q.query_secdesc.out.sd->dacl != NULL) {
1508 ret = false;
1509 torture_fail_goto(tctx, done, "DACL has been created on the server!\n");
1511 done:
1512 smb2_util_close(tree, handle);
1513 smb2_util_unlink(tree, fname);
1514 smb2_tdis(tree);
1515 smb2_logoff(tree->session);
1516 return ret;
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";
1528 NTSTATUS status;
1529 bool ret = true;
1530 union smb_open io;
1531 struct smb2_tree **trees;
1532 struct smb2_request **requests;
1533 union smb_open *ios;
1534 int i, num_files = 2;
1535 int num_ok = 0;
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) ||
1545 (ios == NULL)) {
1546 torture_fail(tctx, ("talloc failed\n"));
1547 ret = false;
1548 goto done;
1551 tree->session->transport->options.request_timeout = 60;
1553 for (i=0; i<num_files; i++) {
1554 if (!torture_smb2_connection(tctx, &(trees[i]))) {
1555 torture_fail(tctx,
1556 talloc_asprintf(tctx,
1557 "Could not open %d'th connection\n", i));
1558 ret = false;
1559 goto done;
1561 trees[i]->session->transport->options.request_timeout = 60;
1564 /* cleanup */
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++) {
1587 ios[i] = io;
1588 requests[i] = smb2_create_send(trees[i], &(ios[i].smb2));
1589 if (requests[i] == NULL) {
1590 torture_fail(tctx,
1591 talloc_asprintf(tctx,
1592 "could not send %d'th request\n", i));
1593 ret = false;
1594 goto done;
1598 torture_comment(tctx, "waiting for replies\n");
1599 while (1) {
1600 bool unreplied = false;
1601 for (i=0; i<num_files; i++) {
1602 if (requests[i] == NULL) {
1603 continue;
1605 if (requests[i]->state < SMB2_REQUEST_DONE) {
1606 unreplied = true;
1607 break;
1609 status = smb2_create_recv(requests[i], tctx,
1610 &(ios[i].smb2));
1612 if (NT_STATUS_IS_OK(status)) {
1613 num_ok += 1;
1615 if (ios[i].smb2.out.create_action ==
1616 NTCREATEX_ACTION_CREATED) {
1617 num_created++;
1619 if (ios[i].smb2.out.create_action ==
1620 NTCREATEX_ACTION_EXISTED) {
1621 num_existed++;
1623 } else {
1624 torture_fail(tctx,
1625 talloc_asprintf(tctx,
1626 "File %d returned status %s\n", i,
1627 nt_errstr(status)));
1631 requests[i] = NULL;
1633 if (!unreplied) {
1634 break;
1637 if (tevent_loop_once(tctx->ev) != 0) {
1638 torture_fail(tctx, "tevent_loop_once failed\n");
1639 ret = false;
1640 goto done;
1644 if (num_ok != 2) {
1645 torture_fail(tctx,
1646 talloc_asprintf(tctx,
1647 "num_ok == %d\n", num_ok));
1648 ret = false;
1650 if (num_created != 1) {
1651 torture_fail(tctx,
1652 talloc_asprintf(tctx,
1653 "num_created == %d\n", num_created));
1654 ret = false;
1656 if (num_existed != 1) {
1657 torture_fail(tctx,
1658 talloc_asprintf(tctx,
1659 "num_existed == %d\n", num_existed));
1660 ret = false;
1662 done:
1663 smb2_deltree(tree, fname);
1665 return ret;
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;
1678 bool ok;
1681 struct test_mkdir_visible_open {
1682 struct test_mkdir_visible_state *state;
1683 struct smb2_tree *tree;
1684 uint64_t try;
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;
1698 NTSTATUS status;
1699 uint64_t fid_persistent;
1700 uint64_t fid_volatile;
1701 struct smb_create_returns cr;
1702 bool done;
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;
1713 if (!state->ok) {
1714 return;
1717 torture_assert_goto(tctx, op->subreq == subreq,
1718 state->ok, done, "subreq");
1719 op->subreq = NULL;
1721 op->status = smb2cli_create_recv(subreq,
1722 &op->fid_persistent,
1723 &op->fid_volatile,
1724 &op->cr,
1726 NULL,
1727 NULL);
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)) {
1733 goto done;
1735 torture_assert_ntstatus_equal_goto(tctx,
1736 op->status, NT_STATUS_OBJECT_PATH_NOT_FOUND,
1737 state->ok, done, "smb2cli_create_recv");
1739 op->try += 1;
1740 torture_comment(tctx, "%s:%s: try[%"PRIu64"] starting\n",
1741 __func__, op->filename, op->try);
1742 subreq = smb2cli_create_send(op,
1743 tctx->ev,
1744 op->conn,
1745 op->timeout_msec,
1746 op->session,
1747 op->tcon,
1748 op->filename,
1749 op->oplock_level,
1750 op->impersonation_level,
1751 op->desired_access,
1752 op->file_attributes,
1753 op->share_access,
1754 op->create_disposition,
1755 op->create_options,
1756 NULL);
1757 torture_assert_not_null_goto(tctx, subreq,
1758 state->ok, done,
1759 "smb2cli_create_send");
1760 tevent_req_set_callback(subreq,
1761 test_mkdir_visible_open_retry,
1762 op);
1763 op->subreq = subreq;
1764 return;
1766 done:
1767 op->done = true;
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;
1779 if (!state->ok) {
1780 return;
1783 torture_assert_goto(tctx, op->subreq == subreq,
1784 state->ok, done, "subreq");
1785 op->subreq = NULL;
1787 op->status = smb2cli_create_recv(subreq,
1788 &op->fid_persistent,
1789 &op->fid_volatile,
1790 &op->cr,
1792 NULL,
1793 NULL);
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");
1801 done:
1802 op->done = true;
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 = {
1810 .state = NULL,
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;
1824 NTSTATUS status;
1825 bool ret = true;
1826 size_t i;
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");
1837 state->tctx = tctx;
1838 state->ok = true;
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,
1851 "talloc_asprintf");
1852 file_fail = talloc_asprintf(state, "%s\\file_fail", base_dname);
1853 torture_assert_not_null_goto(tctx, file_fail, ret, done,
1854 "talloc_asprintf");
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,
1879 SID_WORLD,
1880 SEC_ACE_TYPE_ACCESS_DENIED,
1881 SEC_DIR_ADD_FILE,
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,
1903 ret, done,
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 |
1917 FILE_SHARE_WRITE |
1918 FILE_SHARE_DELETE;
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");
1925 *dop = templ;
1926 dop->filename = talloc_asprintf(dop, "%s\\visible_dir", base_dname);
1927 torture_assert_not_null_goto(tctx, dop->filename, ret, done,
1928 "talloc_asprintf");
1929 dop->desired_access |= SEC_STD_READ_CONTROL;
1930 dop->file_attributes = FILE_ATTRIBUTE_DIRECTORY;
1931 dop->create_options = FILE_DIRECTORY_FILE;
1932 dop->tree = tree;
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 *,
1939 num_loops);
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");
1949 *op = templ;
1950 op->filename = talloc_asprintf(op, "%s\\visible_dir\\file_%zu",
1951 base_dname, i);
1952 torture_assert_not_null_goto(tctx, op->filename, ret, done,
1953 "talloc_asprintf");
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;
1963 loops[i] = op;
1966 for (i = 0; i < num_loops; i++) {
1967 struct test_mkdir_visible_open *op = loops[i];
1969 op->try = 1;
1970 torture_comment(tctx, "%s:%s: try[%"PRIu64"] starting\n",
1971 __func__, op->filename, op->try);
1972 op->subreq = smb2cli_create_send(op,
1973 tctx->ev,
1974 op->conn,
1975 op->timeout_msec,
1976 op->session,
1977 op->tcon,
1978 op->filename,
1979 op->oplock_level,
1980 op->impersonation_level,
1981 op->desired_access,
1982 op->file_attributes,
1983 op->share_access,
1984 op->create_disposition,
1985 op->create_options,
1986 NULL);
1987 torture_assert_not_null_goto(tctx, op->subreq,
1988 state->ok, done,
1989 "smb2cli_create_send");
1990 tevent_req_set_callback(op->subreq,
1991 test_mkdir_visible_open_retry,
1992 op);
1993 state->loops_running += 1;
1996 torture_comment(tctx, "%s:%s: starting\n",
1997 __func__, dop->filename);
1998 dop->subreq = smb2cli_create_send(dop,
1999 tctx->ev,
2000 dop->conn,
2001 dop->timeout_msec,
2002 dop->session,
2003 dop->tcon,
2004 dop->filename,
2005 dop->oplock_level,
2006 dop->impersonation_level,
2007 dop->desired_access,
2008 dop->file_attributes,
2009 dop->share_access,
2010 dop->create_disposition,
2011 dop->create_options,
2012 NULL);
2013 torture_assert_not_null_goto(tctx, dop->subreq,
2014 state->ok, done,
2015 "smb2cli_create_send");
2016 tevent_req_set_callback(dop->subreq,
2017 test_mkdir_visible_open_done,
2018 dop);
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,
2029 ret, done,
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,
2035 ret, done,
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");
2052 done:
2053 TALLOC_FREE(state);
2054 smb2_keepalive(tree->session->transport);
2055 smb2_deltree(tree, base_dname);
2056 smb2_keepalive(tree->session->transport);
2058 return ret;
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)
2067 bool ret = true;
2068 const char *dname = DNAME "\\torture_alloc_size.dir";
2069 NTSTATUS status;
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");
2080 ZERO_STRUCT(c);
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;
2086 c.in.fname = dname;
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
2093 * default.
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));
2117 done:
2118 if (!smb2_util_handle_empty(h1)) {
2119 smb2_util_close(tree, h1);
2121 smb2_deltree(tree, DNAME);
2122 return ret;
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}};
2129 NTSTATUS status;
2130 bool ret = true;
2131 char *p = NULL;
2132 struct tm tm;
2133 time_t t;
2134 uint64_t nttime;
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 {
2143 const char *file;
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);
2151 if (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. */
2166 ZERO_STRUCT(tm);
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");
2172 t = mktime(&tm);
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,
2180 .in.fname = file,
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,
2187 "smb2_create\n");
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,
2195 expected_access,
2196 ret, done, "Bad access\n");
2200 * Test create dispositions
2202 struct create_disps_tests cd_tests[] = {
2204 .file = file,
2205 .create_disposition = NTCREATEX_DISP_OPEN,
2206 .expected_status = NT_STATUS_OK,
2209 .file = file,
2210 .create_disposition = NTCREATEX_DISP_OPEN_IF,
2211 .expected_status = NT_STATUS_OK,
2214 .file = file,
2215 .create_disposition = NTCREATEX_DISP_OVERWRITE,
2216 .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2219 .file = file,
2220 .create_disposition = NTCREATEX_DISP_OVERWRITE_IF,
2221 .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2224 .file = file,
2225 .create_disposition = NTCREATEX_DISP_SUPERSEDE,
2226 .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2229 .file = "newfile",
2230 .create_disposition = NTCREATEX_DISP_OPEN_IF,
2231 .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2234 .file = "newfile",
2235 .create_disposition = NTCREATEX_DISP_OVERWRITE_IF,
2236 .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2239 .file = "newfile",
2240 .create_disposition = NTCREATEX_DISP_CREATE,
2241 .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2244 .file = "newfile",
2245 .create_disposition = NTCREATEX_DISP_SUPERSEDE,
2246 .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2249 .file = "newdir",
2250 .create_disposition = NTCREATEX_DISP_OPEN_IF,
2251 .create_options = NTCREATEX_OPTIONS_DIRECTORY,
2252 .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2255 .file = "newdir",
2256 .create_disposition = NTCREATEX_DISP_CREATE,
2257 .create_options = NTCREATEX_OPTIONS_DIRECTORY,
2258 .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
2261 .file = NULL,
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,
2280 "Bad status\n");
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,
2289 .in.fname = file,
2290 .in.timewarp = nttime,
2293 status = smb2_create(tree, tctx, &io);
2294 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2295 "smb2_create\n");
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(
2316 tctx,
2317 getinfo.access_information.out.access_flags,
2318 expected_access,
2319 ret, done,
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,
2339 0, NULL, NULL,
2340 owner_sid,
2341 SEC_ACE_TYPE_ACCESS_ALLOWED,
2342 SEC_FILE_WRITE_DATA,
2344 NULL);
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(
2356 tctx,
2357 status,
2358 NT_STATUS_MEDIA_WRITE_PROTECTED,
2359 ret, done,
2360 "smb2_setinfo_file\n");
2362 /* Try to delete */
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(
2371 tctx,
2372 status,
2373 NT_STATUS_MEDIA_WRITE_PROTECTED,
2374 ret, done,
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(
2384 tctx,
2385 status,
2386 NT_STATUS_MEDIA_WRITE_PROTECTED,
2387 ret, done,
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(
2399 tctx,
2400 status,
2401 NT_STATUS_MEDIA_WRITE_PROTECTED,
2402 ret, done,
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(
2414 tctx,
2415 status,
2416 NT_STATUS_NOT_SAME_DEVICE,
2417 ret, done,
2418 "smb2_setinfo_file\n");
2420 /* Try to rename */
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(
2429 tctx,
2430 status,
2431 NT_STATUS_NOT_SAME_DEVICE,
2432 ret, done,
2433 "smb2_setinfo_file\n");
2435 smb2_util_close(tree, h1);
2436 ZERO_STRUCT(h1);
2438 done:
2439 if (!smb2_util_handle_empty(h1)) {
2440 smb2_util_close(tree, h1);
2442 return ret;
2445 static bool test_twrp_stream(struct torture_context *tctx,
2446 struct smb2_tree *tree)
2448 struct smb2_create io;
2449 NTSTATUS status;
2450 bool ret = true;
2451 char *p = NULL;
2452 struct tm tm;
2453 time_t t;
2454 uint64_t nttime;
2455 const char *file = NULL;
2456 const char *stream = NULL;
2457 const char *snapshot = NULL;
2458 int stream_size;
2459 char *path = NULL;
2460 uint8_t *buf = NULL;
2461 struct smb2_handle h1 = {{0}};
2462 struct smb2_read r;
2464 file = torture_setting_string(tctx, "twrp_file", NULL);
2465 if (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",
2485 file, snapshot);
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. */
2497 ZERO_STRUCT(tm);
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");
2503 t = mktime(&tm);
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,
2511 .in.fname = path,
2512 .in.timewarp = nttime,
2515 status = smb2_create(tree, tctx, &io);
2516 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2517 "smb2_create\n");
2518 h1 = io.out.file.handle;
2520 r = (struct smb2_read) {
2521 .in.file.handle = h1,
2522 .in.length = stream_size,
2523 .in.offset = 0,
2526 status = smb2_read(tree, tree, &r);
2527 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2528 "smb2_create\n");
2530 smb2_util_close(tree, h1);
2532 done:
2533 return ret;
2536 static bool test_twrp_openroot(struct torture_context *tctx, struct smb2_tree *tree)
2538 struct smb2_create io;
2539 NTSTATUS status;
2540 bool ret = true;
2541 char *p = NULL;
2542 struct tm tm;
2543 time_t t;
2544 uint64_t nttime;
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",
2554 snapshot);
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. */
2560 ZERO_STRUCT(tm);
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");
2566 t = mktime(&tm);
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,
2574 .in.fname = "",
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,
2581 "smb2_create\n");
2582 smb2_util_close(tree, io.out.file.handle);
2584 done:
2585 return ret;
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;
2594 unsigned int count;
2595 union smb_search_data *d;
2596 char *p = NULL;
2597 struct tm tm;
2598 time_t t;
2599 uint64_t nttime;
2600 const char *snapshot = NULL;
2601 uint64_t normal_fileid;
2602 uint64_t snapshot_fileid;
2603 NTSTATUS status;
2604 bool ret = true;
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",
2613 snapshot);
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. */
2619 ZERO_STRUCT(tm);
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");
2625 t = mktime(&tm);
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,
2661 "smb2_create\n");
2662 h = create.out.file.handle;
2664 find = (struct smb2_find) {
2665 .in.file.handle = h,
2666 .in.pattern = "*",
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,
2680 "hardlink",
2681 ret, done, "bad name");
2682 torture_assert_u64_equal_goto(tctx,
2683 d[2].id_both_directory_info.file_id,
2684 normal_fileid,
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,
2726 "smb2_create\n");
2727 h = create.out.file.handle;
2729 find = (struct smb2_find) {
2730 .in.file.handle = h,
2731 .in.pattern = "*",
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,
2744 "hardlink",
2745 ret, done, "bad name");
2746 torture_assert_u64_equal_goto(tctx,
2747 snapshot_fileid,
2748 d[2].id_both_directory_info.file_id,
2749 ret, done, "bad fileid\n");
2751 done:
2752 return ret;
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;
2766 struct smb2_find f;
2767 unsigned int count;
2768 union smb_search_data *d;
2769 uint64_t expected_fileid;
2770 uint64_t returned_fileid;
2771 NTSTATUS status;
2772 bool ret = true;
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,
2788 .in.fname = fname,
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,
2811 expected_fileid,
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,
2822 .in.fname = fname,
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,
2847 expected_fileid,
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,
2858 .in.fname = fname,
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,
2883 expected_fileid,
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,
2895 .in.fname = fname,
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,
2916 expected_fileid,
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,
2938 expected_fileid,
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,
2950 .in.fname = sname,
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,
2975 expected_fileid,
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,
2987 .in.fname = sname,
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,
3012 expected_fileid,
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,
3024 .in.fname = sname,
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,
3049 expected_fileid,
3050 ret, done, "bad fileid\n");
3053 * Do some modifications on the stream (IO, setinfo), verifying File-ID
3054 * after each step.
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,
3061 .in.fname = sname,
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,
3082 expected_fileid,
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,
3104 expected_fileid,
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,
3115 .in.fname = fname,
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,
3140 expected_fileid,
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,
3160 expected_fileid,
3161 ret, done, "bad fileid\n");
3163 done:
3164 smb2_util_close(tree, testdirh);
3165 smb2_deltree(tree, DNAME);
3166 talloc_free(mem_ctx);
3167 return ret;
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;
3181 struct smb2_find f;
3182 unsigned int count;
3183 union smb_search_data *d;
3184 uint64_t expected_fileid;
3185 uint64_t returned_fileid;
3186 NTSTATUS status;
3187 bool ret = true;
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,
3204 .in.fname = dname,
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,
3227 expected_fileid,
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,
3239 .in.fname = dname,
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,
3264 expected_fileid,
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,
3276 .in.fname = sname,
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,
3301 expected_fileid,
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,
3313 .in.fname = sname,
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,
3338 expected_fileid,
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,
3350 .in.fname = sname,
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,
3375 expected_fileid,
3376 ret, done, "bad fileid\n");
3379 * Do some modifications on the stream (IO, setinfo), verifying File-ID
3380 * after each step.
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,
3387 .in.fname = sname,
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,
3408 expected_fileid,
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,
3430 expected_fileid,
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,
3442 .in.fname = dname,
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,
3467 expected_fileid,
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,
3487 expected_fileid,
3488 ret, done, "bad fileid\n");
3490 done:
3491 smb2_util_close(tree, testdirh);
3492 smb2_deltree(tree, DNAME);
3493 talloc_free(mem_ctx);
3494 return ret;
3497 static bool test_fileid_unique_object(
3498 struct torture_context *tctx,
3499 struct smb2_tree *tree,
3500 unsigned int num_objs,
3501 bool create_dirs)
3503 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3504 char *fname = NULL;
3505 struct smb2_handle testdirh;
3506 struct smb2_handle h1;
3507 struct smb2_create create;
3508 unsigned int i;
3509 uint64_t fileid_array[num_objs];
3510 NTSTATUS status;
3511 bool ret = true;
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,
3523 "%s\\testfile.%u",
3524 DNAME,
3526 torture_assert_goto(tctx,
3527 fname != NULL,
3528 ret,
3529 done,
3530 "talloc failed\n");
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,
3537 .in.fname = fname,
3540 if (create_dirs) {
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)) {
3547 torture_fail(tctx,
3548 talloc_asprintf(tctx,
3549 "test file %s could not be created\n",
3550 fname));
3551 TALLOC_FREE(fname);
3552 ret = false;
3553 goto done;
3556 h1 = create.out.file.handle;
3557 smb2_util_close(tree, h1);
3558 TALLOC_FREE(fname);
3562 * Get the file ids.
3564 for (i = 0; i < num_objs; i++) {
3565 union smb_fileinfo finfo;
3567 fname = talloc_asprintf(mem_ctx,
3568 "%s\\testfile.%u",
3569 DNAME,
3571 torture_assert_goto(tctx,
3572 fname != NULL,
3573 ret,
3574 done,
3575 "talloc failed\n");
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,
3582 .in.fname = fname,
3585 if (create_dirs) {
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)) {
3592 torture_fail(tctx,
3593 talloc_asprintf(tctx,
3594 "test file %s could not "
3595 "be opened: %s\n",
3596 fname,
3597 nt_errstr(status)));
3598 TALLOC_FREE(fname);
3599 ret = false;
3600 goto done;
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)) {
3612 torture_fail(tctx,
3613 talloc_asprintf(tctx,
3614 "failed to get fileid for "
3615 "test file %s: %s\n",
3616 fname,
3617 nt_errstr(status)));
3618 TALLOC_FREE(fname);
3619 ret = false;
3620 goto done;
3622 smb2_util_close(tree, h1);
3624 fileid_array[i] = finfo.all_info2.out.file_id;
3625 TALLOC_FREE(fname);
3628 /* All returned fileids must be unique. 100 is small so brute force. */
3629 for (i = 0; i < num_objs - 1; i++) {
3630 unsigned int j;
3631 for (j = i + 1; j < num_objs; j++) {
3632 if (fileid_array[i] == fileid_array[j]) {
3633 torture_fail(tctx,
3634 talloc_asprintf(tctx,
3635 "fileid %u == fileid %u (0x%"PRIu64")\n",
3638 fileid_array[i]));
3639 ret = false;
3640 goto done;
3645 done:
3647 smb2_util_close(tree, testdirh);
3648 smb2_deltree(tree, DNAME);
3649 talloc_free(mem_ctx);
3650 return ret;
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)
3670 bool ret = true;
3671 NTSTATUS status;
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,
3687 .in.fname = DNAME,
3690 status = smb2_create(tree, tctx, &c);
3691 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3692 "smb2_create\n");
3693 h1 = c.out.file.handle;
3695 /* Try to set temporary attribute on directory */
3696 SET_ATTRIB(FILE_ATTRIBUTE_TEMPORARY, NT_STATUS_INVALID_PARAMETER);
3698 done:
3699 if (!smb2_util_handle_empty(h1)) {
3700 smb2_util_close(tree, h1);
3702 smb2_util_unlink(tree, fname);
3703 smb2_deltree(tree, fname);
3705 return ret;
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}};
3717 NTSTATUS status;
3718 bool ret = true;
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,
3726 .in.fname = fname,
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,
3740 ret,
3741 done,
3742 "Wrong attributes\n");
3744 torture_assert_u64_equal_goto(tctx,
3745 create.out.create_time, 0,
3746 ret,
3747 done,
3748 "create_time is not 0\n");
3749 torture_assert_u64_equal_goto(tctx,
3750 create.out.access_time, 0,
3751 ret,
3752 done,
3753 "access_time is not 0\n");
3754 torture_assert_u64_equal_goto(tctx,
3755 create.out.write_time, 0,
3756 ret,
3757 done,
3758 "write_time is not 0\n");
3759 torture_assert_u64_equal_goto(tctx,
3760 create.out.change_time, 0,
3761 ret,
3762 done,
3763 "change_time is not 0\n");
3765 done:
3766 smb2_util_close(tree, h);
3767 return ret;
3771 Find Maximum Path Length
3773 static bool generate_path(const size_t len,
3774 char *buffer,
3775 const size_t buf_len)
3777 size_t i;
3779 if (len >= buf_len) {
3780 return false;
3783 for (i = 0; i < len ; i++) {
3784 buffer[i] = (char)(i % 10) + 48;
3786 buffer[i] = '\0';
3787 return true;
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);
3803 NTSTATUS status;
3804 bool ret = true;
3806 if (!is_interactive) {
3807 torture_result(tctx, TORTURE_SKIP,
3808 "Interactive Test: Skipping... "
3809 "(enable with --interactive)\n");
3810 return ret;
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.");
3820 return false;
3823 status = torture_smb2_testfile(tree, name, &fh);
3824 if (!NT_STATUS_IS_OK(status)) {
3825 break;
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,
3835 "Name too big\n");
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");
3855 return false;
3858 while (true) {
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)) {
3865 break;
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.");
3875 return false;
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)) {
3884 break;
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);
3894 done:
3895 return ret;
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");
3926 return suite;
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");
3940 return suite;
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");
3957 return suite;
3960 static bool test_no_stream(struct torture_context *tctx,
3961 struct smb2_tree *tree)
3963 struct smb2_create c;
3964 NTSTATUS status;
3965 bool ret = true;
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",
3971 NULL
3973 int i;
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)) {
3986 torture_comment(
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");
3993 done:
3994 return ret;
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");
4005 return suite;