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