2 Unix SMB/CIFS implementation.
4 test suite for SMB2 durable opens
6 Copyright (C) Stefan Metzmacher 2008
7 Copyright (C) Michael Adam 2011-2012
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "../libcli/smb/smbXcli_base.h"
27 #include "torture/torture.h"
28 #include "torture/smb2/proto.h"
29 #include "../libcli/smb/smbXcli_base.h"
31 #define CHECK_VAL(v, correct) do { \
32 if ((v) != (correct)) { \
33 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%llx - should be 0x%llx\n", \
34 __location__, #v, (unsigned long long)v, (unsigned long long)correct); \
38 #define CHECK_NOT_VAL(v, correct) do { \
39 if ((v) == (correct)) { \
40 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%llx - should not be 0x%llx\n", \
41 __location__, #v, (unsigned long long)v, (unsigned long long)correct); \
45 #define CHECK_STATUS(status, correct) do { \
46 if (!NT_STATUS_EQUAL(status, correct)) { \
47 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
48 nt_errstr(status), nt_errstr(correct)); \
53 #define CHECK_CREATED(__io, __created, __attribute) \
55 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
56 CHECK_VAL((__io)->out.alloc_size, 0); \
57 CHECK_VAL((__io)->out.size, 0); \
58 CHECK_VAL((__io)->out.file_attr, (__attribute)); \
59 CHECK_VAL((__io)->out.reserved2, 0); \
62 #define CHECK_CREATED_SIZE(__io, __created, __attribute, __alloc_size, __size) \
64 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
65 CHECK_VAL((__io)->out.alloc_size, (__alloc_size)); \
66 CHECK_VAL((__io)->out.size, (__size)); \
67 CHECK_VAL((__io)->out.file_attr, (__attribute)); \
68 CHECK_VAL((__io)->out.reserved2, 0); \
74 * basic durable_open test.
75 * durable state should only be granted when requested
76 * along with a batch oplock or a handle lease.
78 * This test tests durable open with all possible oplock types.
81 struct durable_open_vs_oplock {
83 const char *share_mode;
87 #define NUM_OPLOCK_TYPES 4
88 #define NUM_SHARE_MODES 8
89 #define NUM_OPLOCK_OPEN_TESTS ( NUM_OPLOCK_TYPES * NUM_SHARE_MODES )
90 static struct durable_open_vs_oplock durable_open_vs_oplock_table[NUM_OPLOCK_OPEN_TESTS] =
105 { "s", "RD", false },
106 { "s", "RW", false },
107 { "s", "WD", false },
108 { "s", "RWD", false },
114 { "x", "RD", false },
115 { "x", "RW", false },
116 { "x", "WD", false },
117 { "x", "RWD", false },
126 { "b", "RWD", true },
129 static bool test_one_durable_open_open_oplock(struct torture_context *tctx,
130 struct smb2_tree *tree,
132 struct durable_open_vs_oplock test)
135 TALLOC_CTX *mem_ctx = talloc_new(tctx);
136 struct smb2_handle _h;
137 struct smb2_handle *h = NULL;
139 struct smb2_create io;
141 smb2_util_unlink(tree, fname);
143 smb2_oplock_create_share(&io, fname,
144 smb2_util_share_access(test.share_mode),
145 smb2_util_oplock_level(test.level));
146 io.in.durable_open = true;
148 status = smb2_create(tree, mem_ctx, &io);
149 CHECK_STATUS(status, NT_STATUS_OK);
150 _h = io.out.file.handle;
152 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
153 CHECK_VAL(io.out.durable_open, test.expected);
154 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(test.level));
158 smb2_util_close(tree, *h);
160 smb2_util_unlink(tree, fname);
161 talloc_free(mem_ctx);
166 static bool test_durable_open_open_oplock(struct torture_context *tctx,
167 struct smb2_tree *tree)
169 TALLOC_CTX *mem_ctx = talloc_new(tctx);
174 /* Choose a random name in case the state is left a little funky. */
175 snprintf(fname, 256, "durable_open_open_oplock_%s.dat", generate_random_str(tctx, 8));
177 smb2_util_unlink(tree, fname);
179 /* test various oplock levels with durable open */
181 for (i = 0; i < NUM_OPLOCK_OPEN_TESTS; i++) {
182 ret = test_one_durable_open_open_oplock(tctx,
185 durable_open_vs_oplock_table[i]);
192 smb2_util_unlink(tree, fname);
194 talloc_free(mem_ctx);
200 * basic durable_open test.
201 * durable state should only be granted when requested
202 * along with a batch oplock or a handle lease.
204 * This test tests durable open with all valid lease types.
207 struct durable_open_vs_lease {
209 const char *share_mode;
213 #define NUM_LEASE_TYPES 5
214 #define NUM_LEASE_OPEN_TESTS ( NUM_LEASE_TYPES * NUM_SHARE_MODES )
215 static struct durable_open_vs_lease durable_open_vs_lease_table[NUM_LEASE_OPEN_TESTS] =
224 { "", "RWD", false },
230 { "R", "RW", false },
231 { "R", "RD", false },
232 { "R", "DW", false },
233 { "R", "RWD", false },
236 { "RW", "R", false },
237 { "RW", "W", false },
238 { "RW", "D", false },
239 { "RW", "RW", false },
240 { "RW", "RD", false },
241 { "RW", "WD", false },
242 { "RW", "RWD", false },
248 { "RH", "RW", true },
249 { "RH", "RD", true },
250 { "RH", "WD", true },
251 { "RH", "RWD", true },
254 { "RHW", "R", true },
255 { "RHW", "W", true },
256 { "RHW", "D", true },
257 { "RHW", "RW", true },
258 { "RHW", "RD", true },
259 { "RHW", "WD", true },
260 { "RHW", "RWD", true },
263 static bool test_one_durable_open_open_lease(struct torture_context *tctx,
264 struct smb2_tree *tree,
266 struct durable_open_vs_lease test)
269 TALLOC_CTX *mem_ctx = talloc_new(tctx);
270 struct smb2_handle _h;
271 struct smb2_handle *h = NULL;
273 struct smb2_create io;
274 struct smb2_lease ls;
278 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
279 if (!(caps & SMB2_CAP_LEASING)) {
280 torture_skip(tctx, "leases are not supported");
283 smb2_util_unlink(tree, fname);
287 smb2_lease_create_share(&io, &ls, false /* dir */, fname,
288 smb2_util_share_access(test.share_mode),
290 smb2_util_lease_state(test.type));
291 io.in.durable_open = true;
293 status = smb2_create(tree, mem_ctx, &io);
294 CHECK_STATUS(status, NT_STATUS_OK);
295 _h = io.out.file.handle;
297 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
298 CHECK_VAL(io.out.durable_open, test.expected);
299 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
300 CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
301 CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
302 CHECK_VAL(io.out.lease_response.lease_state,
303 smb2_util_lease_state(test.type));
306 smb2_util_close(tree, *h);
308 smb2_util_unlink(tree, fname);
309 talloc_free(mem_ctx);
314 static bool test_durable_open_open_lease(struct torture_context *tctx,
315 struct smb2_tree *tree)
317 TALLOC_CTX *mem_ctx = talloc_new(tctx);
323 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
324 if (!(caps & SMB2_CAP_LEASING)) {
325 torture_skip(tctx, "leases are not supported");
328 /* Choose a random name in case the state is left a little funky. */
329 snprintf(fname, 256, "durable_open_open_lease_%s.dat", generate_random_str(tctx, 8));
331 smb2_util_unlink(tree, fname);
334 /* test various oplock levels with durable open */
336 for (i = 0; i < NUM_LEASE_OPEN_TESTS; i++) {
337 ret = test_one_durable_open_open_lease(tctx,
340 durable_open_vs_lease_table[i]);
347 smb2_util_unlink(tree, fname);
349 talloc_free(mem_ctx);
355 * basic test for doing a durable open
356 * and do a durable reopen on the same connection
357 * while the first open is still active (fails)
359 static bool test_durable_open_reopen1(struct torture_context *tctx,
360 struct smb2_tree *tree)
363 TALLOC_CTX *mem_ctx = talloc_new(tctx);
365 struct smb2_handle _h;
366 struct smb2_handle *h = NULL;
367 struct smb2_create io1, io2;
370 /* Choose a random name in case the state is left a little funky. */
371 snprintf(fname, 256, "durable_open_reopen1_%s.dat",
372 generate_random_str(tctx, 8));
374 smb2_util_unlink(tree, fname);
376 smb2_oplock_create_share(&io1, fname,
377 smb2_util_share_access(""),
378 smb2_util_oplock_level("b"));
379 io1.in.durable_open = true;
381 status = smb2_create(tree, mem_ctx, &io1);
382 CHECK_STATUS(status, NT_STATUS_OK);
383 _h = io1.out.file.handle;
385 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
386 CHECK_VAL(io1.out.durable_open, true);
387 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
389 /* try a durable reconnect while the file is still open */
391 io2.in.fname = fname;
392 io2.in.durable_handle = h;
394 status = smb2_create(tree, mem_ctx, &io2);
395 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
399 smb2_util_close(tree, *h);
402 smb2_util_unlink(tree, fname);
406 talloc_free(mem_ctx);
412 * basic test for doing a durable open
413 * tcp disconnect, reconnect, do a durable reopen (succeeds)
415 static bool test_durable_open_reopen2(struct torture_context *tctx,
416 struct smb2_tree *tree)
419 TALLOC_CTX *mem_ctx = talloc_new(tctx);
421 struct smb2_handle _h;
422 struct smb2_handle *h = NULL;
423 struct smb2_create io1, io2;
426 /* Choose a random name in case the state is left a little funky. */
427 snprintf(fname, 256, "durable_open_reopen2_%s.dat",
428 generate_random_str(tctx, 8));
430 smb2_util_unlink(tree, fname);
432 smb2_oplock_create_share(&io1, fname,
433 smb2_util_share_access(""),
434 smb2_util_oplock_level("b"));
435 io1.in.durable_open = true;
437 status = smb2_create(tree, mem_ctx, &io1);
438 CHECK_STATUS(status, NT_STATUS_OK);
439 _h = io1.out.file.handle;
441 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
442 CHECK_VAL(io1.out.durable_open, true);
443 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
445 /* disconnect, reconnect and then do durable reopen */
449 if (!torture_smb2_connection(tctx, &tree)) {
450 torture_warning(tctx, "couldn't reconnect, bailing\n");
456 /* the path name is ignored by the server */
457 io2.in.fname = "__non_existing_fname__";
458 io2.in.durable_handle = h;
461 status = smb2_create(tree, mem_ctx, &io2);
462 CHECK_STATUS(status, NT_STATUS_OK);
463 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
464 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
465 _h = io2.out.file.handle;
471 smb2_util_close(tree, *h);
474 smb2_util_unlink(tree, fname);
479 talloc_free(mem_ctx);
485 * lease variant of reopen2
486 * basic test for doing a durable open
487 * tcp disconnect, reconnect, do a durable reopen (succeeds)
489 static bool test_durable_open_reopen2_lease(struct torture_context *tctx,
490 struct smb2_tree *tree)
493 TALLOC_CTX *mem_ctx = talloc_new(tctx);
495 struct smb2_handle _h;
496 struct smb2_handle *h = NULL;
497 struct smb2_create io;
498 struct smb2_lease ls;
501 struct smbcli_options options;
504 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
505 if (!(caps & SMB2_CAP_LEASING)) {
506 torture_skip(tctx, "leases are not supported");
509 options = tree->session->transport->options;
511 /* Choose a random name in case the state is left a little funky. */
512 snprintf(fname, 256, "durable_open_reopen2_%s.dat",
513 generate_random_str(tctx, 8));
515 smb2_util_unlink(tree, fname);
517 lease_key = random();
518 smb2_lease_create(&io, &ls, false /* dir */, fname, lease_key,
519 smb2_util_lease_state("RWH"));
520 io.in.durable_open = true;
522 status = smb2_create(tree, mem_ctx, &io);
523 CHECK_STATUS(status, NT_STATUS_OK);
524 _h = io.out.file.handle;
526 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
528 CHECK_VAL(io.out.durable_open, true);
529 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
530 CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
531 CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
532 CHECK_VAL(io.out.lease_response.lease_state,
533 smb2_util_lease_state("RWH"));
534 CHECK_VAL(io.out.lease_response.lease_flags, 0);
535 CHECK_VAL(io.out.lease_response.lease_duration, 0);
537 /* disconnect, reconnect and then do durable reopen */
540 if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
541 torture_warning(tctx, "couldn't reconnect, bailing\n");
547 /* a few failure tests: */
550 * several attempts without lease attached:
551 * all fail with NT_STATUS_OBJECT_NAME_NOT_FOUND
552 * irrespective of file name provided
557 io.in.durable_handle = h;
558 status = smb2_create(tree, mem_ctx, &io);
559 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
562 io.in.fname = "__non_existing_fname__";
563 io.in.durable_handle = h;
564 status = smb2_create(tree, mem_ctx, &io);
565 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
569 io.in.durable_handle = h;
570 status = smb2_create(tree, mem_ctx, &io);
571 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
574 * attempt with lease provided, but
575 * with a changed lease key. => fails
579 io.in.durable_open = false;
580 io.in.durable_handle = h;
581 io.in.lease_request = &ls;
582 io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
583 /* a wrong lease key lets the request fail */
584 ls.lease_key.data[0]++;
586 status = smb2_create(tree, mem_ctx, &io);
587 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
589 /* restore the correct lease key */
590 ls.lease_key.data[0]--;
593 * this last failing attempt is almost correct:
594 * only problem is: we use the wrong filename...
595 * Note that this gives INVALID_PARAMETER.
596 * This is different from oplocks!
599 io.in.fname = "__non_existing_fname__";
600 io.in.durable_open = false;
601 io.in.durable_handle = h;
602 io.in.lease_request = &ls;
603 io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
605 status = smb2_create(tree, mem_ctx, &io);
606 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
609 * Now for a succeeding reconnect:
614 io.in.durable_open = false;
615 io.in.durable_handle = h;
616 io.in.lease_request = &ls;
617 io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
619 /* the requested lease state is irrelevant */
620 ls.lease_state = smb2_util_lease_state("");
624 status = smb2_create(tree, mem_ctx, &io);
625 CHECK_STATUS(status, NT_STATUS_OK);
627 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
628 CHECK_VAL(io.out.durable_open, false);
629 CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
630 CHECK_VAL(io.out.persistent_open, false);
631 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
632 CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
633 CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
634 CHECK_VAL(io.out.lease_response.lease_state,
635 smb2_util_lease_state("RWH"));
636 CHECK_VAL(io.out.lease_response.lease_flags, 0);
637 CHECK_VAL(io.out.lease_response.lease_duration, 0);
638 _h = io.out.file.handle;
641 /* disconnect one more time */
644 if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
645 torture_warning(tctx, "couldn't reconnect, bailing\n");
651 * demonstrate that various parameters are ignored
657 * These are completely ignored by the server
659 io.in.security_flags = 0x78;
660 io.in.oplock_level = 0x78;
661 io.in.impersonation_level = 0x12345678;
662 io.in.create_flags = 0x12345678;
663 io.in.reserved = 0x12345678;
664 io.in.desired_access = 0x12345678;
665 io.in.file_attributes = 0x12345678;
666 io.in.share_access = 0x12345678;
667 io.in.create_disposition = 0x12345678;
668 io.in.create_options = 0x12345678;
671 * only these are checked:
673 * - io.in.durable_handle,
674 * - io.in.lease_request->lease_key
678 io.in.durable_open_v2 = false;
679 io.in.durable_handle_v2 = h;
680 io.in.lease_request = &ls;
682 /* the requested lease state is irrelevant */
683 ls.lease_state = smb2_util_lease_state("");
687 status = smb2_create(tree, mem_ctx, &io);
688 CHECK_STATUS(status, NT_STATUS_OK);
690 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
691 CHECK_VAL(io.out.durable_open, false);
692 CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
693 CHECK_VAL(io.out.persistent_open, false);
694 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
695 CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
696 CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
697 CHECK_VAL(io.out.lease_response.lease_state,
698 smb2_util_lease_state("RWH"));
699 CHECK_VAL(io.out.lease_response.lease_flags, 0);
700 CHECK_VAL(io.out.lease_response.lease_duration, 0);
702 _h = io.out.file.handle;
708 smb2_util_close(tree, *h);
711 smb2_util_unlink(tree, fname);
716 talloc_free(mem_ctx);
722 * lease v2 variant of reopen2
723 * basic test for doing a durable open
724 * tcp disconnect, reconnect, do a durable reopen (succeeds)
726 static bool test_durable_open_reopen2_lease_v2(struct torture_context *tctx,
727 struct smb2_tree *tree)
730 TALLOC_CTX *mem_ctx = talloc_new(tctx);
732 struct smb2_handle _h;
733 struct smb2_handle *h = NULL;
734 struct smb2_create io;
735 struct smb2_lease ls;
738 struct smbcli_options options;
741 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
742 if (!(caps & SMB2_CAP_LEASING)) {
743 torture_skip(tctx, "leases are not supported");
746 options = tree->session->transport->options;
748 /* Choose a random name in case the state is left a little funky. */
749 snprintf(fname, 256, "durable_open_reopen2_%s.dat",
750 generate_random_str(tctx, 8));
752 smb2_util_unlink(tree, fname);
754 lease_key = random();
755 smb2_lease_v2_create(&io, &ls, false /* dir */, fname,
756 lease_key, 0, /* parent lease key */
757 smb2_util_lease_state("RWH"), 0 /* lease epoch */);
758 io.in.durable_open = true;
760 status = smb2_create(tree, mem_ctx, &io);
761 CHECK_STATUS(status, NT_STATUS_OK);
762 _h = io.out.file.handle;
764 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
766 CHECK_VAL(io.out.durable_open, true);
767 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
768 CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
769 CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
770 CHECK_VAL(io.out.lease_response_v2.lease_state,
771 smb2_util_lease_state("RWH"));
772 CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
773 CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
775 /* disconnect, reconnect and then do durable reopen */
778 if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
779 torture_warning(tctx, "couldn't reconnect, bailing\n");
784 /* a few failure tests: */
787 * several attempts without lease attached:
788 * all fail with NT_STATUS_OBJECT_NAME_NOT_FOUND
789 * irrespective of file name provided
794 io.in.durable_handle = h;
795 status = smb2_create(tree, mem_ctx, &io);
796 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
799 io.in.fname = "__non_existing_fname__";
800 io.in.durable_handle = h;
801 status = smb2_create(tree, mem_ctx, &io);
802 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
806 io.in.durable_handle = h;
807 status = smb2_create(tree, mem_ctx, &io);
808 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
811 * attempt with lease provided, but
812 * with a changed lease key. => fails
816 io.in.durable_open = false;
817 io.in.durable_handle = h;
818 io.in.lease_request_v2 = &ls;
819 io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
820 /* a wrong lease key lets the request fail */
821 ls.lease_key.data[0]++;
823 status = smb2_create(tree, mem_ctx, &io);
824 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
826 /* restore the correct lease key */
827 ls.lease_key.data[0]--;
830 * this last failing attempt is almost correct:
831 * only problem is: we use the wrong filename...
832 * Note that this gives INVALID_PARAMETER.
833 * This is different from oplocks!
836 io.in.fname = "__non_existing_fname__";
837 io.in.durable_open = false;
838 io.in.durable_handle = h;
839 io.in.lease_request_v2 = &ls;
840 io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
842 status = smb2_create(tree, mem_ctx, &io);
843 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
846 * Now for a succeeding reconnect:
851 io.in.durable_open = false;
852 io.in.durable_handle = h;
853 io.in.lease_request_v2 = &ls;
854 io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
856 /* the requested lease state is irrelevant */
857 ls.lease_state = smb2_util_lease_state("");
861 status = smb2_create(tree, mem_ctx, &io);
862 CHECK_STATUS(status, NT_STATUS_OK);
864 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
865 CHECK_VAL(io.out.durable_open, false);
866 CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
867 CHECK_VAL(io.out.persistent_open, false);
868 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
869 CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
870 CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
871 CHECK_VAL(io.out.lease_response_v2.lease_state,
872 smb2_util_lease_state("RWH"));
873 CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
874 CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
875 _h = io.out.file.handle;
878 /* disconnect one more time */
881 if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
882 torture_warning(tctx, "couldn't reconnect, bailing\n");
888 * demonstrate that various parameters are ignored
894 * These are completely ignored by the server
896 io.in.security_flags = 0x78;
897 io.in.oplock_level = 0x78;
898 io.in.impersonation_level = 0x12345678;
899 io.in.create_flags = 0x12345678;
900 io.in.reserved = 0x12345678;
901 io.in.desired_access = 0x12345678;
902 io.in.file_attributes = 0x12345678;
903 io.in.share_access = 0x12345678;
904 io.in.create_disposition = 0x12345678;
905 io.in.create_options = 0x12345678;
908 * only these are checked:
910 * - io.in.durable_handle,
911 * - io.in.lease_request->lease_key
915 io.in.durable_open_v2 = false;
916 io.in.durable_handle_v2 = h;
917 io.in.lease_request_v2 = &ls;
919 /* the requested lease state is irrelevant */
920 ls.lease_state = smb2_util_lease_state("");
924 status = smb2_create(tree, mem_ctx, &io);
925 CHECK_STATUS(status, NT_STATUS_OK);
927 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
928 CHECK_VAL(io.out.durable_open, false);
929 CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
930 CHECK_VAL(io.out.persistent_open, false);
931 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
932 CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
933 CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
934 CHECK_VAL(io.out.lease_response_v2.lease_state,
935 smb2_util_lease_state("RWH"));
936 CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
937 CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
939 _h = io.out.file.handle;
945 smb2_util_close(tree, *h);
948 smb2_util_unlink(tree, fname);
953 talloc_free(mem_ctx);
959 * basic test for doing a durable open
960 * tcp disconnect, reconnect with a session reconnect and
961 * do a durable reopen (succeeds)
963 static bool test_durable_open_reopen2a(struct torture_context *tctx,
964 struct smb2_tree *tree)
967 TALLOC_CTX *mem_ctx = talloc_new(tctx);
969 struct smb2_handle _h;
970 struct smb2_handle *h = NULL;
971 struct smb2_create io1, io2;
972 uint64_t previous_session_id;
974 struct smbcli_options options;
976 options = tree->session->transport->options;
978 /* Choose a random name in case the state is left a little funky. */
979 snprintf(fname, 256, "durable_open_reopen2_%s.dat",
980 generate_random_str(tctx, 8));
982 smb2_util_unlink(tree, fname);
984 smb2_oplock_create_share(&io1, fname,
985 smb2_util_share_access(""),
986 smb2_util_oplock_level("b"));
987 io1.in.durable_open = true;
989 status = smb2_create(tree, mem_ctx, &io1);
990 CHECK_STATUS(status, NT_STATUS_OK);
991 _h = io1.out.file.handle;
993 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
994 CHECK_VAL(io1.out.durable_open, true);
995 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
997 /* disconnect, reconnect and then do durable reopen */
998 previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
1002 if (!torture_smb2_connection_ext(tctx, previous_session_id,
1005 torture_warning(tctx, "couldn't reconnect, bailing\n");
1011 io2.in.fname = fname;
1012 io2.in.durable_handle = h;
1015 status = smb2_create(tree, mem_ctx, &io2);
1016 CHECK_STATUS(status, NT_STATUS_OK);
1017 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1018 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
1019 _h = io2.out.file.handle;
1025 smb2_util_close(tree, *h);
1028 smb2_util_unlink(tree, fname);
1033 talloc_free(mem_ctx);
1040 * basic test for doing a durable open:
1041 * tdis, new tcon, try durable reopen (fails)
1043 static bool test_durable_open_reopen3(struct torture_context *tctx,
1044 struct smb2_tree *tree)
1047 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1049 struct smb2_handle _h;
1050 struct smb2_handle *h = NULL;
1051 struct smb2_create io1, io2;
1053 struct smb2_tree *tree2;
1055 /* Choose a random name in case the state is left a little funky. */
1056 snprintf(fname, 256, "durable_open_reopen3_%s.dat",
1057 generate_random_str(tctx, 8));
1059 smb2_util_unlink(tree, fname);
1061 smb2_oplock_create_share(&io1, fname,
1062 smb2_util_share_access(""),
1063 smb2_util_oplock_level("b"));
1064 io1.in.durable_open = true;
1066 status = smb2_create(tree, mem_ctx, &io1);
1067 CHECK_STATUS(status, NT_STATUS_OK);
1068 _h = io1.out.file.handle;
1070 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1071 CHECK_VAL(io1.out.durable_open, true);
1072 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
1074 /* disconnect, reconnect and then do durable reopen */
1075 status = smb2_tdis(tree);
1076 CHECK_STATUS(status, NT_STATUS_OK);
1078 if (!torture_smb2_tree_connect(tctx, tree->session, mem_ctx, &tree2)) {
1079 torture_warning(tctx, "couldn't reconnect to share, bailing\n");
1086 io2.in.fname = fname;
1087 io2.in.durable_handle = h;
1089 status = smb2_create(tree2, mem_ctx, &io2);
1090 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1095 smb2_util_close(tree, *h);
1098 smb2_util_unlink(tree2, fname);
1103 talloc_free(mem_ctx);
1109 * basic test for doing a durable open:
1110 * logoff, create a new session, do a durable reopen (succeeds)
1112 static bool test_durable_open_reopen4(struct torture_context *tctx,
1113 struct smb2_tree *tree)
1116 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1118 struct smb2_handle _h;
1119 struct smb2_handle *h = NULL;
1120 struct smb2_create io1, io2;
1122 struct smb2_transport *transport;
1123 struct smb2_session *session2;
1124 struct smb2_tree *tree2;
1126 /* Choose a random name in case the state is left a little funky. */
1127 snprintf(fname, 256, "durable_open_reopen4_%s.dat",
1128 generate_random_str(tctx, 8));
1130 smb2_util_unlink(tree, fname);
1132 smb2_oplock_create_share(&io1, fname,
1133 smb2_util_share_access(""),
1134 smb2_util_oplock_level("b"));
1135 io1.in.durable_open = true;
1136 io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1138 status = smb2_create(tree, mem_ctx, &io1);
1139 CHECK_STATUS(status, NT_STATUS_OK);
1140 _h = io1.out.file.handle;
1142 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1143 CHECK_VAL(io1.out.durable_open, true);
1144 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
1147 * do a session logoff, establish a new session and tree
1148 * connect on the same transport, and try a durable reopen
1150 transport = tree->session->transport;
1151 status = smb2_logoff(tree->session);
1152 CHECK_STATUS(status, NT_STATUS_OK);
1154 if (!torture_smb2_session_setup(tctx, transport,
1155 0, /* previous_session_id */
1156 mem_ctx, &session2))
1158 torture_warning(tctx, "session setup failed.\n");
1164 * the session setup has talloc-stolen the transport,
1165 * so we can safely free the old tree+session for clarity
1169 if (!torture_smb2_tree_connect(tctx, session2, mem_ctx, &tree2)) {
1170 torture_warning(tctx, "tree connect failed.\n");
1176 io2.in.fname = fname;
1177 io2.in.durable_handle = h;
1180 status = smb2_create(tree2, mem_ctx, &io2);
1181 CHECK_STATUS(status, NT_STATUS_OK);
1183 _h = io2.out.file.handle;
1185 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1186 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
1191 smb2_util_close(tree2, *h);
1194 smb2_util_unlink(tree2, fname);
1199 talloc_free(mem_ctx);
1204 static bool test_durable_open_delete_on_close1(struct torture_context *tctx,
1205 struct smb2_tree *tree)
1208 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1210 struct smb2_handle _h;
1211 struct smb2_handle *h = NULL;
1212 struct smb2_create io1, io2;
1216 /* Choose a random name in case the state is left a little funky. */
1217 snprintf(fname, 256, "durable_open_delete_on_close1_%s.dat",
1218 generate_random_str(tctx, 8));
1220 smb2_util_unlink(tree, fname);
1222 smb2_oplock_create_share(&io1, fname,
1223 smb2_util_share_access(""),
1224 smb2_util_oplock_level("b"));
1225 io1.in.durable_open = true;
1226 io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1228 status = smb2_create(tree, mem_ctx, &io1);
1229 CHECK_STATUS(status, NT_STATUS_OK);
1230 _h = io1.out.file.handle;
1232 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1233 CHECK_VAL(io1.out.durable_open, true);
1234 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
1236 status = smb2_util_write(tree, *h, &b, 0, 1);
1237 CHECK_STATUS(status, NT_STATUS_OK);
1239 /* disconnect, leaving the durable handle in place */
1242 if (!torture_smb2_connection(tctx, &tree)) {
1243 torture_warning(tctx, "could not reconnect, bailing\n");
1249 * Open the file on the new connection again
1250 * and check that it has been newly created,
1251 * i.e. delete on close was effective on the disconnected handle.
1252 * Also check that the file is really empty,
1253 * the previously written byte gone.
1255 smb2_oplock_create_share(&io2, fname,
1256 smb2_util_share_access(""),
1257 smb2_util_oplock_level("b"));
1258 io2.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1260 status = smb2_create(tree, mem_ctx, &io2);
1261 CHECK_STATUS(status, NT_STATUS_OK);
1262 _h = io2.out.file.handle;
1264 CHECK_CREATED_SIZE(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE, 0, 0);
1265 CHECK_VAL(io2.out.durable_open, false);
1266 CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
1271 smb2_util_close(tree, *h);
1274 smb2_util_unlink(tree, fname);
1279 talloc_free(mem_ctx);
1285 static bool test_durable_open_delete_on_close2(struct torture_context *tctx,
1286 struct smb2_tree *tree)
1289 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1291 struct smb2_handle _h;
1292 struct smb2_handle *h = NULL;
1293 struct smb2_create io;
1296 uint64_t previous_session_id;
1297 uint64_t alloc_size_step;
1298 struct smbcli_options options;
1300 options = tree->session->transport->options;
1302 /* Choose a random name in case the state is left a little funky. */
1303 snprintf(fname, 256, "durable_open_delete_on_close2_%s.dat",
1304 generate_random_str(tctx, 8));
1306 smb2_util_unlink(tree, fname);
1308 smb2_oplock_create_share(&io, fname,
1309 smb2_util_share_access(""),
1310 smb2_util_oplock_level("b"));
1311 io.in.durable_open = true;
1312 io.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1314 status = smb2_create(tree, mem_ctx, &io);
1315 CHECK_STATUS(status, NT_STATUS_OK);
1316 _h = io.out.file.handle;
1318 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1319 CHECK_VAL(io.out.durable_open, true);
1320 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
1322 status = smb2_util_write(tree, *h, &b, 0, 1);
1323 CHECK_STATUS(status, NT_STATUS_OK);
1325 previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
1327 /* disconnect, leaving the durable handle in place */
1330 if (!torture_smb2_connection_ext(tctx, previous_session_id,
1333 torture_warning(tctx, "could not reconnect, bailing\n");
1339 io.in.fname = fname;
1340 io.in.durable_handle = h;
1342 status = smb2_create(tree, mem_ctx, &io);
1343 CHECK_STATUS(status, NT_STATUS_OK);
1344 _h = io.out.file.handle;
1346 alloc_size_step = io.out.alloc_size;
1347 CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE, alloc_size_step, 1);
1348 CHECK_VAL(io.out.durable_open, false);
1349 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
1351 /* close the file, thereby deleting it */
1352 smb2_util_close(tree, *h);
1353 status = smb2_logoff(tree->session);
1356 if (!torture_smb2_connection(tctx, &tree)) {
1357 torture_warning(tctx, "could not reconnect, bailing\n");
1363 * Open the file on the new connection again
1364 * and check that it has been newly created,
1365 * i.e. delete on close was effective on the reconnected handle.
1366 * Also check that the file is really empty,
1367 * the previously written byte gone.
1369 smb2_oplock_create_share(&io, fname,
1370 smb2_util_share_access(""),
1371 smb2_util_oplock_level("b"));
1372 io.in.durable_open = true;
1373 io.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1375 status = smb2_create(tree, mem_ctx, &io);
1376 CHECK_STATUS(status, NT_STATUS_OK);
1377 _h = io.out.file.handle;
1379 CHECK_CREATED_SIZE(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE, 0, 0);
1380 CHECK_VAL(io.out.durable_open, true);
1381 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
1386 smb2_util_close(tree, *h);
1389 smb2_util_unlink(tree, fname);
1394 talloc_free(mem_ctx);
1400 basic testing of SMB2 durable opens
1401 regarding the position information on the handle
1403 static bool test_durable_open_file_position(struct torture_context *tctx,
1404 struct smb2_tree *tree)
1406 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1407 struct smb2_handle h;
1408 struct smb2_create io;
1410 const char *fname = "durable_open_position.dat";
1411 union smb_fileinfo qfinfo;
1412 union smb_setfileinfo sfinfo;
1415 uint64_t previous_session_id;
1416 struct smbcli_options options;
1418 options = tree->session->transport->options;
1420 smb2_util_unlink(tree, fname);
1422 smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_BATCH);
1423 io.in.durable_open = true;
1425 status = smb2_create(tree, mem_ctx, &io);
1426 CHECK_STATUS(status, NT_STATUS_OK);
1427 h = io.out.file.handle;
1428 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1429 CHECK_VAL(io.out.durable_open, true);
1430 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1432 /* TODO: check extra blob content */
1434 ZERO_STRUCT(qfinfo);
1435 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
1436 qfinfo.generic.in.file.handle = h;
1437 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
1438 CHECK_STATUS(status, NT_STATUS_OK);
1439 CHECK_VAL(qfinfo.position_information.out.position, 0);
1440 pos = qfinfo.position_information.out.position;
1441 torture_comment(tctx, "position: %llu\n",
1442 (unsigned long long)pos);
1444 ZERO_STRUCT(sfinfo);
1445 sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
1446 sfinfo.generic.in.file.handle = h;
1447 sfinfo.position_information.in.position = 0x1000;
1448 status = smb2_setinfo_file(tree, &sfinfo);
1449 CHECK_STATUS(status, NT_STATUS_OK);
1451 ZERO_STRUCT(qfinfo);
1452 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
1453 qfinfo.generic.in.file.handle = h;
1454 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
1455 CHECK_STATUS(status, NT_STATUS_OK);
1456 CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
1457 pos = qfinfo.position_information.out.position;
1458 torture_comment(tctx, "position: %llu\n",
1459 (unsigned long long)pos);
1461 previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
1463 /* tcp disconnect */
1467 /* do a session reconnect */
1468 if (!torture_smb2_connection_ext(tctx, previous_session_id,
1471 torture_warning(tctx, "couldn't reconnect, bailing\n");
1476 ZERO_STRUCT(qfinfo);
1477 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
1478 qfinfo.generic.in.file.handle = h;
1479 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
1480 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1483 io.in.fname = fname;
1484 io.in.durable_handle = &h;
1486 status = smb2_create(tree, mem_ctx, &io);
1487 CHECK_STATUS(status, NT_STATUS_OK);
1488 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1489 CHECK_VAL(io.out.reserved, 0x00);
1490 CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
1491 CHECK_VAL(io.out.alloc_size, 0);
1492 CHECK_VAL(io.out.size, 0);
1493 CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
1494 CHECK_VAL(io.out.reserved2, 0);
1496 h = io.out.file.handle;
1498 ZERO_STRUCT(qfinfo);
1499 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
1500 qfinfo.generic.in.file.handle = h;
1501 status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
1502 CHECK_STATUS(status, NT_STATUS_OK);
1503 CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
1504 pos = qfinfo.position_information.out.position;
1505 torture_comment(tctx, "position: %llu\n",
1506 (unsigned long long)pos);
1508 smb2_util_close(tree, h);
1510 talloc_free(mem_ctx);
1512 smb2_util_unlink(tree, fname);
1521 Open, disconnect, oplock break, reconnect.
1523 static bool test_durable_open_oplock(struct torture_context *tctx,
1524 struct smb2_tree *tree1,
1525 struct smb2_tree *tree2)
1527 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1528 struct smb2_create io1, io2;
1529 struct smb2_handle h1, h2;
1534 /* Choose a random name in case the state is left a little funky. */
1535 snprintf(fname, 256, "durable_open_oplock_%s.dat", generate_random_str(tctx, 8));
1538 smb2_util_unlink(tree1, fname);
1540 /* Create with batch oplock */
1541 smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
1542 io1.in.durable_open = true;
1545 io2.in.create_disposition = NTCREATEX_DISP_OPEN;
1547 status = smb2_create(tree1, mem_ctx, &io1);
1548 CHECK_STATUS(status, NT_STATUS_OK);
1549 h1 = io1.out.file.handle;
1550 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1551 CHECK_VAL(io1.out.durable_open, true);
1552 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1554 /* Disconnect after getting the batch */
1559 * Windows7 (build 7000) will break a batch oplock immediately if the
1560 * original client is gone. (ZML: This seems like a bug. It should give
1561 * some time for the client to reconnect!)
1563 status = smb2_create(tree2, mem_ctx, &io2);
1564 CHECK_STATUS(status, NT_STATUS_OK);
1565 h2 = io2.out.file.handle;
1566 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1567 CHECK_VAL(io2.out.durable_open, true);
1568 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1570 /* What if tree1 tries to come back and reclaim? */
1571 if (!torture_smb2_connection(tctx, &tree1)) {
1572 torture_warning(tctx, "couldn't reconnect, bailing\n");
1578 io1.in.fname = fname;
1579 io1.in.durable_handle = &h1;
1581 status = smb2_create(tree1, mem_ctx, &io1);
1582 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1585 smb2_util_close(tree2, h2);
1586 smb2_util_unlink(tree2, fname);
1595 Open, disconnect, lease break, reconnect.
1597 static bool test_durable_open_lease(struct torture_context *tctx,
1598 struct smb2_tree *tree1,
1599 struct smb2_tree *tree2)
1601 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1602 struct smb2_create io1, io2;
1603 struct smb2_lease ls1, ls2;
1604 struct smb2_handle h1, h2;
1608 uint64_t lease1, lease2;
1611 caps = smb2cli_conn_server_capabilities(tree1->session->transport->conn);
1612 if (!(caps & SMB2_CAP_LEASING)) {
1613 torture_skip(tctx, "leases are not supported");
1617 * Choose a random name and random lease in case the state is left a
1622 snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));
1625 smb2_util_unlink(tree1, fname);
1627 /* Create with lease */
1628 smb2_lease_create(&io1, &ls1, false /* dir */, fname,
1629 lease1, smb2_util_lease_state("RHW"));
1630 io1.in.durable_open = true;
1632 smb2_lease_create(&io2, &ls2, false /* dir */, fname,
1633 lease2, smb2_util_lease_state("RHW"));
1634 io2.in.durable_open = true;
1635 io2.in.create_disposition = NTCREATEX_DISP_OPEN;
1637 status = smb2_create(tree1, mem_ctx, &io1);
1638 CHECK_STATUS(status, NT_STATUS_OK);
1639 h1 = io1.out.file.handle;
1640 CHECK_VAL(io1.out.durable_open, true);
1641 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1643 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
1644 CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease1);
1645 CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease1);
1646 CHECK_VAL(io1.out.lease_response.lease_state,
1647 SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
1649 /* Disconnect after getting the lease */
1654 * Windows7 (build 7000) will grant an RH lease immediate (not an RHW?)
1655 * even if the original client is gone. (ZML: This seems like a bug. It
1656 * should give some time for the client to reconnect! And why RH?)
1658 * obnox: Current windows 7 and w2k8r2 grant RHW instead of RH.
1659 * Test is adapted accordingly.
1661 status = smb2_create(tree2, mem_ctx, &io2);
1662 CHECK_STATUS(status, NT_STATUS_OK);
1663 h2 = io2.out.file.handle;
1664 CHECK_VAL(io2.out.durable_open, true);
1665 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1667 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
1668 CHECK_VAL(io2.out.lease_response.lease_key.data[0], lease2);
1669 CHECK_VAL(io2.out.lease_response.lease_key.data[1], ~lease2);
1670 CHECK_VAL(io2.out.lease_response.lease_state,
1671 SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
1673 /* What if tree1 tries to come back and reclaim? */
1674 if (!torture_smb2_connection(tctx, &tree1)) {
1675 torture_warning(tctx, "couldn't reconnect, bailing\n");
1681 io1.in.fname = fname;
1682 io1.in.durable_handle = &h1;
1683 io1.in.lease_request = &ls1;
1685 status = smb2_create(tree1, mem_ctx, &io1);
1686 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1689 smb2_util_close(tree2, h2);
1690 smb2_util_unlink(tree2, fname);
1698 static bool test_durable_open_lock_oplock(struct torture_context *tctx,
1699 struct smb2_tree *tree)
1701 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1702 struct smb2_create io;
1703 struct smb2_handle h;
1704 struct smb2_lock lck;
1705 struct smb2_lock_element el[2];
1712 snprintf(fname, 256, "durable_open_oplock_lock_%s.dat", generate_random_str(tctx, 8));
1715 smb2_util_unlink(tree, fname);
1717 /* Create with oplock */
1719 smb2_oplock_create_share(&io, fname,
1720 smb2_util_share_access(""),
1721 smb2_util_oplock_level("b"));
1722 io.in.durable_open = true;
1724 status = smb2_create(tree, mem_ctx, &io);
1725 CHECK_STATUS(status, NT_STATUS_OK);
1726 h = io.out.file.handle;
1727 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1729 CHECK_VAL(io.out.durable_open, true);
1730 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
1735 lck.in.lock_count = 0x0001;
1736 lck.in.lock_sequence = 0x00000000;
1737 lck.in.file.handle = h;
1740 el[0].reserved = 0x00000000;
1741 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
1742 status = smb2_lock(tree, &lck);
1743 CHECK_STATUS(status, NT_STATUS_OK);
1745 /* Disconnect/Reconnect. */
1749 if (!torture_smb2_connection(tctx, &tree)) {
1750 torture_warning(tctx, "couldn't reconnect, bailing\n");
1756 io.in.fname = fname;
1757 io.in.durable_handle = &h;
1759 status = smb2_create(tree, mem_ctx, &io);
1760 CHECK_STATUS(status, NT_STATUS_OK);
1761 h = io.out.file.handle;
1763 lck.in.file.handle = h;
1764 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1765 status = smb2_lock(tree, &lck);
1766 CHECK_STATUS(status, NT_STATUS_OK);
1769 smb2_util_close(tree, h);
1770 smb2_util_unlink(tree, fname);
1777 Open, take BRL, disconnect, reconnect.
1779 static bool test_durable_open_lock_lease(struct torture_context *tctx,
1780 struct smb2_tree *tree)
1782 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1783 struct smb2_create io;
1784 struct smb2_lease ls;
1785 struct smb2_handle h;
1786 struct smb2_lock lck;
1787 struct smb2_lock_element el[2];
1793 struct smbcli_options options;
1795 options = tree->session->transport->options;
1797 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1798 if (!(caps & SMB2_CAP_LEASING)) {
1799 torture_skip(tctx, "leases are not supported");
1803 * Choose a random name and random lease in case the state is left a
1807 snprintf(fname, 256, "durable_open_lease_lock_%s.dat", generate_random_str(tctx, 8));
1810 smb2_util_unlink(tree, fname);
1812 /* Create with lease */
1814 smb2_lease_create(&io, &ls, false /* dir */, fname, lease,
1815 smb2_util_lease_state("RWH"));
1816 io.in.durable_open = true;
1818 status = smb2_create(tree, mem_ctx, &io);
1819 CHECK_STATUS(status, NT_STATUS_OK);
1820 h = io.out.file.handle;
1821 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1823 CHECK_VAL(io.out.durable_open, true);
1824 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
1825 CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
1826 CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
1827 CHECK_VAL(io.out.lease_response.lease_state,
1828 SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
1833 lck.in.lock_count = 0x0001;
1834 lck.in.lock_sequence = 0x00000000;
1835 lck.in.file.handle = h;
1838 el[0].reserved = 0x00000000;
1839 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
1840 status = smb2_lock(tree, &lck);
1841 CHECK_STATUS(status, NT_STATUS_OK);
1843 /* Disconnect/Reconnect. */
1847 if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
1848 torture_warning(tctx, "couldn't reconnect, bailing\n");
1854 io.in.fname = fname;
1855 io.in.durable_handle = &h;
1856 io.in.lease_request = &ls;
1858 status = smb2_create(tree, mem_ctx, &io);
1859 CHECK_STATUS(status, NT_STATUS_OK);
1860 h = io.out.file.handle;
1862 lck.in.file.handle = h;
1863 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1864 status = smb2_lock(tree, &lck);
1865 CHECK_STATUS(status, NT_STATUS_OK);
1868 smb2_util_close(tree, h);
1869 smb2_util_unlink(tree, fname);
1876 * Open with a RH lease, disconnect, open in another tree, reconnect.
1878 * This test actually demonstrates a minimum level of respect for the durable
1879 * open in the face of another open. As long as this test shows an inability to
1880 * reconnect after an open, the oplock/lease tests above will certainly
1881 * demonstrate an error on reconnect.
1883 static bool test_durable_open_open2_lease(struct torture_context *tctx,
1884 struct smb2_tree *tree1,
1885 struct smb2_tree *tree2)
1887 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1888 struct smb2_create io1, io2;
1889 struct smb2_lease ls;
1890 struct smb2_handle h1, h2;
1896 struct smbcli_options options;
1898 options = tree1->session->transport->options;
1900 caps = smb2cli_conn_server_capabilities(tree1->session->transport->conn);
1901 if (!(caps & SMB2_CAP_LEASING)) {
1902 torture_skip(tctx, "leases are not supported");
1906 * Choose a random name and random lease in case the state is left a
1910 snprintf(fname, 256, "durable_open_open2_lease_%s.dat",
1911 generate_random_str(tctx, 8));
1914 smb2_util_unlink(tree1, fname);
1916 /* Create with lease */
1917 smb2_lease_create_share(&io1, &ls, false /* dir */, fname,
1918 smb2_util_share_access(""),
1920 smb2_util_lease_state("RH"));
1921 io1.in.durable_open = true;
1923 status = smb2_create(tree1, mem_ctx, &io1);
1924 CHECK_STATUS(status, NT_STATUS_OK);
1925 h1 = io1.out.file.handle;
1926 CHECK_VAL(io1.out.durable_open, true);
1927 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1929 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
1930 CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease);
1931 CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease);
1932 CHECK_VAL(io1.out.lease_response.lease_state,
1933 smb2_util_lease_state("RH"));
1939 /* Open the file in tree2 */
1940 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
1942 status = smb2_create(tree2, mem_ctx, &io2);
1943 CHECK_STATUS(status, NT_STATUS_OK);
1944 h2 = io2.out.file.handle;
1945 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1948 if (!torture_smb2_connection_ext(tctx, 0, &options, &tree1)) {
1949 torture_warning(tctx, "couldn't reconnect, bailing\n");
1955 io1.in.fname = fname;
1956 io1.in.durable_handle = &h1;
1957 io1.in.lease_request = &ls;
1960 * Windows7 (build 7000) will give away an open immediately if the
1961 * original client is gone. (ZML: This seems like a bug. It should give
1962 * some time for the client to reconnect!)
1964 status = smb2_create(tree1, mem_ctx, &io1);
1965 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
1966 h1 = io1.out.file.handle;
1969 smb2_util_close(tree2, h2);
1970 smb2_util_unlink(tree2, fname);
1971 smb2_util_close(tree1, h1);
1972 smb2_util_unlink(tree1, fname);
1981 * Open with a batch oplock, disconnect, open in another tree, reconnect.
1983 * This test actually demonstrates a minimum level of respect for the durable
1984 * open in the face of another open. As long as this test shows an inability to
1985 * reconnect after an open, the oplock/lease tests above will certainly
1986 * demonstrate an error on reconnect.
1988 static bool test_durable_open_open2_oplock(struct torture_context *tctx,
1989 struct smb2_tree *tree1,
1990 struct smb2_tree *tree2)
1992 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1993 struct smb2_create io1, io2;
1994 struct smb2_handle h1, h2;
2000 * Choose a random name and random lease in case the state is left a
2003 snprintf(fname, 256, "durable_open_open2_oplock_%s.dat",
2004 generate_random_str(tctx, 8));
2007 smb2_util_unlink(tree1, fname);
2009 /* Create with batch oplock */
2010 smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
2011 io1.in.durable_open = true;
2013 status = smb2_create(tree1, mem_ctx, &io1);
2014 CHECK_STATUS(status, NT_STATUS_OK);
2015 h1 = io1.out.file.handle;
2016 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2017 CHECK_VAL(io1.out.durable_open, true);
2018 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2024 /* Open the file in tree2 */
2025 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2027 status = smb2_create(tree2, mem_ctx, &io2);
2028 CHECK_STATUS(status, NT_STATUS_OK);
2029 h2 = io2.out.file.handle;
2030 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2033 if (!torture_smb2_connection(tctx, &tree1)) {
2034 torture_warning(tctx, "couldn't reconnect, bailing\n");
2040 io1.in.fname = fname;
2041 io1.in.durable_handle = &h1;
2043 status = smb2_create(tree1, mem_ctx, &io1);
2044 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
2045 h1 = io1.out.file.handle;
2048 smb2_util_close(tree2, h2);
2049 smb2_util_unlink(tree2, fname);
2050 if (tree1 != NULL) {
2051 smb2_util_close(tree1, h1);
2052 smb2_util_unlink(tree1, fname);
2062 * test behaviour with initial allocation size
2064 static bool test_durable_open_alloc_size(struct torture_context *tctx,
2065 struct smb2_tree *tree)
2068 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2070 struct smb2_handle _h;
2071 struct smb2_handle *h = NULL;
2072 struct smb2_create io;
2074 uint64_t previous_session_id;
2075 uint64_t alloc_size_step;
2076 uint64_t initial_alloc_size = 0x100;
2077 const uint8_t *b = NULL;
2078 struct smbcli_options options;
2080 options = tree->session->transport->options;
2082 /* Choose a random name in case the state is left a little funky. */
2083 snprintf(fname, 256, "durable_open_alloc_size_%s.dat",
2084 generate_random_str(tctx, 8));
2086 smb2_util_unlink(tree, fname);
2088 smb2_oplock_create_share(&io, fname,
2089 smb2_util_share_access(""),
2090 smb2_util_oplock_level("b"));
2091 io.in.durable_open = true;
2092 io.in.alloc_size = initial_alloc_size;
2094 status = smb2_create(tree, mem_ctx, &io);
2095 CHECK_STATUS(status, NT_STATUS_OK);
2096 _h = io.out.file.handle;
2098 CHECK_NOT_VAL(io.out.alloc_size, 0);
2099 alloc_size_step = io.out.alloc_size;
2100 CHECK_CREATED_SIZE(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE,
2101 alloc_size_step, 0);
2102 CHECK_VAL(io.out.durable_open, true);
2103 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
2105 /* prepare buffer */
2106 b = talloc_zero_size(mem_ctx, alloc_size_step);
2107 CHECK_NOT_VAL(b, NULL);
2109 previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
2111 /* disconnect, reconnect and then do durable reopen */
2115 if (!torture_smb2_connection_ext(tctx, previous_session_id,
2118 torture_warning(tctx, "couldn't reconnect, bailing\n");
2124 io.in.fname = fname;
2125 io.in.durable_handle = h;
2128 status = smb2_create(tree, mem_ctx, &io);
2129 CHECK_STATUS(status, NT_STATUS_OK);
2130 CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE,
2131 alloc_size_step, 0);
2132 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
2133 _h = io.out.file.handle;
2136 previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
2138 /* write one byte */
2139 status = smb2_util_write(tree, *h, b, 0, 1);
2140 CHECK_STATUS(status, NT_STATUS_OK);
2142 /* disconnect, reconnect and then do durable reopen */
2146 if (!torture_smb2_connection_ext(tctx, previous_session_id,
2149 torture_warning(tctx, "couldn't reconnect, bailing\n");
2155 io.in.fname = fname;
2156 io.in.durable_handle = h;
2159 status = smb2_create(tree, mem_ctx, &io);
2160 CHECK_STATUS(status, NT_STATUS_OK);
2161 CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE,
2162 alloc_size_step, 1);
2163 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
2164 _h = io.out.file.handle;
2167 previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
2169 /* write more byte than initial allocation size */
2170 status = smb2_util_write(tree, *h, b, 1, alloc_size_step);
2172 /* disconnect, reconnect and then do durable reopen */
2176 if (!torture_smb2_connection_ext(tctx, previous_session_id,
2179 torture_warning(tctx, "couldn't reconnect, bailing\n");
2185 io.in.fname = fname;
2186 io.in.durable_handle = h;
2189 status = smb2_create(tree, mem_ctx, &io);
2190 CHECK_STATUS(status, NT_STATUS_OK);
2191 CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE,
2192 alloc_size_step * 2, alloc_size_step + 1);
2193 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
2194 _h = io.out.file.handle;
2199 smb2_util_close(tree, *h);
2202 smb2_util_unlink(tree, fname);
2206 talloc_free(mem_ctx);
2212 * test behaviour when a disconnect happens while creating a read-only file
2214 static bool test_durable_open_read_only(struct torture_context *tctx,
2215 struct smb2_tree *tree)
2218 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2220 struct smb2_handle _h;
2221 struct smb2_handle *h = NULL;
2222 struct smb2_create io;
2224 uint64_t previous_session_id;
2225 const uint8_t b = 0;
2226 uint64_t alloc_size = 0;
2227 struct smbcli_options options;
2229 options = tree->session->transport->options;
2231 /* Choose a random name in case the state is left a little funky. */
2232 snprintf(fname, 256, "durable_open_initial_alloc_%s.dat",
2233 generate_random_str(tctx, 8));
2235 smb2_util_unlink(tree, fname);
2237 smb2_oplock_create_share(&io, fname,
2238 smb2_util_share_access(""),
2239 smb2_util_oplock_level("b"));
2240 io.in.durable_open = true;
2241 io.in.file_attributes = FILE_ATTRIBUTE_READONLY;
2243 status = smb2_create(tree, mem_ctx, &io);
2244 CHECK_STATUS(status, NT_STATUS_OK);
2245 _h = io.out.file.handle;
2247 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE);
2248 CHECK_VAL(io.out.durable_open, true);
2249 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
2251 previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
2253 /* write one byte */
2254 status = smb2_util_write(tree, *h, &b, 0, 1);
2255 CHECK_STATUS(status, NT_STATUS_OK);
2257 /* disconnect, reconnect and then do durable reopen */
2261 if (!torture_smb2_connection_ext(tctx, previous_session_id,
2264 torture_warning(tctx, "couldn't reconnect, bailing\n");
2270 io.in.fname = fname;
2271 io.in.durable_handle = h;
2274 status = smb2_create(tree, mem_ctx, &io);
2275 CHECK_STATUS(status, NT_STATUS_OK);
2276 alloc_size = io.out.alloc_size;
2277 CHECK_CREATED_SIZE(&io, EXISTED,
2278 FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE,
2280 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
2281 _h = io.out.file.handle;
2284 /* write one byte */
2285 status = smb2_util_write(tree, *h, &b, 1, 1);
2286 CHECK_STATUS(status, NT_STATUS_OK);
2290 union smb_setfileinfo sfinfo;
2292 ZERO_STRUCT(sfinfo);
2293 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
2294 sfinfo.basic_info.in.file.handle = *h;
2295 sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
2296 smb2_setinfo_file(tree, &sfinfo);
2298 smb2_util_close(tree, *h);
2301 smb2_util_unlink(tree, fname);
2305 talloc_free(mem_ctx);
2311 * durable open with oplock, disconnect, exit
2313 static bool test_durable_open_oplock_disconnect(struct torture_context *tctx,
2314 struct smb2_tree *tree)
2316 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2317 struct smb2_create io;
2318 struct smb2_handle _h;
2319 struct smb2_handle *h = NULL;
2324 snprintf(fname, 256, "durable_open_oplock_disconnect_%s.dat",
2325 generate_random_str(mem_ctx, 8));
2327 smb2_util_unlink(tree, fname);
2329 smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_BATCH);
2330 io.in.durable_open = true;
2332 status = smb2_create(tree, mem_ctx, &io);
2333 CHECK_STATUS(status, NT_STATUS_OK);
2335 _h = io.out.file.handle;
2338 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2339 CHECK_VAL(io.out.durable_open, true);
2340 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2349 smb2_util_close(tree, *h);
2351 smb2_util_unlink(tree, fname);
2353 talloc_free(mem_ctx);
2358 struct torture_suite *torture_smb2_durable_open_init(void)
2360 struct torture_suite *suite =
2361 torture_suite_create(talloc_autofree_context(), "durable-open");
2363 torture_suite_add_1smb2_test(suite, "open-oplock", test_durable_open_open_oplock);
2364 torture_suite_add_1smb2_test(suite, "open-lease", test_durable_open_open_lease);
2365 torture_suite_add_1smb2_test(suite, "reopen1", test_durable_open_reopen1);
2366 torture_suite_add_1smb2_test(suite, "reopen2", test_durable_open_reopen2);
2367 torture_suite_add_1smb2_test(suite, "reopen2-lease", test_durable_open_reopen2_lease);
2368 torture_suite_add_1smb2_test(suite, "reopen2-lease-v2", test_durable_open_reopen2_lease_v2);
2369 torture_suite_add_1smb2_test(suite, "reopen2a", test_durable_open_reopen2a);
2370 torture_suite_add_1smb2_test(suite, "reopen3", test_durable_open_reopen3);
2371 torture_suite_add_1smb2_test(suite, "reopen4", test_durable_open_reopen4);
2372 torture_suite_add_1smb2_test(suite, "delete_on_close1",
2373 test_durable_open_delete_on_close1);
2374 torture_suite_add_1smb2_test(suite, "delete_on_close2",
2375 test_durable_open_delete_on_close2);
2376 torture_suite_add_1smb2_test(suite, "file-position",
2377 test_durable_open_file_position);
2378 torture_suite_add_2smb2_test(suite, "oplock", test_durable_open_oplock);
2379 torture_suite_add_2smb2_test(suite, "lease", test_durable_open_lease);
2380 torture_suite_add_1smb2_test(suite, "lock-oplock", test_durable_open_lock_oplock);
2381 torture_suite_add_1smb2_test(suite, "lock-lease", test_durable_open_lock_lease);
2382 torture_suite_add_2smb2_test(suite, "open2-lease",
2383 test_durable_open_open2_lease);
2384 torture_suite_add_2smb2_test(suite, "open2-oplock",
2385 test_durable_open_open2_oplock);
2386 torture_suite_add_1smb2_test(suite, "alloc-size",
2387 test_durable_open_alloc_size);
2388 torture_suite_add_1smb2_test(suite, "read-only",
2389 test_durable_open_read_only);
2391 suite->description = talloc_strdup(suite, "SMB2-DURABLE-OPEN tests");
2396 struct torture_suite *torture_smb2_durable_open_disconnect_init(void)
2398 struct torture_suite *suite =
2399 torture_suite_create(talloc_autofree_context(),
2400 "durable-open-disconnect");
2402 torture_suite_add_1smb2_test(suite, "open-oplock-disconnect",
2403 test_durable_open_oplock_disconnect);
2405 suite->description = talloc_strdup(suite,
2406 "SMB2-DURABLE-OPEN-DISCONNECT tests");