s3-selftest: Remove some unnecessary comma
[Samba/gebeck_regimport.git] / source4 / torture / smb2 / durable_v2_open.c
blobc1a2c883b956e1d9911298eff15ed51980c32190
1 /*
2 Unix SMB/CIFS implementation.
4 test suite for SMB2 version two of durable opens
6 Copyright (C) Michael Adam 2012
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
25 #include "../libcli/smb/smbXcli_base.h"
26 #include "torture/torture.h"
27 #include "torture/smb2/proto.h"
28 #include "librpc/ndr/libndr.h"
30 #define CHECK_VAL(v, correct) do { \
31 if ((v) != (correct)) { \
32 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
33 __location__, #v, (int)v, (int)correct); \
34 ret = false; \
35 }} while (0)
37 #define CHECK_STATUS(status, correct) do { \
38 if (!NT_STATUS_EQUAL(status, correct)) { \
39 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
40 nt_errstr(status), nt_errstr(correct)); \
41 ret = false; \
42 goto done; \
43 }} while (0)
45 #define CHECK_CREATED(__io, __created, __attribute) \
46 do { \
47 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
48 CHECK_VAL((__io)->out.alloc_size, 0); \
49 CHECK_VAL((__io)->out.size, 0); \
50 CHECK_VAL((__io)->out.file_attr, (__attribute)); \
51 CHECK_VAL((__io)->out.reserved2, 0); \
52 } while(0)
54 /**
55 * basic durable_open test.
56 * durable state should only be granted when requested
57 * along with a batch oplock or a handle lease.
59 * This test tests durable open with all possible oplock types.
62 struct durable_open_vs_oplock {
63 const char *level;
64 const char *share_mode;
65 bool durable;
66 bool persistent;
69 #define NUM_OPLOCK_TYPES 4
70 #define NUM_SHARE_MODES 8
71 #define NUM_OPLOCK_OPEN_TESTS ( NUM_OPLOCK_TYPES * NUM_SHARE_MODES )
72 static struct durable_open_vs_oplock durable_open_vs_oplock_table[NUM_OPLOCK_OPEN_TESTS] =
74 { "", "", false, false },
75 { "", "R", false, false },
76 { "", "W", false, false },
77 { "", "D", false, false },
78 { "", "RD", false, false },
79 { "", "RW", false, false },
80 { "", "WD", false, false },
81 { "", "RWD", false, false },
83 { "s", "", false, false },
84 { "s", "R", false, false },
85 { "s", "W", false, false },
86 { "s", "D", false, false },
87 { "s", "RD", false, false },
88 { "s", "RW", false, false },
89 { "s", "WD", false, false },
90 { "s", "RWD", false, false },
92 { "x", "", false, false },
93 { "x", "R", false, false },
94 { "x", "W", false, false },
95 { "x", "D", false, false },
96 { "x", "RD", false, false },
97 { "x", "RW", false, false },
98 { "x", "WD", false, false },
99 { "x", "RWD", false, false },
101 { "b", "", true, false },
102 { "b", "R", true, false },
103 { "b", "W", true, false },
104 { "b", "D", true, false },
105 { "b", "RD", true, false },
106 { "b", "RW", true, false },
107 { "b", "WD", true, false },
108 { "b", "RWD", true, false },
111 static bool test_one_durable_v2_open_oplock(struct torture_context *tctx,
112 struct smb2_tree *tree,
113 const char *fname,
114 bool request_persistent,
115 struct durable_open_vs_oplock test)
117 NTSTATUS status;
118 TALLOC_CTX *mem_ctx = talloc_new(tctx);
119 struct smb2_handle _h;
120 struct smb2_handle *h = NULL;
121 bool ret = true;
122 struct smb2_create io;
124 smb2_util_unlink(tree, fname);
126 smb2_oplock_create_share(&io, fname,
127 smb2_util_share_access(test.share_mode),
128 smb2_util_oplock_level(test.level));
129 io.in.durable_open = false;
130 io.in.durable_open_v2 = true;
131 io.in.persistent_open = request_persistent;
132 io.in.create_guid = GUID_random();
134 status = smb2_create(tree, mem_ctx, &io);
135 CHECK_STATUS(status, NT_STATUS_OK);
136 _h = io.out.file.handle;
137 h = &_h;
138 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
139 CHECK_VAL(io.out.durable_open, false);
140 CHECK_VAL(io.out.durable_open_v2, test.durable);
141 CHECK_VAL(io.out.persistent_open, test.persistent);
142 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(test.level));
144 done:
145 if (h != NULL) {
146 smb2_util_close(tree, *h);
148 smb2_util_unlink(tree, fname);
149 talloc_free(mem_ctx);
151 return ret;
154 static bool test_durable_v2_open_oplock_table(struct torture_context *tctx,
155 struct smb2_tree *tree,
156 const char *fname,
157 bool request_persistent,
158 struct durable_open_vs_oplock *table,
159 uint8_t num_tests)
161 bool ret = true;
162 uint8_t i;
164 smb2_util_unlink(tree, fname);
166 for (i = 0; i < num_tests; i++) {
167 ret = test_one_durable_v2_open_oplock(tctx,
168 tree,
169 fname,
170 request_persistent,
171 table[i]);
172 if (ret == false) {
173 goto done;
177 done:
178 smb2_util_unlink(tree, fname);
180 return ret;
183 bool test_durable_v2_open_oplock(struct torture_context *tctx,
184 struct smb2_tree *tree)
186 bool ret;
187 char fname[256];
189 /* Choose a random name in case the state is left a little funky. */
190 snprintf(fname, 256, "durable_open_oplock_%s.dat",
191 generate_random_str(tctx, 8));
193 ret = test_durable_v2_open_oplock_table(tctx, tree, fname,
194 false, /* request_persistent */
195 durable_open_vs_oplock_table,
196 NUM_OPLOCK_OPEN_TESTS);
198 talloc_free(tree);
200 return ret;
204 * basic durable handle open test.
205 * persistent state should only be granted when requested
206 * along with a batch oplock or a handle lease.
208 * This test tests persistent open with all valid lease types.
211 struct durable_open_vs_lease {
212 const char *type;
213 const char *share_mode;
214 bool durable;
215 bool persistent;
218 #define NUM_LEASE_TYPES 5
219 #define NUM_LEASE_OPEN_TESTS ( NUM_LEASE_TYPES * NUM_SHARE_MODES )
220 static struct durable_open_vs_lease durable_open_vs_lease_table[NUM_LEASE_OPEN_TESTS] =
222 { "", "", false, false },
223 { "", "R", false, false },
224 { "", "W", false, false },
225 { "", "D", false, false },
226 { "", "RW", false, false },
227 { "", "RD", false, false },
228 { "", "WD", false, false },
229 { "", "RWD", false, false },
231 { "R", "", false, false },
232 { "R", "R", false, false },
233 { "R", "W", false, false },
234 { "R", "D", false, false },
235 { "R", "RW", false, false },
236 { "R", "RD", false, false },
237 { "R", "DW", false, false },
238 { "R", "RWD", false, false },
240 { "RW", "", false, false },
241 { "RW", "R", false, false },
242 { "RW", "W", false, false },
243 { "RW", "D", false, false },
244 { "RW", "RW", false, false },
245 { "RW", "RD", false, false },
246 { "RW", "WD", false, false },
247 { "RW", "RWD", false, false },
249 { "RH", "", true, false },
250 { "RH", "R", true, false },
251 { "RH", "W", true, false },
252 { "RH", "D", true, false },
253 { "RH", "RW", true, false },
254 { "RH", "RD", true, false },
255 { "RH", "WD", true, false },
256 { "RH", "RWD", true, false },
258 { "RHW", "", true, false },
259 { "RHW", "R", true, false },
260 { "RHW", "W", true, false },
261 { "RHW", "D", true, false },
262 { "RHW", "RW", true, false },
263 { "RHW", "RD", true, false },
264 { "RHW", "WD", true, false },
265 { "RHW", "RWD", true, false },
268 static bool test_one_durable_v2_open_lease(struct torture_context *tctx,
269 struct smb2_tree *tree,
270 const char *fname,
271 bool request_persistent,
272 struct durable_open_vs_lease test)
274 NTSTATUS status;
275 TALLOC_CTX *mem_ctx = talloc_new(tctx);
276 struct smb2_handle _h;
277 struct smb2_handle *h = NULL;
278 bool ret = true;
279 struct smb2_create io;
280 struct smb2_lease ls;
281 uint64_t lease;
283 smb2_util_unlink(tree, fname);
285 lease = random();
287 smb2_lease_create_share(&io, &ls, false /* dir */, fname,
288 smb2_util_share_access(test.share_mode),
289 lease,
290 smb2_util_lease_state(test.type));
291 io.in.durable_open = false;
292 io.in.durable_open_v2 = true;
293 io.in.persistent_open = request_persistent;
294 io.in.create_guid = GUID_random();
296 status = smb2_create(tree, mem_ctx, &io);
297 CHECK_STATUS(status, NT_STATUS_OK);
298 _h = io.out.file.handle;
299 h = &_h;
300 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
301 CHECK_VAL(io.out.durable_open, false);
302 CHECK_VAL(io.out.durable_open_v2, test.durable);
303 CHECK_VAL(io.out.persistent_open, test.persistent);
304 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
305 CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
306 CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
307 CHECK_VAL(io.out.lease_response.lease_state,
308 smb2_util_lease_state(test.type));
309 done:
310 if (h != NULL) {
311 smb2_util_close(tree, *h);
313 smb2_util_unlink(tree, fname);
314 talloc_free(mem_ctx);
316 return ret;
319 static bool test_durable_v2_open_lease_table(struct torture_context *tctx,
320 struct smb2_tree *tree,
321 const char *fname,
322 bool request_persistent,
323 struct durable_open_vs_lease *table,
324 uint8_t num_tests)
326 bool ret = true;
327 uint8_t i;
329 smb2_util_unlink(tree, fname);
331 for (i = 0; i < num_tests; i++) {
332 ret = test_one_durable_v2_open_lease(tctx,
333 tree,
334 fname,
335 request_persistent,
336 table[i]);
337 if (ret == false) {
338 goto done;
342 done:
343 smb2_util_unlink(tree, fname);
345 return ret;
348 bool test_durable_v2_open_lease(struct torture_context *tctx,
349 struct smb2_tree *tree)
351 char fname[256];
352 bool ret = true;
353 uint32_t caps;
355 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
356 if (!(caps & SMB2_CAP_LEASING)) {
357 torture_skip(tctx, "leases are not supported");
360 /* Choose a random name in case the state is left a little funky. */
361 snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));
363 ret = test_durable_v2_open_lease_table(tctx, tree, fname,
364 false, /* request_persistent */
365 durable_open_vs_lease_table,
366 NUM_LEASE_OPEN_TESTS);
368 talloc_free(tree);
369 return ret;
374 * basic persistent open test.
376 * This test tests durable open with all possible oplock types.
379 struct durable_open_vs_oplock persistent_open_oplock_ca_table[NUM_OPLOCK_OPEN_TESTS] =
381 { "", "", true, true },
382 { "", "R", true, true },
383 { "", "W", true, true },
384 { "", "D", true, true },
385 { "", "RD", true, true },
386 { "", "RW", true, true },
387 { "", "WD", true, true },
388 { "", "RWD", true, true },
390 { "s", "", true, true },
391 { "s", "R", true, true },
392 { "s", "W", true, true },
393 { "s", "D", true, true },
394 { "s", "RD", true, true },
395 { "s", "RW", true, true },
396 { "s", "WD", true, true },
397 { "s", "RWD", true, true },
399 { "x", "", true, true },
400 { "x", "R", true, true },
401 { "x", "W", true, true },
402 { "x", "D", true, true },
403 { "x", "RD", true, true },
404 { "x", "RW", true, true },
405 { "x", "WD", true, true },
406 { "x", "RWD", true, true },
408 { "b", "", true, true },
409 { "b", "R", true, true },
410 { "b", "W", true, true },
411 { "b", "D", true, true },
412 { "b", "RD", true, true },
413 { "b", "RW", true, true },
414 { "b", "WD", true, true },
415 { "b", "RWD", true, true },
418 bool test_persistent_open_oplock(struct torture_context *tctx,
419 struct smb2_tree *tree)
421 char fname[256];
422 bool ret = true;
423 bool share_is_ca = false;
424 struct durable_open_vs_oplock *table;
426 /* Choose a random name in case the state is left a little funky. */
427 snprintf(fname, 256, "persistent_open_oplock_%s.dat", generate_random_str(tctx, 8));
429 share_is_ca = tree->capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY;
431 if (share_is_ca) {
432 table = persistent_open_oplock_ca_table;
433 } else {
434 table = durable_open_vs_oplock_table;
437 ret = test_durable_v2_open_oplock_table(tctx, tree, fname,
438 true, /* request_persistent */
439 table,
440 NUM_OPLOCK_OPEN_TESTS);
442 talloc_free(tree);
444 return ret;
448 * basic persistent handle open test.
449 * persistent state should only be granted when requested
450 * along with a batch oplock or a handle lease.
452 * This test tests persistent open with all valid lease types.
455 struct durable_open_vs_lease persistent_open_lease_ca_table[NUM_LEASE_OPEN_TESTS] =
457 { "", "", true, true },
458 { "", "R", true, true },
459 { "", "W", true, true },
460 { "", "D", true, true },
461 { "", "RW", true, true },
462 { "", "RD", true, true },
463 { "", "WD", true, true },
464 { "", "RWD", true, true },
466 { "R", "", true, true },
467 { "R", "R", true, true },
468 { "R", "W", true, true },
469 { "R", "D", true, true },
470 { "R", "RW", true, true },
471 { "R", "RD", true, true },
472 { "R", "DW", true, true },
473 { "R", "RWD", true, true },
475 { "RW", "", true, true },
476 { "RW", "R", true, true },
477 { "RW", "W", true, true },
478 { "RW", "D", true, true },
479 { "RW", "RW", true, true },
480 { "RW", "RD", true, true },
481 { "RW", "WD", true, true },
482 { "RW", "RWD", true, true },
484 { "RH", "", true, true },
485 { "RH", "R", true, true },
486 { "RH", "W", true, true },
487 { "RH", "D", true, true },
488 { "RH", "RW", true, true },
489 { "RH", "RD", true, true },
490 { "RH", "WD", true, true },
491 { "RH", "RWD", true, true },
493 { "RHW", "", true, true },
494 { "RHW", "R", true, true },
495 { "RHW", "W", true, true },
496 { "RHW", "D", true, true },
497 { "RHW", "RW", true, true },
498 { "RHW", "RD", true, true },
499 { "RHW", "WD", true, true },
500 { "RHW", "RWD", true, true },
503 bool test_persistent_open_lease(struct torture_context *tctx,
504 struct smb2_tree *tree)
506 char fname[256];
507 bool ret = true;
508 uint32_t caps;
509 bool share_is_ca;
510 struct durable_open_vs_lease *table;
512 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
513 if (!(caps & SMB2_CAP_LEASING)) {
514 torture_skip(tctx, "leases are not supported");
517 /* Choose a random name in case the state is left a little funky. */
518 snprintf(fname, 256, "persistent_open_lease_%s.dat", generate_random_str(tctx, 8));
520 share_is_ca = tree->capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY;
522 if (share_is_ca) {
523 table = persistent_open_lease_ca_table;
524 } else {
525 table = durable_open_vs_lease_table;
528 ret = test_durable_v2_open_lease_table(tctx, tree, fname,
529 true, /* request_persistent */
530 table,
531 NUM_LEASE_OPEN_TESTS);
533 talloc_free(tree);
535 return ret;
538 struct torture_suite *torture_smb2_durable_v2_open_init(void)
540 struct torture_suite *suite =
541 torture_suite_create(talloc_autofree_context(), "durable-v2-open");
543 torture_suite_add_1smb2_test(suite, "open-oplock", test_durable_v2_open_oplock);
544 torture_suite_add_1smb2_test(suite, "open-lease", test_durable_v2_open_lease);
545 torture_suite_add_1smb2_test(suite, "persistent-open-oplock", test_persistent_open_oplock);
546 torture_suite_add_1smb2_test(suite, "persistent-open-lease", test_persistent_open_lease);
548 suite->description = talloc_strdup(suite, "SMB2-DURABLE-V2-OPEN tests");
550 return suite;