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/>.
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); \
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)); \
45 #define CHECK_CREATED(__io, __created, __attribute) \
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); \
59 static void torture_oplock_close_callback(struct smb2_request
*req
)
61 smb2_close_recv(req
, &break_info
.cl
);
64 /* A general oplock break notification handler. This should be used when a
65 * test expects to break from batch or exclusive to a lower level. */
66 static bool torture_oplock_handler(struct smb2_transport
*transport
,
67 const struct smb2_handle
*handle
,
71 struct smb2_tree
*tree
= private_data
;
72 struct smb2_request
*req
;
76 ZERO_STRUCT(break_info
.cl
);
77 break_info
.cl
.in
.file
.handle
= *handle
;
79 req
= smb2_close_send(tree
, &break_info
.cl
);
80 req
->async
.fn
= torture_oplock_close_callback
;
81 req
->async
.private_data
= NULL
;
86 * basic durable_open test.
87 * durable state should only be granted when requested
88 * along with a batch oplock or a handle lease.
90 * This test tests durable open with all possible oplock types.
93 struct durable_open_vs_oplock
{
95 const char *share_mode
;
100 #define NUM_OPLOCK_TYPES 4
101 #define NUM_SHARE_MODES 8
102 #define NUM_OPLOCK_OPEN_TESTS ( NUM_OPLOCK_TYPES * NUM_SHARE_MODES )
103 static struct durable_open_vs_oplock durable_open_vs_oplock_table
[NUM_OPLOCK_OPEN_TESTS
] =
105 { "", "", false, false },
106 { "", "R", false, false },
107 { "", "W", false, false },
108 { "", "D", false, false },
109 { "", "RD", false, false },
110 { "", "RW", false, false },
111 { "", "WD", false, false },
112 { "", "RWD", false, false },
114 { "s", "", false, false },
115 { "s", "R", false, false },
116 { "s", "W", false, false },
117 { "s", "D", false, false },
118 { "s", "RD", false, false },
119 { "s", "RW", false, false },
120 { "s", "WD", false, false },
121 { "s", "RWD", false, false },
123 { "x", "", false, false },
124 { "x", "R", false, false },
125 { "x", "W", false, false },
126 { "x", "D", false, false },
127 { "x", "RD", false, false },
128 { "x", "RW", false, false },
129 { "x", "WD", false, false },
130 { "x", "RWD", false, false },
132 { "b", "", true, false },
133 { "b", "R", true, false },
134 { "b", "W", true, false },
135 { "b", "D", true, false },
136 { "b", "RD", true, false },
137 { "b", "RW", true, false },
138 { "b", "WD", true, false },
139 { "b", "RWD", true, false },
142 static bool test_one_durable_v2_open_oplock(struct torture_context
*tctx
,
143 struct smb2_tree
*tree
,
145 bool request_persistent
,
146 struct durable_open_vs_oplock test
)
149 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
150 struct smb2_handle _h
;
151 struct smb2_handle
*h
= NULL
;
153 struct smb2_create io
;
155 smb2_util_unlink(tree
, fname
);
157 smb2_oplock_create_share(&io
, fname
,
158 smb2_util_share_access(test
.share_mode
),
159 smb2_util_oplock_level(test
.level
));
160 io
.in
.durable_open
= false;
161 io
.in
.durable_open_v2
= true;
162 io
.in
.persistent_open
= request_persistent
;
163 io
.in
.create_guid
= GUID_random();
165 status
= smb2_create(tree
, mem_ctx
, &io
);
166 CHECK_STATUS(status
, NT_STATUS_OK
);
167 _h
= io
.out
.file
.handle
;
169 CHECK_CREATED(&io
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
170 CHECK_VAL(io
.out
.durable_open
, false);
171 CHECK_VAL(io
.out
.durable_open_v2
, test
.durable
);
172 CHECK_VAL(io
.out
.persistent_open
, test
.persistent
);
173 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level(test
.level
));
177 smb2_util_close(tree
, *h
);
179 smb2_util_unlink(tree
, fname
);
180 talloc_free(mem_ctx
);
185 static bool test_durable_v2_open_oplock_table(struct torture_context
*tctx
,
186 struct smb2_tree
*tree
,
188 bool request_persistent
,
189 struct durable_open_vs_oplock
*table
,
195 smb2_util_unlink(tree
, fname
);
197 for (i
= 0; i
< num_tests
; i
++) {
198 ret
= test_one_durable_v2_open_oplock(tctx
,
209 smb2_util_unlink(tree
, fname
);
214 bool test_durable_v2_open_oplock(struct torture_context
*tctx
,
215 struct smb2_tree
*tree
)
220 /* Choose a random name in case the state is left a little funky. */
221 snprintf(fname
, 256, "durable_open_oplock_%s.dat",
222 generate_random_str(tctx
, 8));
224 ret
= test_durable_v2_open_oplock_table(tctx
, tree
, fname
,
225 false, /* request_persistent */
226 durable_open_vs_oplock_table
,
227 NUM_OPLOCK_OPEN_TESTS
);
235 * basic durable handle open test.
236 * persistent state should only be granted when requested
237 * along with a batch oplock or a handle lease.
239 * This test tests persistent open with all valid lease types.
242 struct durable_open_vs_lease
{
244 const char *share_mode
;
249 #define NUM_LEASE_TYPES 5
250 #define NUM_LEASE_OPEN_TESTS ( NUM_LEASE_TYPES * NUM_SHARE_MODES )
251 static struct durable_open_vs_lease durable_open_vs_lease_table
[NUM_LEASE_OPEN_TESTS
] =
253 { "", "", false, false },
254 { "", "R", false, false },
255 { "", "W", false, false },
256 { "", "D", false, false },
257 { "", "RW", false, false },
258 { "", "RD", false, false },
259 { "", "WD", false, false },
260 { "", "RWD", false, false },
262 { "R", "", false, false },
263 { "R", "R", false, false },
264 { "R", "W", false, false },
265 { "R", "D", false, false },
266 { "R", "RW", false, false },
267 { "R", "RD", false, false },
268 { "R", "DW", false, false },
269 { "R", "RWD", false, false },
271 { "RW", "", false, false },
272 { "RW", "R", false, false },
273 { "RW", "W", false, false },
274 { "RW", "D", false, false },
275 { "RW", "RW", false, false },
276 { "RW", "RD", false, false },
277 { "RW", "WD", false, false },
278 { "RW", "RWD", false, false },
280 { "RH", "", true, false },
281 { "RH", "R", true, false },
282 { "RH", "W", true, false },
283 { "RH", "D", true, false },
284 { "RH", "RW", true, false },
285 { "RH", "RD", true, false },
286 { "RH", "WD", true, false },
287 { "RH", "RWD", true, false },
289 { "RHW", "", true, false },
290 { "RHW", "R", true, false },
291 { "RHW", "W", true, false },
292 { "RHW", "D", true, false },
293 { "RHW", "RW", true, false },
294 { "RHW", "RD", true, false },
295 { "RHW", "WD", true, false },
296 { "RHW", "RWD", true, false },
299 static bool test_one_durable_v2_open_lease(struct torture_context
*tctx
,
300 struct smb2_tree
*tree
,
302 bool request_persistent
,
303 struct durable_open_vs_lease test
)
306 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
307 struct smb2_handle _h
;
308 struct smb2_handle
*h
= NULL
;
310 struct smb2_create io
;
311 struct smb2_lease ls
;
314 smb2_util_unlink(tree
, fname
);
318 smb2_lease_create_share(&io
, &ls
, false /* dir */, fname
,
319 smb2_util_share_access(test
.share_mode
),
321 smb2_util_lease_state(test
.type
));
322 io
.in
.durable_open
= false;
323 io
.in
.durable_open_v2
= true;
324 io
.in
.persistent_open
= request_persistent
;
325 io
.in
.create_guid
= GUID_random();
327 status
= smb2_create(tree
, mem_ctx
, &io
);
328 CHECK_STATUS(status
, NT_STATUS_OK
);
329 _h
= io
.out
.file
.handle
;
331 CHECK_CREATED(&io
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
332 CHECK_VAL(io
.out
.durable_open
, false);
333 CHECK_VAL(io
.out
.durable_open_v2
, test
.durable
);
334 CHECK_VAL(io
.out
.persistent_open
, test
.persistent
);
335 CHECK_VAL(io
.out
.oplock_level
, SMB2_OPLOCK_LEVEL_LEASE
);
336 CHECK_VAL(io
.out
.lease_response
.lease_key
.data
[0], lease
);
337 CHECK_VAL(io
.out
.lease_response
.lease_key
.data
[1], ~lease
);
338 CHECK_VAL(io
.out
.lease_response
.lease_state
,
339 smb2_util_lease_state(test
.type
));
342 smb2_util_close(tree
, *h
);
344 smb2_util_unlink(tree
, fname
);
345 talloc_free(mem_ctx
);
350 static bool test_durable_v2_open_lease_table(struct torture_context
*tctx
,
351 struct smb2_tree
*tree
,
353 bool request_persistent
,
354 struct durable_open_vs_lease
*table
,
360 smb2_util_unlink(tree
, fname
);
362 for (i
= 0; i
< num_tests
; i
++) {
363 ret
= test_one_durable_v2_open_lease(tctx
,
374 smb2_util_unlink(tree
, fname
);
379 bool test_durable_v2_open_lease(struct torture_context
*tctx
,
380 struct smb2_tree
*tree
)
386 caps
= smb2cli_conn_server_capabilities(tree
->session
->transport
->conn
);
387 if (!(caps
& SMB2_CAP_LEASING
)) {
388 torture_skip(tctx
, "leases are not supported");
391 /* Choose a random name in case the state is left a little funky. */
392 snprintf(fname
, 256, "durable_open_lease_%s.dat", generate_random_str(tctx
, 8));
394 ret
= test_durable_v2_open_lease_table(tctx
, tree
, fname
,
395 false, /* request_persistent */
396 durable_open_vs_lease_table
,
397 NUM_LEASE_OPEN_TESTS
);
404 * basic test for doing a durable open
405 * and do a durable reopen on the same connection
406 * while the first open is still active (fails)
408 bool test_durable_v2_open_reopen1(struct torture_context
*tctx
,
409 struct smb2_tree
*tree
)
412 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
414 struct smb2_handle _h
;
415 struct smb2_handle
*h
= NULL
;
416 struct smb2_create io
;
417 struct GUID create_guid
= GUID_random();
420 /* Choose a random name in case the state is left a little funky. */
421 snprintf(fname
, 256, "durable_v2_open_reopen1_%s.dat",
422 generate_random_str(tctx
, 8));
424 smb2_util_unlink(tree
, fname
);
426 smb2_oplock_create_share(&io
, fname
,
427 smb2_util_share_access(""),
428 smb2_util_oplock_level("b"));
429 io
.in
.durable_open
= false;
430 io
.in
.durable_open_v2
= true;
431 io
.in
.persistent_open
= false;
432 io
.in
.create_guid
= create_guid
;
433 io
.in
.timeout
= UINT32_MAX
;
435 status
= smb2_create(tree
, mem_ctx
, &io
);
436 CHECK_STATUS(status
, NT_STATUS_OK
);
437 _h
= io
.out
.file
.handle
;
439 CHECK_CREATED(&io
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
440 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("b"));
441 CHECK_VAL(io
.out
.durable_open
, false);
442 CHECK_VAL(io
.out
.durable_open_v2
, true);
443 CHECK_VAL(io
.out
.persistent_open
, false);
444 CHECK_VAL(io
.out
.timeout
, io
.in
.timeout
);
446 /* try a durable reconnect while the file is still open */
449 io
.in
.durable_handle_v2
= h
;
450 io
.in
.create_guid
= create_guid
;
451 status
= smb2_create(tree
, mem_ctx
, &io
);
452 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
456 smb2_util_close(tree
, *h
);
459 smb2_util_unlink(tree
, fname
);
463 talloc_free(mem_ctx
);
469 * basic test for doing a durable open
470 * tcp disconnect, reconnect, do a durable reopen (succeeds)
472 bool test_durable_v2_open_reopen2(struct torture_context
*tctx
,
473 struct smb2_tree
*tree
)
476 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
478 struct smb2_handle _h
;
479 struct smb2_handle
*h
= NULL
;
480 struct smb2_create io
;
481 struct GUID create_guid
= GUID_random();
484 /* Choose a random name in case the state is left a little funky. */
485 snprintf(fname
, 256, "durable_v2_open_reopen2_%s.dat",
486 generate_random_str(tctx
, 8));
488 smb2_util_unlink(tree
, fname
);
490 smb2_oplock_create_share(&io
, fname
,
491 smb2_util_share_access(""),
492 smb2_util_oplock_level("b"));
493 io
.in
.durable_open
= false;
494 io
.in
.durable_open_v2
= true;
495 io
.in
.persistent_open
= false;
496 io
.in
.create_guid
= create_guid
;
497 io
.in
.timeout
= UINT32_MAX
;
499 status
= smb2_create(tree
, mem_ctx
, &io
);
500 CHECK_STATUS(status
, NT_STATUS_OK
);
501 _h
= io
.out
.file
.handle
;
503 CHECK_CREATED(&io
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
504 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("b"));
505 CHECK_VAL(io
.out
.durable_open
, false);
506 CHECK_VAL(io
.out
.durable_open_v2
, true);
507 CHECK_VAL(io
.out
.persistent_open
, false);
508 CHECK_VAL(io
.out
.timeout
, io
.in
.timeout
);
510 /* disconnect, reconnect and then do durable reopen */
514 if (!torture_smb2_connection(tctx
, &tree
)) {
515 torture_warning(tctx
, "couldn't reconnect, bailing\n");
522 io
.in
.durable_handle_v2
= h
;
523 status
= smb2_create(tree
, mem_ctx
, &io
);
524 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
527 io
.in
.fname
= "__non_existing_fname__";
528 io
.in
.durable_handle_v2
= h
;
529 status
= smb2_create(tree
, mem_ctx
, &io
);
530 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
534 io
.in
.durable_handle_v2
= h
;
535 status
= smb2_create(tree
, mem_ctx
, &io
);
536 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
540 * These are completely ignored by the server
542 io
.in
.security_flags
= 0x78;
543 io
.in
.oplock_level
= 0x78;
544 io
.in
.impersonation_level
= 0x12345678;
545 io
.in
.create_flags
= 0x12345678;
546 io
.in
.reserved
= 0x12345678;
547 io
.in
.desired_access
= 0x12345678;
548 io
.in
.file_attributes
= 0x12345678;
549 io
.in
.share_access
= 0x12345678;
550 io
.in
.create_disposition
= 0x12345678;
551 io
.in
.create_options
= 0x12345678;
552 io
.in
.fname
= "__non_existing_fname__";
555 * only io.in.durable_handle_v2 and
556 * io.in.create_guid are checked
558 io
.in
.durable_open_v2
= false;
559 io
.in
.durable_handle_v2
= h
;
560 io
.in
.create_guid
= create_guid
;
563 status
= smb2_create(tree
, mem_ctx
, &io
);
564 CHECK_STATUS(status
, NT_STATUS_OK
);
565 CHECK_CREATED(&io
, EXISTED
, FILE_ATTRIBUTE_ARCHIVE
);
566 CHECK_VAL(io
.out
.durable_open
, false);
567 CHECK_VAL(io
.out
.durable_open_v2
, false); /* no dh2q response blob */
568 CHECK_VAL(io
.out
.persistent_open
, false);
569 CHECK_VAL(io
.out
.oplock_level
, smb2_util_oplock_level("b"));
570 _h
= io
.out
.file
.handle
;
575 smb2_util_close(tree
, *h
);
578 smb2_util_unlink(tree
, fname
);
582 talloc_free(mem_ctx
);
588 * Test durable request / reconnect with AppInstanceId
590 bool test_durable_v2_open_app_instance(struct torture_context
*tctx
,
591 struct smb2_tree
*tree1
,
592 struct smb2_tree
*tree2
)
595 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
597 struct smb2_handle _h1
, _h2
;
598 struct smb2_handle
*h1
= NULL
, *h2
= NULL
;
599 struct smb2_create io1
, io2
;
601 struct GUID create_guid_1
= GUID_random();
602 struct GUID create_guid_2
= GUID_random();
603 struct GUID app_instance_id
= GUID_random();
605 /* Choose a random name in case the state is left a little funky. */
606 snprintf(fname
, 256, "durable_v2_open_app_instance_%s.dat",
607 generate_random_str(tctx
, 8));
609 smb2_util_unlink(tree1
, fname
);
611 ZERO_STRUCT(break_info
);
612 tree1
->session
->transport
->oplock
.handler
= torture_oplock_handler
;
613 tree1
->session
->transport
->oplock
.private_data
= tree1
;
615 smb2_oplock_create_share(&io1
, fname
,
616 smb2_util_share_access(""),
617 smb2_util_oplock_level("b"));
618 io1
.in
.durable_open
= false;
619 io1
.in
.durable_open_v2
= true;
620 io1
.in
.persistent_open
= false;
621 io1
.in
.create_guid
= create_guid_1
;
622 io1
.in
.app_instance_id
= &app_instance_id
;
623 io1
.in
.timeout
= UINT32_MAX
;
625 status
= smb2_create(tree1
, mem_ctx
, &io1
);
626 CHECK_STATUS(status
, NT_STATUS_OK
);
627 _h1
= io1
.out
.file
.handle
;
629 CHECK_CREATED(&io1
, CREATED
, FILE_ATTRIBUTE_ARCHIVE
);
630 CHECK_VAL(io1
.out
.oplock_level
, smb2_util_oplock_level("b"));
631 CHECK_VAL(io1
.out
.durable_open
, false);
632 CHECK_VAL(io1
.out
.durable_open_v2
, true);
633 CHECK_VAL(io1
.out
.persistent_open
, false);
634 CHECK_VAL(io1
.out
.timeout
, io1
.in
.timeout
);
637 * try to open the file as durable from a second tree with
638 * a different create guid but the same app_instance_id
639 * while the first handle is still open.
642 smb2_oplock_create_share(&io2
, fname
,
643 smb2_util_share_access(""),
644 smb2_util_oplock_level("b"));
645 io2
.in
.durable_open
= false;
646 io2
.in
.durable_open_v2
= true;
647 io2
.in
.persistent_open
= false;
648 io2
.in
.create_guid
= create_guid_2
;
649 io2
.in
.app_instance_id
= &app_instance_id
;
650 io2
.in
.timeout
= UINT32_MAX
;
652 status
= smb2_create(tree2
, mem_ctx
, &io2
);
653 CHECK_STATUS(status
, NT_STATUS_OK
);
654 _h2
= io2
.out
.file
.handle
;
656 CHECK_CREATED(&io2
, EXISTED
, FILE_ATTRIBUTE_ARCHIVE
);
657 CHECK_VAL(io2
.out
.oplock_level
, smb2_util_oplock_level("b"));
658 CHECK_VAL(io2
.out
.durable_open
, false);
659 CHECK_VAL(io2
.out
.durable_open_v2
, true);
660 CHECK_VAL(io2
.out
.persistent_open
, false);
661 CHECK_VAL(io2
.out
.timeout
, io2
.in
.timeout
);
663 CHECK_VAL(break_info
.count
, 0);
665 status
= smb2_util_close(tree1
, *h1
);
666 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
671 smb2_util_close(tree1
, *h1
);
674 smb2_util_close(tree2
, *h2
);
677 smb2_util_unlink(tree2
, fname
);
682 talloc_free(mem_ctx
);
689 * basic persistent open test.
691 * This test tests durable open with all possible oplock types.
694 struct durable_open_vs_oplock persistent_open_oplock_ca_table
[NUM_OPLOCK_OPEN_TESTS
] =
696 { "", "", true, true },
697 { "", "R", true, true },
698 { "", "W", true, true },
699 { "", "D", true, true },
700 { "", "RD", true, true },
701 { "", "RW", true, true },
702 { "", "WD", true, true },
703 { "", "RWD", true, true },
705 { "s", "", true, true },
706 { "s", "R", true, true },
707 { "s", "W", true, true },
708 { "s", "D", true, true },
709 { "s", "RD", true, true },
710 { "s", "RW", true, true },
711 { "s", "WD", true, true },
712 { "s", "RWD", true, true },
714 { "x", "", true, true },
715 { "x", "R", true, true },
716 { "x", "W", true, true },
717 { "x", "D", true, true },
718 { "x", "RD", true, true },
719 { "x", "RW", true, true },
720 { "x", "WD", true, true },
721 { "x", "RWD", true, true },
723 { "b", "", true, true },
724 { "b", "R", true, true },
725 { "b", "W", true, true },
726 { "b", "D", true, true },
727 { "b", "RD", true, true },
728 { "b", "RW", true, true },
729 { "b", "WD", true, true },
730 { "b", "RWD", true, true },
733 bool test_persistent_open_oplock(struct torture_context
*tctx
,
734 struct smb2_tree
*tree
)
738 uint32_t share_capabilities
;
739 bool share_is_ca
= false;
740 struct durable_open_vs_oplock
*table
;
742 /* Choose a random name in case the state is left a little funky. */
743 snprintf(fname
, 256, "persistent_open_oplock_%s.dat", generate_random_str(tctx
, 8));
745 share_capabilities
= smb2cli_tcon_capabilities(tree
->smbXcli
);
746 share_is_ca
= share_capabilities
& SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY
;
749 table
= persistent_open_oplock_ca_table
;
751 table
= durable_open_vs_oplock_table
;
754 ret
= test_durable_v2_open_oplock_table(tctx
, tree
, fname
,
755 true, /* request_persistent */
757 NUM_OPLOCK_OPEN_TESTS
);
765 * basic persistent handle open test.
766 * persistent state should only be granted when requested
767 * along with a batch oplock or a handle lease.
769 * This test tests persistent open with all valid lease types.
772 struct durable_open_vs_lease persistent_open_lease_ca_table
[NUM_LEASE_OPEN_TESTS
] =
774 { "", "", true, true },
775 { "", "R", true, true },
776 { "", "W", true, true },
777 { "", "D", true, true },
778 { "", "RW", true, true },
779 { "", "RD", true, true },
780 { "", "WD", true, true },
781 { "", "RWD", true, true },
783 { "R", "", true, true },
784 { "R", "R", true, true },
785 { "R", "W", true, true },
786 { "R", "D", true, true },
787 { "R", "RW", true, true },
788 { "R", "RD", true, true },
789 { "R", "DW", true, true },
790 { "R", "RWD", true, true },
792 { "RW", "", true, true },
793 { "RW", "R", true, true },
794 { "RW", "W", true, true },
795 { "RW", "D", true, true },
796 { "RW", "RW", true, true },
797 { "RW", "RD", true, true },
798 { "RW", "WD", true, true },
799 { "RW", "RWD", true, true },
801 { "RH", "", true, true },
802 { "RH", "R", true, true },
803 { "RH", "W", true, true },
804 { "RH", "D", true, true },
805 { "RH", "RW", true, true },
806 { "RH", "RD", true, true },
807 { "RH", "WD", true, true },
808 { "RH", "RWD", true, true },
810 { "RHW", "", true, true },
811 { "RHW", "R", true, true },
812 { "RHW", "W", true, true },
813 { "RHW", "D", true, true },
814 { "RHW", "RW", true, true },
815 { "RHW", "RD", true, true },
816 { "RHW", "WD", true, true },
817 { "RHW", "RWD", true, true },
820 bool test_persistent_open_lease(struct torture_context
*tctx
,
821 struct smb2_tree
*tree
)
826 uint32_t share_capabilities
;
828 struct durable_open_vs_lease
*table
;
830 caps
= smb2cli_conn_server_capabilities(tree
->session
->transport
->conn
);
831 if (!(caps
& SMB2_CAP_LEASING
)) {
832 torture_skip(tctx
, "leases are not supported");
835 /* Choose a random name in case the state is left a little funky. */
836 snprintf(fname
, 256, "persistent_open_lease_%s.dat", generate_random_str(tctx
, 8));
838 share_capabilities
= smb2cli_tcon_capabilities(tree
->smbXcli
);
839 share_is_ca
= share_capabilities
& SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY
;
842 table
= persistent_open_lease_ca_table
;
844 table
= durable_open_vs_lease_table
;
847 ret
= test_durable_v2_open_lease_table(tctx
, tree
, fname
,
848 true, /* request_persistent */
850 NUM_LEASE_OPEN_TESTS
);
857 struct torture_suite
*torture_smb2_durable_v2_open_init(void)
859 struct torture_suite
*suite
=
860 torture_suite_create(talloc_autofree_context(), "durable-v2-open");
862 torture_suite_add_1smb2_test(suite
, "open-oplock", test_durable_v2_open_oplock
);
863 torture_suite_add_1smb2_test(suite
, "open-lease", test_durable_v2_open_lease
);
864 torture_suite_add_1smb2_test(suite
, "reopen1", test_durable_v2_open_reopen1
);
865 torture_suite_add_1smb2_test(suite
, "reopen2", test_durable_v2_open_reopen2
);
866 torture_suite_add_2smb2_test(suite
, "app-instance", test_durable_v2_open_app_instance
);
867 torture_suite_add_1smb2_test(suite
, "persistent-open-oplock", test_persistent_open_oplock
);
868 torture_suite_add_1smb2_test(suite
, "persistent-open-lease", test_persistent_open_lease
);
870 suite
->description
= talloc_strdup(suite
, "SMB2-DURABLE-V2-OPEN tests");