Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : SMB2 create test suite
5 :
6 : Copyright (C) Andrew Tridgell 2008
7 :
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.
12 :
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.
17 :
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/>.
20 : */
21 :
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"
31 :
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"
37 :
38 : #define FNAME "test_create.dat"
39 : #define DNAME "smb2_open"
40 :
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)
48 :
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)
59 :
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)
77 :
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)
94 :
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)
108 :
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)
116 :
117 : #define SET_ATTRIB(sattrib) 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 : if (!NT_STATUS_IS_OK(status)) { \
125 : torture_comment(tctx, \
126 : "(%s) Failed to set attrib 0x%x on %s\n", \
127 : __location__, (unsigned int)(sattrib), fname); \
128 : }} while (0)
129 :
130 : /*
131 : test some interesting combinations found by gentest
132 : */
133 6 : static bool test_create_gentest(struct torture_context *tctx, struct smb2_tree *tree)
134 : {
135 0 : struct smb2_create io;
136 0 : NTSTATUS status;
137 0 : uint32_t access_mask, file_attributes_set;
138 0 : uint32_t ok_mask, not_supported_mask, invalid_parameter_mask;
139 0 : uint32_t not_a_directory_mask, unexpected_mask;
140 0 : union smb_fileinfo q;
141 :
142 6 : ZERO_STRUCT(io);
143 6 : io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
144 6 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
145 6 : io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
146 6 : io.in.share_access =
147 : NTCREATEX_SHARE_ACCESS_DELETE|
148 : NTCREATEX_SHARE_ACCESS_READ|
149 : NTCREATEX_SHARE_ACCESS_WRITE;
150 6 : io.in.create_options = 0;
151 6 : io.in.fname = FNAME;
152 :
153 6 : status = smb2_create(tree, tctx, &io);
154 6 : CHECK_STATUS(status, NT_STATUS_OK);
155 :
156 6 : status = smb2_util_close(tree, io.out.file.handle);
157 6 : CHECK_STATUS(status, NT_STATUS_OK);
158 :
159 6 : io.in.create_options = 0xF0000000;
160 6 : status = smb2_create(tree, tctx, &io);
161 6 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
162 :
163 6 : io.in.create_options = 0;
164 :
165 6 : io.in.file_attributes = FILE_ATTRIBUTE_DEVICE;
166 6 : status = smb2_create(tree, tctx, &io);
167 6 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
168 :
169 1 : io.in.file_attributes = FILE_ATTRIBUTE_VOLUME;
170 1 : status = smb2_create(tree, tctx, &io);
171 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
172 :
173 1 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
174 1 : io.in.file_attributes = FILE_ATTRIBUTE_VOLUME;
175 1 : status = smb2_create(tree, tctx, &io);
176 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
177 :
178 1 : io.in.create_disposition = NTCREATEX_DISP_CREATE;
179 1 : io.in.desired_access = 0x08000000;
180 1 : status = smb2_create(tree, tctx, &io);
181 1 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
182 :
183 1 : io.in.desired_access = 0x04000000;
184 1 : status = smb2_create(tree, tctx, &io);
185 1 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
186 :
187 1 : io.in.file_attributes = 0;
188 1 : io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
189 1 : io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
190 1 : ok_mask = 0;
191 1 : not_supported_mask = 0;
192 1 : invalid_parameter_mask = 0;
193 1 : not_a_directory_mask = 0;
194 1 : unexpected_mask = 0;
195 : {
196 0 : int i;
197 33 : for (i=0;i<32;i++) {
198 32 : io.in.create_options = (uint32_t)1<<i;
199 32 : if (io.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
200 1 : continue;
201 : }
202 31 : status = smb2_create(tree, tctx, &io);
203 31 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
204 3 : not_supported_mask |= 1<<i;
205 28 : } else if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
206 8 : invalid_parameter_mask |= 1<<i;
207 20 : } else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
208 1 : not_a_directory_mask |= 1<<i;
209 19 : } else if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
210 19 : ok_mask |= 1<<i;
211 19 : status = smb2_util_close(tree, io.out.file.handle);
212 19 : CHECK_STATUS(status, NT_STATUS_OK);
213 : } else {
214 0 : unexpected_mask |= 1<<i;
215 0 : torture_comment(tctx,
216 : "create option 0x%08x returned %s\n",
217 : 1<<i, nt_errstr(status));
218 : }
219 : }
220 : }
221 1 : io.in.create_options = 0;
222 :
223 1 : CHECK_EQUAL(ok_mask, 0x00efcf7e);
224 1 : CHECK_EQUAL(not_a_directory_mask, 0x00000001);
225 1 : CHECK_EQUAL(not_supported_mask, 0x00102080);
226 1 : CHECK_EQUAL(invalid_parameter_mask, 0xff000000);
227 1 : CHECK_EQUAL(unexpected_mask, 0x00000000);
228 :
229 1 : io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
230 1 : io.in.file_attributes = 0;
231 1 : access_mask = 0;
232 : {
233 0 : int i;
234 33 : for (i=0;i<32;i++) {
235 32 : io.in.desired_access = (uint32_t)1<<i;
236 32 : status = smb2_create(tree, tctx, &io);
237 32 : if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
238 19 : NT_STATUS_EQUAL(status, NT_STATUS_PRIVILEGE_NOT_HELD)) {
239 13 : access_mask |= io.in.desired_access;
240 : } else {
241 19 : CHECK_STATUS(status, NT_STATUS_OK);
242 19 : status = smb2_util_close(tree, io.out.file.handle);
243 19 : CHECK_STATUS(status, NT_STATUS_OK);
244 : }
245 : }
246 : }
247 :
248 1 : if (TARGET_IS_WIN7(tctx)) {
249 0 : CHECK_EQUAL(access_mask, 0x0de0fe00);
250 1 : } else if (torture_setting_bool(tctx, "samba4", false)) {
251 1 : CHECK_EQUAL(access_mask, 0x0cf0fe00);
252 : } else {
253 0 : CHECK_EQUAL(access_mask, 0x0df0fe00);
254 : }
255 :
256 1 : io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
257 1 : io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
258 1 : io.in.file_attributes = 0;
259 1 : ok_mask = 0;
260 1 : invalid_parameter_mask = 0;
261 1 : unexpected_mask = 0;
262 1 : file_attributes_set = 0;
263 : {
264 0 : int i;
265 33 : for (i=0;i<32;i++) {
266 32 : io.in.file_attributes = (uint32_t)1<<i;
267 32 : if (io.in.file_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
268 1 : continue;
269 : }
270 31 : smb2_deltree(tree, FNAME);
271 31 : status = smb2_create(tree, tctx, &io);
272 31 : if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
273 19 : invalid_parameter_mask |= 1<<i;
274 12 : } else if (NT_STATUS_IS_OK(status)) {
275 0 : uint32_t expected;
276 12 : ok_mask |= 1<<i;
277 :
278 12 : expected = (io.in.file_attributes | FILE_ATTRIBUTE_ARCHIVE) & 0x00005127;
279 12 : io.out.file_attr &= ~FILE_ATTRIBUTE_NONINDEXED;
280 12 : CHECK_EQUAL(io.out.file_attr, expected);
281 12 : file_attributes_set |= io.out.file_attr;
282 :
283 12 : status = smb2_util_close(tree, io.out.file.handle);
284 12 : CHECK_STATUS(status, NT_STATUS_OK);
285 : } else {
286 0 : unexpected_mask |= 1<<i;
287 0 : torture_comment(tctx,
288 : "file attribute 0x%08x returned %s\n",
289 : 1<<i, nt_errstr(status));
290 : }
291 : }
292 : }
293 :
294 1 : CHECK_EQUAL(ok_mask, 0x00003fb7);
295 1 : CHECK_EQUAL(invalid_parameter_mask, 0xffff8048);
296 1 : CHECK_EQUAL(unexpected_mask, 0x00000000);
297 1 : CHECK_EQUAL(file_attributes_set, 0x00001127);
298 :
299 1 : smb2_deltree(tree, FNAME);
300 :
301 : /*
302 : * Standalone servers doesn't support encryption
303 : */
304 1 : io.in.file_attributes = FILE_ATTRIBUTE_ENCRYPTED;
305 1 : status = smb2_create(tree, tctx, &io);
306 1 : if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
307 1 : torture_comment(tctx,
308 : "FILE_ATTRIBUTE_ENCRYPTED returned %s\n",
309 : nt_errstr(status));
310 : } else {
311 0 : CHECK_STATUS(status, NT_STATUS_OK);
312 0 : CHECK_EQUAL(io.out.file_attr, (FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_ARCHIVE));
313 0 : status = smb2_util_close(tree, io.out.file.handle);
314 0 : CHECK_STATUS(status, NT_STATUS_OK);
315 : }
316 :
317 1 : smb2_deltree(tree, FNAME);
318 :
319 1 : ZERO_STRUCT(io);
320 1 : io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
321 1 : io.in.file_attributes = 0;
322 1 : io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
323 1 : io.in.share_access =
324 : NTCREATEX_SHARE_ACCESS_READ|
325 : NTCREATEX_SHARE_ACCESS_WRITE;
326 1 : io.in.create_options = 0;
327 1 : io.in.fname = FNAME ":stream1";
328 1 : status = smb2_create(tree, tctx, &io);
329 1 : CHECK_STATUS(status, NT_STATUS_OK);
330 :
331 1 : status = smb2_util_close(tree, io.out.file.handle);
332 1 : CHECK_STATUS(status, NT_STATUS_OK);
333 :
334 1 : io.in.fname = FNAME;
335 1 : io.in.file_attributes = 0x8040;
336 1 : io.in.share_access =
337 : NTCREATEX_SHARE_ACCESS_READ;
338 1 : status = smb2_create(tree, tctx, &io);
339 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
340 :
341 1 : io.in.fname = FNAME;
342 1 : io.in.file_attributes = 0;
343 1 : io.in.desired_access = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA;
344 1 : io.in.query_maximal_access = true;
345 1 : status = smb2_create(tree, tctx, &io);
346 1 : CHECK_STATUS(status, NT_STATUS_OK);
347 1 : CHECK_EQUAL(io.out.maximal_access, 0x001f01ff);
348 :
349 1 : q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION;
350 1 : q.access_information.in.file.handle = io.out.file.handle;
351 1 : status = smb2_getinfo_file(tree, tctx, &q);
352 1 : CHECK_STATUS(status, NT_STATUS_OK);
353 1 : CHECK_EQUAL(q.access_information.out.access_flags, io.in.desired_access);
354 :
355 1 : io.in.file_attributes = 0;
356 1 : io.in.desired_access = 0;
357 1 : io.in.query_maximal_access = false;
358 1 : io.in.share_access = 0;
359 1 : status = smb2_create(tree, tctx, &io);
360 1 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
361 :
362 1 : smb2_deltree(tree, FNAME);
363 :
364 1 : return true;
365 : }
366 :
367 :
368 : /*
369 : try the various request blobs
370 : */
371 6 : static bool test_create_blob(struct torture_context *tctx, struct smb2_tree *tree)
372 : {
373 0 : struct smb2_create io;
374 0 : NTSTATUS status;
375 :
376 6 : smb2_deltree(tree, FNAME);
377 :
378 6 : ZERO_STRUCT(io);
379 6 : io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
380 6 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
381 6 : io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
382 6 : io.in.share_access =
383 : NTCREATEX_SHARE_ACCESS_DELETE|
384 : NTCREATEX_SHARE_ACCESS_READ|
385 : NTCREATEX_SHARE_ACCESS_WRITE;
386 6 : io.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
387 : NTCREATEX_OPTIONS_ASYNC_ALERT |
388 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
389 : 0x00200000;
390 6 : io.in.fname = FNAME;
391 :
392 6 : status = smb2_create(tree, tctx, &io);
393 6 : CHECK_STATUS(status, NT_STATUS_OK);
394 :
395 6 : status = smb2_util_close(tree, io.out.file.handle);
396 6 : CHECK_STATUS(status, NT_STATUS_OK);
397 :
398 6 : 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 6 : io.in.alloc_size = 0x00100000;
403 6 : status = smb2_create(tree, tctx, &io);
404 6 : CHECK_STATUS(status, NT_STATUS_OK);
405 6 : CHECK_EQUAL(io.out.alloc_size, io.in.alloc_size);
406 :
407 6 : status = smb2_util_close(tree, io.out.file.handle);
408 6 : CHECK_STATUS(status, NT_STATUS_OK);
409 :
410 6 : torture_comment(tctx, "Testing durable open\n");
411 6 : io.in.durable_open = true;
412 6 : status = smb2_create(tree, tctx, &io);
413 6 : CHECK_STATUS(status, NT_STATUS_OK);
414 :
415 6 : status = smb2_util_close(tree, io.out.file.handle);
416 6 : CHECK_STATUS(status, NT_STATUS_OK);
417 :
418 6 : torture_comment(tctx, "Testing query maximal access\n");
419 6 : io.in.query_maximal_access = true;
420 6 : status = smb2_create(tree, tctx, &io);
421 6 : CHECK_STATUS(status, NT_STATUS_OK);
422 6 : CHECK_EQUAL(io.out.maximal_access, 0x001f01ff);
423 :
424 6 : status = smb2_util_close(tree, io.out.file.handle);
425 6 : CHECK_STATUS(status, NT_STATUS_OK);
426 :
427 6 : torture_comment(tctx, "Testing timewarp\n");
428 6 : io.in.timewarp = 10000;
429 6 : status = smb2_create(tree, tctx, &io);
430 6 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
431 1 : io.in.timewarp = 0;
432 :
433 1 : torture_comment(tctx, "Testing query_on_disk\n");
434 1 : io.in.query_on_disk_id = true;
435 1 : status = smb2_create(tree, tctx, &io);
436 1 : CHECK_STATUS(status, NT_STATUS_OK);
437 :
438 1 : status = smb2_util_close(tree, io.out.file.handle);
439 1 : CHECK_STATUS(status, NT_STATUS_OK);
440 :
441 1 : torture_comment(tctx, "Testing unknown tag\n");
442 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
443 : "FooO", data_blob(NULL, 0));
444 1 : CHECK_STATUS(status, NT_STATUS_OK);
445 :
446 1 : status = smb2_create(tree, tctx, &io);
447 1 : CHECK_STATUS(status, NT_STATUS_OK);
448 :
449 1 : status = smb2_util_close(tree, io.out.file.handle);
450 1 : CHECK_STATUS(status, NT_STATUS_OK);
451 :
452 1 : torture_comment(tctx, "Testing bad tag length 0\n");
453 1 : ZERO_STRUCT(io.in.blobs);
454 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
455 : "x", data_blob(NULL, 0));
456 1 : CHECK_STATUS(status, NT_STATUS_OK);
457 1 : status = smb2_create(tree, tctx, &io);
458 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
459 :
460 1 : torture_comment(tctx, "Testing bad tag length 1\n");
461 1 : ZERO_STRUCT(io.in.blobs);
462 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
463 : "x", data_blob(NULL, 0));
464 1 : CHECK_STATUS(status, NT_STATUS_OK);
465 1 : status = smb2_create(tree, tctx, &io);
466 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
467 :
468 1 : torture_comment(tctx, "Testing bad tag length 2\n");
469 1 : ZERO_STRUCT(io.in.blobs);
470 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
471 : "xx", data_blob(NULL, 0));
472 1 : CHECK_STATUS(status, NT_STATUS_OK);
473 1 : status = smb2_create(tree, tctx, &io);
474 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
475 :
476 1 : torture_comment(tctx, "Testing bad tag length 3\n");
477 1 : ZERO_STRUCT(io.in.blobs);
478 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
479 : "xxx", data_blob(NULL, 0));
480 1 : CHECK_STATUS(status, NT_STATUS_OK);
481 1 : status = smb2_create(tree, tctx, &io);
482 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
483 :
484 1 : torture_comment(tctx, "Testing tag length 4\n");
485 1 : ZERO_STRUCT(io.in.blobs);
486 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
487 : "xxxx", data_blob(NULL, 0));
488 1 : CHECK_STATUS(status, NT_STATUS_OK);
489 1 : status = smb2_create(tree, tctx, &io);
490 1 : CHECK_STATUS(status, NT_STATUS_OK);
491 :
492 1 : torture_comment(tctx, "Testing tag length 5\n");
493 1 : ZERO_STRUCT(io.in.blobs);
494 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
495 : "xxxxx", data_blob(NULL, 0));
496 1 : CHECK_STATUS(status, NT_STATUS_OK);
497 1 : status = smb2_create(tree, tctx, &io);
498 1 : CHECK_STATUS(status, NT_STATUS_OK);
499 :
500 1 : torture_comment(tctx, "Testing tag length 6\n");
501 1 : ZERO_STRUCT(io.in.blobs);
502 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
503 : "xxxxxx", data_blob(NULL, 0));
504 1 : CHECK_STATUS(status, NT_STATUS_OK);
505 1 : status = smb2_create(tree, tctx, &io);
506 1 : CHECK_STATUS(status, NT_STATUS_OK);
507 :
508 1 : torture_comment(tctx, "Testing tag length 7\n");
509 1 : ZERO_STRUCT(io.in.blobs);
510 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
511 : "xxxxxxx", data_blob(NULL, 0));
512 1 : CHECK_STATUS(status, NT_STATUS_OK);
513 1 : status = smb2_create(tree, tctx, &io);
514 1 : CHECK_STATUS(status, NT_STATUS_OK);
515 :
516 1 : torture_comment(tctx, "Testing tag length 8\n");
517 1 : ZERO_STRUCT(io.in.blobs);
518 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
519 : "xxxxxxxx", data_blob(NULL, 0));
520 1 : CHECK_STATUS(status, NT_STATUS_OK);
521 1 : status = smb2_create(tree, tctx, &io);
522 1 : CHECK_STATUS(status, NT_STATUS_OK);
523 :
524 1 : torture_comment(tctx, "Testing tag length 16\n");
525 1 : ZERO_STRUCT(io.in.blobs);
526 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
527 : "xxxxxxxxxxxxxxxx", data_blob(NULL, 0));
528 1 : CHECK_STATUS(status, NT_STATUS_OK);
529 1 : status = smb2_create(tree, tctx, &io);
530 1 : CHECK_STATUS(status, NT_STATUS_OK);
531 :
532 1 : torture_comment(tctx, "Testing tag length 17\n");
533 1 : ZERO_STRUCT(io.in.blobs);
534 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
535 : "xxxxxxxxxxxxxxxxx", data_blob(NULL, 0));
536 1 : CHECK_STATUS(status, NT_STATUS_OK);
537 1 : status = smb2_create(tree, tctx, &io);
538 1 : CHECK_STATUS(status, NT_STATUS_OK);
539 :
540 1 : torture_comment(tctx, "Testing tag length 34\n");
541 1 : ZERO_STRUCT(io.in.blobs);
542 1 : status = smb2_create_blob_add(tctx, &io.in.blobs,
543 : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
544 : data_blob(NULL, 0));
545 1 : CHECK_STATUS(status, NT_STATUS_OK);
546 1 : status = smb2_create(tree, tctx, &io);
547 1 : CHECK_STATUS(status, NT_STATUS_OK);
548 :
549 1 : smb2_deltree(tree, FNAME);
550 :
551 1 : return true;
552 : }
553 :
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; \
560 : } \
561 : } while(0)
562 :
563 : /*
564 : try creating with acls
565 : */
566 12 : static bool test_create_acl_ext(struct torture_context *tctx, struct smb2_tree *tree, bool test_dir)
567 : {
568 12 : bool ret = true;
569 0 : struct smb2_create io;
570 0 : NTSTATUS status;
571 0 : struct security_ace ace;
572 0 : struct security_descriptor *sd;
573 0 : struct dom_sid *test_sid;
574 12 : union smb_fileinfo q = {};
575 12 : uint32_t attrib =
576 : FILE_ATTRIBUTE_HIDDEN |
577 : FILE_ATTRIBUTE_SYSTEM |
578 : (test_dir ? FILE_ATTRIBUTE_DIRECTORY : 0);
579 12 : NTSTATUS (*delete_func)(struct smb2_tree *, const char *) =
580 12 : test_dir ? smb2_util_rmdir : smb2_util_unlink;
581 :
582 12 : ZERO_STRUCT(ace);
583 :
584 12 : smb2_deltree(tree, FNAME);
585 :
586 12 : ZERO_STRUCT(io);
587 12 : io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
588 12 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
589 12 : io.in.create_disposition = NTCREATEX_DISP_CREATE;
590 12 : io.in.share_access =
591 : NTCREATEX_SHARE_ACCESS_DELETE |
592 : NTCREATEX_SHARE_ACCESS_READ |
593 : NTCREATEX_SHARE_ACCESS_WRITE;
594 12 : io.in.create_options = NTCREATEX_OPTIONS_ASYNC_ALERT | 0x00200000 |
595 : (test_dir ? NTCREATEX_OPTIONS_DIRECTORY :
596 : (NTCREATEX_OPTIONS_NON_DIRECTORY_FILE));
597 :
598 12 : io.in.fname = FNAME;
599 :
600 12 : torture_comment(tctx, "basic create\n");
601 :
602 12 : status = smb2_create(tree, tctx, &io);
603 12 : CHECK_STATUS(status, NT_STATUS_OK);
604 :
605 12 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
606 12 : q.query_secdesc.in.file.handle = io.out.file.handle;
607 12 : q.query_secdesc.in.secinfo_flags =
608 : SECINFO_OWNER |
609 : SECINFO_GROUP |
610 : SECINFO_DACL;
611 12 : status = smb2_getinfo_file(tree, tctx, &q);
612 12 : CHECK_STATUS(status, NT_STATUS_OK);
613 12 : sd = q.query_secdesc.out.sd;
614 :
615 12 : status = smb2_util_close(tree, io.out.file.handle);
616 12 : CHECK_STATUS(status, NT_STATUS_OK);
617 12 : status = delete_func(tree, FNAME);
618 12 : CHECK_STATUS(status, NT_STATUS_OK);
619 :
620 12 : torture_comment(tctx, "adding a new ACE\n");
621 12 : test_sid = dom_sid_parse_talloc(tctx, SID_NT_AUTHENTICATED_USERS);
622 :
623 12 : ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
624 12 : ace.flags = 0;
625 12 : ace.access_mask = SEC_STD_ALL;
626 12 : ace.trustee = *test_sid;
627 :
628 12 : status = security_descriptor_dacl_add(sd, &ace);
629 12 : CHECK_STATUS(status, NT_STATUS_OK);
630 :
631 12 : torture_comment(tctx, "creating a file with an initial ACL\n");
632 :
633 12 : io.in.sec_desc = sd;
634 12 : status = smb2_create(tree, tctx, &io);
635 12 : CHECK_STATUS(status, NT_STATUS_OK);
636 :
637 12 : FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, io.out.file.handle, sd));
638 :
639 12 : status = smb2_util_close(tree, io.out.file.handle);
640 12 : CHECK_STATUS(status, NT_STATUS_OK);
641 12 : status = delete_func(tree, FNAME);
642 12 : CHECK_STATUS(status, NT_STATUS_OK);
643 :
644 12 : torture_comment(tctx, "creating with attributes\n");
645 :
646 12 : io.in.sec_desc = NULL;
647 12 : io.in.file_attributes = attrib;
648 12 : status = smb2_create(tree, tctx, &io);
649 12 : CHECK_STATUS(status, NT_STATUS_OK);
650 :
651 12 : FAIL_UNLESS(smb2_util_verify_attrib(tctx, tree, io.out.file.handle, attrib));
652 :
653 11 : status = smb2_util_close(tree, io.out.file.handle);
654 11 : CHECK_STATUS(status, NT_STATUS_OK);
655 11 : status = delete_func(tree, FNAME);
656 11 : CHECK_STATUS(status, NT_STATUS_OK);
657 :
658 11 : torture_comment(tctx, "creating with attributes and ACL\n");
659 :
660 11 : io.in.sec_desc = sd;
661 11 : io.in.file_attributes = attrib;
662 11 : status = smb2_create(tree, tctx, &io);
663 11 : CHECK_STATUS(status, NT_STATUS_OK);
664 :
665 11 : FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, io.out.file.handle, sd));
666 11 : FAIL_UNLESS(smb2_util_verify_attrib(tctx, tree, io.out.file.handle, attrib));
667 :
668 11 : status = smb2_util_close(tree, io.out.file.handle);
669 11 : CHECK_STATUS(status, NT_STATUS_OK);
670 11 : status = delete_func(tree, FNAME);
671 11 : CHECK_STATUS(status, NT_STATUS_OK);
672 :
673 11 : torture_comment(tctx, "creating with attributes, ACL and owner\n");
674 11 : 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,
679 : 0,
680 : NULL);
681 :
682 11 : io.in.sec_desc = sd;
683 11 : io.in.file_attributes = attrib;
684 11 : status = smb2_create(tree, tctx, &io);
685 11 : CHECK_STATUS(status, NT_STATUS_OK);
686 :
687 11 : FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, io.out.file.handle, sd));
688 11 : FAIL_UNLESS(smb2_util_verify_attrib(tctx, tree, io.out.file.handle, attrib));
689 :
690 12 : done:
691 12 : status = smb2_util_close(tree, io.out.file.handle);
692 12 : CHECK_STATUS(status, NT_STATUS_OK);
693 12 : status = delete_func(tree, FNAME);
694 12 : CHECK_STATUS(status, NT_STATUS_OK);
695 :
696 12 : return ret;
697 : }
698 :
699 : /*
700 : test SMB2 open
701 : */
702 6 : static bool test_smb2_open(struct torture_context *tctx,
703 : struct smb2_tree *tree)
704 : {
705 0 : union smb_open io;
706 0 : union smb_fileinfo finfo;
707 6 : const char *fname = DNAME "\\torture_ntcreatex.txt";
708 6 : const char *dname = DNAME "\\torture_ntcreatex.dir";
709 0 : NTSTATUS status;
710 6 : struct smb2_handle h = {{0}};
711 6 : struct smb2_handle h1 = {{0}};
712 6 : bool ret = true;
713 0 : size_t i;
714 0 : struct {
715 : uint32_t create_disp;
716 : bool with_file;
717 : NTSTATUS correct_status;
718 6 : } 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 },
733 : };
734 :
735 6 : torture_comment(tctx, "Checking SMB2 Open\n");
736 :
737 6 : smb2_util_unlink(tree, fname);
738 6 : smb2_util_rmdir(tree, dname);
739 :
740 6 : status = torture_smb2_testdir(tree, DNAME, &h);
741 6 : CHECK_STATUS(status, NT_STATUS_OK);
742 :
743 6 : ZERO_STRUCT(io.smb2);
744 : /* reasonable default parameters */
745 6 : io.generic.level = RAW_OPEN_SMB2;
746 6 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
747 6 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
748 6 : io.smb2.in.alloc_size = 1024*1024;
749 6 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
750 6 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
751 6 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
752 6 : io.smb2.in.create_options = 0;
753 6 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
754 6 : io.smb2.in.security_flags = 0;
755 6 : io.smb2.in.fname = fname;
756 :
757 : /* test the create disposition */
758 90 : for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
759 84 : if (open_funcs[i].with_file) {
760 42 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
761 42 : status= smb2_create(tree, tctx, &(io.smb2));
762 42 : if (!NT_STATUS_IS_OK(status)) {
763 0 : torture_comment(tctx,
764 : "Failed to create file %s status %s %zu\n",
765 : fname, nt_errstr(status), i);
766 :
767 0 : ret = false;
768 0 : goto done;
769 : }
770 42 : smb2_util_close(tree, io.smb2.out.file.handle);
771 : }
772 84 : io.smb2.in.create_disposition = open_funcs[i].create_disp;
773 84 : status = smb2_create(tree, tctx, &(io.smb2));
774 84 : if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
775 0 : torture_comment(tctx,
776 : "(%s) incorrect status %s should be %s (i=%zu "
777 : "with_file=%d open_disp=%d)\n",
778 : __location__, nt_errstr(status),
779 : nt_errstr(open_funcs[i].correct_status),
780 0 : i, (int)open_funcs[i].with_file,
781 0 : (int)open_funcs[i].create_disp);
782 :
783 0 : ret = false;
784 0 : goto done;
785 : }
786 84 : if (NT_STATUS_IS_OK(status) || open_funcs[i].with_file) {
787 66 : smb2_util_close(tree, io.smb2.out.file.handle);
788 66 : smb2_util_unlink(tree, fname);
789 : }
790 : }
791 :
792 : /* basic field testing */
793 6 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
794 :
795 6 : status = smb2_create(tree, tctx, &(io.smb2));
796 6 : CHECK_STATUS(status, NT_STATUS_OK);
797 6 : h1 = io.smb2.out.file.handle;
798 :
799 6 : CHECK_VAL(io.smb2.out.oplock_level, 0);
800 6 : CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED);
801 6 : CHECK_NTTIME(io.smb2.out.create_time, create_time);
802 6 : CHECK_NTTIME(io.smb2.out.access_time, access_time);
803 6 : CHECK_NTTIME(io.smb2.out.write_time, write_time);
804 6 : CHECK_NTTIME(io.smb2.out.change_time, change_time);
805 6 : CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
806 6 : CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size);
807 6 : CHECK_ALL_INFO(io.smb2.out.size, size);
808 :
809 : /* check fields when the file already existed */
810 6 : smb2_util_close(tree, h1);
811 6 : smb2_util_unlink(tree, fname);
812 :
813 6 : status = smb2_create_complex_file(tctx, tree, fname, &h1);
814 6 : CHECK_STATUS(status, NT_STATUS_OK);
815 :
816 1 : smb2_util_close(tree, h1);
817 :
818 1 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
819 1 : status = smb2_create(tree, tctx, &(io.smb2));
820 1 : CHECK_STATUS(status, NT_STATUS_OK);
821 1 : h1 = io.smb2.out.file.handle;
822 :
823 1 : CHECK_VAL(io.smb2.out.oplock_level, 0);
824 1 : CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_EXISTED);
825 1 : CHECK_NTTIME(io.smb2.out.create_time, create_time);
826 1 : CHECK_NTTIME(io.smb2.out.access_time, access_time);
827 1 : CHECK_NTTIME(io.smb2.out.write_time, write_time);
828 1 : CHECK_NTTIME(io.smb2.out.change_time, change_time);
829 1 : CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
830 1 : CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size);
831 1 : CHECK_ALL_INFO(io.smb2.out.size, size);
832 1 : smb2_util_close(tree, h1);
833 1 : smb2_util_unlink(tree, fname);
834 :
835 : /* create a directory */
836 1 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
837 1 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
838 1 : io.smb2.in.alloc_size = 0;
839 1 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
840 1 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
841 1 : io.smb2.in.create_options = 0;
842 1 : io.smb2.in.fname = dname;
843 1 : fname = dname;
844 :
845 1 : smb2_util_rmdir(tree, fname);
846 1 : smb2_util_unlink(tree, fname);
847 :
848 1 : io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
849 1 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
850 1 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
851 1 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
852 : NTCREATEX_SHARE_ACCESS_WRITE;
853 1 : status = smb2_create(tree, tctx, &(io.smb2));
854 1 : CHECK_STATUS(status, NT_STATUS_OK);
855 1 : h1 = io.smb2.out.file.handle;
856 :
857 1 : CHECK_VAL(io.smb2.out.oplock_level, 0);
858 1 : CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED);
859 1 : CHECK_NTTIME(io.smb2.out.create_time, create_time);
860 1 : CHECK_NTTIME(io.smb2.out.access_time, access_time);
861 1 : CHECK_NTTIME(io.smb2.out.write_time, write_time);
862 1 : CHECK_NTTIME(io.smb2.out.change_time, change_time);
863 1 : CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
864 1 : CHECK_VAL(io.smb2.out.file_attr & ~FILE_ATTRIBUTE_NONINDEXED,
865 : FILE_ATTRIBUTE_DIRECTORY);
866 1 : CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size);
867 1 : CHECK_ALL_INFO(io.smb2.out.size, size);
868 1 : CHECK_VAL(io.smb2.out.size, 0);
869 1 : smb2_util_unlink(tree, fname);
870 :
871 1 : done:
872 1 : smb2_util_close(tree, h1);
873 1 : smb2_util_unlink(tree, fname);
874 1 : smb2_deltree(tree, DNAME);
875 1 : return ret;
876 : }
877 :
878 : /*
879 : test with an already opened and byte range locked file
880 : */
881 :
882 6 : static bool test_smb2_open_brlocked(struct torture_context *tctx,
883 : struct smb2_tree *tree)
884 : {
885 0 : union smb_open io, io1;
886 0 : union smb_lock io2;
887 0 : struct smb2_lock_element lock[1];
888 6 : const char *fname = DNAME "\\torture_ntcreatex.txt";
889 0 : NTSTATUS status;
890 6 : bool ret = true;
891 0 : struct smb2_handle h;
892 6 : char b = 42;
893 :
894 6 : torture_comment(tctx,
895 : "Testing SMB2 open with a byte range locked file\n");
896 :
897 6 : smb2_util_unlink(tree, fname);
898 :
899 6 : status = torture_smb2_testdir(tree, DNAME, &h);
900 6 : CHECK_STATUS(status, NT_STATUS_OK);
901 :
902 6 : ZERO_STRUCT(io.smb2);
903 6 : io.generic.level = RAW_OPEN_SMB2;
904 6 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
905 6 : io.smb2.in.desired_access = 0x2019f;
906 6 : io.smb2.in.alloc_size = 0;
907 6 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
908 6 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
909 : NTCREATEX_SHARE_ACCESS_WRITE;
910 6 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
911 6 : io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
912 6 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
913 6 : io.smb2.in.security_flags = SMB2_SECURITY_DYNAMIC_TRACKING;
914 6 : io.smb2.in.fname = fname;
915 :
916 6 : status = smb2_create(tree, tctx, &(io.smb2));
917 6 : CHECK_STATUS(status, NT_STATUS_OK);
918 :
919 6 : status = smb2_util_write(tree, io.smb2.out.file.handle, &b, 0, 1);
920 6 : CHECK_STATUS(status, NT_STATUS_OK);
921 :
922 6 : ZERO_STRUCT(io2.smb2);
923 6 : io2.smb2.level = RAW_LOCK_SMB2;
924 6 : io2.smb2.in.file.handle = io.smb2.out.file.handle;
925 6 : io2.smb2.in.lock_count = 1;
926 :
927 6 : ZERO_STRUCT(lock);
928 6 : lock[0].offset = 0;
929 6 : lock[0].length = 1;
930 6 : lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
931 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
932 6 : io2.smb2.in.locks = &lock[0];
933 6 : status = smb2_lock(tree, &(io2.smb2));
934 6 : CHECK_STATUS(status, NT_STATUS_OK);
935 :
936 6 : ZERO_STRUCT(io1.smb2);
937 6 : io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
938 6 : io1.smb2.in.desired_access = 0x20196;
939 6 : io1.smb2.in.alloc_size = 0;
940 6 : io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
941 6 : io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
942 : NTCREATEX_SHARE_ACCESS_WRITE;
943 6 : io1.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
944 6 : io1.smb2.in.create_options = 0;
945 6 : io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
946 6 : io1.smb2.in.security_flags = SMB2_SECURITY_DYNAMIC_TRACKING;
947 6 : io1.smb2.in.fname = fname;
948 :
949 6 : status = smb2_create(tree, tctx, &(io1.smb2));
950 6 : CHECK_STATUS(status, NT_STATUS_OK);
951 :
952 6 : smb2_util_close(tree, io.smb2.out.file.handle);
953 6 : smb2_util_close(tree, io1.smb2.out.file.handle);
954 6 : smb2_util_unlink(tree, fname);
955 6 : smb2_deltree(tree, DNAME);
956 :
957 6 : return ret;
958 : }
959 :
960 : /* A little torture test to expose a race condition in Samba 3.0.20 ... :-) */
961 :
962 6 : static bool test_smb2_open_multi(struct torture_context *tctx,
963 : struct smb2_tree *tree)
964 : {
965 6 : const char *fname = "test_oplock.dat";
966 0 : NTSTATUS status;
967 6 : bool ret = true;
968 0 : union smb_open io;
969 0 : struct smb2_tree **trees;
970 0 : struct smb2_request **requests;
971 0 : union smb_open *ios;
972 6 : int i, num_files = 3;
973 6 : int num_ok = 0;
974 6 : int num_collision = 0;
975 :
976 6 : torture_comment(tctx,
977 : "Testing SMB2 Open with multiple connections\n");
978 6 : trees = talloc_array(tctx, struct smb2_tree *, num_files);
979 6 : requests = talloc_array(tctx, struct smb2_request *, num_files);
980 6 : ios = talloc_array(tctx, union smb_open, num_files);
981 6 : if ((tctx->ev == NULL) || (trees == NULL) || (requests == NULL) ||
982 : (ios == NULL)) {
983 0 : torture_comment(tctx, ("talloc failed\n"));
984 0 : ret = false;
985 0 : goto done;
986 : }
987 :
988 6 : tree->session->transport->options.request_timeout = 60;
989 :
990 24 : for (i=0; i<num_files; i++) {
991 18 : if (!torture_smb2_connection(tctx, &(trees[i]))) {
992 0 : torture_comment(tctx,
993 : "Could not open %d'th connection\n", i);
994 0 : ret = false;
995 0 : goto done;
996 : }
997 18 : trees[i]->session->transport->options.request_timeout = 60;
998 : }
999 :
1000 : /* cleanup */
1001 6 : smb2_util_unlink(tree, fname);
1002 :
1003 : /*
1004 : base ntcreatex parms
1005 : */
1006 6 : ZERO_STRUCT(io.smb2);
1007 6 : io.generic.level = RAW_OPEN_SMB2;
1008 6 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1009 6 : io.smb2.in.alloc_size = 0;
1010 6 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1011 6 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1012 : NTCREATEX_SHARE_ACCESS_WRITE|
1013 : NTCREATEX_SHARE_ACCESS_DELETE;
1014 6 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1015 6 : io.smb2.in.create_options = 0;
1016 6 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1017 6 : io.smb2.in.security_flags = 0;
1018 6 : io.smb2.in.fname = fname;
1019 6 : io.smb2.in.create_flags = 0;
1020 :
1021 24 : for (i=0; i<num_files; i++) {
1022 18 : ios[i] = io;
1023 18 : requests[i] = smb2_create_send(trees[i], &(ios[i].smb2));
1024 18 : if (requests[i] == NULL) {
1025 0 : torture_comment(tctx,
1026 : "could not send %d'th request\n", i);
1027 0 : ret = false;
1028 0 : goto done;
1029 : }
1030 : }
1031 :
1032 6 : torture_comment(tctx, "waiting for replies\n");
1033 72 : while (1) {
1034 78 : bool unreplied = false;
1035 107 : for (i=0; i<num_files; i++) {
1036 101 : if (requests[i] == NULL) {
1037 11 : continue;
1038 : }
1039 90 : if (requests[i]->state < SMB2_REQUEST_DONE) {
1040 72 : unreplied = true;
1041 72 : break;
1042 : }
1043 18 : status = smb2_create_recv(requests[i], tctx,
1044 18 : &(ios[i].smb2));
1045 :
1046 18 : torture_comment(tctx,
1047 : "File %d returned status %s\n", i,
1048 : nt_errstr(status));
1049 :
1050 18 : if (NT_STATUS_IS_OK(status)) {
1051 6 : num_ok += 1;
1052 : }
1053 :
1054 18 : if (NT_STATUS_EQUAL(status,
1055 : NT_STATUS_OBJECT_NAME_COLLISION)) {
1056 12 : num_collision += 1;
1057 : }
1058 :
1059 18 : requests[i] = NULL;
1060 : }
1061 78 : if (!unreplied) {
1062 6 : break;
1063 : }
1064 :
1065 72 : if (tevent_loop_once(tctx->ev) != 0) {
1066 0 : torture_comment(tctx, "tevent_loop_once failed\n");
1067 0 : ret = false;
1068 0 : goto done;
1069 : }
1070 : }
1071 :
1072 6 : if ((num_ok != 1) || (num_ok + num_collision != num_files)) {
1073 0 : ret = false;
1074 : }
1075 6 : done:
1076 6 : smb2_deltree(tree, fname);
1077 :
1078 6 : return ret;
1079 : }
1080 :
1081 : /*
1082 : test opening for delete on a read-only attribute file.
1083 : */
1084 :
1085 6 : static bool test_smb2_open_for_delete(struct torture_context *tctx,
1086 : struct smb2_tree *tree)
1087 : {
1088 0 : union smb_open io;
1089 0 : union smb_fileinfo finfo;
1090 6 : const char *fname = DNAME "\\torture_open_for_delete.txt";
1091 0 : NTSTATUS status;
1092 0 : struct smb2_handle h, h1;
1093 6 : bool ret = true;
1094 :
1095 6 : torture_comment(tctx,
1096 : "Checking SMB2_OPEN for delete on a readonly file.\n");
1097 6 : smb2_util_unlink(tree, fname);
1098 6 : smb2_deltree(tree, fname);
1099 :
1100 6 : status = torture_smb2_testdir(tree, DNAME, &h);
1101 6 : CHECK_STATUS(status, NT_STATUS_OK);
1102 :
1103 : /* reasonable default parameters */
1104 6 : ZERO_STRUCT(io.smb2);
1105 6 : io.generic.level = RAW_OPEN_SMB2;
1106 6 : io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1107 6 : io.smb2.in.alloc_size = 0;
1108 6 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1109 6 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_READONLY;
1110 6 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1111 6 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1112 6 : io.smb2.in.create_options = 0;
1113 6 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1114 6 : io.smb2.in.security_flags = 0;
1115 6 : io.smb2.in.fname = fname;
1116 :
1117 : /* Create the readonly file. */
1118 :
1119 6 : status = smb2_create(tree, tctx, &(io.smb2));
1120 6 : CHECK_STATUS(status, NT_STATUS_OK);
1121 6 : h1 = io.smb2.out.file.handle;
1122 :
1123 6 : CHECK_VAL(io.smb2.out.oplock_level, 0);
1124 6 : io.smb2.in.create_options = 0;
1125 6 : CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED);
1126 6 : CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
1127 6 : smb2_util_close(tree, h1);
1128 :
1129 : /* Now try and open for delete only - should succeed. */
1130 6 : io.smb2.in.desired_access = SEC_STD_DELETE;
1131 6 : io.smb2.in.file_attributes = 0;
1132 6 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1133 : NTCREATEX_SHARE_ACCESS_WRITE |
1134 : NTCREATEX_SHARE_ACCESS_DELETE;
1135 6 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1136 6 : status = smb2_create(tree, tctx, &(io.smb2));
1137 6 : CHECK_STATUS(status, NT_STATUS_OK);
1138 6 : smb2_util_close(tree, io.smb2.out.file.handle);
1139 :
1140 : /* Clear readonly flag to allow file deletion */
1141 6 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1142 : SEC_FILE_WRITE_ATTRIBUTE;
1143 6 : status = smb2_create(tree, tctx, &(io.smb2));
1144 6 : CHECK_STATUS(status, NT_STATUS_OK);
1145 6 : h1 = io.smb2.out.file.handle;
1146 6 : SET_ATTRIB(FILE_ATTRIBUTE_ARCHIVE);
1147 6 : smb2_util_close(tree, h1);
1148 :
1149 6 : smb2_util_close(tree, h);
1150 6 : smb2_util_unlink(tree, fname);
1151 6 : smb2_deltree(tree, DNAME);
1152 :
1153 6 : return ret;
1154 : }
1155 :
1156 : /*
1157 : test SMB2 open with a leading slash on the path.
1158 : Trying to create a directory with a leading slash
1159 : should give NT_STATUS_INVALID_PARAMETER error
1160 : */
1161 6 : static bool test_smb2_leading_slash(struct torture_context *tctx,
1162 : struct smb2_tree *tree)
1163 : {
1164 0 : union smb_open io;
1165 6 : const char *dnameslash = "\\"DNAME;
1166 0 : NTSTATUS status;
1167 6 : bool ret = true;
1168 :
1169 6 : torture_comment(tctx,
1170 : "Trying to create a directory with leading slash on path\n");
1171 6 : smb2_deltree(tree, dnameslash);
1172 :
1173 6 : ZERO_STRUCT(io.smb2);
1174 6 : io.generic.level = RAW_OPEN_SMB2;
1175 6 : io.smb2.in.oplock_level = 0;
1176 6 : io.smb2.in.desired_access = SEC_RIGHTS_DIR_ALL;
1177 6 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
1178 6 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1179 6 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1180 : NTCREATEX_SHARE_ACCESS_WRITE |
1181 : NTCREATEX_SHARE_ACCESS_DELETE;
1182 6 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1183 6 : io.smb2.in.fname = dnameslash;
1184 :
1185 6 : status = smb2_create(tree, tree, &(io.smb2));
1186 6 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1187 :
1188 6 : smb2_deltree(tree, dnameslash);
1189 6 : return ret;
1190 : }
1191 :
1192 : /*
1193 : test SMB2 open with an invalid impersonation level.
1194 : Should give NT_STATUS_BAD_IMPERSONATION_LEVEL error
1195 : */
1196 6 : static bool test_smb2_impersonation_level(struct torture_context *tctx,
1197 : struct smb2_tree *tree)
1198 : {
1199 0 : union smb_open io;
1200 6 : const char *fname = DNAME "\\torture_invalid_impersonation_level.txt";
1201 0 : NTSTATUS status;
1202 0 : struct smb2_handle h;
1203 6 : bool ret = true;
1204 :
1205 6 : torture_comment(tctx,
1206 : "Testing SMB2 open with an invalid impersonation level.\n");
1207 :
1208 6 : smb2_util_unlink(tree, fname);
1209 6 : smb2_util_rmdir(tree, DNAME);
1210 :
1211 6 : status = torture_smb2_testdir(tree, DNAME, &h);
1212 6 : CHECK_STATUS(status, NT_STATUS_OK);
1213 :
1214 6 : ZERO_STRUCT(io.smb2);
1215 6 : io.generic.level = RAW_OPEN_SMB2;
1216 6 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1217 6 : io.smb2.in.alloc_size = 0;
1218 6 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1219 6 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1220 : NTCREATEX_SHARE_ACCESS_WRITE|
1221 : NTCREATEX_SHARE_ACCESS_DELETE;
1222 6 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1223 6 : io.smb2.in.create_options = 0;
1224 6 : io.smb2.in.impersonation_level = 0x12345678;
1225 6 : io.smb2.in.security_flags = 0;
1226 6 : io.smb2.in.fname = fname;
1227 6 : io.smb2.in.create_flags = 0;
1228 :
1229 6 : status = smb2_create(tree, tree, &(io.smb2));
1230 6 : CHECK_STATUS(status, NT_STATUS_BAD_IMPERSONATION_LEVEL);
1231 :
1232 5 : smb2_util_close(tree, h);
1233 5 : smb2_util_unlink(tree, fname);
1234 5 : smb2_deltree(tree, DNAME);
1235 5 : return ret;
1236 : }
1237 :
1238 6 : static bool test_create_acl_file(struct torture_context *tctx,
1239 : struct smb2_tree *tree)
1240 : {
1241 6 : torture_comment(tctx, "Testing nttrans create with sec_desc on files\n");
1242 :
1243 6 : return test_create_acl_ext(tctx, tree, false);
1244 : }
1245 :
1246 6 : static bool test_create_acl_dir(struct torture_context *tctx,
1247 : struct smb2_tree *tree)
1248 : {
1249 6 : torture_comment(tctx, "Testing nttrans create with sec_desc on directories\n");
1250 :
1251 6 : return test_create_acl_ext(tctx, tree, true);
1252 : }
1253 :
1254 : #define CHECK_ACCESS_FLAGS(_fh, flags) do { \
1255 : union smb_fileinfo _q; \
1256 : _q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION; \
1257 : _q.access_information.in.file.handle = (_fh); \
1258 : status = smb2_getinfo_file(tree, tctx, &_q); \
1259 : CHECK_STATUS(status, NT_STATUS_OK); \
1260 : if (_q.access_information.out.access_flags != (flags)) { \
1261 : torture_result(tctx, TORTURE_FAIL, "(%s) Incorrect access_flags 0x%08x - should be 0x%08x\n", \
1262 : __location__, _q.access_information.out.access_flags, (flags)); \
1263 : ret = false; \
1264 : goto done; \
1265 : } \
1266 : } while (0)
1267 :
1268 : /*
1269 : * Test creating a file with a NULL DACL.
1270 : */
1271 6 : static bool test_create_null_dacl(struct torture_context *tctx,
1272 : struct smb2_tree *tree)
1273 : {
1274 0 : NTSTATUS status;
1275 0 : struct smb2_create io;
1276 6 : const char *fname = "nulldacl.txt";
1277 6 : bool ret = true;
1278 0 : struct smb2_handle handle;
1279 0 : union smb_fileinfo q;
1280 0 : union smb_setfileinfo s;
1281 6 : struct security_descriptor *sd = security_descriptor_initialise(tctx);
1282 0 : struct security_acl dacl;
1283 :
1284 6 : torture_comment(tctx, "TESTING SEC_DESC WITH A NULL DACL\n");
1285 :
1286 6 : smb2_util_unlink(tree, fname);
1287 :
1288 6 : ZERO_STRUCT(io);
1289 6 : io.level = RAW_OPEN_SMB2;
1290 6 : io.in.create_flags = 0;
1291 6 : io.in.desired_access = SEC_STD_READ_CONTROL | SEC_STD_WRITE_DAC
1292 : | SEC_STD_WRITE_OWNER;
1293 6 : io.in.create_options = 0;
1294 6 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1295 6 : io.in.share_access =
1296 : NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1297 6 : io.in.alloc_size = 0;
1298 6 : io.in.create_disposition = NTCREATEX_DISP_CREATE;
1299 6 : io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
1300 6 : io.in.security_flags = 0;
1301 6 : io.in.fname = fname;
1302 6 : io.in.sec_desc = sd;
1303 : /* XXX create_options ? */
1304 6 : io.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
1305 : NTCREATEX_OPTIONS_ASYNC_ALERT |
1306 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
1307 : 0x00200000;
1308 :
1309 6 : torture_comment(tctx, "creating a file with a empty sd\n");
1310 6 : status = smb2_create(tree, tctx, &io);
1311 6 : CHECK_STATUS(status, NT_STATUS_OK);
1312 6 : handle = io.out.file.handle;
1313 :
1314 6 : torture_comment(tctx, "get the original sd\n");
1315 6 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
1316 6 : q.query_secdesc.in.file.handle = handle;
1317 6 : q.query_secdesc.in.secinfo_flags =
1318 : SECINFO_OWNER |
1319 : SECINFO_GROUP |
1320 : SECINFO_DACL;
1321 6 : status = smb2_getinfo_file(tree, tctx, &q);
1322 6 : CHECK_STATUS(status, NT_STATUS_OK);
1323 :
1324 : /*
1325 : * Testing the created DACL,
1326 : * the server should add the inherited DACL
1327 : * when SEC_DESC_DACL_PRESENT isn't specified
1328 : */
1329 6 : if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
1330 0 : ret = false;
1331 0 : torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
1332 : }
1333 6 : if (q.query_secdesc.out.sd->dacl == NULL) {
1334 0 : ret = false;
1335 0 : torture_fail_goto(tctx, done, "no DACL has been created on the server!\n");
1336 : }
1337 :
1338 6 : torture_comment(tctx, "set NULL DACL\n");
1339 6 : sd->type |= SEC_DESC_DACL_PRESENT;
1340 :
1341 6 : s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
1342 6 : s.set_secdesc.in.file.handle = handle;
1343 6 : s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
1344 6 : s.set_secdesc.in.sd = sd;
1345 6 : status = smb2_setinfo_file(tree, &s);
1346 6 : CHECK_STATUS(status, NT_STATUS_OK);
1347 :
1348 6 : torture_comment(tctx, "get the sd\n");
1349 6 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
1350 6 : q.query_secdesc.in.file.handle = handle;
1351 6 : q.query_secdesc.in.secinfo_flags =
1352 : SECINFO_OWNER |
1353 : SECINFO_GROUP |
1354 : SECINFO_DACL;
1355 6 : status = smb2_getinfo_file(tree, tctx, &q);
1356 6 : CHECK_STATUS(status, NT_STATUS_OK);
1357 :
1358 : /* Testing the modified DACL */
1359 6 : if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
1360 0 : ret = false;
1361 0 : torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
1362 : }
1363 6 : if (q.query_secdesc.out.sd->dacl != NULL) {
1364 0 : ret = false;
1365 0 : torture_fail_goto(tctx, done, "DACL has been created on the server!\n");
1366 : }
1367 :
1368 6 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
1369 :
1370 6 : torture_comment(tctx, "try open for read control\n");
1371 6 : io.in.desired_access = SEC_STD_READ_CONTROL;
1372 6 : status = smb2_create(tree, tctx, &io);
1373 6 : CHECK_STATUS(status, NT_STATUS_OK);
1374 6 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1375 : SEC_STD_READ_CONTROL);
1376 6 : smb2_util_close(tree, io.out.file.handle);
1377 :
1378 6 : torture_comment(tctx, "try open for write\n");
1379 6 : io.in.desired_access = SEC_FILE_WRITE_DATA;
1380 6 : status = smb2_create(tree, tctx, &io);
1381 6 : CHECK_STATUS(status, NT_STATUS_OK);
1382 6 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1383 : SEC_FILE_WRITE_DATA);
1384 6 : smb2_util_close(tree, io.out.file.handle);
1385 :
1386 6 : torture_comment(tctx, "try open for read\n");
1387 6 : io.in.desired_access = SEC_FILE_READ_DATA;
1388 6 : status = smb2_create(tree, tctx, &io);
1389 6 : CHECK_STATUS(status, NT_STATUS_OK);
1390 6 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1391 : SEC_FILE_READ_DATA);
1392 6 : smb2_util_close(tree, io.out.file.handle);
1393 :
1394 6 : torture_comment(tctx, "try open for generic write\n");
1395 6 : io.in.desired_access = SEC_GENERIC_WRITE;
1396 6 : status = smb2_create(tree, tctx, &io);
1397 6 : CHECK_STATUS(status, NT_STATUS_OK);
1398 6 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1399 : SEC_RIGHTS_FILE_WRITE);
1400 6 : smb2_util_close(tree, io.out.file.handle);
1401 :
1402 6 : torture_comment(tctx, "try open for generic read\n");
1403 6 : io.in.desired_access = SEC_GENERIC_READ;
1404 6 : status = smb2_create(tree, tctx, &io);
1405 6 : CHECK_STATUS(status, NT_STATUS_OK);
1406 6 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1407 : SEC_RIGHTS_FILE_READ);
1408 6 : smb2_util_close(tree, io.out.file.handle);
1409 :
1410 6 : torture_comment(tctx, "set DACL with 0 aces\n");
1411 6 : ZERO_STRUCT(dacl);
1412 6 : dacl.revision = SECURITY_ACL_REVISION_NT4;
1413 6 : dacl.num_aces = 0;
1414 6 : sd->dacl = &dacl;
1415 :
1416 6 : s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
1417 6 : s.set_secdesc.in.file.handle = handle;
1418 6 : s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
1419 6 : s.set_secdesc.in.sd = sd;
1420 6 : status = smb2_setinfo_file(tree, &s);
1421 6 : CHECK_STATUS(status, NT_STATUS_OK);
1422 :
1423 6 : torture_comment(tctx, "get the sd\n");
1424 6 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
1425 6 : q.query_secdesc.in.file.handle = handle;
1426 6 : q.query_secdesc.in.secinfo_flags =
1427 : SECINFO_OWNER |
1428 : SECINFO_GROUP |
1429 : SECINFO_DACL;
1430 6 : status = smb2_getinfo_file(tree, tctx, &q);
1431 6 : CHECK_STATUS(status, NT_STATUS_OK);
1432 :
1433 : /* Testing the modified DACL */
1434 6 : if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
1435 0 : ret = false;
1436 0 : torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
1437 : }
1438 6 : if (q.query_secdesc.out.sd->dacl == NULL) {
1439 0 : ret = false;
1440 0 : torture_fail_goto(tctx, done, "no DACL has been created on the server!\n");
1441 : }
1442 6 : if (q.query_secdesc.out.sd->dacl->num_aces != 0) {
1443 0 : torture_result(tctx, TORTURE_FAIL, "DACL has %u aces!\n",
1444 0 : q.query_secdesc.out.sd->dacl->num_aces);
1445 0 : ret = false;
1446 0 : goto done;
1447 : }
1448 :
1449 6 : torture_comment(tctx, "try open for read control\n");
1450 6 : io.in.desired_access = SEC_STD_READ_CONTROL;
1451 6 : status = smb2_create(tree, tctx, &io);
1452 6 : CHECK_STATUS(status, NT_STATUS_OK);
1453 6 : CHECK_ACCESS_FLAGS(io.out.file.handle,
1454 : SEC_STD_READ_CONTROL);
1455 6 : smb2_util_close(tree, io.out.file.handle);
1456 :
1457 6 : torture_comment(tctx, "try open for write => access_denied\n");
1458 6 : io.in.desired_access = SEC_FILE_WRITE_DATA;
1459 6 : status = smb2_create(tree, tctx, &io);
1460 6 : if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
1461 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1462 : } else {
1463 6 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1464 : }
1465 :
1466 6 : torture_comment(tctx, "try open for read => access_denied\n");
1467 6 : io.in.desired_access = SEC_FILE_READ_DATA;
1468 6 : status = smb2_create(tree, tctx, &io);
1469 6 : if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
1470 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1471 : } else {
1472 6 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1473 : }
1474 :
1475 6 : torture_comment(tctx, "try open for generic write => access_denied\n");
1476 6 : io.in.desired_access = SEC_GENERIC_WRITE;
1477 6 : status = smb2_create(tree, tctx, &io);
1478 6 : if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
1479 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1480 : } else {
1481 6 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1482 : }
1483 :
1484 6 : torture_comment(tctx, "try open for generic read => access_denied\n");
1485 6 : io.in.desired_access = SEC_GENERIC_READ;
1486 6 : status = smb2_create(tree, tctx, &io);
1487 6 : if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
1488 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1489 : } else {
1490 6 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
1491 : }
1492 :
1493 6 : torture_comment(tctx, "set empty sd\n");
1494 6 : sd->type &= ~SEC_DESC_DACL_PRESENT;
1495 6 : sd->dacl = NULL;
1496 :
1497 6 : s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
1498 6 : s.set_secdesc.in.file.handle = handle;
1499 6 : s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
1500 6 : s.set_secdesc.in.sd = sd;
1501 6 : status = smb2_setinfo_file(tree, &s);
1502 6 : CHECK_STATUS(status, NT_STATUS_OK);
1503 :
1504 6 : torture_comment(tctx, "get the sd\n");
1505 6 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
1506 6 : q.query_secdesc.in.file.handle = handle;
1507 6 : q.query_secdesc.in.secinfo_flags =
1508 : SECINFO_OWNER |
1509 : SECINFO_GROUP |
1510 : SECINFO_DACL;
1511 6 : status = smb2_getinfo_file(tree, tctx, &q);
1512 6 : CHECK_STATUS(status, NT_STATUS_OK);
1513 :
1514 : /* Testing the modified DACL */
1515 6 : if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
1516 0 : ret = false;
1517 0 : torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
1518 : }
1519 6 : if (q.query_secdesc.out.sd->dacl != NULL) {
1520 0 : ret = false;
1521 0 : torture_fail_goto(tctx, done, "DACL has been created on the server!\n");
1522 : }
1523 6 : done:
1524 6 : smb2_util_close(tree, handle);
1525 6 : smb2_util_unlink(tree, fname);
1526 6 : smb2_tdis(tree);
1527 6 : smb2_logoff(tree->session);
1528 6 : return ret;
1529 : }
1530 :
1531 : /*
1532 : test SMB2 mkdir with OPEN_IF on the same name twice.
1533 : Must use 2 connections to hit the race.
1534 : */
1535 :
1536 6 : static bool test_mkdir_dup(struct torture_context *tctx,
1537 : struct smb2_tree *tree)
1538 : {
1539 6 : const char *fname = "mkdir_dup";
1540 0 : NTSTATUS status;
1541 6 : bool ret = true;
1542 0 : union smb_open io;
1543 0 : struct smb2_tree **trees;
1544 0 : struct smb2_request **requests;
1545 0 : union smb_open *ios;
1546 6 : int i, num_files = 2;
1547 6 : int num_ok = 0;
1548 6 : int num_created = 0;
1549 6 : int num_existed = 0;
1550 :
1551 6 : torture_comment(tctx,
1552 : "Testing SMB2 Create Directory with multiple connections\n");
1553 6 : trees = talloc_array(tctx, struct smb2_tree *, num_files);
1554 6 : requests = talloc_array(tctx, struct smb2_request *, num_files);
1555 6 : ios = talloc_array(tctx, union smb_open, num_files);
1556 6 : if ((tctx->ev == NULL) || (trees == NULL) || (requests == NULL) ||
1557 : (ios == NULL)) {
1558 0 : torture_fail(tctx, ("talloc failed\n"));
1559 : ret = false;
1560 : goto done;
1561 : }
1562 :
1563 6 : tree->session->transport->options.request_timeout = 60;
1564 :
1565 18 : for (i=0; i<num_files; i++) {
1566 12 : if (!torture_smb2_connection(tctx, &(trees[i]))) {
1567 0 : torture_fail(tctx,
1568 : talloc_asprintf(tctx,
1569 : "Could not open %d'th connection\n", i));
1570 : ret = false;
1571 : goto done;
1572 : }
1573 12 : trees[i]->session->transport->options.request_timeout = 60;
1574 : }
1575 :
1576 : /* cleanup */
1577 6 : smb2_util_unlink(tree, fname);
1578 6 : smb2_util_rmdir(tree, fname);
1579 :
1580 : /*
1581 : base ntcreatex parms
1582 : */
1583 6 : ZERO_STRUCT(io.smb2);
1584 6 : io.generic.level = RAW_OPEN_SMB2;
1585 6 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1586 6 : io.smb2.in.alloc_size = 0;
1587 6 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1588 6 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1589 : NTCREATEX_SHARE_ACCESS_WRITE|
1590 : NTCREATEX_SHARE_ACCESS_DELETE;
1591 6 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1592 6 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1593 6 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1594 6 : io.smb2.in.security_flags = 0;
1595 6 : io.smb2.in.fname = fname;
1596 6 : io.smb2.in.create_flags = 0;
1597 :
1598 18 : for (i=0; i<num_files; i++) {
1599 12 : ios[i] = io;
1600 12 : requests[i] = smb2_create_send(trees[i], &(ios[i].smb2));
1601 12 : if (requests[i] == NULL) {
1602 0 : torture_fail(tctx,
1603 : talloc_asprintf(tctx,
1604 : "could not send %d'th request\n", i));
1605 : ret = false;
1606 : goto done;
1607 : }
1608 : }
1609 :
1610 6 : torture_comment(tctx, "waiting for replies\n");
1611 48 : while (1) {
1612 54 : bool unreplied = false;
1613 80 : for (i=0; i<num_files; i++) {
1614 74 : if (requests[i] == NULL) {
1615 14 : continue;
1616 : }
1617 60 : if (requests[i]->state < SMB2_REQUEST_DONE) {
1618 48 : unreplied = true;
1619 48 : break;
1620 : }
1621 12 : status = smb2_create_recv(requests[i], tctx,
1622 12 : &(ios[i].smb2));
1623 :
1624 12 : if (NT_STATUS_IS_OK(status)) {
1625 12 : num_ok += 1;
1626 :
1627 12 : if (ios[i].smb2.out.create_action ==
1628 : NTCREATEX_ACTION_CREATED) {
1629 6 : num_created++;
1630 : }
1631 12 : if (ios[i].smb2.out.create_action ==
1632 : NTCREATEX_ACTION_EXISTED) {
1633 6 : num_existed++;
1634 : }
1635 : } else {
1636 0 : torture_fail(tctx,
1637 : talloc_asprintf(tctx,
1638 : "File %d returned status %s\n", i,
1639 : nt_errstr(status)));
1640 : }
1641 :
1642 :
1643 12 : requests[i] = NULL;
1644 : }
1645 54 : if (!unreplied) {
1646 6 : break;
1647 : }
1648 :
1649 48 : if (tevent_loop_once(tctx->ev) != 0) {
1650 0 : torture_fail(tctx, "tevent_loop_once failed\n");
1651 : ret = false;
1652 : goto done;
1653 : }
1654 : }
1655 :
1656 6 : if (num_ok != 2) {
1657 0 : torture_fail(tctx,
1658 : talloc_asprintf(tctx,
1659 : "num_ok == %d\n", num_ok));
1660 : ret = false;
1661 : }
1662 6 : if (num_created != 1) {
1663 0 : torture_fail(tctx,
1664 : talloc_asprintf(tctx,
1665 : "num_created == %d\n", num_created));
1666 : ret = false;
1667 : }
1668 6 : if (num_existed != 1) {
1669 0 : torture_fail(tctx,
1670 : talloc_asprintf(tctx,
1671 : "num_existed == %d\n", num_existed));
1672 : ret = false;
1673 : }
1674 6 : done:
1675 6 : smb2_deltree(tree, fname);
1676 :
1677 6 : return ret;
1678 : }
1679 :
1680 : /*
1681 : test directory creation with an initial allocation size > 0
1682 : */
1683 6 : static bool test_dir_alloc_size(struct torture_context *tctx,
1684 : struct smb2_tree *tree)
1685 : {
1686 6 : bool ret = true;
1687 6 : const char *dname = DNAME "\\torture_alloc_size.dir";
1688 0 : NTSTATUS status;
1689 0 : struct smb2_create c;
1690 6 : struct smb2_handle h1 = {{0}}, h2;
1691 :
1692 6 : torture_comment(tctx, "Checking initial allocation size on directories\n");
1693 :
1694 6 : smb2_deltree(tree, dname);
1695 :
1696 6 : status = torture_smb2_testdir(tree, DNAME, &h1);
1697 6 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir failed");
1698 :
1699 6 : ZERO_STRUCT(c);
1700 6 : c.in.create_disposition = NTCREATEX_DISP_CREATE;
1701 6 : c.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
1702 6 : c.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
1703 6 : c.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1704 6 : c.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1705 6 : c.in.fname = dname;
1706 : /*
1707 : * An insanely large value so we can check the value is
1708 : * ignored: Samba either returns 0 (current behaviour), or,
1709 : * once vfswrap_get_alloc_size() is fixed to allow retrieving
1710 : * the allocated size for directories, returns
1711 : * smb_roundup(..., stat.st_size) which would be 1 MB by
1712 : * default.
1713 : *
1714 : * Windows returns 0 for empty directories, once directories
1715 : * have a few entries it starts replying with values > 0.
1716 : */
1717 6 : c.in.alloc_size = 1024*1024*1024;
1718 :
1719 6 : status = smb2_create(tree, tctx, &c);
1720 6 : h2 = c.out.file.handle;
1721 6 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1722 : "dir create with initial alloc size failed");
1723 :
1724 6 : smb2_util_close(tree, h2);
1725 :
1726 6 : torture_comment(tctx, "Got directory alloc size: %ju\n", (uintmax_t)c.out.alloc_size);
1727 :
1728 : /*
1729 : * See above for the rational for this test
1730 : */
1731 6 : if (c.out.alloc_size > 1024*1024) {
1732 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "bad alloc size: %ju",
1733 : (uintmax_t)c.out.alloc_size));
1734 : }
1735 :
1736 6 : done:
1737 6 : if (!smb2_util_handle_empty(h1)) {
1738 6 : smb2_util_close(tree, h1);
1739 : }
1740 6 : smb2_deltree(tree, DNAME);
1741 6 : return ret;
1742 : }
1743 :
1744 2 : static bool test_twrp_write(struct torture_context *tctx, struct smb2_tree *tree)
1745 : {
1746 0 : struct smb2_create io;
1747 2 : struct smb2_handle h1 = {{0}};
1748 0 : NTSTATUS status;
1749 2 : bool ret = true;
1750 2 : char *p = NULL;
1751 0 : struct tm tm;
1752 0 : time_t t;
1753 0 : uint64_t nttime;
1754 2 : const char *file = NULL;
1755 2 : const char *snapshot = NULL;
1756 :
1757 2 : file = torture_setting_string(tctx, "twrp_file", NULL);
1758 2 : if (file == NULL) {
1759 0 : torture_skip(tctx, "missing 'twrp_file' option\n");
1760 : }
1761 :
1762 2 : snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
1763 2 : if (snapshot == NULL) {
1764 0 : torture_skip(tctx, "missing 'twrp_snapshot' option\n");
1765 : }
1766 :
1767 2 : torture_comment(tctx, "Testing timewarp (%s) (%s)\n", file, snapshot);
1768 :
1769 2 : setenv("TZ", "GMT", 1);
1770 :
1771 : /* strptime does not set tm.tm_isdst but mktime assumes DST is in
1772 : * effect if it is greater than 1. */
1773 2 : ZERO_STRUCT(tm);
1774 :
1775 2 : p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
1776 2 : torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
1777 2 : torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
1778 :
1779 2 : t = mktime(&tm);
1780 2 : unix_to_nt_time(&nttime, t);
1781 :
1782 2 : io = (struct smb2_create) {
1783 : .in.desired_access = SEC_FILE_READ_DATA,
1784 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
1785 : .in.create_disposition = NTCREATEX_DISP_OPEN,
1786 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
1787 : .in.fname = file,
1788 : .in.query_maximal_access = true,
1789 : .in.timewarp = nttime,
1790 : };
1791 :
1792 2 : status = smb2_create(tree, tctx, &io);
1793 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1794 : "smb2_create\n");
1795 2 : smb2_util_close(tree, io.out.file.handle);
1796 :
1797 2 : ret = io.out.maximal_access & (SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA);
1798 2 : torture_assert_goto(tctx, ret, ret, done, "Bad access\n");
1799 :
1800 2 : io = (struct smb2_create) {
1801 : .in.desired_access = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA,
1802 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
1803 : .in.create_disposition = NTCREATEX_DISP_OPEN,
1804 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
1805 : .in.fname = file,
1806 : .in.timewarp = nttime,
1807 : };
1808 :
1809 2 : status = smb2_create(tree, tctx, &io);
1810 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1811 : "smb2_create\n");
1812 2 : h1 = io.out.file.handle;
1813 :
1814 2 : status = smb2_util_write(tree, h1, "123", 0, 3);
1815 2 : torture_assert_ntstatus_equal_goto(tctx, status,
1816 : NT_STATUS_MEDIA_WRITE_PROTECTED,
1817 : ret, done, "smb2_create\n");
1818 :
1819 2 : smb2_util_close(tree, h1);
1820 :
1821 2 : done:
1822 2 : return ret;
1823 : }
1824 :
1825 2 : static bool test_twrp_stream(struct torture_context *tctx,
1826 : struct smb2_tree *tree)
1827 : {
1828 0 : struct smb2_create io;
1829 0 : NTSTATUS status;
1830 2 : bool ret = true;
1831 2 : char *p = NULL;
1832 0 : struct tm tm;
1833 0 : time_t t;
1834 0 : uint64_t nttime;
1835 2 : const char *file = NULL;
1836 2 : const char *stream = NULL;
1837 2 : const char *snapshot = NULL;
1838 0 : int stream_size;
1839 2 : char *path = NULL;
1840 2 : uint8_t *buf = NULL;
1841 2 : struct smb2_handle h1 = {{0}};
1842 0 : struct smb2_read r;
1843 :
1844 2 : file = torture_setting_string(tctx, "twrp_file", NULL);
1845 2 : if (file == NULL) {
1846 0 : torture_skip(tctx, "missing 'twrp_file' option\n");
1847 : }
1848 :
1849 2 : stream = torture_setting_string(tctx, "twrp_stream", NULL);
1850 2 : if (stream == NULL) {
1851 0 : torture_skip(tctx, "missing 'twrp_stream' option\n");
1852 : }
1853 :
1854 2 : snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
1855 2 : if (snapshot == NULL) {
1856 0 : torture_skip(tctx, "missing 'twrp_snapshot' option\n");
1857 : }
1858 :
1859 2 : stream_size = torture_setting_int(tctx, "twrp_stream_size", 0);
1860 2 : if (stream_size == 0) {
1861 0 : torture_skip(tctx, "missing 'twrp_stream_size' option\n");
1862 : }
1863 :
1864 2 : torture_comment(tctx, "Testing timewarp on stream (%s) (%s)\n",
1865 : file, snapshot);
1866 :
1867 2 : path = talloc_asprintf(tree, "%s:%s", file, stream);
1868 2 : torture_assert_not_null_goto(tctx, path, ret, done, "path\n");
1869 :
1870 2 : buf = talloc_zero_array(tree, uint8_t, stream_size);
1871 2 : torture_assert_not_null_goto(tctx, buf, ret, done, "buf\n");
1872 :
1873 2 : setenv("TZ", "GMT", 1);
1874 :
1875 : /* strptime does not set tm.tm_isdst but mktime assumes DST is in
1876 : * effect if it is greater than 1. */
1877 2 : ZERO_STRUCT(tm);
1878 :
1879 2 : p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
1880 2 : torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
1881 2 : torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
1882 :
1883 2 : t = mktime(&tm);
1884 2 : unix_to_nt_time(&nttime, t);
1885 :
1886 2 : io = (struct smb2_create) {
1887 : .in.desired_access = SEC_FILE_READ_DATA,
1888 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
1889 : .in.create_disposition = NTCREATEX_DISP_OPEN,
1890 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
1891 : .in.fname = path,
1892 : .in.timewarp = nttime,
1893 : };
1894 :
1895 2 : status = smb2_create(tree, tctx, &io);
1896 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1897 : "smb2_create\n");
1898 2 : h1 = io.out.file.handle;
1899 :
1900 2 : r = (struct smb2_read) {
1901 : .in.file.handle = h1,
1902 : .in.length = stream_size,
1903 : .in.offset = 0,
1904 : };
1905 :
1906 2 : status = smb2_read(tree, tree, &r);
1907 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1908 : "smb2_create\n");
1909 :
1910 2 : smb2_util_close(tree, h1);
1911 :
1912 2 : done:
1913 2 : return ret;
1914 : }
1915 :
1916 2 : static bool test_twrp_openroot(struct torture_context *tctx, struct smb2_tree *tree)
1917 : {
1918 0 : struct smb2_create io;
1919 0 : NTSTATUS status;
1920 2 : bool ret = true;
1921 2 : char *p = NULL;
1922 0 : struct tm tm;
1923 0 : time_t t;
1924 0 : uint64_t nttime;
1925 2 : const char *snapshot = NULL;
1926 :
1927 2 : snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
1928 2 : if (snapshot == NULL) {
1929 0 : torture_skip(tctx, "missing 'twrp_snapshot' option\n");
1930 : }
1931 :
1932 2 : torture_comment(tctx, "Testing open of root of "
1933 : "share with timewarp (%s)\n",
1934 : snapshot);
1935 :
1936 2 : setenv("TZ", "GMT", 1);
1937 :
1938 : /* strptime does not set tm.tm_isdst but mktime assumes DST is in
1939 : * effect if it is greater than 1. */
1940 2 : ZERO_STRUCT(tm);
1941 :
1942 2 : p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
1943 2 : torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
1944 2 : torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
1945 :
1946 2 : t = mktime(&tm);
1947 2 : unix_to_nt_time(&nttime, t);
1948 :
1949 2 : io = (struct smb2_create) {
1950 : .in.desired_access = SEC_FILE_READ_DATA,
1951 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
1952 : .in.create_disposition = NTCREATEX_DISP_OPEN,
1953 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
1954 : .in.fname = "",
1955 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
1956 : .in.timewarp = nttime,
1957 : };
1958 :
1959 2 : status = smb2_create(tree, tctx, &io);
1960 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1961 : "smb2_create\n");
1962 2 : smb2_util_close(tree, io.out.file.handle);
1963 :
1964 2 : done:
1965 2 : return ret;
1966 : }
1967 :
1968 2 : static bool test_twrp_listdir(struct torture_context *tctx,
1969 : struct smb2_tree *tree)
1970 : {
1971 0 : struct smb2_create create;
1972 2 : struct smb2_handle h = {{0}};
1973 0 : struct smb2_find find;
1974 0 : unsigned int count;
1975 0 : union smb_search_data *d;
1976 2 : char *p = NULL;
1977 0 : struct tm tm;
1978 0 : time_t t;
1979 0 : uint64_t nttime;
1980 2 : const char *snapshot = NULL;
1981 0 : uint64_t normal_fileid;
1982 0 : uint64_t snapshot_fileid;
1983 0 : NTSTATUS status;
1984 2 : bool ret = true;
1985 :
1986 2 : snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
1987 2 : if (snapshot == NULL) {
1988 0 : torture_fail(tctx, "missing 'twrp_snapshot' option\n");
1989 : }
1990 :
1991 2 : torture_comment(tctx, "Testing File-Ids of directory listing "
1992 : "with timewarp (%s)\n",
1993 : snapshot);
1994 :
1995 2 : setenv("TZ", "GMT", 1);
1996 :
1997 : /* strptime does not set tm.tm_isdst but mktime assumes DST is in
1998 : * effect if it is greater than 1. */
1999 2 : ZERO_STRUCT(tm);
2000 :
2001 2 : p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
2002 2 : torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
2003 2 : torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
2004 :
2005 2 : t = mktime(&tm);
2006 2 : unix_to_nt_time(&nttime, t);
2007 :
2008 : /*
2009 : * 1: Query the file's File-Id
2010 : */
2011 2 : create = (struct smb2_create) {
2012 : .in.desired_access = SEC_FILE_READ_DATA,
2013 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2014 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2015 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2016 : .in.fname = "subdir/hardlink",
2017 : .in.query_on_disk_id = true,
2018 : };
2019 :
2020 2 : status = smb2_create(tree, tctx, &create);
2021 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2022 : "test file could not be created\n");
2023 2 : smb2_util_close(tree, create.out.file.handle);
2024 2 : normal_fileid = BVAL(&create.out.on_disk_id, 0);
2025 :
2026 : /*
2027 : * 2: check directory listing of the file returns same File-Id
2028 : */
2029 :
2030 2 : create = (struct smb2_create) {
2031 : .in.desired_access = SEC_DIR_LIST,
2032 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
2033 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2034 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2035 : .in.fname = "subdir",
2036 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
2037 : };
2038 :
2039 2 : status = smb2_create(tree, tctx, &create);
2040 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2041 : "smb2_create\n");
2042 2 : h = create.out.file.handle;
2043 :
2044 2 : find = (struct smb2_find) {
2045 : .in.file.handle = h,
2046 : .in.pattern = "*",
2047 : .in.max_response_size = 0x1000,
2048 : .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
2049 : };
2050 :
2051 2 : status = smb2_find_level(tree, tree, &find, &count, &d);
2052 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2053 : "smb2_find_level failed\n");
2054 :
2055 2 : smb2_util_close(tree, h);
2056 :
2057 2 : torture_assert_int_equal_goto(tctx, count, 3, ret, done, "Bad count\n");
2058 2 : torture_assert_str_equal_goto(tctx,
2059 : d[2].id_both_directory_info.name.s,
2060 : "hardlink",
2061 : ret, done, "bad name");
2062 2 : torture_assert_u64_equal_goto(tctx,
2063 : d[2].id_both_directory_info.file_id,
2064 : normal_fileid,
2065 : ret, done, "bad fileid\n");
2066 :
2067 : /*
2068 : * 3: Query File-Id of snapshot of the file and check the File-Id is
2069 : * different compared to the basefile
2070 : */
2071 :
2072 2 : create = (struct smb2_create) {
2073 : .in.desired_access = SEC_FILE_READ_DATA,
2074 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2075 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2076 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2077 : .in.fname = "subdir/hardlink",
2078 : .in.query_on_disk_id = true,
2079 : .in.timewarp = nttime,
2080 : };
2081 :
2082 2 : status = smb2_create(tree, tctx, &create);
2083 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2084 : "test file could not be created\n");
2085 2 : smb2_util_close(tree, create.out.file.handle);
2086 :
2087 2 : snapshot_fileid = BVAL(&create.out.on_disk_id, 0);
2088 :
2089 : /*
2090 : * 4: List directory of the snapshot and check the File-Id returned here
2091 : * is the same as in 3.
2092 : */
2093 :
2094 2 : create = (struct smb2_create) {
2095 : .in.desired_access = SEC_DIR_LIST,
2096 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
2097 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2098 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2099 : .in.fname = "subdir",
2100 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
2101 : .in.timewarp = nttime,
2102 : };
2103 :
2104 2 : status = smb2_create(tree, tctx, &create);
2105 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2106 : "smb2_create\n");
2107 2 : h = create.out.file.handle;
2108 :
2109 2 : find = (struct smb2_find) {
2110 : .in.file.handle = h,
2111 : .in.pattern = "*",
2112 : .in.max_response_size = 0x1000,
2113 : .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
2114 : };
2115 :
2116 2 : status = smb2_find_level(tree, tree, &find, &count, &d);
2117 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2118 : "smb2_find_level failed\n");
2119 2 : smb2_util_close(tree, h);
2120 :
2121 2 : torture_assert_int_equal_goto(tctx, count, 3, ret, done, "Bad count\n");
2122 2 : torture_assert_str_equal_goto(tctx,
2123 : d[2].id_both_directory_info.name.s,
2124 : "hardlink",
2125 : ret, done, "bad name");
2126 2 : torture_assert_u64_equal_goto(tctx,
2127 : snapshot_fileid,
2128 : d[2].id_both_directory_info.file_id,
2129 : ret, done, "bad fileid\n");
2130 :
2131 2 : done:
2132 2 : return ret;
2133 : }
2134 :
2135 2 : static bool test_fileid(struct torture_context *tctx,
2136 : struct smb2_tree *tree)
2137 : {
2138 2 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
2139 2 : const char *fname = DNAME "\\foo";
2140 2 : const char *sname = DNAME "\\foo:bar";
2141 0 : struct smb2_handle testdirh;
2142 0 : struct smb2_handle h1;
2143 0 : struct smb2_create create;
2144 0 : union smb_fileinfo finfo;
2145 0 : union smb_setfileinfo sinfo;
2146 0 : struct smb2_find f;
2147 0 : unsigned int count;
2148 0 : union smb_search_data *d;
2149 0 : uint64_t expected_fileid;
2150 0 : uint64_t returned_fileid;
2151 0 : NTSTATUS status;
2152 2 : bool ret = true;
2153 :
2154 2 : smb2_deltree(tree, DNAME);
2155 :
2156 2 : status = torture_smb2_testdir(tree, DNAME, &testdirh);
2157 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2158 : "torture_smb2_testdir failed\n");
2159 :
2160 : /*
2161 : * Initial create with QFID
2162 : */
2163 2 : create = (struct smb2_create) {
2164 : .in.desired_access = SEC_FILE_ALL,
2165 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2166 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2167 : .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
2168 : .in.fname = fname,
2169 : .in.query_on_disk_id = true,
2170 : };
2171 :
2172 2 : status = smb2_create(tree, tctx, &create);
2173 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2174 : "test file could not be created\n");
2175 2 : h1 = create.out.file.handle;
2176 2 : expected_fileid = BVAL(&create.out.on_disk_id, 0);
2177 :
2178 : /*
2179 : * Getinfo the File-ID on the just opened handle
2180 : */
2181 2 : finfo = (union smb_fileinfo) {
2182 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2183 : .generic.in.file.handle = h1,
2184 : };
2185 :
2186 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2187 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2188 : "torture_smb2_testdir\n");
2189 2 : smb2_util_close(tree, h1);
2190 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2191 : expected_fileid,
2192 : ret, done, "bad fileid\n");
2193 :
2194 : /*
2195 : * Open existing with QFID
2196 : */
2197 2 : create = (struct smb2_create) {
2198 : .in.desired_access = SEC_FILE_ALL,
2199 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2200 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2201 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2202 : .in.fname = fname,
2203 : .in.query_on_disk_id = true,
2204 : };
2205 :
2206 2 : status = smb2_create(tree, tctx, &create);
2207 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2208 : "test file could not be created\n");
2209 2 : h1 = create.out.file.handle;
2210 2 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2211 2 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2212 : ret, done, "bad fileid\n");
2213 :
2214 : /*
2215 : * Getinfo the File-ID on the just opened handle
2216 : */
2217 2 : finfo = (union smb_fileinfo) {
2218 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2219 : .generic.in.file.handle = h1,
2220 : };
2221 :
2222 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2223 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2224 : "torture_smb2_testdir\n");
2225 2 : smb2_util_close(tree, h1);
2226 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2227 : expected_fileid,
2228 : ret, done, "bad fileid\n");
2229 :
2230 : /*
2231 : * Overwrite with QFID
2232 : */
2233 2 : create = (struct smb2_create) {
2234 : .in.desired_access = SEC_FILE_ALL,
2235 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2236 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2237 : .in.create_disposition = NTCREATEX_DISP_OVERWRITE,
2238 : .in.fname = fname,
2239 : .in.query_on_disk_id = true,
2240 : };
2241 :
2242 2 : status = smb2_create(tree, tctx, &create);
2243 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2244 : "test file could not be created\n");
2245 2 : h1 = create.out.file.handle;
2246 2 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2247 2 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2248 : ret, done, "bad fileid\n");
2249 :
2250 : /*
2251 : * Getinfo the File-ID on the open with overwrite handle
2252 : */
2253 2 : finfo = (union smb_fileinfo) {
2254 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2255 : .generic.in.file.handle = h1,
2256 : };
2257 :
2258 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2259 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2260 : "torture_smb2_testdir\n");
2261 2 : smb2_util_close(tree, h1);
2262 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2263 : expected_fileid,
2264 : ret, done, "bad fileid\n");
2265 :
2266 : /*
2267 : * Do some modifications on the basefile (IO, setinfo), verifying
2268 : * File-ID after each step.
2269 : */
2270 2 : create = (struct smb2_create) {
2271 : .in.desired_access = SEC_FILE_ALL,
2272 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2273 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2274 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2275 : .in.fname = fname,
2276 : .in.query_on_disk_id = true,
2277 : };
2278 :
2279 2 : status = smb2_create(tree, tctx, &create);
2280 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2281 : "test file could not be created\n");
2282 2 : h1 = create.out.file.handle;
2283 :
2284 2 : status = smb2_util_write(tree, h1, "foo", 0, strlen("foo"));
2285 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2286 : "smb2_util_write failed\n");
2287 :
2288 2 : finfo = (union smb_fileinfo) {
2289 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2290 : .generic.in.file.handle = h1,
2291 : };
2292 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2293 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2294 : "smb2_getinfo_file failed\n");
2295 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2296 : expected_fileid,
2297 : ret, done, "bad fileid\n");
2298 :
2299 2 : sinfo = (union smb_setfileinfo) {
2300 : .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
2301 : .basic_info.in.file.handle = h1,
2302 : };
2303 2 : unix_to_nt_time(&sinfo.basic_info.in.write_time, time(NULL));
2304 :
2305 2 : status = smb2_setinfo_file(tree, &sinfo);
2306 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2307 : "smb2_setinfo_file failed\n");
2308 :
2309 2 : finfo = (union smb_fileinfo) {
2310 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2311 : .generic.in.file.handle = h1,
2312 : };
2313 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2314 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2315 : "smb2_getinfo_file failed\n");
2316 2 : smb2_util_close(tree, h1);
2317 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2318 : expected_fileid,
2319 : ret, done, "bad fileid\n");
2320 :
2321 : /*
2322 : * Create stream, check the stream's File-ID, should be the same as the
2323 : * base file (sic!, tested against Windows).
2324 : */
2325 2 : create = (struct smb2_create) {
2326 : .in.desired_access = SEC_FILE_ALL,
2327 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2328 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2329 : .in.create_disposition = NTCREATEX_DISP_CREATE,
2330 : .in.fname = sname,
2331 : .in.query_on_disk_id = true,
2332 : };
2333 :
2334 2 : status = smb2_create(tree, tctx, &create);
2335 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2336 : "test file could not be created\n");
2337 2 : h1 = create.out.file.handle;
2338 2 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2339 2 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2340 : ret, done, "bad fileid\n");
2341 :
2342 : /*
2343 : * Getinfo the File-ID on the created stream
2344 : */
2345 2 : finfo = (union smb_fileinfo) {
2346 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2347 : .generic.in.file.handle = h1,
2348 : };
2349 :
2350 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2351 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2352 : "smb2_getinfo_file failed\n");
2353 2 : smb2_util_close(tree, h1);
2354 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2355 : expected_fileid,
2356 : ret, done, "bad fileid\n");
2357 :
2358 : /*
2359 : * Open stream, check the stream's File-ID, should be the same as the
2360 : * base file (sic!, tested against Windows).
2361 : */
2362 2 : create = (struct smb2_create) {
2363 : .in.desired_access = SEC_FILE_ALL,
2364 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2365 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2366 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2367 : .in.fname = sname,
2368 : .in.query_on_disk_id = true,
2369 : };
2370 :
2371 2 : status = smb2_create(tree, tctx, &create);
2372 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2373 : "test file could not be created\n");
2374 2 : h1 = create.out.file.handle;
2375 2 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2376 2 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2377 : ret, done, "bad fileid\n");
2378 :
2379 : /*
2380 : * Getinfo the File-ID on the opened stream
2381 : */
2382 2 : finfo = (union smb_fileinfo) {
2383 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2384 : .generic.in.file.handle = h1,
2385 : };
2386 :
2387 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2388 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2389 : "smb2_getinfo_file failed\n");
2390 2 : smb2_util_close(tree, h1);
2391 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2392 : expected_fileid,
2393 : ret, done, "bad fileid\n");
2394 :
2395 : /*
2396 : * Overwrite stream, check the stream's File-ID, should be the same as
2397 : * the base file (sic!, tested against Windows).
2398 : */
2399 2 : create = (struct smb2_create) {
2400 : .in.desired_access = SEC_FILE_ALL,
2401 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2402 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2403 : .in.create_disposition = NTCREATEX_DISP_OVERWRITE,
2404 : .in.fname = sname,
2405 : .in.query_on_disk_id = true,
2406 : };
2407 :
2408 2 : status = smb2_create(tree, tctx, &create);
2409 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2410 : "test file could not be created\n");
2411 2 : h1 = create.out.file.handle;
2412 2 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2413 2 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2414 : ret, done, "bad fileid\n");
2415 :
2416 : /*
2417 : * Getinfo the File-ID on the overwritten stream
2418 : */
2419 2 : finfo = (union smb_fileinfo) {
2420 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2421 : .generic.in.file.handle = h1,
2422 : };
2423 :
2424 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2425 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2426 : "smb2_getinfo_file failed\n");
2427 2 : smb2_util_close(tree, h1);
2428 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2429 : expected_fileid,
2430 : ret, done, "bad fileid\n");
2431 :
2432 : /*
2433 : * Do some modifications on the stream (IO, setinfo), verifying File-ID
2434 : * after each step.
2435 : */
2436 2 : create = (struct smb2_create) {
2437 : .in.desired_access = SEC_FILE_ALL,
2438 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2439 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2440 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2441 : .in.fname = sname,
2442 : .in.query_on_disk_id = true,
2443 : };
2444 :
2445 2 : status = smb2_create(tree, tctx, &create);
2446 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2447 : "test file could not be created\n");
2448 2 : h1 = create.out.file.handle;
2449 :
2450 2 : status = smb2_util_write(tree, h1, "foo", 0, strlen("foo"));
2451 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2452 : "smb2_util_write failed\n");
2453 :
2454 2 : finfo = (union smb_fileinfo) {
2455 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2456 : .generic.in.file.handle = h1,
2457 : };
2458 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2459 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2460 : "smb2_getinfo_file failed\n");
2461 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2462 : expected_fileid,
2463 : ret, done, "bad fileid\n");
2464 :
2465 2 : sinfo = (union smb_setfileinfo) {
2466 : .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
2467 : .basic_info.in.file.handle = h1,
2468 : };
2469 2 : unix_to_nt_time(&sinfo.basic_info.in.write_time, time(NULL));
2470 :
2471 2 : status = smb2_setinfo_file(tree, &sinfo);
2472 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2473 : "smb2_setinfo_file failed\n");
2474 :
2475 2 : finfo = (union smb_fileinfo) {
2476 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2477 : .generic.in.file.handle = h1,
2478 : };
2479 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2480 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2481 : "smb2_getinfo_file failed\n");
2482 2 : smb2_util_close(tree, h1);
2483 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2484 : expected_fileid,
2485 : ret, done, "bad fileid\n");
2486 :
2487 : /*
2488 : * Final open of the basefile with QFID
2489 : */
2490 2 : create = (struct smb2_create) {
2491 : .in.desired_access = SEC_FILE_ALL,
2492 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2493 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2494 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2495 : .in.fname = fname,
2496 : .in.query_on_disk_id = true,
2497 : };
2498 :
2499 2 : status = smb2_create(tree, tctx, &create);
2500 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2501 : "test file could not be created\n");
2502 2 : h1 = create.out.file.handle;
2503 2 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2504 2 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2505 : ret, done, "bad fileid\n");
2506 :
2507 : /*
2508 : * Final Getinfo checking File-ID
2509 : */
2510 2 : finfo = (union smb_fileinfo) {
2511 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2512 : .generic.in.file.handle = h1,
2513 : };
2514 :
2515 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2516 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2517 : "torture_smb2_testdir\n");
2518 2 : smb2_util_close(tree, h1);
2519 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2520 : expected_fileid,
2521 : ret, done, "bad fileid\n");
2522 :
2523 : /*
2524 : * Final list directory, verifying the operations on basefile and stream
2525 : * didn't modify the base file metadata.
2526 : */
2527 2 : f = (struct smb2_find) {
2528 : .in.file.handle = testdirh,
2529 : .in.pattern = "foo",
2530 : .in.max_response_size = 0x1000,
2531 : .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
2532 : .in.continue_flags = SMB2_CONTINUE_FLAG_RESTART,
2533 : };
2534 :
2535 2 : status = smb2_find_level(tree, tree, &f, &count, &d);
2536 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2537 : "smb2_find_level failed\n");
2538 2 : torture_assert_u64_equal_goto(tctx,
2539 : d->id_both_directory_info.file_id,
2540 : expected_fileid,
2541 : ret, done, "bad fileid\n");
2542 :
2543 2 : done:
2544 2 : smb2_util_close(tree, testdirh);
2545 2 : smb2_deltree(tree, DNAME);
2546 2 : talloc_free(mem_ctx);
2547 2 : return ret;
2548 : }
2549 :
2550 2 : static bool test_fileid_dir(struct torture_context *tctx,
2551 : struct smb2_tree *tree)
2552 : {
2553 2 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
2554 2 : const char *dname = DNAME "\\foo";
2555 2 : const char *sname = DNAME "\\foo:bar";
2556 0 : struct smb2_handle testdirh;
2557 0 : struct smb2_handle h1;
2558 0 : struct smb2_create create;
2559 0 : union smb_fileinfo finfo;
2560 0 : union smb_setfileinfo sinfo;
2561 0 : struct smb2_find f;
2562 0 : unsigned int count;
2563 0 : union smb_search_data *d;
2564 0 : uint64_t expected_fileid;
2565 0 : uint64_t returned_fileid;
2566 0 : NTSTATUS status;
2567 2 : bool ret = true;
2568 :
2569 2 : smb2_deltree(tree, DNAME);
2570 :
2571 2 : status = torture_smb2_testdir(tree, DNAME, &testdirh);
2572 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2573 : "torture_smb2_testdir failed\n");
2574 :
2575 : /*
2576 : * Initial directory create with QFID
2577 : */
2578 2 : create = (struct smb2_create) {
2579 : .in.desired_access = SEC_FILE_ALL,
2580 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2581 : .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
2582 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
2583 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
2584 : .in.fname = dname,
2585 : .in.query_on_disk_id = true,
2586 : };
2587 :
2588 2 : status = smb2_create(tree, tctx, &create);
2589 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2590 : "test file could not be created\n");
2591 2 : h1 = create.out.file.handle;
2592 2 : expected_fileid = BVAL(&create.out.on_disk_id, 0);
2593 :
2594 : /*
2595 : * Getinfo the File-ID on the just opened handle
2596 : */
2597 2 : finfo = (union smb_fileinfo) {
2598 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2599 : .generic.in.file.handle = h1,
2600 : };
2601 :
2602 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2603 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2604 : "torture_smb2_testdir\n");
2605 2 : smb2_util_close(tree, h1);
2606 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2607 : expected_fileid,
2608 : ret, done, "bad fileid\n");
2609 :
2610 : /*
2611 : * Open existing directory with QFID
2612 : */
2613 2 : create = (struct smb2_create) {
2614 : .in.desired_access = SEC_FILE_ALL,
2615 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2616 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2617 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
2618 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
2619 : .in.fname = dname,
2620 : .in.query_on_disk_id = true,
2621 : };
2622 :
2623 2 : status = smb2_create(tree, tctx, &create);
2624 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2625 : "test file could not be created\n");
2626 2 : h1 = create.out.file.handle;
2627 2 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2628 2 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2629 : ret, done, "bad fileid\n");
2630 :
2631 : /*
2632 : * Getinfo the File-ID on the just opened handle
2633 : */
2634 2 : finfo = (union smb_fileinfo) {
2635 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2636 : .generic.in.file.handle = h1,
2637 : };
2638 :
2639 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2640 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2641 : "torture_smb2_testdir\n");
2642 2 : smb2_util_close(tree, h1);
2643 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2644 : expected_fileid,
2645 : ret, done, "bad fileid\n");
2646 :
2647 : /*
2648 : * Create stream, check the stream's File-ID, should be the same as the
2649 : * base file (sic!, tested against Windows).
2650 : */
2651 2 : create = (struct smb2_create) {
2652 : .in.desired_access = SEC_FILE_ALL,
2653 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2654 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2655 : .in.create_disposition = NTCREATEX_DISP_CREATE,
2656 : .in.fname = sname,
2657 : .in.query_on_disk_id = true,
2658 : };
2659 :
2660 2 : status = smb2_create(tree, tctx, &create);
2661 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2662 : "test file could not be created\n");
2663 2 : h1 = create.out.file.handle;
2664 2 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2665 2 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2666 : ret, done, "bad fileid\n");
2667 :
2668 : /*
2669 : * Getinfo the File-ID on the created stream
2670 : */
2671 2 : finfo = (union smb_fileinfo) {
2672 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2673 : .generic.in.file.handle = h1,
2674 : };
2675 :
2676 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2677 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2678 : "smb2_getinfo_file failed\n");
2679 2 : smb2_util_close(tree, h1);
2680 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2681 : expected_fileid,
2682 : ret, done, "bad fileid\n");
2683 :
2684 : /*
2685 : * Open stream, check the stream's File-ID, should be the same as the
2686 : * base file (sic!, tested against Windows).
2687 : */
2688 2 : create = (struct smb2_create) {
2689 : .in.desired_access = SEC_FILE_ALL,
2690 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2691 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2692 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2693 : .in.fname = sname,
2694 : .in.query_on_disk_id = true,
2695 : };
2696 :
2697 2 : status = smb2_create(tree, tctx, &create);
2698 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2699 : "test file could not be created\n");
2700 2 : h1 = create.out.file.handle;
2701 2 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2702 2 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2703 : ret, done, "bad fileid\n");
2704 :
2705 : /*
2706 : * Getinfo the File-ID on the opened stream
2707 : */
2708 2 : finfo = (union smb_fileinfo) {
2709 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2710 : .generic.in.file.handle = h1,
2711 : };
2712 :
2713 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2714 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2715 : "smb2_getinfo_file failed\n");
2716 2 : smb2_util_close(tree, h1);
2717 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2718 : expected_fileid,
2719 : ret, done, "bad fileid\n");
2720 :
2721 : /*
2722 : * Overwrite stream, check the stream's File-ID, should be the same as
2723 : * the base file (sic!, tested against Windows).
2724 : */
2725 2 : create = (struct smb2_create) {
2726 : .in.desired_access = SEC_FILE_ALL,
2727 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2728 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2729 : .in.create_disposition = NTCREATEX_DISP_OVERWRITE,
2730 : .in.fname = sname,
2731 : .in.query_on_disk_id = true,
2732 : };
2733 :
2734 2 : status = smb2_create(tree, tctx, &create);
2735 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2736 : "test file could not be created\n");
2737 2 : h1 = create.out.file.handle;
2738 2 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2739 2 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2740 : ret, done, "bad fileid\n");
2741 :
2742 : /*
2743 : * Getinfo the File-ID on the overwritten stream
2744 : */
2745 2 : finfo = (union smb_fileinfo) {
2746 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2747 : .generic.in.file.handle = h1,
2748 : };
2749 :
2750 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2751 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2752 : "smb2_getinfo_file failed\n");
2753 2 : smb2_util_close(tree, h1);
2754 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2755 : expected_fileid,
2756 : ret, done, "bad fileid\n");
2757 :
2758 : /*
2759 : * Do some modifications on the stream (IO, setinfo), verifying File-ID
2760 : * after each step.
2761 : */
2762 2 : create = (struct smb2_create) {
2763 : .in.desired_access = SEC_FILE_ALL,
2764 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2765 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2766 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2767 : .in.fname = sname,
2768 : .in.query_on_disk_id = true,
2769 : };
2770 :
2771 2 : status = smb2_create(tree, tctx, &create);
2772 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2773 : "test file could not be created\n");
2774 2 : h1 = create.out.file.handle;
2775 :
2776 2 : status = smb2_util_write(tree, h1, "foo", 0, strlen("foo"));
2777 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2778 : "smb2_util_write failed\n");
2779 :
2780 2 : finfo = (union smb_fileinfo) {
2781 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2782 : .generic.in.file.handle = h1,
2783 : };
2784 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2785 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2786 : "smb2_getinfo_file failed\n");
2787 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2788 : expected_fileid,
2789 : ret, done, "bad fileid\n");
2790 :
2791 2 : sinfo = (union smb_setfileinfo) {
2792 : .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
2793 : .basic_info.in.file.handle = h1,
2794 : };
2795 2 : unix_to_nt_time(&sinfo.basic_info.in.write_time, time(NULL));
2796 :
2797 2 : status = smb2_setinfo_file(tree, &sinfo);
2798 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2799 : "smb2_setinfo_file failed\n");
2800 :
2801 2 : finfo = (union smb_fileinfo) {
2802 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2803 : .generic.in.file.handle = h1,
2804 : };
2805 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2806 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2807 : "smb2_getinfo_file failed\n");
2808 2 : smb2_util_close(tree, h1);
2809 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2810 : expected_fileid,
2811 : ret, done, "bad fileid\n");
2812 :
2813 : /*
2814 : * Final open of the directory with QFID
2815 : */
2816 2 : create = (struct smb2_create) {
2817 : .in.desired_access = SEC_FILE_ALL,
2818 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2819 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
2820 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
2821 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2822 : .in.fname = dname,
2823 : .in.query_on_disk_id = true,
2824 : };
2825 :
2826 2 : status = smb2_create(tree, tctx, &create);
2827 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2828 : "test file could not be created\n");
2829 2 : h1 = create.out.file.handle;
2830 2 : returned_fileid = BVAL(&create.out.on_disk_id, 0);
2831 2 : torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
2832 : ret, done, "bad fileid\n");
2833 :
2834 : /*
2835 : * Final Getinfo checking File-ID
2836 : */
2837 2 : finfo = (union smb_fileinfo) {
2838 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2839 : .generic.in.file.handle = h1,
2840 : };
2841 :
2842 2 : status = smb2_getinfo_file(tree, tctx, &finfo);
2843 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2844 : "torture_smb2_testdir\n");
2845 2 : smb2_util_close(tree, h1);
2846 2 : torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
2847 : expected_fileid,
2848 : ret, done, "bad fileid\n");
2849 :
2850 : /*
2851 : * Final list directory, verifying the operations on basefile and stream
2852 : * didn't modify the base file metadata.
2853 : */
2854 2 : f = (struct smb2_find) {
2855 : .in.file.handle = testdirh,
2856 : .in.pattern = "foo",
2857 : .in.max_response_size = 0x1000,
2858 : .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
2859 : .in.continue_flags = SMB2_CONTINUE_FLAG_RESTART,
2860 : };
2861 :
2862 2 : status = smb2_find_level(tree, tree, &f, &count, &d);
2863 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2864 : "smb2_find_level failed\n");
2865 2 : torture_assert_u64_equal_goto(tctx,
2866 : d->id_both_directory_info.file_id,
2867 : expected_fileid,
2868 : ret, done, "bad fileid\n");
2869 :
2870 2 : done:
2871 2 : smb2_util_close(tree, testdirh);
2872 2 : smb2_deltree(tree, DNAME);
2873 2 : talloc_free(mem_ctx);
2874 2 : return ret;
2875 : }
2876 :
2877 4 : static bool test_fileid_unique_object(
2878 : struct torture_context *tctx,
2879 : struct smb2_tree *tree,
2880 : unsigned int num_objs,
2881 : bool create_dirs)
2882 4 : {
2883 4 : TALLOC_CTX *mem_ctx = talloc_new(tctx);
2884 4 : char *fname = NULL;
2885 0 : struct smb2_handle testdirh;
2886 0 : struct smb2_handle h1;
2887 0 : struct smb2_create create;
2888 0 : unsigned int i;
2889 4 : uint64_t fileid_array[num_objs];
2890 0 : NTSTATUS status;
2891 4 : bool ret = true;
2892 :
2893 4 : smb2_deltree(tree, DNAME);
2894 :
2895 4 : status = torture_smb2_testdir(tree, DNAME, &testdirh);
2896 4 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2897 : "test_fileid_unique failed\n");
2898 4 : smb2_util_close(tree, testdirh);
2899 :
2900 : /* Create num_obj files as rapidly as we can. */
2901 404 : for (i = 0; i < num_objs; i++) {
2902 400 : fname = talloc_asprintf(mem_ctx,
2903 : "%s\\testfile.%u",
2904 : DNAME,
2905 : i);
2906 400 : torture_assert_goto(tctx,
2907 : fname != NULL,
2908 : ret,
2909 : done,
2910 : "talloc failed\n");
2911 :
2912 400 : create = (struct smb2_create) {
2913 : .in.desired_access = SEC_FILE_READ_ATTRIBUTE,
2914 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2915 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2916 : .in.create_disposition = NTCREATEX_DISP_CREATE,
2917 : .in.fname = fname,
2918 : };
2919 :
2920 400 : if (create_dirs) {
2921 200 : create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
2922 200 : create.in.create_options = FILE_DIRECTORY_FILE;
2923 : }
2924 :
2925 400 : status = smb2_create(tree, tctx, &create);
2926 400 : if (!NT_STATUS_IS_OK(status)) {
2927 0 : torture_fail(tctx,
2928 : talloc_asprintf(tctx,
2929 : "test file %s could not be created\n",
2930 : fname));
2931 : TALLOC_FREE(fname);
2932 : ret = false;
2933 : goto done;
2934 : }
2935 :
2936 400 : h1 = create.out.file.handle;
2937 400 : smb2_util_close(tree, h1);
2938 400 : TALLOC_FREE(fname);
2939 : }
2940 :
2941 : /*
2942 : * Get the file ids.
2943 : */
2944 404 : for (i = 0; i < num_objs; i++) {
2945 0 : union smb_fileinfo finfo;
2946 :
2947 400 : fname = talloc_asprintf(mem_ctx,
2948 : "%s\\testfile.%u",
2949 : DNAME,
2950 : i);
2951 400 : torture_assert_goto(tctx,
2952 : fname != NULL,
2953 : ret,
2954 : done,
2955 : "talloc failed\n");
2956 :
2957 400 : create = (struct smb2_create) {
2958 : .in.desired_access = SEC_FILE_READ_ATTRIBUTE,
2959 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
2960 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
2961 : .in.create_disposition = NTCREATEX_DISP_OPEN,
2962 : .in.fname = fname,
2963 : };
2964 :
2965 400 : if (create_dirs) {
2966 200 : create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
2967 200 : create.in.create_options = FILE_DIRECTORY_FILE;
2968 : }
2969 :
2970 400 : status = smb2_create(tree, tctx, &create);
2971 400 : if (!NT_STATUS_IS_OK(status)) {
2972 0 : torture_fail(tctx,
2973 : talloc_asprintf(tctx,
2974 : "test file %s could not "
2975 : "be opened: %s\n",
2976 : fname,
2977 : nt_errstr(status)));
2978 : TALLOC_FREE(fname);
2979 : ret = false;
2980 : goto done;
2981 : }
2982 :
2983 400 : h1 = create.out.file.handle;
2984 :
2985 400 : finfo = (union smb_fileinfo) {
2986 : .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
2987 : .generic.in.file.handle = h1,
2988 : };
2989 :
2990 400 : status = smb2_getinfo_file(tree, tctx, &finfo);
2991 400 : if (!NT_STATUS_IS_OK(status)) {
2992 0 : torture_fail(tctx,
2993 : talloc_asprintf(tctx,
2994 : "failed to get fileid for "
2995 : "test file %s: %s\n",
2996 : fname,
2997 : nt_errstr(status)));
2998 : TALLOC_FREE(fname);
2999 : ret = false;
3000 : goto done;
3001 : }
3002 400 : smb2_util_close(tree, h1);
3003 :
3004 400 : fileid_array[i] = finfo.all_info2.out.file_id;
3005 400 : TALLOC_FREE(fname);
3006 : }
3007 :
3008 : /* All returned fileids must be unique. 100 is small so brute force. */
3009 400 : for (i = 0; i < num_objs - 1; i++) {
3010 0 : unsigned int j;
3011 20196 : for (j = i + 1; j < num_objs; j++) {
3012 19800 : if (fileid_array[i] == fileid_array[j]) {
3013 0 : torture_fail(tctx,
3014 : talloc_asprintf(tctx,
3015 : "fileid %u == fileid %u (0x%"PRIu64")\n",
3016 : i,
3017 : j,
3018 : fileid_array[i]));
3019 : ret = false;
3020 : goto done;
3021 : }
3022 : }
3023 : }
3024 :
3025 4 : done:
3026 :
3027 4 : smb2_util_close(tree, testdirh);
3028 4 : smb2_deltree(tree, DNAME);
3029 4 : talloc_free(mem_ctx);
3030 4 : return ret;
3031 : }
3032 :
3033 2 : static bool test_fileid_unique(
3034 : struct torture_context *tctx,
3035 : struct smb2_tree *tree)
3036 : {
3037 2 : return test_fileid_unique_object(tctx, tree, 100, false);
3038 : }
3039 :
3040 2 : static bool test_fileid_unique_dir(
3041 : struct torture_context *tctx,
3042 : struct smb2_tree *tree)
3043 : {
3044 2 : return test_fileid_unique_object(tctx, tree, 100, true);
3045 : }
3046 :
3047 6 : static bool test_dosattr_tmp_dir(struct torture_context *tctx,
3048 : struct smb2_tree *tree)
3049 : {
3050 6 : bool ret = true;
3051 0 : NTSTATUS status;
3052 0 : struct smb2_create c;
3053 6 : struct smb2_handle h1 = {{0}};
3054 6 : const char *fname = DNAME;
3055 :
3056 6 : smb2_deltree(tree, fname);
3057 6 : smb2_util_rmdir(tree, fname);
3058 :
3059 6 : c = (struct smb2_create) {
3060 : .in.desired_access = SEC_RIGHTS_DIR_ALL,
3061 : .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
3062 : .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
3063 : .in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3064 : NTCREATEX_SHARE_ACCESS_WRITE |
3065 : NTCREATEX_SHARE_ACCESS_DELETE,
3066 : .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
3067 : .in.fname = DNAME,
3068 : };
3069 :
3070 6 : status = smb2_create(tree, tctx, &c);
3071 6 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3072 : "smb2_create\n");
3073 6 : h1 = c.out.file.handle;
3074 :
3075 : /* Try to set temporary attribute on directory */
3076 6 : SET_ATTRIB(FILE_ATTRIBUTE_TEMPORARY);
3077 :
3078 6 : torture_assert_ntstatus_equal_goto(tctx, status,
3079 : NT_STATUS_INVALID_PARAMETER,
3080 : ret, done,
3081 : "Unexpected setinfo result\n");
3082 :
3083 6 : done:
3084 6 : if (!smb2_util_handle_empty(h1)) {
3085 6 : smb2_util_close(tree, h1);
3086 : }
3087 6 : smb2_util_unlink(tree, fname);
3088 6 : smb2_deltree(tree, fname);
3089 :
3090 6 : return ret;
3091 : }
3092 :
3093 : /*
3094 : test opening quota fakefile handle and returned attributes
3095 : */
3096 6 : static bool test_smb2_open_quota_fake_file(struct torture_context *tctx,
3097 : struct smb2_tree *tree)
3098 : {
3099 6 : const char *fname = "$Extend\\$Quota:$Q:$INDEX_ALLOCATION";
3100 0 : struct smb2_create create;
3101 6 : struct smb2_handle h = {{0}};
3102 0 : NTSTATUS status;
3103 6 : bool ret = true;
3104 :
3105 6 : create = (struct smb2_create) {
3106 : .in.desired_access = SEC_RIGHTS_FILE_READ,
3107 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
3108 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3109 : .in.create_disposition = NTCREATEX_DISP_OPEN,
3110 : .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
3111 : .in.fname = fname,
3112 : };
3113 :
3114 6 : status = smb2_create(tree, tree, &create);
3115 6 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
3116 : "smb2_create failed\n");
3117 5 : h = create.out.file.handle;
3118 :
3119 5 : torture_assert_u64_equal_goto(tctx,
3120 : create.out.file_attr,
3121 : FILE_ATTRIBUTE_HIDDEN
3122 : | FILE_ATTRIBUTE_SYSTEM
3123 : | FILE_ATTRIBUTE_DIRECTORY
3124 : | FILE_ATTRIBUTE_ARCHIVE,
3125 : ret,
3126 : done,
3127 : "Wrong attributes\n");
3128 :
3129 5 : torture_assert_u64_equal_goto(tctx,
3130 : create.out.create_time, 0,
3131 : ret,
3132 : done,
3133 : "create_time is not 0\n");
3134 5 : torture_assert_u64_equal_goto(tctx,
3135 : create.out.access_time, 0,
3136 : ret,
3137 : done,
3138 : "access_time is not 0\n");
3139 5 : torture_assert_u64_equal_goto(tctx,
3140 : create.out.write_time, 0,
3141 : ret,
3142 : done,
3143 : "write_time is not 0\n");
3144 5 : torture_assert_u64_equal_goto(tctx,
3145 : create.out.change_time, 0,
3146 : ret,
3147 : done,
3148 : "change_time is not 0\n");
3149 :
3150 5 : done:
3151 6 : smb2_util_close(tree, h);
3152 6 : return ret;
3153 : }
3154 :
3155 : /**
3156 : Find Maximum Path Length
3157 : */
3158 0 : static bool generate_path(const size_t len,
3159 : char *buffer,
3160 : const size_t buf_len)
3161 : {
3162 : size_t i;
3163 :
3164 0 : if (len >= buf_len) {
3165 0 : return false;
3166 : }
3167 :
3168 0 : for (i = 0; i < len ; i++) {
3169 0 : buffer[i] = (char)(i % 10) + 48;
3170 : }
3171 0 : buffer[i] = '\0';
3172 0 : return true;
3173 : }
3174 :
3175 6 : static bool test_path_length_test(struct torture_context *tctx,
3176 : struct smb2_tree *tree)
3177 : {
3178 6 : const size_t max_name = 2048;
3179 6 : char *name = talloc_array(tctx, char, max_name);
3180 6 : struct smb2_handle fh = {{0}};
3181 6 : size_t length = 128;
3182 6 : size_t max_file_name = 0;
3183 6 : size_t max_path_length = 0;
3184 6 : char *path_ok = NULL;
3185 6 : char *path_next = NULL;
3186 6 : char *topdir = NULL;
3187 6 : bool is_interactive = torture_setting_bool(tctx, "interactive", false);
3188 0 : NTSTATUS status;
3189 6 : bool ret = true;
3190 :
3191 6 : if (!is_interactive) {
3192 6 : torture_result(tctx, TORTURE_SKIP,
3193 : "Interactive Test: Skipping... "
3194 : "(enable with --interactive)\n");
3195 6 : return ret;
3196 : }
3197 :
3198 0 : torture_comment(tctx, "Testing filename and path lengths\n");
3199 :
3200 : /* Find Longest File Name */
3201 0 : for (length = 128; length < max_name; length++) {
3202 0 : if (!generate_path(length, name, max_name)) {
3203 0 : torture_result(tctx, TORTURE_FAIL,
3204 : "Failed to generate path.");
3205 0 : return false;
3206 : }
3207 :
3208 0 : status = torture_smb2_testfile(tree, name, &fh);
3209 0 : if (!NT_STATUS_IS_OK(status)) {
3210 0 : break;
3211 : }
3212 :
3213 0 : smb2_util_close(tree, fh);
3214 0 : smb2_util_unlink(tree, name);
3215 :
3216 0 : max_file_name = length;
3217 : }
3218 :
3219 0 : torture_assert_int_not_equal_goto(tctx, length, max_name, ret, done,
3220 : "Name too big\n");
3221 :
3222 0 : torture_comment(tctx, "Max file name length: %zu\n", max_file_name);
3223 :
3224 : /* Remove one char that caused the failure above */
3225 0 : name[max_file_name] = '\0';
3226 :
3227 0 : path_ok = talloc_strdup(tree, name);
3228 0 : torture_assert_not_null_goto(tctx, path_ok, ret, done,
3229 : "talloc_strdup failed\n");
3230 :
3231 0 : topdir = talloc_strdup(tree, name);
3232 0 : torture_assert_not_null_goto(tctx, topdir, ret, done,
3233 : "talloc_strdup failed\n");
3234 :
3235 0 : status = smb2_util_mkdir(tree, path_ok);
3236 0 : if (!NT_STATUS_IS_OK(status)) {
3237 0 : torture_comment(tctx, "mkdir [%s] failed: %s\n",
3238 : path_ok, nt_errstr(status));
3239 0 : torture_result(tctx, TORTURE_FAIL, "Initial mkdir failed");
3240 0 : return false;
3241 : }
3242 :
3243 0 : while (true) {
3244 0 : path_next = talloc_asprintf(tctx, "%s\\%s", path_ok, name);
3245 0 : torture_assert_not_null_goto(tctx, path_next, ret, done,
3246 : "talloc_asprintf failed\n");
3247 :
3248 0 : status = smb2_util_mkdir(tree, path_next);
3249 0 : if (!NT_STATUS_IS_OK(status)) {
3250 0 : break;
3251 : }
3252 :
3253 0 : path_ok = path_next;
3254 : }
3255 :
3256 0 : for (length = 1; length < max_name; length++) {
3257 0 : if (!generate_path(length, name, max_name)) {
3258 0 : torture_result(tctx, TORTURE_FAIL,
3259 : "Failed to generate path.");
3260 0 : return false;
3261 : }
3262 :
3263 0 : path_next = talloc_asprintf(tctx, "%s\\%s", path_ok, name);
3264 0 : torture_assert_not_null_goto(tctx, path_next, ret, done,
3265 : "talloc_asprintf failed\n");
3266 :
3267 0 : status = torture_smb2_testfile(tree, path_next, &fh);
3268 0 : if (!NT_STATUS_IS_OK(status)) {
3269 0 : break;
3270 : }
3271 0 : smb2_util_close(tree, fh);
3272 0 : path_ok = path_next;
3273 : }
3274 :
3275 0 : max_path_length = talloc_array_length(path_ok);
3276 :
3277 0 : torture_comment(tctx, "Max path name length: %zu\n", max_path_length);
3278 :
3279 0 : done:
3280 0 : return ret;
3281 : }
3282 :
3283 : /*
3284 : basic testing of SMB2 read
3285 : */
3286 2358 : struct torture_suite *torture_smb2_create_init(TALLOC_CTX *ctx)
3287 : {
3288 2358 : struct torture_suite *suite = torture_suite_create(ctx, "create");
3289 :
3290 2358 : torture_suite_add_1smb2_test(suite, "gentest", test_create_gentest);
3291 2358 : torture_suite_add_1smb2_test(suite, "blob", test_create_blob);
3292 2358 : torture_suite_add_1smb2_test(suite, "open", test_smb2_open);
3293 2358 : torture_suite_add_1smb2_test(suite, "brlocked", test_smb2_open_brlocked);
3294 2358 : torture_suite_add_1smb2_test(suite, "multi", test_smb2_open_multi);
3295 2358 : torture_suite_add_1smb2_test(suite, "delete", test_smb2_open_for_delete);
3296 2358 : torture_suite_add_1smb2_test(suite, "leading-slash", test_smb2_leading_slash);
3297 2358 : torture_suite_add_1smb2_test(suite, "impersonation", test_smb2_impersonation_level);
3298 2358 : torture_suite_add_1smb2_test(suite, "aclfile", test_create_acl_file);
3299 2358 : torture_suite_add_1smb2_test(suite, "acldir", test_create_acl_dir);
3300 2358 : torture_suite_add_1smb2_test(suite, "nulldacl", test_create_null_dacl);
3301 2358 : torture_suite_add_1smb2_test(suite, "mkdir-dup", test_mkdir_dup);
3302 2358 : torture_suite_add_1smb2_test(suite, "dir-alloc-size", test_dir_alloc_size);
3303 2358 : torture_suite_add_1smb2_test(suite, "dosattr_tmp_dir", test_dosattr_tmp_dir);
3304 2358 : torture_suite_add_1smb2_test(suite, "quota-fake-file", test_smb2_open_quota_fake_file);
3305 2358 : torture_suite_add_1smb2_test(suite, "path-length", test_path_length_test);
3306 2358 : torture_suite_add_1smb2_test(suite, "bench-path-contention-shared", test_smb2_bench_path_contention_shared);
3307 :
3308 2358 : suite->description = talloc_strdup(suite, "SMB2-CREATE tests");
3309 :
3310 2358 : return suite;
3311 : }
3312 :
3313 2358 : struct torture_suite *torture_smb2_twrp_init(TALLOC_CTX *ctx)
3314 : {
3315 2358 : struct torture_suite *suite = torture_suite_create(ctx, "twrp");
3316 :
3317 2358 : torture_suite_add_1smb2_test(suite, "write", test_twrp_write);
3318 2358 : torture_suite_add_1smb2_test(suite, "stream", test_twrp_stream);
3319 2358 : torture_suite_add_1smb2_test(suite, "openroot", test_twrp_openroot);
3320 2358 : torture_suite_add_1smb2_test(suite, "listdir", test_twrp_listdir);
3321 :
3322 2358 : suite->description = talloc_strdup(suite, "SMB2-TWRP tests");
3323 :
3324 2358 : return suite;
3325 : }
3326 :
3327 : /*
3328 : basic testing of SMB2 File-IDs
3329 : */
3330 2358 : struct torture_suite *torture_smb2_fileid_init(TALLOC_CTX *ctx)
3331 : {
3332 2358 : struct torture_suite *suite = torture_suite_create(ctx, "fileid");
3333 :
3334 2358 : torture_suite_add_1smb2_test(suite, "fileid", test_fileid);
3335 2358 : torture_suite_add_1smb2_test(suite, "fileid-dir", test_fileid_dir);
3336 2358 : torture_suite_add_1smb2_test(suite, "unique", test_fileid_unique);
3337 2358 : torture_suite_add_1smb2_test(suite, "unique-dir", test_fileid_unique_dir);
3338 :
3339 2358 : suite->description = talloc_strdup(suite, "SMB2-FILEID tests");
3340 :
3341 2358 : return suite;
3342 : }
3343 :
3344 2 : static bool test_no_stream(struct torture_context *tctx,
3345 : struct smb2_tree *tree)
3346 : {
3347 0 : struct smb2_create c;
3348 0 : NTSTATUS status;
3349 2 : bool ret = true;
3350 2 : const char *names[] = {
3351 : "test_no_stream::$DATA",
3352 : "test_no_stream::foooooooooooo",
3353 : "test_no_stream:stream",
3354 : "test_no_stream:stream:$DATA",
3355 : NULL
3356 : };
3357 0 : int i;
3358 :
3359 10 : for (i = 0; names[i] != NULL; i++) {
3360 8 : c = (struct smb2_create) {
3361 : .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
3362 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
3363 : .in.create_disposition = NTCREATEX_DISP_OPEN,
3364 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
3365 8 : .in.fname = names[i],
3366 : };
3367 :
3368 8 : status = smb2_create(tree, tctx, &c);
3369 8 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_INVALID)) {
3370 0 : torture_comment(
3371 : tctx, "Expected NT_STATUS_OBJECT_NAME_INVALID, "
3372 : "got %s, name: '%s'\n",
3373 : nt_errstr(status), names[i]);
3374 0 : torture_fail_goto(tctx, done, "Bad create result\n");
3375 : }
3376 : }
3377 2 : done:
3378 2 : return ret;
3379 : }
3380 :
3381 2358 : struct torture_suite *torture_smb2_create_no_streams_init(TALLOC_CTX *ctx)
3382 : {
3383 2358 : struct torture_suite *suite = torture_suite_create(ctx, "create_no_streams");
3384 :
3385 2358 : torture_suite_add_1smb2_test(suite, "no_stream", test_no_stream);
3386 :
3387 2358 : suite->description = talloc_strdup(suite, "SMB2-CREATE stream test on share without streams support");
3388 :
3389 2358 : return suite;
3390 : }
|