Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : test suite for SMB2 sharemodes
5 :
6 : Copyright (C) Christof Schmitt 2017
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/security/security.h"
26 : #include "torture/torture.h"
27 : #include "torture/smb2/proto.h"
28 : #include "lib/util/smb_strtox.h"
29 : #include <tevent.h>
30 :
31 : #define BASEDIRHOLD "sharemode_hold_test"
32 :
33 : struct hold_sharemode_info {
34 : const char *sharemode;
35 : const char *filename;
36 : struct smb2_handle handle;
37 : } hold_sharemode_table[] = {
38 : {
39 : .sharemode = "",
40 : .filename = BASEDIRHOLD "\\N",
41 : },
42 : {
43 : .sharemode = "R",
44 : .filename = BASEDIRHOLD "\\R",
45 : },
46 : {
47 : .sharemode = "W",
48 : .filename = BASEDIRHOLD "\\W",
49 : },
50 : {
51 : .sharemode = "D",
52 : .filename = BASEDIRHOLD "\\D",
53 : },
54 : {
55 : .sharemode = "RW",
56 : .filename = BASEDIRHOLD "\\RW",
57 : },
58 : {
59 : .sharemode = "RD",
60 : .filename = BASEDIRHOLD "\\RD",
61 : },
62 : {
63 : .sharemode = "WD",
64 : .filename = BASEDIRHOLD "\\WD",
65 : },
66 : {
67 : .sharemode = "RWD",
68 : .filename = BASEDIRHOLD "\\RWD",
69 : },
70 : };
71 :
72 0 : static void signal_handler(struct tevent_context *ev,
73 : struct tevent_signal *se,
74 : int signum,
75 : int count,
76 : void *siginfo,
77 : void *private_data)
78 : {
79 0 : struct torture_context *tctx = private_data;
80 :
81 0 : torture_comment(tctx, "Received signal %d\n", signum);
82 0 : }
83 :
84 : /*
85 : * Used for manual testing of sharemodes - especially interaction with
86 : * other filesystems (such as NFS and local access). The scenario is
87 : * that this test holds files open and then concurrent access to the same
88 : * files outside of Samba can be tested.
89 : */
90 0 : bool torture_smb2_hold_sharemode(struct torture_context *tctx)
91 : {
92 0 : struct tevent_context *ev = tctx->ev;
93 0 : struct smb2_tree *tree = NULL;
94 0 : struct smb2_handle dir_handle;
95 0 : struct tevent_signal *s;
96 0 : NTSTATUS status;
97 0 : bool ret = true;
98 0 : int i;
99 :
100 0 : if (!torture_smb2_connection(tctx, &tree)) {
101 0 : torture_comment(tctx, "Initializing smb2 connection failed.\n");
102 0 : return false;
103 : }
104 :
105 0 : s = tevent_add_signal(ev, tctx, SIGINT, 0, signal_handler, tctx);
106 0 : torture_assert_not_null_goto(tctx, s, ret, done,
107 : "Error registering signal handler.");
108 :
109 0 : torture_comment(tctx, "Setting up open files with sharemodes in %s\n",
110 : BASEDIRHOLD);
111 :
112 0 : status = torture_smb2_testdir(tree, BASEDIRHOLD, &dir_handle);
113 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
114 : "Error creating directory.");
115 :
116 0 : for (i = 0; i < ARRAY_SIZE(hold_sharemode_table); i++) {
117 0 : struct hold_sharemode_info *info = &hold_sharemode_table[i];
118 0 : struct smb2_create create = { 0 };
119 :
120 0 : create.in.desired_access = SEC_RIGHTS_FILE_ALL;
121 0 : create.in.alloc_size = 0;
122 0 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
123 0 : create.in.share_access =
124 0 : smb2_util_share_access(info->sharemode);
125 0 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
126 0 : create.in.create_options = 0;
127 0 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
128 0 : create.in.security_flags = 0;
129 0 : create.in.fname = info->filename;
130 0 : create.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
131 0 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
132 :
133 0 : torture_comment(tctx, "opening %s\n", info->filename);
134 :
135 0 : status = smb2_create(tree, tctx, &create);
136 :
137 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
138 : "CREATE file failed\n");
139 :
140 0 : info->handle = create.out.file.handle;
141 : }
142 :
143 0 : torture_comment(tctx, "Waiting for SIGINT (ctrl-c)\n");
144 0 : tevent_loop_wait(ev);
145 :
146 0 : torture_comment(tctx, "Closing and deleting files\n");
147 :
148 0 : for (i = 0; i < ARRAY_SIZE(hold_sharemode_table); i++) {
149 0 : struct hold_sharemode_info *info = &hold_sharemode_table[i];
150 :
151 0 : union smb_setfileinfo sfinfo = { };
152 :
153 0 : sfinfo.disposition_info.in.delete_on_close = 1;
154 0 : sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
155 0 : sfinfo.generic.in.file.handle = info->handle;
156 0 : status = smb2_setinfo_file(tree, &sfinfo);
157 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
158 : "SETINFO failed\n");
159 :
160 0 : status = smb2_util_close(tree, info->handle);
161 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
162 0 : torture_comment(tctx, "File %s not found, could have "
163 : "been deleted outside of SMB\n",
164 : info->filename);
165 0 : continue;
166 : }
167 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
168 : "CLOSE failed\n");
169 : }
170 :
171 0 : done:
172 0 : smb2_deltree(tree, BASEDIRHOLD);
173 0 : return ret;
174 : }
175 :
176 : /*
177 : * Used for manual testing of sharemodes, especially interaction with
178 : * file systems that can enforce sharemodes. The scenario here is that
179 : * a file is already open outside of Samba with a sharemode and this
180 : * can be used to test accessing the same file from Samba.
181 : */
182 0 : bool torture_smb2_check_sharemode(struct torture_context *tctx)
183 : {
184 0 : const char *sharemode_string, *access_string, *filename, *operation;
185 0 : uint32_t sharemode, access;
186 0 : struct smb2_tree *tree;
187 0 : struct smb2_create create = { 0 };
188 0 : NTSTATUS status;
189 0 : bool ret = true;
190 0 : int error = 0;
191 :
192 0 : sharemode_string = torture_setting_string(tctx, "sharemode", "RWD");
193 0 : sharemode = smb2_util_share_access(sharemode_string);
194 :
195 0 : access_string = torture_setting_string(tctx, "access", "0xf01ff");
196 0 : access = smb_strtoul(access_string, NULL, 0, &error, SMB_STR_STANDARD);
197 0 : if (error != 0) {
198 0 : torture_comment(tctx, "Initializing access failed.\n");
199 0 : return false;
200 : }
201 :
202 0 : filename = torture_setting_string(tctx, "filename", "testfile");
203 0 : operation = torture_setting_string(tctx, "operation", "WD");
204 :
205 0 : if (!torture_smb2_connection(tctx, &tree)) {
206 0 : torture_comment(tctx, "Initializing smb2 connection failed.\n");
207 0 : return false;
208 : }
209 :
210 0 : create.in.desired_access = access;
211 0 : create.in.alloc_size = 0;
212 0 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
213 0 : create.in.share_access = sharemode;
214 0 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
215 0 : create.in.create_options = 0;
216 0 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
217 0 : create.in.security_flags = 0;
218 0 : create.in.fname = filename;
219 0 : create.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
220 0 : create.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
221 :
222 0 : status = smb2_create(tree, tctx, &create);
223 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
224 : "CREATE failed\n");
225 :
226 0 : if (strchr(operation, 'R')) {
227 0 : struct smb2_read read = { 0 };
228 :
229 0 : read.in.file.handle = create.out.file.handle;
230 0 : read.in.offset = 0;
231 0 : read.in.length = 1;
232 :
233 0 : status = smb2_read(tree, tctx, &read);
234 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
235 : "READ failed\n");
236 : }
237 :
238 0 : if (strchr(operation, 'W')) {
239 0 : char buf[1];
240 0 : status = smb2_util_write(tree, create.out.file.handle,
241 : &buf, 0, sizeof(buf));
242 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
243 : "WRITE failed\n");
244 : }
245 :
246 0 : if (strchr(operation, 'D')) {
247 0 : union smb_setfileinfo sfinfo = { };
248 :
249 0 : sfinfo.disposition_info.in.delete_on_close = 1;
250 0 : sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
251 0 : sfinfo.generic.in.file.handle = create.out.file.handle;
252 :
253 0 : status = smb2_setinfo_file(tree, &sfinfo);
254 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
255 : "SETINFO failed\n");
256 :
257 0 : status = smb2_util_close(tree, create.out.file.handle);
258 0 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
259 : "CLOSE failed\n");
260 : }
261 :
262 0 : done:
263 0 : return ret;
264 : }
265 :
266 : struct sharemode_info {
267 : const char *sharemode;
268 : uint32_t access_mask;
269 : bool expect_ok;
270 : } sharemode_table[] = {
271 :
272 : /*
273 : * Basic tests, check each permission bit against every
274 : * possible sharemode combination.
275 : */
276 :
277 : { "R", SEC_FILE_READ_DATA, true, },
278 : { "R", SEC_FILE_WRITE_DATA, false, },
279 : { "R", SEC_FILE_APPEND_DATA, false, },
280 : { "R", SEC_FILE_READ_EA, true, },
281 : { "R", SEC_FILE_WRITE_EA, true, },
282 : { "R", SEC_FILE_EXECUTE, true, },
283 : { "R", SEC_FILE_READ_ATTRIBUTE, true, },
284 : { "R", SEC_FILE_WRITE_ATTRIBUTE, true, },
285 : { "R", SEC_STD_DELETE, false, },
286 : { "R", SEC_STD_READ_CONTROL, true, },
287 : { "R", SEC_STD_WRITE_DAC, true, },
288 : { "R", SEC_STD_WRITE_OWNER, true, },
289 : { "R", SEC_STD_SYNCHRONIZE, true, },
290 :
291 : { "W", SEC_FILE_READ_DATA, false },
292 : { "W", SEC_FILE_WRITE_DATA, true, },
293 : { "W", SEC_FILE_APPEND_DATA, true, },
294 : { "W", SEC_FILE_READ_EA, true, },
295 : { "W", SEC_FILE_WRITE_EA, true, },
296 : { "W", SEC_FILE_EXECUTE, false, },
297 : { "W", SEC_FILE_READ_ATTRIBUTE, true, },
298 : { "W", SEC_FILE_WRITE_ATTRIBUTE, true, },
299 : { "W", SEC_STD_DELETE, false, },
300 : { "W", SEC_STD_READ_CONTROL, true, },
301 : { "W", SEC_STD_WRITE_DAC, true, },
302 : { "W", SEC_STD_WRITE_OWNER, true, },
303 : { "W", SEC_STD_SYNCHRONIZE, true, },
304 :
305 : { "D", SEC_FILE_READ_DATA, false },
306 : { "D", SEC_FILE_WRITE_DATA, false },
307 : { "D", SEC_FILE_APPEND_DATA, false },
308 : { "D", SEC_FILE_READ_EA, true, },
309 : { "D", SEC_FILE_WRITE_EA, true, },
310 : { "D", SEC_FILE_EXECUTE, false, },
311 : { "D", SEC_FILE_READ_ATTRIBUTE, true, },
312 : { "D", SEC_FILE_WRITE_ATTRIBUTE, true, },
313 : { "D", SEC_STD_DELETE, true, },
314 : { "D", SEC_STD_READ_CONTROL, true, },
315 : { "D", SEC_STD_WRITE_DAC, true, },
316 : { "D", SEC_STD_WRITE_OWNER, true, },
317 : { "D", SEC_STD_SYNCHRONIZE, true, },
318 :
319 : { "RW", SEC_FILE_READ_DATA, true, },
320 : { "RW", SEC_FILE_WRITE_DATA, true, },
321 : { "RW", SEC_FILE_APPEND_DATA, true, },
322 : { "RW", SEC_FILE_READ_EA, true, },
323 : { "RW", SEC_FILE_WRITE_EA, true, },
324 : { "RW", SEC_FILE_EXECUTE, true, },
325 : { "RW", SEC_FILE_READ_ATTRIBUTE, true, },
326 : { "RW", SEC_FILE_WRITE_ATTRIBUTE, true, },
327 : { "RW", SEC_STD_DELETE, false, },
328 : { "RW", SEC_STD_READ_CONTROL, true, },
329 : { "RW", SEC_STD_WRITE_DAC, true, },
330 : { "RW", SEC_STD_WRITE_OWNER, true, },
331 : { "RW", SEC_STD_SYNCHRONIZE, true, },
332 :
333 : { "RD", SEC_FILE_READ_DATA, true, },
334 : { "RD", SEC_FILE_WRITE_DATA, false, },
335 : { "RD", SEC_FILE_APPEND_DATA, false, },
336 : { "RD", SEC_FILE_READ_EA, true, },
337 : { "RD", SEC_FILE_WRITE_EA, true, },
338 : { "RD", SEC_FILE_EXECUTE, true, },
339 : { "RD", SEC_FILE_READ_ATTRIBUTE, true, },
340 : { "RD", SEC_FILE_WRITE_ATTRIBUTE, true, },
341 : { "RD", SEC_STD_DELETE, true, },
342 : { "RD", SEC_STD_READ_CONTROL, true, },
343 : { "RD", SEC_STD_WRITE_DAC, true, },
344 : { "RD", SEC_STD_WRITE_OWNER, true, },
345 : { "RD", SEC_STD_SYNCHRONIZE, true, },
346 :
347 : { "WD", SEC_FILE_READ_DATA, false },
348 : { "WD", SEC_FILE_WRITE_DATA, true, },
349 : { "WD", SEC_FILE_APPEND_DATA, true, },
350 : { "WD", SEC_FILE_READ_EA, true },
351 : { "WD", SEC_FILE_WRITE_EA, true, },
352 : { "WD", SEC_FILE_EXECUTE, false },
353 : { "WD", SEC_FILE_READ_ATTRIBUTE, true, },
354 : { "WD", SEC_FILE_WRITE_ATTRIBUTE, true, },
355 : { "WD", SEC_STD_DELETE, true, },
356 : { "WD", SEC_STD_READ_CONTROL, true, },
357 : { "WD", SEC_STD_WRITE_DAC, true, },
358 : { "WD", SEC_STD_WRITE_OWNER, true, },
359 : { "WD", SEC_STD_SYNCHRONIZE, true, },
360 :
361 : { "RWD", SEC_FILE_READ_DATA, true },
362 : { "RWD", SEC_FILE_WRITE_DATA, true, },
363 : { "RWD", SEC_FILE_APPEND_DATA, true, },
364 : { "RWD", SEC_FILE_READ_EA, true },
365 : { "RWD", SEC_FILE_WRITE_EA, true, },
366 : { "RWD", SEC_FILE_EXECUTE, true, },
367 : { "RWD", SEC_FILE_READ_ATTRIBUTE, true, },
368 : { "RWD", SEC_FILE_WRITE_ATTRIBUTE, true, },
369 : { "RWD", SEC_STD_DELETE, true, },
370 : { "RWD", SEC_STD_READ_CONTROL, true, },
371 : { "RWD", SEC_STD_WRITE_DAC, true, },
372 : { "RWD", SEC_STD_WRITE_OWNER, true, },
373 : { "RWD", SEC_STD_SYNCHRONIZE, true, },
374 :
375 : /*
376 : * Some more interesting cases. Always request READ or WRITE
377 : * access, as that will trigger the opening of a file
378 : * description in Samba. This especially useful for file
379 : * systems that enforce share modes on open file descriptors.
380 : */
381 :
382 : { "R", SEC_FILE_READ_DATA, true, },
383 : { "R", SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, false, },
384 : { "R", SEC_FILE_READ_DATA|SEC_FILE_APPEND_DATA, false, },
385 : { "R", SEC_FILE_READ_DATA|SEC_FILE_READ_EA, true, },
386 : { "R", SEC_FILE_READ_DATA|SEC_FILE_WRITE_EA, true, },
387 : { "R", SEC_FILE_READ_DATA|SEC_FILE_EXECUTE, true, },
388 : { "R", SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE, true, },
389 : { "R", SEC_FILE_READ_DATA|SEC_FILE_WRITE_ATTRIBUTE, true, },
390 : { "R", SEC_FILE_READ_DATA|SEC_STD_DELETE, false, },
391 : { "R", SEC_FILE_READ_DATA|SEC_STD_READ_CONTROL, true, },
392 : { "R", SEC_FILE_READ_DATA|SEC_STD_WRITE_DAC, true, },
393 : { "R", SEC_FILE_READ_DATA|SEC_STD_WRITE_OWNER, true, },
394 : { "R", SEC_FILE_READ_DATA|SEC_STD_SYNCHRONIZE, true, },
395 :
396 : { "W", SEC_FILE_WRITE_DATA|SEC_FILE_READ_DATA, false, },
397 : { "W", SEC_FILE_WRITE_DATA, true, },
398 : { "W", SEC_FILE_WRITE_DATA|SEC_FILE_APPEND_DATA, true, },
399 : { "W", SEC_FILE_WRITE_DATA|SEC_FILE_READ_EA, true, },
400 : { "W", SEC_FILE_WRITE_DATA|SEC_FILE_WRITE_EA, true, },
401 : { "W", SEC_FILE_WRITE_DATA|SEC_FILE_EXECUTE, false, },
402 : { "W", SEC_FILE_WRITE_DATA|SEC_FILE_READ_ATTRIBUTE, true, },
403 : { "W", SEC_FILE_WRITE_DATA|SEC_FILE_WRITE_ATTRIBUTE, true, },
404 : { "W", SEC_FILE_WRITE_DATA|SEC_STD_DELETE, false, },
405 : { "W", SEC_FILE_WRITE_DATA|SEC_STD_READ_CONTROL, true, },
406 : { "W", SEC_FILE_WRITE_DATA|SEC_STD_WRITE_DAC, true, },
407 : { "W", SEC_FILE_WRITE_DATA|SEC_STD_WRITE_OWNER, true, },
408 : { "W", SEC_FILE_WRITE_DATA|SEC_STD_SYNCHRONIZE, true, },
409 :
410 : { "RW", SEC_FILE_READ_DATA, true, },
411 : { "RW", SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, true, },
412 : { "RW", SEC_FILE_READ_DATA|SEC_FILE_APPEND_DATA, true, },
413 : { "RW", SEC_FILE_READ_DATA|SEC_FILE_READ_EA, true, },
414 : { "RW", SEC_FILE_READ_DATA|SEC_FILE_WRITE_EA, true, },
415 : { "RW", SEC_FILE_READ_DATA|SEC_FILE_EXECUTE, true, },
416 : { "RW", SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE, true, },
417 : { "RW", SEC_FILE_READ_DATA|SEC_FILE_WRITE_ATTRIBUTE, true, },
418 : { "RW", SEC_FILE_READ_DATA|SEC_STD_DELETE, false, },
419 : { "RW", SEC_FILE_READ_DATA|SEC_STD_READ_CONTROL, true, },
420 : { "RW", SEC_FILE_READ_DATA|SEC_STD_WRITE_DAC, true, },
421 : { "RW", SEC_FILE_READ_DATA|SEC_STD_WRITE_OWNER, true, },
422 : { "RW", SEC_FILE_READ_DATA|SEC_STD_SYNCHRONIZE, true, },
423 :
424 : { "RD", SEC_FILE_READ_DATA, true, },
425 : { "RD", SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, false, },
426 : { "RD", SEC_FILE_READ_DATA|SEC_FILE_APPEND_DATA, false, },
427 : { "RD", SEC_FILE_READ_DATA|SEC_FILE_READ_EA, true },
428 : { "RD", SEC_FILE_READ_DATA|SEC_FILE_WRITE_EA, true, },
429 : { "RD", SEC_FILE_READ_DATA|SEC_FILE_EXECUTE, true, },
430 : { "RD", SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE, true, },
431 : { "RD", SEC_FILE_READ_DATA|SEC_FILE_WRITE_ATTRIBUTE, true, },
432 : { "RD", SEC_FILE_READ_DATA|SEC_STD_DELETE, true, },
433 : { "RD", SEC_FILE_READ_DATA|SEC_STD_READ_CONTROL, true, },
434 : { "RD", SEC_FILE_READ_DATA|SEC_STD_WRITE_DAC, true, },
435 : { "RD", SEC_FILE_READ_DATA|SEC_STD_WRITE_OWNER, true, },
436 : { "RD", SEC_FILE_READ_DATA|SEC_STD_SYNCHRONIZE, true, },
437 :
438 : { "WD", SEC_FILE_WRITE_DATA|SEC_FILE_READ_DATA, false },
439 : { "WD", SEC_FILE_WRITE_DATA, true, },
440 : { "WD", SEC_FILE_WRITE_DATA|SEC_FILE_APPEND_DATA, true, },
441 : { "WD", SEC_FILE_WRITE_DATA|SEC_FILE_READ_EA, true },
442 : { "WD", SEC_FILE_WRITE_DATA|SEC_FILE_WRITE_EA, true, },
443 : { "WD", SEC_FILE_WRITE_DATA|SEC_FILE_EXECUTE, false },
444 : { "WD", SEC_FILE_WRITE_DATA|SEC_FILE_READ_ATTRIBUTE, true, },
445 : { "WD", SEC_FILE_WRITE_DATA|SEC_FILE_WRITE_ATTRIBUTE, true, },
446 : { "WD", SEC_FILE_WRITE_DATA|SEC_STD_DELETE, true, },
447 : { "WD", SEC_FILE_WRITE_DATA|SEC_STD_READ_CONTROL, true, },
448 : { "WD", SEC_FILE_WRITE_DATA|SEC_STD_WRITE_DAC, true, },
449 : { "WD", SEC_FILE_WRITE_DATA|SEC_STD_WRITE_OWNER, true, },
450 : { "WD", SEC_FILE_WRITE_DATA|SEC_STD_SYNCHRONIZE, true, },
451 :
452 : { "RWD", SEC_FILE_READ_DATA, true },
453 : { "RWD", SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, true, },
454 : { "RWD", SEC_FILE_READ_DATA|SEC_FILE_APPEND_DATA, true, },
455 : { "RWD", SEC_FILE_READ_DATA|SEC_FILE_READ_EA, true, },
456 : { "RWD", SEC_FILE_READ_DATA|SEC_FILE_WRITE_EA, true, },
457 : { "RWD", SEC_FILE_READ_DATA|SEC_FILE_EXECUTE, true, },
458 : { "RWD", SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE, true, },
459 : { "RWD", SEC_FILE_READ_DATA|SEC_FILE_WRITE_ATTRIBUTE, true, },
460 : { "RWD", SEC_FILE_READ_DATA|SEC_STD_DELETE, true, },
461 : { "RWD", SEC_FILE_READ_DATA|SEC_STD_READ_CONTROL, true, },
462 : { "RWD", SEC_FILE_READ_DATA|SEC_STD_WRITE_DAC, true, },
463 : { "RWD", SEC_FILE_READ_DATA|SEC_STD_WRITE_OWNER, true, },
464 : { "RWD", SEC_FILE_READ_DATA|SEC_STD_SYNCHRONIZE, true, },
465 : };
466 :
467 : /*
468 : * Test conflicting sharemodes through SMB2: First open takes a
469 : * sharemode, second open with potentially conflicting access.
470 : */
471 5 : static bool test_smb2_sharemode_access(struct torture_context *tctx,
472 : struct smb2_tree *tree1,
473 : struct smb2_tree *tree2)
474 : {
475 5 : const char *fname = "test_sharemode";
476 0 : NTSTATUS status;
477 5 : bool ret = true;
478 0 : int i;
479 :
480 693 : for (i = 0; i < ARRAY_SIZE(sharemode_table); i++) {
481 689 : struct sharemode_info *info = &sharemode_table[i];
482 689 : struct smb2_create create1 = { 0 }, create2 = { 0 };
483 0 : NTSTATUS expected_status;
484 :
485 689 : torture_comment(tctx, "index %3d, sharemode %3s, "
486 : "access mask 0x%06x\n",
487 : i, info->sharemode, info->access_mask);
488 :
489 689 : create1.in.desired_access = SEC_RIGHTS_FILE_ALL;
490 689 : create1.in.alloc_size = 0;
491 689 : create1.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
492 689 : create1.in.share_access =
493 689 : smb2_util_share_access(info->sharemode);
494 689 : create1.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
495 689 : create1.in.create_options = 0;
496 689 : create1.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
497 689 : create1.in.fname = fname;
498 689 : create1.in.security_flags = 0;
499 689 : create1.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
500 689 : create1.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
501 :
502 689 : status = smb2_create(tree1, tctx, &create1);
503 :
504 689 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
505 : "CREATE file failed\n");
506 :
507 689 : create2.in.desired_access = info->access_mask;
508 689 : create2.in.alloc_size = 0;
509 689 : create2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
510 689 : create2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
511 : NTCREATEX_SHARE_ACCESS_WRITE |
512 : NTCREATEX_SHARE_ACCESS_DELETE;
513 689 : create2.in.create_disposition = NTCREATEX_DISP_OPEN;
514 689 : create2.in.create_options = 0;
515 689 : create2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
516 689 : create2.in.fname = fname;
517 689 : create2.in.security_flags = 0;
518 689 : create2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
519 689 : create2.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
520 :
521 689 : status = smb2_create(tree2, tctx, &create2);
522 689 : expected_status = info->expect_ok ?
523 169 : NT_STATUS_OK : NT_STATUS_SHARING_VIOLATION;
524 689 : torture_assert_ntstatus_equal_goto(tctx, status,
525 : expected_status, ret,
526 : done, "Unexpected status on "
527 : "second create.\n");
528 :
529 688 : status = smb2_util_close(tree1, create1.out.file.handle);
530 688 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
531 : "Failed to close "
532 : "first handle.\n");
533 :
534 688 : if (info->expect_ok) {
535 581 : status = smb2_util_close(tree2, create2.out.file.handle);
536 581 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
537 : "Failed to close "
538 : "second handle.\n");
539 : }
540 : }
541 :
542 4 : done:
543 5 : smb2_util_unlink(tree1, fname);
544 5 : return ret;
545 : }
546 :
547 : /*
548 : * Test conflicting sharemodes through SMB2: First open file with
549 : * different access masks, second open requests potentially conflicting
550 : * sharemode.
551 : */
552 5 : static bool test_smb2_access_sharemode(struct torture_context *tctx,
553 : struct smb2_tree *tree1,
554 : struct smb2_tree *tree2)
555 : {
556 5 : const char *fname = "test_sharemode";
557 0 : NTSTATUS status;
558 5 : bool ret = true;
559 0 : int i;
560 :
561 693 : for (i = 0; i < ARRAY_SIZE(sharemode_table); i++) {
562 689 : struct sharemode_info *info = &sharemode_table[i];
563 689 : struct smb2_create create1 = { 0 }, create2 = { 0 };
564 0 : NTSTATUS expected_status;
565 :
566 689 : torture_comment(tctx, "index %3d, access mask 0x%06x, "
567 : "sharemode %3s\n",
568 : i, info->access_mask, info->sharemode);
569 :
570 689 : create1.in.desired_access = info->access_mask;
571 689 : create1.in.alloc_size = 0;
572 689 : create1.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
573 689 : create1.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
574 : NTCREATEX_SHARE_ACCESS_WRITE |
575 : NTCREATEX_SHARE_ACCESS_DELETE;
576 689 : create1.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
577 689 : create1.in.create_options = 0;
578 689 : create1.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
579 689 : create1.in.fname = fname;
580 689 : create1.in.security_flags = 0;
581 689 : create1.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
582 689 : create1.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
583 :
584 689 : status = smb2_create(tree1, tctx, &create1);
585 :
586 689 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
587 : "CREATE file failed\n");
588 :
589 688 : create2.in.desired_access = SEC_RIGHTS_FILE_ALL;
590 688 : create2.in.alloc_size = 0;
591 688 : create2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
592 688 : create2.in.share_access =
593 688 : smb2_util_share_access(info->sharemode);
594 688 : create2.in.create_disposition = NTCREATEX_DISP_OPEN;
595 688 : create2.in.create_options = 0;
596 688 : create2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
597 688 : create2.in.fname = fname;
598 688 : create2.in.security_flags = 0;
599 688 : create2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
600 688 : create2.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
601 :
602 688 : status = smb2_create(tree2, tctx, &create2);
603 :
604 688 : expected_status = info->expect_ok ?
605 169 : NT_STATUS_OK : NT_STATUS_SHARING_VIOLATION;
606 688 : torture_assert_ntstatus_equal_goto(tctx, status,
607 : expected_status, ret,
608 : done, "Unexpected status on "
609 : "second create.\n");
610 :
611 688 : status = smb2_util_close(tree1, create1.out.file.handle);
612 688 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
613 : "Failed to close "
614 : "first handle.\n");
615 :
616 688 : if (info->expect_ok) {
617 581 : status = smb2_util_close(tree2, create2.out.file.handle);
618 581 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
619 : "Failed to close "
620 : "second handle.\n");
621 : }
622 : }
623 :
624 4 : done:
625 5 : smb2_util_unlink(tree1, fname);
626 5 : return ret;
627 : }
628 :
629 : /*
630 : * Test initial stat open with share nothing doesn't trigger SHARING_VIOLTION
631 : * errors.
632 : */
633 5 : static bool test_smb2_bug14375(struct torture_context *tctx,
634 : struct smb2_tree *tree)
635 : {
636 5 : const char *fname = "test_bug14375";
637 0 : struct smb2_create cr1;
638 0 : struct smb2_create cr2;
639 0 : struct smb2_create cr3;
640 0 : NTSTATUS status;
641 5 : bool ret = true;
642 :
643 5 : smb2_util_unlink(tree, fname);
644 :
645 5 : cr1 = (struct smb2_create) {
646 : .in.desired_access = SEC_FILE_READ_ATTRIBUTE,
647 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
648 : .in.share_access = NTCREATEX_SHARE_ACCESS_NONE,
649 : .in.create_disposition = NTCREATEX_DISP_CREATE,
650 : .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
651 : .in.fname = fname,
652 : };
653 :
654 5 : status = smb2_create(tree, tctx, &cr1);
655 5 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
656 : "CREATE file failed\n");
657 :
658 5 : cr2 = (struct smb2_create) {
659 : .in.desired_access = SEC_FILE_READ_DATA,
660 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
661 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
662 : .in.create_disposition = NTCREATEX_DISP_OPEN,
663 : .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
664 : .in.fname = fname,
665 : };
666 :
667 5 : status = smb2_create(tree, tctx, &cr2);
668 5 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
669 : "CREATE file failed\n");
670 :
671 5 : cr3 = (struct smb2_create) {
672 : .in.desired_access = SEC_FILE_READ_DATA,
673 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
674 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
675 : .in.create_disposition = NTCREATEX_DISP_OPEN,
676 : .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
677 : .in.fname = fname,
678 : };
679 :
680 5 : status = smb2_create(tree, tctx, &cr3);
681 5 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
682 : "CREATE file failed\n");
683 :
684 5 : status = smb2_util_close(tree, cr1.out.file.handle);
685 5 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
686 : "CLOSE file failed\n");
687 5 : status = smb2_util_close(tree, cr2.out.file.handle);
688 5 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
689 : "CLOSE file failed\n");
690 5 : status = smb2_util_close(tree, cr3.out.file.handle);
691 5 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
692 : "CLOSE file failed\n");
693 :
694 5 : cr1 = (struct smb2_create) {
695 : .in.desired_access = SEC_FILE_READ_DATA,
696 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
697 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
698 : .in.create_disposition = NTCREATEX_DISP_OPEN,
699 : .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
700 : .in.fname = fname,
701 : };
702 :
703 5 : status = smb2_create(tree, tctx, &cr1);
704 5 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
705 : "CREATE file failed\n");
706 :
707 5 : cr2 = (struct smb2_create) {
708 : .in.desired_access = SEC_FILE_READ_ATTRIBUTE,
709 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
710 : .in.share_access = NTCREATEX_SHARE_ACCESS_NONE,
711 : .in.create_disposition = NTCREATEX_DISP_OPEN,
712 : .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
713 : .in.fname = fname,
714 : };
715 :
716 5 : status = smb2_create(tree, tctx, &cr2);
717 5 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
718 : "CREATE file failed\n");
719 :
720 5 : cr3 = (struct smb2_create) {
721 : .in.desired_access = SEC_FILE_READ_DATA,
722 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
723 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
724 : .in.create_disposition = NTCREATEX_DISP_OPEN,
725 : .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
726 : .in.fname = fname,
727 : };
728 :
729 5 : status = smb2_create(tree, tctx, &cr3);
730 5 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
731 : "CREATE file failed\n");
732 :
733 5 : done:
734 5 : smb2_util_close(tree, cr1.out.file.handle);
735 5 : smb2_util_close(tree, cr2.out.file.handle);
736 5 : smb2_util_close(tree, cr3.out.file.handle);
737 5 : smb2_util_unlink(tree, fname);
738 5 : return ret;
739 : }
740 :
741 2354 : struct torture_suite *torture_smb2_sharemode_init(TALLOC_CTX *ctx)
742 : {
743 2354 : struct torture_suite *suite = torture_suite_create(ctx, "sharemode");
744 :
745 2354 : torture_suite_add_2smb2_test(suite, "sharemode-access",
746 : test_smb2_sharemode_access);
747 2354 : torture_suite_add_2smb2_test(suite, "access-sharemode",
748 : test_smb2_access_sharemode);
749 2354 : torture_suite_add_1smb2_test(suite, "bug14375",
750 : test_smb2_bug14375);
751 :
752 2354 : suite->description = talloc_strdup(suite, "SMB2-SHAREMODE tests");
753 :
754 2354 : return suite;
755 : }
|