2 Unix SMB/CIFS implementation.
4 test suite for SMB2 leases
6 Copyright (C) Zachary Loafman 2009
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/>.
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "torture/torture.h"
27 #include "torture/smb2/proto.h"
28 #include "torture/util.h"
29 #include "libcli/smb/smbXcli_base.h"
30 #include "libcli/security/security.h"
31 #include "lib/param/param.h"
32 #include "lease_break_handler.h"
34 #define CHECK_VAL(v, correct) do { \
35 if ((v) != (correct)) { \
36 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
37 __location__, #v, (int)(v), (int)(correct)); \
41 #define CHECK_STATUS(status, correct) do { \
42 if (!NT_STATUS_EQUAL(status, correct)) { \
43 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
44 nt_errstr(status), nt_errstr(correct)); \
49 #define CHECK_CREATED(__io, __created, __attribute) \
51 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
52 CHECK_VAL((__io)->out.size, 0); \
53 CHECK_VAL((__io)->out.file_attr, (__attribute)); \
54 CHECK_VAL((__io)->out.reserved2, 0); \
57 #define CHECK_LEASE(__io, __state, __oplevel, __key, __flags) \
59 CHECK_VAL((__io)->out.lease_response.lease_version, 1); \
61 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
62 CHECK_VAL((__io)->out.lease_response.lease_key.data[0], (__key)); \
63 CHECK_VAL((__io)->out.lease_response.lease_key.data[1], ~(__key)); \
64 CHECK_VAL((__io)->out.lease_response.lease_state, smb2_util_lease_state(__state)); \
66 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
67 CHECK_VAL((__io)->out.lease_response.lease_key.data[0], 0); \
68 CHECK_VAL((__io)->out.lease_response.lease_key.data[1], 0); \
69 CHECK_VAL((__io)->out.lease_response.lease_state, 0); \
72 CHECK_VAL((__io)->out.lease_response.lease_flags, (__flags)); \
73 CHECK_VAL((__io)->out.lease_response.lease_duration, 0); \
74 CHECK_VAL((__io)->out.lease_response.lease_epoch, 0); \
77 #define CHECK_LEASE_V2(__io, __state, __oplevel, __key, __flags, __parent, __epoch) \
79 CHECK_VAL((__io)->out.lease_response_v2.lease_version, 2); \
81 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
82 CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], (__key)); \
83 CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], ~(__key)); \
84 CHECK_VAL((__io)->out.lease_response_v2.lease_state, smb2_util_lease_state(__state)); \
86 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
87 CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], 0); \
88 CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], 0); \
89 CHECK_VAL((__io)->out.lease_response_v2.lease_state, 0); \
92 CHECK_VAL((__io)->out.lease_response_v2.lease_flags, __flags); \
93 if (__flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET) { \
94 CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[0], (__parent)); \
95 CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[1], ~(__parent)); \
97 CHECK_VAL((__io)->out.lease_response_v2.lease_duration, 0); \
98 CHECK_VAL((__io)->out.lease_response_v2.lease_epoch, (__epoch)); \
101 static const uint64_t LEASE1 = 0xBADC0FFEE0DDF00Dull;
102 static const uint64_t LEASE2 = 0xDEADBEEFFEEDBEADull;
103 static const uint64_t LEASE3 = 0xDAD0FFEDD00DF00Dull;
104 static const uint64_t LEASE4 = 0xBAD0FFEDD00DF00Dull;
106 #define NREQUEST_RESULTS 8
107 static const char *request_results[NREQUEST_RESULTS][2] = {
118 static bool test_lease_request(struct torture_context *tctx,
119 struct smb2_tree *tree)
121 TALLOC_CTX *mem_ctx = talloc_new(tctx);
122 struct smb2_create io;
123 struct smb2_lease ls;
124 struct smb2_handle h1 = {{0}};
125 struct smb2_handle h2 = {{0}};
127 const char *fname = "lease_request.dat";
128 const char *fname2 = "lease_request.2.dat";
129 const char *sname = "lease_request.dat:stream";
130 const char *dname = "lease_request.dir";
135 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
136 if (!(caps & SMB2_CAP_LEASING)) {
137 torture_skip(tctx, "leases are not supported");
140 smb2_util_unlink(tree, fname);
141 smb2_util_unlink(tree, fname2);
142 smb2_util_rmdir(tree, dname);
144 /* Win7 is happy to grant RHW leases on files. */
145 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
146 status = smb2_create(tree, mem_ctx, &io);
147 CHECK_STATUS(status, NT_STATUS_OK);
148 h1 = io.out.file.handle;
149 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
150 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
152 /* But will reject leases on directories. */
153 if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
154 smb2_lease_create(&io, &ls, true, dname, LEASE2, smb2_util_lease_state("RHW"));
155 status = smb2_create(tree, mem_ctx, &io);
156 CHECK_STATUS(status, NT_STATUS_OK);
157 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
158 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
159 smb2_util_close(tree, io.out.file.handle);
162 /* Also rejects multiple files leased under the same key. */
163 smb2_lease_create(&io, &ls, true, fname2, LEASE1, smb2_util_lease_state("RHW"));
164 status = smb2_create(tree, mem_ctx, &io);
165 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
167 /* And grants leases on streams (with separate leasekey). */
168 smb2_lease_create(&io, &ls, false, sname, LEASE2, smb2_util_lease_state("RHW"));
169 status = smb2_create(tree, mem_ctx, &io);
170 h2 = io.out.file.handle;
171 CHECK_STATUS(status, NT_STATUS_OK);
172 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
173 CHECK_LEASE(&io, "RHW", true, LEASE2, 0);
174 smb2_util_close(tree, h2);
176 smb2_util_close(tree, h1);
178 /* Now see what combos are actually granted. */
179 for (i = 0; i < NREQUEST_RESULTS; i++) {
180 torture_comment(tctx, "Requesting lease type %s(%x),"
181 " expecting %s(%x)\n",
182 request_results[i][0], smb2_util_lease_state(request_results[i][0]),
183 request_results[i][1], smb2_util_lease_state(request_results[i][1]));
184 smb2_lease_create(&io, &ls, false, fname, LEASE1,
185 smb2_util_lease_state(request_results[i][0]));
186 status = smb2_create(tree, mem_ctx, &io);
187 h2 = io.out.file.handle;
188 CHECK_STATUS(status, NT_STATUS_OK);
189 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
190 CHECK_LEASE(&io, request_results[i][1], true, LEASE1, 0);
191 smb2_util_close(tree, io.out.file.handle);
195 smb2_util_close(tree, h1);
196 smb2_util_close(tree, h2);
198 smb2_util_unlink(tree, fname);
199 smb2_util_unlink(tree, fname2);
200 smb2_util_rmdir(tree, dname);
202 talloc_free(mem_ctx);
207 static bool test_lease_upgrade(struct torture_context *tctx,
208 struct smb2_tree *tree)
210 TALLOC_CTX *mem_ctx = talloc_new(tctx);
211 struct smb2_create io;
212 struct smb2_lease ls;
213 struct smb2_handle h = {{0}};
214 struct smb2_handle hnew = {{0}};
216 const char *fname = "lease_upgrade.dat";
220 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
221 if (!(caps & SMB2_CAP_LEASING)) {
222 torture_skip(tctx, "leases are not supported");
225 smb2_util_unlink(tree, fname);
227 /* Grab a RH lease. */
228 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
229 status = smb2_create(tree, mem_ctx, &io);
230 CHECK_STATUS(status, NT_STATUS_OK);
231 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
232 CHECK_LEASE(&io, "RH", true, LEASE1, 0);
233 h = io.out.file.handle;
235 /* Upgrades (sidegrades?) to RW leave us with an RH. */
236 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RW"));
237 status = smb2_create(tree, mem_ctx, &io);
238 CHECK_STATUS(status, NT_STATUS_OK);
239 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
240 CHECK_LEASE(&io, "RH", true, LEASE1, 0);
241 hnew = io.out.file.handle;
243 smb2_util_close(tree, hnew);
245 /* Upgrade to RHW lease. */
246 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
247 status = smb2_create(tree, mem_ctx, &io);
248 CHECK_STATUS(status, NT_STATUS_OK);
249 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
250 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
251 hnew = io.out.file.handle;
253 smb2_util_close(tree, h);
256 /* Attempt to downgrade - original lease state is maintained. */
257 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
258 status = smb2_create(tree, mem_ctx, &io);
259 CHECK_STATUS(status, NT_STATUS_OK);
260 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
261 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
262 hnew = io.out.file.handle;
264 smb2_util_close(tree, hnew);
267 smb2_util_close(tree, h);
268 smb2_util_close(tree, hnew);
270 smb2_util_unlink(tree, fname);
272 talloc_free(mem_ctx);
279 * full matrix of lease upgrade combinations
280 * (non-contended case)
282 * The summary of the behaviour is this:
283 * -------------------------------------
284 * An uncontended lease upgrade results in a change
285 * if and only if the requested lease state is
287 * - strictly a superset of the lease state already held.
289 * In that case the resulting lease state is the one
290 * requested in the upgrade.
292 struct lease_upgrade2_test {
294 const char *upgrade_to;
295 const char *expected;
298 #define NUM_LEASE_TYPES 5
299 #define NUM_UPGRADE_TESTS ( NUM_LEASE_TYPES * NUM_LEASE_TYPES )
300 struct lease_upgrade2_test lease_upgrade2_tests[NUM_UPGRADE_TESTS] = {
305 { "", "RWH", "RWH" },
311 { "R", "RWH", "RWH" },
315 { "RH", "RH", "RH" },
316 { "RH", "RW", "RH" },
317 { "RH", "RWH", "RWH" },
321 { "RW", "RH", "RW" },
322 { "RW", "RW", "RW" },
323 { "RW", "RWH", "RWH" },
325 { "RWH", "", "RWH" },
326 { "RWH", "R", "RWH" },
327 { "RWH", "RH", "RWH" },
328 { "RWH", "RW", "RWH" },
329 { "RWH", "RWH", "RWH" },
332 static bool test_lease_upgrade2(struct torture_context *tctx,
333 struct smb2_tree *tree)
335 TALLOC_CTX *mem_ctx = talloc_new(tctx);
336 struct smb2_handle h, hnew;
338 struct smb2_create io;
339 struct smb2_lease ls;
340 const char *fname = "lease_upgrade2.dat";
345 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
346 if (!(caps & SMB2_CAP_LEASING)) {
347 torture_skip(tctx, "leases are not supported");
350 for (i = 0; i < NUM_UPGRADE_TESTS; i++) {
351 struct lease_upgrade2_test t = lease_upgrade2_tests[i];
353 smb2_util_unlink(tree, fname);
356 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.initial));
357 status = smb2_create(tree, mem_ctx, &io);
358 CHECK_STATUS(status, NT_STATUS_OK);
359 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
360 CHECK_LEASE(&io, t.initial, true, LEASE1, 0);
361 h = io.out.file.handle;
364 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to));
365 status = smb2_create(tree, mem_ctx, &io);
366 CHECK_STATUS(status, NT_STATUS_OK);
367 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
368 CHECK_LEASE(&io, t.expected, true, LEASE1, 0);
369 hnew = io.out.file.handle;
371 smb2_util_close(tree, hnew);
372 smb2_util_close(tree, h);
376 smb2_util_close(tree, h);
377 smb2_util_close(tree, hnew);
379 smb2_util_unlink(tree, fname);
381 talloc_free(mem_ctx);
389 * full matrix of lease upgrade combinations
392 * We start with 2 leases, and check how one can
395 * The summary of the behaviour is this:
396 * -------------------------------------
398 * If we have two leases (lease1 and lease2) on the same file,
399 * then attempt to upgrade lease1 results in a change if and only
400 * if the requested lease state:
402 * - is strictly a superset of lease1, and
403 * - can held together with lease2.
405 * In that case, the resuling lease state of the upgraded lease1
406 * is the state requested in the upgrade. lease2 is not broken
407 * and remains unchanged.
409 * Note that this contrasts the case of directly opening with
410 * an initial requested lease state, in which case you get that
411 * portion of the requested state that can be shared with the
412 * already existing leases (or the states that they get broken to).
414 struct lease_upgrade3_test {
417 const char *upgrade_to;
418 const char *upgraded_to;
421 #define NUM_UPGRADE3_TESTS ( 20 )
422 struct lease_upgrade3_test lease_upgrade3_tests[NUM_UPGRADE3_TESTS] = {
423 {"R", "R", "", "R" },
424 {"R", "R", "R", "R" },
425 {"R", "R", "RW", "R" },
426 {"R", "R", "RH", "RH" },
427 {"R", "R", "RHW", "R" },
429 {"R", "RH", "", "R" },
430 {"R", "RH", "R", "R" },
431 {"R", "RH", "RW", "R" },
432 {"R", "RH", "RH", "RH" },
433 {"R", "RH", "RHW", "R" },
435 {"RH", "R", "", "RH" },
436 {"RH", "R", "R", "RH" },
437 {"RH", "R", "RW", "RH" },
438 {"RH", "R", "RH", "RH" },
439 {"RH", "R", "RHW", "RH" },
441 {"RH", "RH", "", "RH" },
442 {"RH", "RH", "R", "RH" },
443 {"RH", "RH", "RW", "RH" },
444 {"RH", "RH", "RH", "RH" },
445 {"RH", "RH", "RHW", "RH" },
448 static bool test_lease_upgrade3(struct torture_context *tctx,
449 struct smb2_tree *tree)
451 TALLOC_CTX *mem_ctx = talloc_new(tctx);
452 struct smb2_handle h, h2, hnew;
454 struct smb2_create io;
455 struct smb2_lease ls;
456 const char *fname = "lease_upgrade3.dat";
461 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
462 if (!(caps & SMB2_CAP_LEASING)) {
463 torture_skip(tctx, "leases are not supported");
466 tree->session->transport->lease.handler = torture_lease_handler;
467 tree->session->transport->lease.private_data = tree;
469 smb2_util_unlink(tree, fname);
471 for (i = 0; i < NUM_UPGRADE3_TESTS; i++) {
472 struct lease_upgrade3_test t = lease_upgrade3_tests[i];
474 smb2_util_unlink(tree, fname);
476 ZERO_STRUCT(lease_break_info);
478 /* grab first lease */
479 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.held1));
480 status = smb2_create(tree, mem_ctx, &io);
481 CHECK_STATUS(status, NT_STATUS_OK);
482 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
483 CHECK_LEASE(&io, t.held1, true, LEASE1, 0);
484 h = io.out.file.handle;
486 /* grab second lease */
487 smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state(t.held2));
488 status = smb2_create(tree, mem_ctx, &io);
489 CHECK_STATUS(status, NT_STATUS_OK);
490 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
491 CHECK_LEASE(&io, t.held2, true, LEASE2, 0);
492 h2 = io.out.file.handle;
494 /* no break has happened */
495 CHECK_VAL(lease_break_info.count, 0);
496 CHECK_VAL(lease_break_info.failures, 0);
498 /* try to upgrade lease1 */
499 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to));
500 status = smb2_create(tree, mem_ctx, &io);
501 CHECK_STATUS(status, NT_STATUS_OK);
502 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
503 CHECK_LEASE(&io, t.upgraded_to, true, LEASE1, 0);
504 hnew = io.out.file.handle;
506 /* no break has happened */
507 CHECK_VAL(lease_break_info.count, 0);
508 CHECK_VAL(lease_break_info.failures, 0);
510 smb2_util_close(tree, hnew);
511 smb2_util_close(tree, h);
512 smb2_util_close(tree, h2);
516 smb2_util_close(tree, h);
517 smb2_util_close(tree, hnew);
518 smb2_util_close(tree, h2);
520 smb2_util_unlink(tree, fname);
522 talloc_free(mem_ctx);
530 break_results should be read as "held lease, new lease, hold broken to, new
531 grant", i.e. { "RH", "RW", "RH", "R" } means that if key1 holds RH and key2
532 tries for RW, key1 will be broken to RH (in this case, not broken at all)
533 and key2 will be granted R.
535 Note: break_results only includes things that Win7 will actually grant (see
536 request_results above).
538 #define NBREAK_RESULTS 16
539 static const char *break_results[NBREAK_RESULTS][4] = {
540 {"R", "R", "R", "R"},
541 {"R", "RH", "R", "RH"},
542 {"R", "RW", "R", "R"},
543 {"R", "RHW", "R", "RH"},
545 {"RH", "R", "RH", "R"},
546 {"RH", "RH", "RH", "RH"},
547 {"RH", "RW", "RH", "R"},
548 {"RH", "RHW", "RH", "RH"},
550 {"RW", "R", "R", "R"},
551 {"RW", "RH", "R", "RH"},
552 {"RW", "RW", "R", "R"},
553 {"RW", "RHW", "R", "RH"},
555 {"RHW", "R", "RH", "R"},
556 {"RHW", "RH", "RH", "RH"},
557 {"RHW", "RW", "RH", "R"},
558 {"RHW", "RHW", "RH", "RH"},
561 static bool test_lease_break(struct torture_context *tctx,
562 struct smb2_tree *tree)
564 TALLOC_CTX *mem_ctx = talloc_new(tctx);
565 struct smb2_create io;
566 struct smb2_lease ls;
567 struct smb2_handle h, h2, h3;
569 const char *fname = "lease_break.dat";
574 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
575 if (!(caps & SMB2_CAP_LEASING)) {
576 torture_skip(tctx, "leases are not supported");
579 tree->session->transport->lease.handler = torture_lease_handler;
580 tree->session->transport->lease.private_data = tree;
582 smb2_util_unlink(tree, fname);
584 for (i = 0; i < NBREAK_RESULTS; i++) {
585 const char *held = break_results[i][0];
586 const char *contend = break_results[i][1];
587 const char *brokento = break_results[i][2];
588 const char *granted = break_results[i][3];
589 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
590 "expecting break to %s(%x) and grant of %s(%x)\n",
591 held, smb2_util_lease_state(held), contend, smb2_util_lease_state(contend),
592 brokento, smb2_util_lease_state(brokento), granted, smb2_util_lease_state(granted));
594 ZERO_STRUCT(lease_break_info);
597 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held));
598 status = smb2_create(tree, mem_ctx, &io);
599 CHECK_STATUS(status, NT_STATUS_OK);
600 h = io.out.file.handle;
601 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
602 CHECK_LEASE(&io, held, true, LEASE1, 0);
604 /* Possibly contend lease. */
605 smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state(contend));
606 status = smb2_create(tree, mem_ctx, &io);
607 CHECK_STATUS(status, NT_STATUS_OK);
608 h2 = io.out.file.handle;
609 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
610 CHECK_LEASE(&io, granted, true, LEASE2, 0);
612 if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) {
613 CHECK_BREAK_INFO(held, brokento, LEASE1);
615 CHECK_NO_BREAK(tctx);
618 ZERO_STRUCT(lease_break_info);
621 Now verify that an attempt to upgrade LEASE1 results in no
622 break and no change in LEASE1.
624 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
625 status = smb2_create(tree, mem_ctx, &io);
626 CHECK_STATUS(status, NT_STATUS_OK);
627 h3 = io.out.file.handle;
628 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
629 CHECK_LEASE(&io, brokento, true, LEASE1, 0);
630 CHECK_VAL(lease_break_info.count, 0);
631 CHECK_VAL(lease_break_info.failures, 0);
633 smb2_util_close(tree, h);
634 smb2_util_close(tree, h2);
635 smb2_util_close(tree, h3);
637 status = smb2_util_unlink(tree, fname);
638 CHECK_STATUS(status, NT_STATUS_OK);
642 smb2_util_close(tree, h);
643 smb2_util_close(tree, h2);
645 smb2_util_unlink(tree, fname);
647 talloc_free(mem_ctx);
652 static bool test_lease_nobreakself(struct torture_context *tctx,
653 struct smb2_tree *tree)
655 TALLOC_CTX *mem_ctx = talloc_new(tctx);
656 struct smb2_create io;
657 struct smb2_lease ls;
658 struct smb2_handle h1 = {{0}};
659 struct smb2_handle h2 = {{0}};
661 const char *fname = "lease_nobreakself.dat";
666 caps = smb2cli_conn_server_capabilities(
667 tree->session->transport->conn);
668 if (!(caps & SMB2_CAP_LEASING)) {
669 torture_skip(tctx, "leases are not supported");
672 smb2_util_unlink(tree, fname);
674 /* Win7 is happy to grant RHW leases on files. */
675 smb2_lease_create(&io, &ls, false, fname, LEASE1,
676 smb2_util_lease_state("R"));
677 status = smb2_create(tree, mem_ctx, &io);
678 CHECK_STATUS(status, NT_STATUS_OK);
679 h1 = io.out.file.handle;
680 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
681 CHECK_LEASE(&io, "R", true, LEASE1, 0);
683 smb2_lease_create(&io, &ls, false, fname, LEASE2,
684 smb2_util_lease_state("R"));
685 status = smb2_create(tree, mem_ctx, &io);
686 CHECK_STATUS(status, NT_STATUS_OK);
687 h2 = io.out.file.handle;
688 CHECK_LEASE(&io, "R", true, LEASE2, 0);
690 ZERO_STRUCT(lease_break_info);
692 tree->session->transport->lease.handler = torture_lease_handler;
693 tree->session->transport->lease.private_data = tree;
695 /* Make sure we don't break ourselves on write */
697 status = smb2_util_write(tree, h1, &c, 0, 1);
698 CHECK_STATUS(status, NT_STATUS_OK);
699 CHECK_BREAK_INFO("R", "", LEASE2);
701 /* Try the other way round. First, upgrade LEASE2 to R again */
703 smb2_lease_create(&io, &ls, false, fname, LEASE2,
704 smb2_util_lease_state("R"));
705 status = smb2_create(tree, mem_ctx, &io);
706 CHECK_STATUS(status, NT_STATUS_OK);
707 CHECK_LEASE(&io, "R", true, LEASE2, 0);
708 smb2_util_close(tree, io.out.file.handle);
710 /* Now break LEASE1 via h2 */
712 ZERO_STRUCT(lease_break_info);
713 status = smb2_util_write(tree, h2, &c, 0, 1);
714 CHECK_STATUS(status, NT_STATUS_OK);
715 CHECK_BREAK_INFO("R", "", LEASE1);
717 /* .. and break LEASE2 via h1 */
719 ZERO_STRUCT(lease_break_info);
720 status = smb2_util_write(tree, h1, &c, 0, 1);
721 CHECK_STATUS(status, NT_STATUS_OK);
722 CHECK_BREAK_INFO("R", "", LEASE2);
725 smb2_util_close(tree, h2);
726 smb2_util_close(tree, h1);
727 smb2_util_unlink(tree, fname);
728 talloc_free(mem_ctx);
732 static bool test_lease_statopen(struct torture_context *tctx,
733 struct smb2_tree *tree)
735 TALLOC_CTX *mem_ctx = talloc_new(tctx);
736 struct smb2_create io;
737 struct smb2_lease ls;
738 struct smb2_handle h1 = {{0}};
739 struct smb2_handle h2 = {{0}};
741 const char *fname = "lease_statopen.dat";
745 caps = smb2cli_conn_server_capabilities(
746 tree->session->transport->conn);
747 if (!(caps & SMB2_CAP_LEASING)) {
748 torture_skip(tctx, "leases are not supported");
751 smb2_util_unlink(tree, fname);
754 smb2_lease_create(&io, &ls, false, fname, LEASE1,
755 smb2_util_lease_state("RWH"));
756 status = smb2_create(tree, mem_ctx, &io);
757 CHECK_STATUS(status, NT_STATUS_OK);
758 h1 = io.out.file.handle;
759 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
760 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
761 smb2_util_close(tree, h1);
763 /* Stat open file with RWH lease. */
764 smb2_lease_create_share(&io, &ls, false, fname, 0, LEASE1,
765 smb2_util_lease_state("RWH"));
766 io.in.desired_access = FILE_READ_ATTRIBUTES;
767 status = smb2_create(tree, mem_ctx, &io);
768 CHECK_STATUS(status, NT_STATUS_OK);
769 h2 = io.out.file.handle;
770 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
772 ZERO_STRUCT(lease_break_info);
774 tree->session->transport->lease.handler = torture_lease_handler;
775 tree->session->transport->lease.private_data = tree;
777 /* Ensure non-stat open doesn't break and gets same lease
778 state as existing stat open. */
779 smb2_lease_create(&io, &ls, false, fname, LEASE1,
780 smb2_util_lease_state(""));
781 status = smb2_create(tree, mem_ctx, &io);
782 CHECK_STATUS(status, NT_STATUS_OK);
783 h1 = io.out.file.handle;
784 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
785 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
787 CHECK_NO_BREAK(tctx);
788 smb2_util_close(tree, h1);
790 /* Open with conflicting lease. stat open should break down to RH */
791 smb2_lease_create(&io, &ls, false, fname, LEASE2,
792 smb2_util_lease_state("RWH"));
793 status = smb2_create(tree, mem_ctx, &io);
794 CHECK_STATUS(status, NT_STATUS_OK);
795 h1 = io.out.file.handle;
796 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
797 CHECK_LEASE(&io, "RH", true, LEASE2, 0);
799 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
802 smb2_util_close(tree, h2);
803 smb2_util_close(tree, h1);
804 smb2_util_unlink(tree, fname);
805 talloc_free(mem_ctx);
809 static bool test_lease_statopen2(struct torture_context *tctx,
810 struct smb2_tree *tree)
812 TALLOC_CTX *mem_ctx = talloc_new(tctx);
813 struct smb2_create io;
814 struct smb2_lease ls;
815 struct smb2_handle h1 = {{0}};
816 struct smb2_handle h2 = {{0}};
817 struct smb2_handle h3 = {{0}};
819 const char *fname = "lease_statopen2.dat";
823 caps = smb2cli_conn_server_capabilities(
824 tree->session->transport->conn);
825 if (!(caps & SMB2_CAP_LEASING)) {
826 torture_skip(tctx, "leases are not supported");
829 smb2_util_unlink(tree, fname);
830 ZERO_STRUCT(lease_break_info);
831 tree->session->transport->lease.handler = torture_lease_handler;
832 tree->session->transport->lease.private_data = tree;
834 status = torture_smb2_testfile(tree, fname, &h1);
835 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
836 "smb2_create failed\n");
837 smb2_util_close(tree, h1);
840 /* Open file with RWH lease. */
841 smb2_lease_create_share(&io, &ls, false, fname,
842 smb2_util_share_access("RWD"),
844 smb2_util_lease_state("RWH"));
845 io.in.desired_access = SEC_FILE_WRITE_DATA;
846 status = smb2_create(tree, mem_ctx, &io);
847 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
848 "smb2_create failed\n");
849 h1 = io.out.file.handle;
850 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
854 io.in.desired_access = FILE_READ_ATTRIBUTES;
855 io.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
856 io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
857 io.in.create_disposition = NTCREATEX_DISP_OPEN;
859 status = smb2_create(tree, mem_ctx, &io);
860 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
861 "smb2_create failed\n");
862 h2 = io.out.file.handle;
864 /* Open file with RWH lease. */
865 smb2_lease_create_share(&io, &ls, false, fname,
866 smb2_util_share_access("RWD"),
868 smb2_util_lease_state("RWH"));
869 io.in.desired_access = SEC_FILE_WRITE_DATA;
870 status = smb2_create(tree, mem_ctx, &io);
871 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
872 "smb2_create failed\n");
873 h3 = io.out.file.handle;
874 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
877 if (!smb2_util_handle_empty(h3)) {
878 smb2_util_close(tree, h3);
880 if (!smb2_util_handle_empty(h2)) {
881 smb2_util_close(tree, h2);
883 if (!smb2_util_handle_empty(h1)) {
884 smb2_util_close(tree, h1);
886 smb2_util_unlink(tree, fname);
887 talloc_free(mem_ctx);
891 static bool test_lease_statopen3(struct torture_context *tctx,
892 struct smb2_tree *tree)
894 TALLOC_CTX *mem_ctx = talloc_new(tctx);
895 struct smb2_create io;
896 struct smb2_lease ls;
897 struct smb2_handle h1 = {{0}};
898 struct smb2_handle h2 = {{0}};
900 const char *fname = "lease_statopen3.dat";
904 caps = smb2cli_conn_server_capabilities(
905 tree->session->transport->conn);
906 if (!(caps & SMB2_CAP_LEASING)) {
907 torture_skip(tctx, "leases are not supported");
910 smb2_util_unlink(tree, fname);
911 ZERO_STRUCT(lease_break_info);
912 tree->session->transport->lease.handler = torture_lease_handler;
913 tree->session->transport->lease.private_data = tree;
915 status = torture_smb2_testfile(tree, fname, &h1);
916 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
917 "smb2_create failed\n");
918 smb2_util_close(tree, h1);
923 io.in.desired_access = FILE_READ_ATTRIBUTES;
924 io.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
925 io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
926 io.in.create_disposition = NTCREATEX_DISP_OPEN;
928 status = smb2_create(tree, mem_ctx, &io);
929 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
930 "smb2_create failed\n");
931 h1 = io.out.file.handle;
933 /* Open file with RWH lease. */
934 smb2_lease_create_share(&io, &ls, false, fname,
935 smb2_util_share_access("RWD"),
937 smb2_util_lease_state("RWH"));
938 io.in.desired_access = SEC_FILE_WRITE_DATA;
939 status = smb2_create(tree, mem_ctx, &io);
940 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
941 "smb2_create failed\n");
942 h2 = io.out.file.handle;
943 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
946 if (!smb2_util_handle_empty(h1)) {
947 smb2_util_close(tree, h1);
949 if (!smb2_util_handle_empty(h2)) {
950 smb2_util_close(tree, h2);
952 smb2_util_unlink(tree, fname);
953 talloc_free(mem_ctx);
957 static void torture_oplock_break_callback(struct smb2_request *req)
960 struct smb2_break br;
963 status = smb2_break_recv(req, &br);
964 if (!NT_STATUS_IS_OK(status))
965 lease_break_info.oplock_failures++;
970 /* a oplock break request handler */
971 static bool torture_oplock_handler(struct smb2_transport *transport,
972 const struct smb2_handle *handle,
973 uint8_t level, void *private_data)
975 struct smb2_tree *tree = private_data;
976 struct smb2_request *req;
977 struct smb2_break br;
979 lease_break_info.oplock_handle = *handle;
980 lease_break_info.oplock_level = level;
981 lease_break_info.oplock_count++;
984 br.in.file.handle = *handle;
985 br.in.oplock_level = level;
987 if (lease_break_info.held_oplock_level > SMB2_OPLOCK_LEVEL_II) {
988 req = smb2_break_send(tree, &br);
989 req->async.fn = torture_oplock_break_callback;
990 req->async.private_data = NULL;
992 lease_break_info.held_oplock_level = level;
997 #define NOPLOCK_RESULTS 12
998 static const char *oplock_results[NOPLOCK_RESULTS][4] = {
999 {"R", "s", "R", "s"},
1000 {"R", "x", "R", "s"},
1001 {"R", "b", "R", "s"},
1003 {"RH", "s", "RH", ""},
1004 {"RH", "x", "RH", ""},
1005 {"RH", "b", "RH", ""},
1007 {"RW", "s", "R", "s"},
1008 {"RW", "x", "R", "s"},
1009 {"RW", "b", "R", "s"},
1011 {"RHW", "s", "RH", ""},
1012 {"RHW", "x", "RH", ""},
1013 {"RHW", "b", "RH", ""},
1016 static const char *oplock_results_2[NOPLOCK_RESULTS][4] = {
1017 {"s", "R", "s", "R"},
1018 {"s", "RH", "s", "R"},
1019 {"s", "RW", "s", "R"},
1020 {"s", "RHW", "s", "R"},
1022 {"x", "R", "s", "R"},
1023 {"x", "RH", "s", "R"},
1024 {"x", "RW", "s", "R"},
1025 {"x", "RHW", "s", "R"},
1027 {"b", "R", "s", "R"},
1028 {"b", "RH", "s", "R"},
1029 {"b", "RW", "s", "R"},
1030 {"b", "RHW", "s", "R"},
1033 static bool test_lease_oplock(struct torture_context *tctx,
1034 struct smb2_tree *tree)
1036 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1037 struct smb2_create io;
1038 struct smb2_lease ls;
1039 struct smb2_handle h, h2;
1041 const char *fname = "lease_oplock.dat";
1046 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1047 if (!(caps & SMB2_CAP_LEASING)) {
1048 torture_skip(tctx, "leases are not supported");
1051 tree->session->transport->lease.handler = torture_lease_handler;
1052 tree->session->transport->lease.private_data = tree;
1053 tree->session->transport->oplock.handler = torture_oplock_handler;
1054 tree->session->transport->oplock.private_data = tree;
1056 smb2_util_unlink(tree, fname);
1058 for (i = 0; i < NOPLOCK_RESULTS; i++) {
1059 const char *held = oplock_results[i][0];
1060 const char *contend = oplock_results[i][1];
1061 const char *brokento = oplock_results[i][2];
1062 const char *granted = oplock_results[i][3];
1063 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
1064 "expecting break to %s(%x) and grant of %s(%x)\n",
1065 held, smb2_util_lease_state(held), contend, smb2_util_oplock_level(contend),
1066 brokento, smb2_util_lease_state(brokento), granted, smb2_util_oplock_level(granted));
1068 ZERO_STRUCT(lease_break_info);
1071 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held));
1072 status = smb2_create(tree, mem_ctx, &io);
1073 CHECK_STATUS(status, NT_STATUS_OK);
1074 h = io.out.file.handle;
1075 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1076 CHECK_LEASE(&io, held, true, LEASE1, 0);
1078 /* Does an oplock contend the lease? */
1079 smb2_oplock_create(&io, fname, smb2_util_oplock_level(contend));
1080 status = smb2_create(tree, mem_ctx, &io);
1081 CHECK_STATUS(status, NT_STATUS_OK);
1082 h2 = io.out.file.handle;
1083 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1084 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(granted));
1085 lease_break_info.held_oplock_level = io.out.oplock_level;
1087 if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) {
1088 CHECK_BREAK_INFO(held, brokento, LEASE1);
1090 CHECK_NO_BREAK(tctx);
1093 smb2_util_close(tree, h);
1094 smb2_util_close(tree, h2);
1096 status = smb2_util_unlink(tree, fname);
1097 CHECK_STATUS(status, NT_STATUS_OK);
1100 for (i = 0; i < NOPLOCK_RESULTS; i++) {
1101 const char *held = oplock_results_2[i][0];
1102 const char *contend = oplock_results_2[i][1];
1103 const char *brokento = oplock_results_2[i][2];
1104 const char *granted = oplock_results_2[i][3];
1105 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
1106 "expecting break to %s(%x) and grant of %s(%x)\n",
1107 held, smb2_util_oplock_level(held), contend, smb2_util_lease_state(contend),
1108 brokento, smb2_util_oplock_level(brokento), granted, smb2_util_lease_state(granted));
1110 ZERO_STRUCT(lease_break_info);
1112 /* Grab an oplock. */
1113 smb2_oplock_create(&io, fname, smb2_util_oplock_level(held));
1114 status = smb2_create(tree, mem_ctx, &io);
1115 CHECK_STATUS(status, NT_STATUS_OK);
1116 h = io.out.file.handle;
1117 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1118 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(held));
1119 lease_break_info.held_oplock_level = io.out.oplock_level;
1122 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(contend));
1123 status = smb2_create(tree, mem_ctx, &io);
1124 CHECK_STATUS(status, NT_STATUS_OK);
1125 h2 = io.out.file.handle;
1126 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1127 CHECK_LEASE(&io, granted, true, LEASE1, 0);
1129 if (smb2_util_oplock_level(held) != smb2_util_oplock_level(brokento)) {
1130 CHECK_OPLOCK_BREAK(brokento);
1132 CHECK_NO_BREAK(tctx);
1135 smb2_util_close(tree, h);
1136 smb2_util_close(tree, h2);
1138 status = smb2_util_unlink(tree, fname);
1139 CHECK_STATUS(status, NT_STATUS_OK);
1143 smb2_util_close(tree, h);
1144 smb2_util_close(tree, h2);
1146 smb2_util_unlink(tree, fname);
1148 talloc_free(mem_ctx);
1153 static bool test_lease_multibreak(struct torture_context *tctx,
1154 struct smb2_tree *tree)
1156 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1157 struct smb2_create io;
1158 struct smb2_lease ls;
1159 struct smb2_handle h = {{0}};
1160 struct smb2_handle h2 = {{0}};
1161 struct smb2_handle h3 = {{0}};
1162 struct smb2_write w;
1164 const char *fname = "lease_multibreak.dat";
1168 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1169 if (!(caps & SMB2_CAP_LEASING)) {
1170 torture_skip(tctx, "leases are not supported");
1173 tree->session->transport->lease.handler = torture_lease_handler;
1174 tree->session->transport->lease.private_data = tree;
1175 tree->session->transport->oplock.handler = torture_oplock_handler;
1176 tree->session->transport->oplock.private_data = tree;
1178 smb2_util_unlink(tree, fname);
1180 ZERO_STRUCT(lease_break_info);
1182 /* Grab lease, upgrade to RHW .. */
1183 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
1184 status = smb2_create(tree, mem_ctx, &io);
1185 CHECK_STATUS(status, NT_STATUS_OK);
1186 h = io.out.file.handle;
1187 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1188 CHECK_LEASE(&io, "RH", true, LEASE1, 0);
1190 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
1191 status = smb2_create(tree, mem_ctx, &io);
1192 CHECK_STATUS(status, NT_STATUS_OK);
1193 h2 = io.out.file.handle;
1194 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1195 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
1197 /* Contend with LEASE2. */
1198 smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state("RHW"));
1199 status = smb2_create(tree, mem_ctx, &io);
1200 CHECK_STATUS(status, NT_STATUS_OK);
1201 h3 = io.out.file.handle;
1202 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1203 CHECK_LEASE(&io, "RH", true, LEASE2, 0);
1205 /* Verify that we were only sent one break. */
1206 CHECK_BREAK_INFO("RHW", "RH", LEASE1);
1208 /* Drop LEASE1 / LEASE2 */
1209 status = smb2_util_close(tree, h);
1210 CHECK_STATUS(status, NT_STATUS_OK);
1211 status = smb2_util_close(tree, h2);
1212 CHECK_STATUS(status, NT_STATUS_OK);
1213 status = smb2_util_close(tree, h3);
1214 CHECK_STATUS(status, NT_STATUS_OK);
1216 ZERO_STRUCT(lease_break_info);
1218 /* Grab an R lease. */
1219 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("R"));
1220 status = smb2_create(tree, mem_ctx, &io);
1221 CHECK_STATUS(status, NT_STATUS_OK);
1222 h = io.out.file.handle;
1223 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1224 CHECK_LEASE(&io, "R", true, LEASE1, 0);
1226 /* Grab a level-II oplock. */
1227 smb2_oplock_create(&io, fname, smb2_util_oplock_level("s"));
1228 status = smb2_create(tree, mem_ctx, &io);
1229 CHECK_STATUS(status, NT_STATUS_OK);
1230 h2 = io.out.file.handle;
1231 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1232 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
1233 lease_break_info.held_oplock_level = io.out.oplock_level;
1235 /* Verify no breaks. */
1236 CHECK_NO_BREAK(tctx);
1238 /* Open for truncate, force a break. */
1239 smb2_generic_create(&io, NULL, false, fname,
1240 NTCREATEX_DISP_OVERWRITE_IF, smb2_util_oplock_level(""), 0, 0);
1241 status = smb2_create(tree, mem_ctx, &io);
1242 CHECK_STATUS(status, NT_STATUS_OK);
1243 h3 = io.out.file.handle;
1244 CHECK_CREATED(&io, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
1245 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(""));
1246 lease_break_info.held_oplock_level = io.out.oplock_level;
1248 /* Sleep, use a write to clear the recv queue. */
1251 w.in.file.handle = h3;
1253 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
1254 memset(w.in.data.data, 'o', w.in.data.length);
1255 status = smb2_write(tree, &w);
1256 CHECK_STATUS(status, NT_STATUS_OK);
1258 /* Verify one oplock break, one lease break. */
1259 CHECK_OPLOCK_BREAK("");
1260 CHECK_BREAK_INFO("R", "", LEASE1);
1263 smb2_util_close(tree, h);
1264 smb2_util_close(tree, h2);
1265 smb2_util_close(tree, h3);
1267 smb2_util_unlink(tree, fname);
1269 talloc_free(mem_ctx);
1274 static bool test_lease_v2_request_parent(struct torture_context *tctx,
1275 struct smb2_tree *tree)
1277 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1278 struct smb2_create io;
1279 struct smb2_lease ls;
1280 struct smb2_handle h1 = {{0}};
1281 uint64_t parent = LEASE2;
1283 const char *fname = "lease_v2_request_parent.dat";
1286 enum protocol_types protocol;
1288 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1289 if (!(caps & SMB2_CAP_LEASING)) {
1290 torture_skip(tctx, "leases are not supported");
1292 if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
1293 torture_skip(tctx, "directory leases are not supported");
1296 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1297 if (protocol < PROTOCOL_SMB3_00) {
1298 torture_skip(tctx, "v2 leases are not supported");
1301 smb2_util_unlink(tree, fname);
1303 ZERO_STRUCT(lease_break_info);
1306 smb2_lease_v2_create_share(&io, &ls, false, fname,
1307 smb2_util_share_access("RWD"),
1309 smb2_util_lease_state("RHW"),
1312 status = smb2_create(tree, mem_ctx, &io);
1313 CHECK_STATUS(status, NT_STATUS_OK);
1314 h1 = io.out.file.handle;
1315 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1316 CHECK_LEASE_V2(&io, "RHW", true, LEASE1,
1317 SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2,
1318 ls.lease_epoch + 1);
1321 smb2_util_close(tree, h1);
1322 smb2_util_unlink(tree, fname);
1324 talloc_free(mem_ctx);
1329 static bool test_lease_break_twice(struct torture_context *tctx,
1330 struct smb2_tree *tree)
1332 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1333 struct smb2_create io;
1334 struct smb2_lease ls1;
1335 struct smb2_lease ls2;
1336 struct smb2_handle h1 = {{0}};
1338 const char *fname = "lease_break_twice.dat";
1341 enum protocol_types protocol;
1343 caps = smb2cli_conn_server_capabilities(
1344 tree->session->transport->conn);
1345 if (!(caps & SMB2_CAP_LEASING)) {
1346 torture_skip(tctx, "leases are not supported");
1349 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1350 if (protocol < PROTOCOL_SMB3_00) {
1351 torture_skip(tctx, "v2 leases are not supported");
1354 smb2_util_unlink(tree, fname);
1356 ZERO_STRUCT(lease_break_info);
1359 smb2_lease_v2_create_share(
1360 &io, &ls1, false, fname, smb2_util_share_access("RWD"),
1361 LEASE1, NULL, smb2_util_lease_state("RWH"), 0x11);
1363 status = smb2_create(tree, mem_ctx, &io);
1364 CHECK_STATUS(status, NT_STATUS_OK);
1365 h1 = io.out.file.handle;
1366 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1367 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch + 1);
1369 tree->session->transport->lease.handler = torture_lease_handler;
1370 tree->session->transport->lease.private_data = tree;
1372 ZERO_STRUCT(lease_break_info);
1374 smb2_lease_v2_create_share(
1375 &io, &ls2, false, fname, smb2_util_share_access("R"),
1376 LEASE2, NULL, smb2_util_lease_state("RWH"), 0x22);
1378 status = smb2_create(tree, mem_ctx, &io);
1379 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
1380 CHECK_BREAK_INFO_V2(tree->session->transport,
1381 "RWH", "RW", LEASE1, ls1.lease_epoch + 2);
1383 smb2_lease_v2_create_share(
1384 &io, &ls2, false, fname, smb2_util_share_access("RWD"),
1385 LEASE2, NULL, smb2_util_lease_state("RWH"), 0x22);
1387 ZERO_STRUCT(lease_break_info);
1389 status = smb2_create(tree, mem_ctx, &io);
1390 CHECK_STATUS(status, NT_STATUS_OK);
1391 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch + 1);
1392 CHECK_BREAK_INFO_V2(tree->session->transport,
1393 "RW", "R", LEASE1, ls1.lease_epoch + 3);
1396 smb2_util_close(tree, h1);
1397 smb2_util_unlink(tree, fname);
1398 talloc_free(mem_ctx);
1402 static bool test_lease_v2_request(struct torture_context *tctx,
1403 struct smb2_tree *tree)
1405 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1406 struct smb2_create io;
1407 struct smb2_lease ls1, ls2, ls2t, ls3, ls4;
1408 struct smb2_handle h1 = {{0}};
1409 struct smb2_handle h2 = {{0}};
1410 struct smb2_handle h3 = {{0}};
1411 struct smb2_handle h4 = {{0}};
1412 struct smb2_handle h5 = {{0}};
1413 struct smb2_write w;
1415 const char *fname = "lease_v2_request.dat";
1416 const char *dname = "lease_v2_request.dir";
1417 const char *dnamefname = "lease_v2_request.dir\\lease.dat";
1418 const char *dnamefname2 = "lease_v2_request.dir\\lease2.dat";
1421 enum protocol_types protocol;
1423 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1424 if (!(caps & SMB2_CAP_LEASING)) {
1425 torture_skip(tctx, "leases are not supported");
1427 if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
1428 torture_skip(tctx, "directory leases are not supported");
1431 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1432 if (protocol < PROTOCOL_SMB3_00) {
1433 torture_skip(tctx, "v2 leases are not supported");
1436 smb2_util_unlink(tree, fname);
1437 smb2_deltree(tree, dname);
1439 tree->session->transport->lease.handler = torture_lease_handler;
1440 tree->session->transport->lease.private_data = tree;
1441 tree->session->transport->oplock.handler = torture_oplock_handler;
1442 tree->session->transport->oplock.private_data = tree;
1444 ZERO_STRUCT(lease_break_info);
1447 smb2_lease_v2_create_share(&io, &ls1, false, fname,
1448 smb2_util_share_access("RWD"),
1450 smb2_util_lease_state("RHW"),
1453 status = smb2_create(tree, mem_ctx, &io);
1454 CHECK_STATUS(status, NT_STATUS_OK);
1455 h1 = io.out.file.handle;
1456 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1457 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch + 1);
1460 smb2_lease_v2_create_share(&io, &ls2, true, dname,
1461 smb2_util_share_access("RWD"),
1463 smb2_util_lease_state("RHW"),
1465 status = smb2_create(tree, mem_ctx, &io);
1466 CHECK_STATUS(status, NT_STATUS_OK);
1467 h2 = io.out.file.handle;
1468 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
1469 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch + 1);
1472 smb2_lease_v2_create_share(&io, &ls3, false, dnamefname,
1473 smb2_util_share_access("RWD"),
1475 smb2_util_lease_state("RHW"),
1477 status = smb2_create(tree, mem_ctx, &io);
1478 CHECK_STATUS(status, NT_STATUS_OK);
1479 h3 = io.out.file.handle;
1480 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1481 CHECK_LEASE_V2(&io, "RHW", true, LEASE3,
1482 SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2,
1483 ls3.lease_epoch + 1);
1485 CHECK_NO_BREAK(tctx);
1488 smb2_lease_v2_create_share(&io, &ls4, false, dnamefname2,
1489 smb2_util_share_access("RWD"),
1491 smb2_util_lease_state("RHW"),
1493 status = smb2_create(tree, mem_ctx, &io);
1494 CHECK_STATUS(status, NT_STATUS_OK);
1495 h4 = io.out.file.handle;
1496 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1497 CHECK_LEASE_V2(&io, "RHW", true, LEASE4, 0, 0, ls4.lease_epoch + 1);
1499 CHECK_BREAK_INFO_V2(tree->session->transport,
1500 "RH", "", LEASE2, ls2.lease_epoch + 2);
1502 ZERO_STRUCT(lease_break_info);
1505 smb2_lease_v2_create_share(&io, &ls2t, true, dname,
1506 smb2_util_share_access("RWD"),
1508 smb2_util_lease_state("RHW"),
1510 io.in.create_disposition = NTCREATEX_DISP_OPEN;
1511 status = smb2_create(tree, mem_ctx, &io);
1512 CHECK_STATUS(status, NT_STATUS_OK);
1513 h5 = io.out.file.handle;
1514 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_DIRECTORY);
1515 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch+3);
1516 smb2_util_close(tree, h5);
1519 w.in.file.handle = h4;
1521 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
1522 memset(w.in.data.data, 'o', w.in.data.length);
1523 status = smb2_write(tree, &w);
1524 CHECK_STATUS(status, NT_STATUS_OK);
1527 * Wait 4 seconds in order to check if the write time
1528 * was updated (after 2 seconds).
1531 CHECK_NO_BREAK(tctx);
1534 * only the close on the modified file break the
1537 smb2_util_close(tree, h4);
1539 CHECK_BREAK_INFO_V2(tree->session->transport,
1540 "RH", "", LEASE2, ls2.lease_epoch+4);
1543 smb2_util_close(tree, h1);
1544 smb2_util_close(tree, h2);
1545 smb2_util_close(tree, h3);
1546 smb2_util_close(tree, h4);
1547 smb2_util_close(tree, h5);
1549 smb2_util_unlink(tree, fname);
1550 smb2_deltree(tree, dname);
1552 talloc_free(mem_ctx);
1557 static bool test_lease_v2_epoch1(struct torture_context *tctx,
1558 struct smb2_tree *tree)
1560 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1561 struct smb2_create io;
1562 struct smb2_lease ls;
1563 struct smb2_handle h;
1564 const char *fname = "lease_v2_epoch1.dat";
1568 enum protocol_types protocol;
1570 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1571 if (!(caps & SMB2_CAP_LEASING)) {
1572 torture_skip(tctx, "leases are not supported");
1575 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1576 if (protocol < PROTOCOL_SMB3_00) {
1577 torture_skip(tctx, "v2 leases are not supported");
1580 smb2_util_unlink(tree, fname);
1582 tree->session->transport->lease.handler = torture_lease_handler;
1583 tree->session->transport->lease.private_data = tree;
1584 tree->session->transport->oplock.handler = torture_oplock_handler;
1585 tree->session->transport->oplock.private_data = tree;
1587 ZERO_STRUCT(lease_break_info);
1590 smb2_lease_v2_create_share(&io, &ls, false, fname,
1591 smb2_util_share_access("RWD"),
1593 smb2_util_lease_state("RHW"),
1595 status = smb2_create(tree, mem_ctx, &io);
1596 CHECK_STATUS(status, NT_STATUS_OK);
1597 h = io.out.file.handle;
1598 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1599 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls.lease_epoch + 1);
1600 smb2_util_close(tree, h);
1601 smb2_util_unlink(tree, fname);
1603 smb2_lease_v2_create_share(&io, &ls, false, fname,
1604 smb2_util_share_access("RWD"),
1606 smb2_util_lease_state("RHW"),
1609 status = smb2_create(tree, mem_ctx, &io);
1610 CHECK_STATUS(status, NT_STATUS_OK);
1611 h = io.out.file.handle;
1612 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1613 CHECK_LEASE_V2(&io, "RWH", true, LEASE1, 0, 0, ls.lease_epoch + 1);
1614 smb2_util_close(tree, h);
1617 smb2_util_unlink(tree, fname);
1618 talloc_free(mem_ctx);
1622 static bool test_lease_v2_epoch2(struct torture_context *tctx,
1623 struct smb2_tree *tree)
1625 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1626 struct smb2_create io;
1627 struct smb2_lease ls1v2, ls1v2t, ls1v1;
1628 struct smb2_handle hv2 = {}, hv1 = {};
1629 const char *fname = "lease_v2_epoch2.dat";
1633 enum protocol_types protocol;
1635 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1636 if (!(caps & SMB2_CAP_LEASING)) {
1637 torture_skip(tctx, "leases are not supported");
1640 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1641 if (protocol < PROTOCOL_SMB3_00) {
1642 torture_skip(tctx, "v2 leases are not supported");
1645 smb2_util_unlink(tree, fname);
1647 tree->session->transport->lease.handler = torture_lease_handler;
1648 tree->session->transport->lease.private_data = tree;
1649 tree->session->transport->oplock.handler = torture_oplock_handler;
1650 tree->session->transport->oplock.private_data = tree;
1652 ZERO_STRUCT(lease_break_info);
1655 smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
1656 smb2_util_share_access("RWD"),
1658 smb2_util_lease_state("R"),
1660 status = smb2_create(tree, mem_ctx, &io);
1661 CHECK_STATUS(status, NT_STATUS_OK);
1662 hv2 = io.out.file.handle;
1663 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1664 CHECK_LEASE_V2(&io, "R", true, LEASE1, 0, 0, ls1v2.lease_epoch + 1);
1667 smb2_lease_create_share(&io, &ls1v1, false, fname,
1668 smb2_util_share_access("RWD"),
1670 smb2_util_lease_state("RH"));
1671 status = smb2_create(tree, mem_ctx, &io);
1672 CHECK_STATUS(status, NT_STATUS_OK);
1673 hv1 = io.out.file.handle;
1674 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1675 CHECK_LEASE_V2(&io, "RH", true, LEASE1, 0, 0, ls1v2.lease_epoch + 2);
1677 smb2_util_close(tree, hv2);
1680 smb2_lease_v2_create_share(&io, &ls1v2t, false, fname,
1681 smb2_util_share_access("RWD"),
1683 smb2_util_lease_state("RHW"),
1685 status = smb2_create(tree, mem_ctx, &io);
1686 CHECK_STATUS(status, NT_STATUS_OK);
1687 hv2 = io.out.file.handle;
1688 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1689 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1v2.lease_epoch + 3);
1691 smb2_util_close(tree, hv2);
1693 smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_NONE);
1694 status = smb2_create(tree, mem_ctx, &io);
1695 CHECK_STATUS(status, NT_STATUS_OK);
1696 hv2 = io.out.file.handle;
1697 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1698 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1700 CHECK_BREAK_INFO_V2(tree->session->transport,
1701 "RWH", "RH", LEASE1, ls1v2.lease_epoch + 4);
1703 smb2_util_close(tree, hv2);
1704 smb2_util_close(tree, hv1);
1707 smb2_lease_create_share(&io, &ls1v1, false, fname,
1708 smb2_util_share_access("RWD"),
1710 smb2_util_lease_state("RHW"));
1711 status = smb2_create(tree, mem_ctx, &io);
1712 CHECK_STATUS(status, NT_STATUS_OK);
1713 hv1 = io.out.file.handle;
1714 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1715 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
1717 smb2_util_close(tree, hv1);
1720 smb2_util_close(tree, hv2);
1721 smb2_util_close(tree, hv1);
1722 smb2_util_unlink(tree, fname);
1723 talloc_free(mem_ctx);
1727 static bool test_lease_v2_epoch3(struct torture_context *tctx,
1728 struct smb2_tree *tree)
1730 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1731 struct smb2_create io;
1732 struct smb2_lease ls1v1 = {}, ls1v1t = {},ls1v2 = {};
1733 struct smb2_handle hv1 = {}, hv2 = {};
1734 const char *fname = "lease_v2_epoch3.dat";
1738 enum protocol_types protocol;
1740 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1741 if (!(caps & SMB2_CAP_LEASING)) {
1742 torture_skip(tctx, "leases are not supported");
1745 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1746 if (protocol < PROTOCOL_SMB3_00) {
1747 torture_skip(tctx, "v2 leases are not supported");
1750 smb2_util_unlink(tree, fname);
1752 tree->session->transport->lease.handler = torture_lease_handler;
1753 tree->session->transport->lease.private_data = tree;
1754 tree->session->transport->oplock.handler = torture_oplock_handler;
1755 tree->session->transport->oplock.private_data = tree;
1757 ZERO_STRUCT(lease_break_info);
1760 smb2_lease_create_share(&io, &ls1v1, false, fname,
1761 smb2_util_share_access("RWD"),
1763 smb2_util_lease_state("R"));
1764 status = smb2_create(tree, mem_ctx, &io);
1765 CHECK_STATUS(status, NT_STATUS_OK);
1766 hv1 = io.out.file.handle;
1767 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1768 CHECK_LEASE(&io, "R", true, LEASE1, 0);
1771 smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
1772 smb2_util_share_access("RWD"),
1774 smb2_util_lease_state("RW"),
1776 status = smb2_create(tree, mem_ctx, &io);
1777 CHECK_STATUS(status, NT_STATUS_OK);
1778 hv2 = io.out.file.handle;
1779 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1780 CHECK_LEASE(&io, "RW", true, LEASE1, 0);
1782 smb2_util_close(tree, hv1);
1785 smb2_lease_create_share(&io, &ls1v1t, false, fname,
1786 smb2_util_share_access("RWD"),
1788 smb2_util_lease_state("RWH"));
1789 status = smb2_create(tree, mem_ctx, &io);
1790 CHECK_STATUS(status, NT_STATUS_OK);
1791 hv1 = io.out.file.handle;
1792 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1793 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
1795 smb2_util_close(tree, hv1);
1797 smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_NONE);
1798 status = smb2_create(tree, mem_ctx, &io);
1799 CHECK_STATUS(status, NT_STATUS_OK);
1800 hv1 = io.out.file.handle;
1801 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1802 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1804 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
1806 smb2_util_close(tree, hv1);
1807 smb2_util_close(tree, hv2);
1810 smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
1811 smb2_util_share_access("RWD"),
1813 smb2_util_lease_state("RWH"),
1815 status = smb2_create(tree, mem_ctx, &io);
1816 CHECK_STATUS(status, NT_STATUS_OK);
1817 hv2 = io.out.file.handle;
1818 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1819 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1v2.lease_epoch + 1);
1820 smb2_util_close(tree, hv2);
1823 smb2_util_close(tree, hv2);
1824 smb2_util_close(tree, hv1);
1825 smb2_util_unlink(tree, fname);
1826 talloc_free(mem_ctx);
1830 static bool test_lease_breaking1(struct torture_context *tctx,
1831 struct smb2_tree *tree)
1833 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1834 struct smb2_create io1 = {};
1835 struct smb2_create io2 = {};
1836 struct smb2_lease ls1 = {};
1837 struct smb2_handle h1a = {};
1838 struct smb2_handle h1b = {};
1839 struct smb2_handle h2 = {};
1840 struct smb2_request *req2 = NULL;
1841 struct smb2_lease_break_ack ack = {};
1842 const char *fname = "lease_breaking1.dat";
1847 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1848 if (!(caps & SMB2_CAP_LEASING)) {
1849 torture_skip(tctx, "leases are not supported");
1852 smb2_util_unlink(tree, fname);
1854 tree->session->transport->lease.handler = torture_lease_handler;
1855 tree->session->transport->lease.private_data = tree;
1856 tree->session->transport->oplock.handler = torture_oplock_handler;
1857 tree->session->transport->oplock.private_data = tree;
1860 * we defer acking the lease break.
1862 ZERO_STRUCT(lease_break_info);
1863 lease_break_info.lease_skip_ack = true;
1865 smb2_lease_create_share(&io1, &ls1, false, fname,
1866 smb2_util_share_access("RWD"),
1868 smb2_util_lease_state("RWH"));
1869 status = smb2_create(tree, mem_ctx, &io1);
1870 CHECK_STATUS(status, NT_STATUS_OK);
1871 h1a = io1.out.file.handle;
1872 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1873 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
1876 * a conflicting open is blocked until we ack the
1879 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
1880 req2 = smb2_create_send(tree, &io2);
1881 torture_assert(tctx, req2 != NULL, "smb2_create_send");
1884 * we got the lease break, but defer the ack.
1886 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
1888 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
1890 ack.in.lease.lease_key =
1891 lease_break_info.lease_break.current_lease.lease_key;
1892 ack.in.lease.lease_state =
1893 lease_break_info.lease_break.new_lease_state;
1894 ZERO_STRUCT(lease_break_info);
1897 * a open using the same lease key is still works,
1898 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
1900 status = smb2_create(tree, mem_ctx, &io1);
1901 CHECK_STATUS(status, NT_STATUS_OK);
1902 h1b = io1.out.file.handle;
1903 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1904 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
1905 smb2_util_close(tree, h1b);
1907 CHECK_NO_BREAK(tctx);
1909 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
1912 * We ack the lease break.
1914 status = smb2_lease_break_ack(tree, &ack);
1915 CHECK_STATUS(status, NT_STATUS_OK);
1916 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
1918 torture_assert(tctx, req2->cancel.can_cancel,
1921 status = smb2_create_recv(req2, tctx, &io2);
1922 CHECK_STATUS(status, NT_STATUS_OK);
1923 h2 = io2.out.file.handle;
1924 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1925 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1927 CHECK_NO_BREAK(tctx);
1929 smb2_util_close(tree, h1a);
1930 smb2_util_close(tree, h1b);
1931 smb2_util_close(tree, h2);
1932 smb2_util_unlink(tree, fname);
1933 talloc_free(mem_ctx);
1937 static bool test_lease_breaking2(struct torture_context *tctx,
1938 struct smb2_tree *tree)
1940 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1941 struct smb2_create io1 = {};
1942 struct smb2_create io2 = {};
1943 struct smb2_lease ls1 = {};
1944 struct smb2_handle h1a = {};
1945 struct smb2_handle h1b = {};
1946 struct smb2_handle h2 = {};
1947 struct smb2_request *req2 = NULL;
1948 struct smb2_lease_break_ack ack = {};
1949 const char *fname = "lease_breaking2.dat";
1954 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1955 if (!(caps & SMB2_CAP_LEASING)) {
1956 torture_skip(tctx, "leases are not supported");
1959 smb2_util_unlink(tree, fname);
1961 tree->session->transport->lease.handler = torture_lease_handler;
1962 tree->session->transport->lease.private_data = tree;
1963 tree->session->transport->oplock.handler = torture_oplock_handler;
1964 tree->session->transport->oplock.private_data = tree;
1967 * we defer acking the lease break.
1969 ZERO_STRUCT(lease_break_info);
1970 lease_break_info.lease_skip_ack = true;
1972 smb2_lease_create_share(&io1, &ls1, false, fname,
1973 smb2_util_share_access("RWD"),
1975 smb2_util_lease_state("RWH"));
1976 status = smb2_create(tree, mem_ctx, &io1);
1977 CHECK_STATUS(status, NT_STATUS_OK);
1978 h1a = io1.out.file.handle;
1979 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1980 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
1983 * a conflicting open is blocked until we ack the
1986 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
1987 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
1988 req2 = smb2_create_send(tree, &io2);
1989 torture_assert(tctx, req2 != NULL, "smb2_create_send");
1992 * we got the lease break, but defer the ack.
1994 CHECK_BREAK_INFO("RWH", "", LEASE1);
1996 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
1998 ack.in.lease.lease_key =
1999 lease_break_info.lease_break.current_lease.lease_key;
2000 ZERO_STRUCT(lease_break_info);
2003 * a open using the same lease key is still works,
2004 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2006 status = smb2_create(tree, mem_ctx, &io1);
2007 CHECK_STATUS(status, NT_STATUS_OK);
2008 h1b = io1.out.file.handle;
2009 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2010 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2011 smb2_util_close(tree, h1b);
2013 CHECK_NO_BREAK(tctx);
2015 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2018 * We ack the lease break.
2020 ack.in.lease.lease_state =
2021 SMB2_LEASE_READ | SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE;
2022 status = smb2_lease_break_ack(tree, &ack);
2023 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2025 ack.in.lease.lease_state =
2026 SMB2_LEASE_READ | SMB2_LEASE_WRITE;
2027 status = smb2_lease_break_ack(tree, &ack);
2028 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2030 ack.in.lease.lease_state =
2031 SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE;
2032 status = smb2_lease_break_ack(tree, &ack);
2033 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2035 ack.in.lease.lease_state =
2036 SMB2_LEASE_READ | SMB2_LEASE_HANDLE;
2037 status = smb2_lease_break_ack(tree, &ack);
2038 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2040 ack.in.lease.lease_state = SMB2_LEASE_WRITE;
2041 status = smb2_lease_break_ack(tree, &ack);
2042 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2044 ack.in.lease.lease_state = SMB2_LEASE_HANDLE;
2045 status = smb2_lease_break_ack(tree, &ack);
2046 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2048 ack.in.lease.lease_state = SMB2_LEASE_READ;
2049 status = smb2_lease_break_ack(tree, &ack);
2050 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2052 /* Try again with the correct state this time. */
2053 ack.in.lease.lease_state = SMB2_LEASE_NONE;;
2054 status = smb2_lease_break_ack(tree, &ack);
2055 CHECK_STATUS(status, NT_STATUS_OK);
2056 CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
2058 status = smb2_lease_break_ack(tree, &ack);
2059 CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
2061 torture_assert(tctx, req2->cancel.can_cancel,
2064 status = smb2_create_recv(req2, tctx, &io2);
2065 CHECK_STATUS(status, NT_STATUS_OK);
2066 h2 = io2.out.file.handle;
2067 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2068 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2070 CHECK_NO_BREAK(tctx);
2072 /* Get state of the original handle. */
2073 smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
2074 status = smb2_create(tree, mem_ctx, &io1);
2075 CHECK_STATUS(status, NT_STATUS_OK);
2076 CHECK_LEASE(&io1, "", true, LEASE1, 0);
2077 smb2_util_close(tree, io1.out.file.handle);
2080 smb2_util_close(tree, h1a);
2081 smb2_util_close(tree, h1b);
2082 smb2_util_close(tree, h2);
2083 smb2_util_unlink(tree, fname);
2084 talloc_free(mem_ctx);
2088 static bool test_lease_breaking3(struct torture_context *tctx,
2089 struct smb2_tree *tree)
2091 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2092 struct smb2_create io1 = {};
2093 struct smb2_create io2 = {};
2094 struct smb2_create io3 = {};
2095 struct smb2_lease ls1 = {};
2096 struct smb2_handle h1a = {};
2097 struct smb2_handle h1b = {};
2098 struct smb2_handle h2 = {};
2099 struct smb2_handle h3 = {};
2100 struct smb2_request *req2 = NULL;
2101 struct smb2_request *req3 = NULL;
2102 struct lease_break_info lease_break_info_tmp = {};
2103 struct smb2_lease_break_ack ack = {};
2104 const char *fname = "lease_breaking3.dat";
2109 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2110 if (!(caps & SMB2_CAP_LEASING)) {
2111 torture_skip(tctx, "leases are not supported");
2114 smb2_util_unlink(tree, fname);
2116 tree->session->transport->lease.handler = torture_lease_handler;
2117 tree->session->transport->lease.private_data = tree;
2118 tree->session->transport->oplock.handler = torture_oplock_handler;
2119 tree->session->transport->oplock.private_data = tree;
2122 * we defer acking the lease break.
2124 ZERO_STRUCT(lease_break_info);
2125 lease_break_info.lease_skip_ack = true;
2127 smb2_lease_create_share(&io1, &ls1, false, fname,
2128 smb2_util_share_access("RWD"),
2130 smb2_util_lease_state("RWH"));
2131 status = smb2_create(tree, mem_ctx, &io1);
2132 CHECK_STATUS(status, NT_STATUS_OK);
2133 h1a = io1.out.file.handle;
2134 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2135 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2138 * a conflicting open is blocked until we ack the
2141 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2142 req2 = smb2_create_send(tree, &io2);
2143 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2146 * we got the lease break, but defer the ack.
2148 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2150 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2153 * a open using the same lease key is still works,
2154 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2156 status = smb2_create(tree, mem_ctx, &io1);
2157 CHECK_STATUS(status, NT_STATUS_OK);
2158 h1b = io1.out.file.handle;
2159 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2160 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2161 smb2_util_close(tree, h1b);
2164 * a conflicting open with NTCREATEX_DISP_OVERWRITE
2165 * doesn't trigger an immediate lease break to none.
2167 lease_break_info_tmp = lease_break_info;
2168 ZERO_STRUCT(lease_break_info);
2169 smb2_oplock_create(&io3, fname, SMB2_OPLOCK_LEVEL_NONE);
2170 io3.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2171 req3 = smb2_create_send(tree, &io3);
2172 torture_assert(tctx, req3 != NULL, "smb2_create_send");
2173 CHECK_NO_BREAK(tctx);
2174 lease_break_info = lease_break_info_tmp;
2176 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2178 ack.in.lease.lease_key =
2179 lease_break_info.lease_break.current_lease.lease_key;
2180 ack.in.lease.lease_state =
2181 lease_break_info.lease_break.new_lease_state;
2182 ZERO_STRUCT(lease_break_info);
2185 * a open using the same lease key is still works,
2186 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2188 status = smb2_create(tree, mem_ctx, &io1);
2189 CHECK_STATUS(status, NT_STATUS_OK);
2190 h1b = io1.out.file.handle;
2191 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2192 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2193 smb2_util_close(tree, h1b);
2195 CHECK_NO_BREAK(tctx);
2198 * We ack the lease break, but defer acking the next break (to "R")
2200 lease_break_info.lease_skip_ack = true;
2201 status = smb2_lease_break_ack(tree, &ack);
2202 CHECK_STATUS(status, NT_STATUS_OK);
2203 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
2206 * We got an additional break downgrading to just "R"
2207 * while we defer the ack.
2209 CHECK_BREAK_INFO("RH", "R", LEASE1);
2211 ack.in.lease.lease_key =
2212 lease_break_info.lease_break.current_lease.lease_key;
2213 ack.in.lease.lease_state =
2214 lease_break_info.lease_break.new_lease_state;
2215 ZERO_STRUCT(lease_break_info);
2218 * a open using the same lease key is still works,
2219 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2221 status = smb2_create(tree, mem_ctx, &io1);
2222 CHECK_STATUS(status, NT_STATUS_OK);
2223 h1b = io1.out.file.handle;
2224 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2225 CHECK_LEASE(&io1, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2226 smb2_util_close(tree, h1b);
2228 CHECK_NO_BREAK(tctx);
2230 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2231 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2234 * We ack the downgrade to "R" and get an immediate break to none
2236 status = smb2_lease_break_ack(tree, &ack);
2237 CHECK_STATUS(status, NT_STATUS_OK);
2238 CHECK_LEASE_BREAK_ACK(&ack, "R", LEASE1);
2241 * We get the downgrade to none.
2243 CHECK_BREAK_INFO("R", "", LEASE1);
2245 torture_assert(tctx, req2->cancel.can_cancel,
2247 torture_assert(tctx, req3->cancel.can_cancel,
2250 ZERO_STRUCT(lease_break_info);
2252 status = smb2_create_recv(req2, tctx, &io2);
2253 CHECK_STATUS(status, NT_STATUS_OK);
2254 h2 = io2.out.file.handle;
2255 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2256 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2258 status = smb2_create_recv(req3, tctx, &io3);
2259 CHECK_STATUS(status, NT_STATUS_OK);
2260 h3 = io3.out.file.handle;
2261 CHECK_CREATED(&io3, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2262 CHECK_VAL(io3.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2264 CHECK_NO_BREAK(tctx);
2266 smb2_util_close(tree, h1a);
2267 smb2_util_close(tree, h1b);
2268 smb2_util_close(tree, h2);
2269 smb2_util_close(tree, h3);
2271 smb2_util_unlink(tree, fname);
2272 talloc_free(mem_ctx);
2276 static bool test_lease_v2_breaking3(struct torture_context *tctx,
2277 struct smb2_tree *tree)
2279 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2280 struct smb2_create io1 = {};
2281 struct smb2_create io2 = {};
2282 struct smb2_create io3 = {};
2283 struct smb2_lease ls1 = {};
2284 struct smb2_handle h1a = {};
2285 struct smb2_handle h1b = {};
2286 struct smb2_handle h2 = {};
2287 struct smb2_handle h3 = {};
2288 struct smb2_request *req2 = NULL;
2289 struct smb2_request *req3 = NULL;
2290 struct lease_break_info lease_break_info_tmp = {};
2291 struct smb2_lease_break_ack ack = {};
2292 const char *fname = "v2_lease_breaking3.dat";
2296 enum protocol_types protocol;
2298 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2299 if (!(caps & SMB2_CAP_LEASING)) {
2300 torture_skip(tctx, "leases are not supported");
2303 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
2304 if (protocol < PROTOCOL_SMB3_00) {
2305 torture_skip(tctx, "v2 leases are not supported");
2308 smb2_util_unlink(tree, fname);
2310 tree->session->transport->lease.handler = torture_lease_handler;
2311 tree->session->transport->lease.private_data = tree;
2312 tree->session->transport->oplock.handler = torture_oplock_handler;
2313 tree->session->transport->oplock.private_data = tree;
2316 * we defer acking the lease break.
2318 ZERO_STRUCT(lease_break_info);
2319 lease_break_info.lease_skip_ack = true;
2321 smb2_lease_v2_create_share(&io1, &ls1, false, fname,
2322 smb2_util_share_access("RWD"),
2324 smb2_util_lease_state("RHW"),
2326 status = smb2_create(tree, mem_ctx, &io1);
2327 CHECK_STATUS(status, NT_STATUS_OK);
2328 h1a = io1.out.file.handle;
2329 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2330 /* Epoch increases on open. */
2331 ls1.lease_epoch += 1;
2332 CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
2335 * a conflicting open is blocked until we ack the
2338 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2339 req2 = smb2_create_send(tree, &io2);
2340 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2343 * we got the lease break, but defer the ack.
2345 CHECK_BREAK_INFO_V2(tree->session->transport,
2346 "RWH", "RH", LEASE1, ls1.lease_epoch + 1);
2348 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2350 /* On receiving a lease break, we must sync the new epoch. */
2351 ls1.lease_epoch = lease_break_info.lease_break.new_epoch;
2354 * a open using the same lease key is still works,
2355 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2357 status = smb2_create(tree, mem_ctx, &io1);
2358 CHECK_STATUS(status, NT_STATUS_OK);
2359 h1b = io1.out.file.handle;
2360 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2361 CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
2362 smb2_util_close(tree, h1b);
2365 * a conflicting open with NTCREATEX_DISP_OVERWRITE
2366 * doesn't trigger an immediate lease break to none.
2368 lease_break_info_tmp = lease_break_info;
2369 ZERO_STRUCT(lease_break_info);
2370 smb2_oplock_create(&io3, fname, SMB2_OPLOCK_LEVEL_NONE);
2371 io3.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2372 req3 = smb2_create_send(tree, &io3);
2373 torture_assert(tctx, req3 != NULL, "smb2_create_send");
2374 CHECK_NO_BREAK(tctx);
2375 lease_break_info = lease_break_info_tmp;
2377 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2379 ack.in.lease.lease_key =
2380 lease_break_info.lease_break.current_lease.lease_key;
2381 ack.in.lease.lease_state =
2382 lease_break_info.lease_break.new_lease_state;
2383 ZERO_STRUCT(lease_break_info);
2386 * a open using the same lease key is still works,
2387 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2389 status = smb2_create(tree, mem_ctx, &io1);
2390 CHECK_STATUS(status, NT_STATUS_OK);
2391 h1b = io1.out.file.handle;
2392 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2393 CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
2394 smb2_util_close(tree, h1b);
2396 CHECK_NO_BREAK(tctx);
2399 * We ack the lease break, but defer acking the next break (to "R")
2401 lease_break_info.lease_skip_ack = true;
2402 status = smb2_lease_break_ack(tree, &ack);
2403 CHECK_STATUS(status, NT_STATUS_OK);
2404 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
2407 * We got an additional break downgrading to just "R"
2408 * while we defer the ack.
2410 CHECK_BREAK_INFO_V2(tree->session->transport,
2411 "RH", "R", LEASE1, ls1.lease_epoch);
2412 /* On receiving a lease break, we must sync the new epoch. */
2413 ls1.lease_epoch = lease_break_info.lease_break.new_epoch;
2415 ack.in.lease.lease_key =
2416 lease_break_info.lease_break.current_lease.lease_key;
2417 ack.in.lease.lease_state =
2418 lease_break_info.lease_break.new_lease_state;
2419 ZERO_STRUCT(lease_break_info);
2422 * a open using the same lease key is still works,
2423 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2425 status = smb2_create(tree, mem_ctx, &io1);
2426 CHECK_STATUS(status, NT_STATUS_OK);
2427 h1b = io1.out.file.handle;
2428 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2429 CHECK_LEASE_V2(&io1, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
2430 smb2_util_close(tree, h1b);
2432 CHECK_NO_BREAK(tctx);
2434 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2435 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2438 * We ack the downgrade to "R" and get an immediate break to none
2440 status = smb2_lease_break_ack(tree, &ack);
2441 CHECK_STATUS(status, NT_STATUS_OK);
2442 CHECK_LEASE_BREAK_ACK(&ack, "R", LEASE1);
2445 * We get the downgrade to none.
2447 CHECK_BREAK_INFO_V2(tree->session->transport,
2448 "R", "", LEASE1, ls1.lease_epoch);
2450 torture_assert(tctx, req2->cancel.can_cancel,
2452 torture_assert(tctx, req3->cancel.can_cancel,
2455 ZERO_STRUCT(lease_break_info);
2457 status = smb2_create_recv(req2, tctx, &io2);
2458 CHECK_STATUS(status, NT_STATUS_OK);
2459 h2 = io2.out.file.handle;
2460 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2461 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2463 status = smb2_create_recv(req3, tctx, &io3);
2464 CHECK_STATUS(status, NT_STATUS_OK);
2465 h3 = io3.out.file.handle;
2466 CHECK_CREATED(&io3, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2467 CHECK_VAL(io3.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2469 CHECK_NO_BREAK(tctx);
2471 smb2_util_close(tree, h1a);
2472 smb2_util_close(tree, h1b);
2473 smb2_util_close(tree, h2);
2474 smb2_util_close(tree, h3);
2476 smb2_util_unlink(tree, fname);
2477 talloc_free(mem_ctx);
2482 static bool test_lease_breaking4(struct torture_context *tctx,
2483 struct smb2_tree *tree)
2485 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2486 struct smb2_create io1 = {};
2487 struct smb2_create io2 = {};
2488 struct smb2_create io3 = {};
2489 struct smb2_lease ls1 = {};
2490 struct smb2_lease ls1t = {};
2491 struct smb2_handle h1 = {};
2492 struct smb2_handle h2 = {};
2493 struct smb2_handle h3 = {};
2494 struct smb2_request *req2 = NULL;
2495 struct lease_break_info lease_break_info_tmp = {};
2496 struct smb2_lease_break_ack ack = {};
2497 const char *fname = "lease_breaking4.dat";
2502 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2503 if (!(caps & SMB2_CAP_LEASING)) {
2504 torture_skip(tctx, "leases are not supported");
2507 smb2_util_unlink(tree, fname);
2509 tree->session->transport->lease.handler = torture_lease_handler;
2510 tree->session->transport->lease.private_data = tree;
2511 tree->session->transport->oplock.handler = torture_oplock_handler;
2512 tree->session->transport->oplock.private_data = tree;
2515 * we defer acking the lease break.
2517 ZERO_STRUCT(lease_break_info);
2518 lease_break_info.lease_skip_ack = true;
2520 smb2_lease_create_share(&io1, &ls1, false, fname,
2521 smb2_util_share_access("RWD"),
2523 smb2_util_lease_state("RH"));
2524 status = smb2_create(tree, mem_ctx, &io1);
2525 CHECK_STATUS(status, NT_STATUS_OK);
2526 h1 = io1.out.file.handle;
2527 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2528 CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
2530 CHECK_NO_BREAK(tctx);
2533 * a conflicting open is *not* blocked until we ack the
2536 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2537 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2538 req2 = smb2_create_send(tree, &io2);
2539 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2542 * We got a break from RH to NONE, we're supported to ack
2545 CHECK_BREAK_INFO("RH", "", LEASE1);
2547 lease_break_info_tmp = lease_break_info;
2548 ZERO_STRUCT(lease_break_info);
2549 CHECK_NO_BREAK(tctx);
2551 torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2553 status = smb2_create_recv(req2, tctx, &io2);
2554 CHECK_STATUS(status, NT_STATUS_OK);
2555 h2 = io2.out.file.handle;
2556 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2557 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2558 smb2_util_close(tree, h2);
2560 CHECK_NO_BREAK(tctx);
2563 * a conflicting open is *not* blocked until we ack the
2564 * lease break, even if the lease is in breaking state.
2566 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2567 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2568 req2 = smb2_create_send(tree, &io2);
2569 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2571 CHECK_NO_BREAK(tctx);
2573 torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2575 status = smb2_create_recv(req2, tctx, &io2);
2576 CHECK_STATUS(status, NT_STATUS_OK);
2577 h2 = io2.out.file.handle;
2578 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2579 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2580 smb2_util_close(tree, h2);
2582 CHECK_NO_BREAK(tctx);
2585 * We now ask the server about the current lease state
2586 * which should still be "RH", but with
2587 * SMB2_LEASE_FLAG_BREAK_IN_PROGRESS.
2589 smb2_lease_create_share(&io3, &ls1t, false, fname,
2590 smb2_util_share_access("RWD"),
2592 smb2_util_lease_state(""));
2593 status = smb2_create(tree, mem_ctx, &io3);
2594 CHECK_STATUS(status, NT_STATUS_OK);
2595 h3 = io3.out.file.handle;
2596 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2597 CHECK_LEASE(&io3, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2600 * We finally ack the lease break...
2602 CHECK_NO_BREAK(tctx);
2603 lease_break_info = lease_break_info_tmp;
2604 ack.in.lease.lease_key =
2605 lease_break_info.lease_break.current_lease.lease_key;
2606 ack.in.lease.lease_state =
2607 lease_break_info.lease_break.new_lease_state;
2608 ZERO_STRUCT(lease_break_info);
2609 lease_break_info.lease_skip_ack = true;
2611 status = smb2_lease_break_ack(tree, &ack);
2612 CHECK_STATUS(status, NT_STATUS_OK);
2613 CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
2615 CHECK_NO_BREAK(tctx);
2618 smb2_util_close(tree, h1);
2619 smb2_util_close(tree, h2);
2620 smb2_util_close(tree, h3);
2622 smb2_util_unlink(tree, fname);
2623 talloc_free(mem_ctx);
2627 static bool test_lease_breaking5(struct torture_context *tctx,
2628 struct smb2_tree *tree)
2630 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2631 struct smb2_create io1 = {};
2632 struct smb2_create io2 = {};
2633 struct smb2_create io3 = {};
2634 struct smb2_lease ls1 = {};
2635 struct smb2_lease ls1t = {};
2636 struct smb2_handle h1 = {};
2637 struct smb2_handle h2 = {};
2638 struct smb2_handle h3 = {};
2639 struct smb2_request *req2 = NULL;
2640 struct lease_break_info lease_break_info_tmp = {};
2641 struct smb2_lease_break_ack ack = {};
2642 const char *fname = "lease_breaking5.dat";
2647 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2648 if (!(caps & SMB2_CAP_LEASING)) {
2649 torture_skip(tctx, "leases are not supported");
2652 smb2_util_unlink(tree, fname);
2654 tree->session->transport->lease.handler = torture_lease_handler;
2655 tree->session->transport->lease.private_data = tree;
2656 tree->session->transport->oplock.handler = torture_oplock_handler;
2657 tree->session->transport->oplock.private_data = tree;
2660 * we defer acking the lease break.
2662 ZERO_STRUCT(lease_break_info);
2663 lease_break_info.lease_skip_ack = true;
2665 smb2_lease_create_share(&io1, &ls1, false, fname,
2666 smb2_util_share_access("RWD"),
2668 smb2_util_lease_state("R"));
2669 status = smb2_create(tree, mem_ctx, &io1);
2670 CHECK_STATUS(status, NT_STATUS_OK);
2671 h1 = io1.out.file.handle;
2672 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2673 CHECK_LEASE(&io1, "R", true, LEASE1, 0);
2675 CHECK_NO_BREAK(tctx);
2678 * a conflicting open is *not* blocked until we ack the
2681 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2682 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2683 req2 = smb2_create_send(tree, &io2);
2684 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2687 * We got a break from RH to NONE, we're supported to ack
2690 CHECK_BREAK_INFO("R", "", LEASE1);
2692 lease_break_info_tmp = lease_break_info;
2693 ZERO_STRUCT(lease_break_info);
2694 CHECK_NO_BREAK(tctx);
2696 torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2698 status = smb2_create_recv(req2, tctx, &io2);
2699 CHECK_STATUS(status, NT_STATUS_OK);
2700 h2 = io2.out.file.handle;
2701 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2702 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2704 CHECK_NO_BREAK(tctx);
2707 * We now ask the server about the current lease state
2708 * which should still be "RH", but with
2709 * SMB2_LEASE_FLAG_BREAK_IN_PROGRESS.
2711 smb2_lease_create_share(&io3, &ls1t, false, fname,
2712 smb2_util_share_access("RWD"),
2714 smb2_util_lease_state(""));
2715 status = smb2_create(tree, mem_ctx, &io3);
2716 CHECK_STATUS(status, NT_STATUS_OK);
2717 h3 = io3.out.file.handle;
2718 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2719 CHECK_LEASE(&io3, "", true, LEASE1, 0);
2722 * We send an ack without without being asked.
2724 CHECK_NO_BREAK(tctx);
2725 lease_break_info = lease_break_info_tmp;
2726 ack.in.lease.lease_key =
2727 lease_break_info.lease_break.current_lease.lease_key;
2728 ack.in.lease.lease_state =
2729 lease_break_info.lease_break.new_lease_state;
2730 ZERO_STRUCT(lease_break_info);
2731 status = smb2_lease_break_ack(tree, &ack);
2732 CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
2734 CHECK_NO_BREAK(tctx);
2737 smb2_util_close(tree, h1);
2738 smb2_util_close(tree, h2);
2739 smb2_util_close(tree, h3);
2741 smb2_util_unlink(tree, fname);
2742 talloc_free(mem_ctx);
2746 static bool test_lease_breaking6(struct torture_context *tctx,
2747 struct smb2_tree *tree)
2749 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2750 struct smb2_create io1 = {};
2751 struct smb2_create io2 = {};
2752 struct smb2_lease ls1 = {};
2753 struct smb2_handle h1a = {};
2754 struct smb2_handle h1b = {};
2755 struct smb2_handle h2 = {};
2756 struct smb2_request *req2 = NULL;
2757 struct smb2_lease_break_ack ack = {};
2758 const char *fname = "lease_breaking6.dat";
2763 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2764 if (!(caps & SMB2_CAP_LEASING)) {
2765 torture_skip(tctx, "leases are not supported");
2768 smb2_util_unlink(tree, fname);
2770 tree->session->transport->lease.handler = torture_lease_handler;
2771 tree->session->transport->lease.private_data = tree;
2772 tree->session->transport->oplock.handler = torture_oplock_handler;
2773 tree->session->transport->oplock.private_data = tree;
2776 * we defer acking the lease break.
2778 ZERO_STRUCT(lease_break_info);
2779 lease_break_info.lease_skip_ack = true;
2781 smb2_lease_create_share(&io1, &ls1, false, fname,
2782 smb2_util_share_access("RWD"),
2784 smb2_util_lease_state("RWH"));
2785 status = smb2_create(tree, mem_ctx, &io1);
2786 CHECK_STATUS(status, NT_STATUS_OK);
2787 h1a = io1.out.file.handle;
2788 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2789 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2792 * a conflicting open is blocked until we ack the
2795 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2796 req2 = smb2_create_send(tree, &io2);
2797 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2800 * we got the lease break, but defer the ack.
2802 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2804 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2806 ack.in.lease.lease_key =
2807 lease_break_info.lease_break.current_lease.lease_key;
2808 ZERO_STRUCT(lease_break_info);
2811 * a open using the same lease key is still works,
2812 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2814 status = smb2_create(tree, mem_ctx, &io1);
2815 CHECK_STATUS(status, NT_STATUS_OK);
2816 h1b = io1.out.file.handle;
2817 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2818 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2819 smb2_util_close(tree, h1b);
2821 CHECK_NO_BREAK(tctx);
2823 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2826 * We are asked to break to "RH", but we are allowed to
2827 * break to any of "RH", "R" or NONE.
2829 ack.in.lease.lease_state = SMB2_LEASE_NONE;
2830 status = smb2_lease_break_ack(tree, &ack);
2831 CHECK_STATUS(status, NT_STATUS_OK);
2832 CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
2834 torture_assert(tctx, req2->cancel.can_cancel,
2837 status = smb2_create_recv(req2, tctx, &io2);
2838 CHECK_STATUS(status, NT_STATUS_OK);
2839 h2 = io2.out.file.handle;
2840 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2841 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2843 CHECK_NO_BREAK(tctx);
2845 smb2_util_close(tree, h1a);
2846 smb2_util_close(tree, h1b);
2847 smb2_util_close(tree, h2);
2848 smb2_util_unlink(tree, fname);
2849 talloc_free(mem_ctx);
2853 static bool test_lease_lock1(struct torture_context *tctx,
2854 struct smb2_tree *tree1a,
2855 struct smb2_tree *tree2)
2857 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2858 struct smb2_create io1 = {};
2859 struct smb2_create io2 = {};
2860 struct smb2_create io3 = {};
2861 struct smb2_lease ls1 = {};
2862 struct smb2_lease ls2 = {};
2863 struct smb2_lease ls3 = {};
2864 struct smb2_handle h1 = {};
2865 struct smb2_handle h2 = {};
2866 struct smb2_handle h3 = {};
2867 struct smb2_lock lck;
2868 struct smb2_lock_element el[1];
2869 const char *fname = "locktest.dat";
2873 struct smbcli_options options1;
2874 struct smb2_tree *tree1b = NULL;
2876 options1 = tree1a->session->transport->options;
2878 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
2879 if (!(caps & SMB2_CAP_LEASING)) {
2880 torture_skip(tctx, "leases are not supported");
2883 /* Set up handlers. */
2884 tree2->session->transport->lease.handler = torture_lease_handler;
2885 tree2->session->transport->lease.private_data = tree2;
2886 tree2->session->transport->oplock.handler = torture_oplock_handler;
2887 tree2->session->transport->oplock.private_data = tree2;
2889 tree1a->session->transport->lease.handler = torture_lease_handler;
2890 tree1a->session->transport->lease.private_data = tree1a;
2891 tree1a->session->transport->oplock.handler = torture_oplock_handler;
2892 tree1a->session->transport->oplock.private_data = tree1a;
2894 /* create a new connection (same client_guid) */
2895 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
2896 torture_warning(tctx, "couldn't reconnect, bailing\n");
2901 tree1b->session->transport->lease.handler = torture_lease_handler;
2902 tree1b->session->transport->lease.private_data = tree1b;
2903 tree1b->session->transport->oplock.handler = torture_oplock_handler;
2904 tree1b->session->transport->oplock.private_data = tree1b;
2906 smb2_util_unlink(tree1a, fname);
2908 ZERO_STRUCT(lease_break_info);
2911 /* Open a handle on tree1a. */
2912 smb2_lease_create_share(&io1, &ls1, false, fname,
2913 smb2_util_share_access("RWD"),
2915 smb2_util_lease_state("RWH"));
2916 status = smb2_create(tree1a, mem_ctx, &io1);
2917 CHECK_STATUS(status, NT_STATUS_OK);
2918 h1 = io1.out.file.handle;
2919 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2920 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2922 /* Open a second handle on tree1b. */
2923 smb2_lease_create_share(&io2, &ls2, false, fname,
2924 smb2_util_share_access("RWD"),
2926 smb2_util_lease_state("RWH"));
2927 status = smb2_create(tree1b, mem_ctx, &io2);
2928 CHECK_STATUS(status, NT_STATUS_OK);
2929 h2 = io2.out.file.handle;
2930 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2931 CHECK_LEASE(&io2, "RH", true, LEASE2, 0);
2932 /* And LEASE1 got broken to RH. */
2933 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2934 ZERO_STRUCT(lease_break_info);
2936 /* Now open a lease on a different client guid. */
2937 smb2_lease_create_share(&io3, &ls3, false, fname,
2938 smb2_util_share_access("RWD"),
2940 smb2_util_lease_state("RWH"));
2941 status = smb2_create(tree2, mem_ctx, &io3);
2942 CHECK_STATUS(status, NT_STATUS_OK);
2943 h3 = io3.out.file.handle;
2944 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2945 CHECK_LEASE(&io3, "RH", true, LEASE3, 0);
2946 /* Doesn't break. */
2947 CHECK_NO_BREAK(tctx);
2951 * Try and get get an exclusive byte
2952 * range lock on H1 (LEASE1).
2955 lck.in.lock_count = 1;
2956 lck.in.lock_sequence = 1;
2957 lck.in.file.handle = h1;
2961 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
2962 status = smb2_lock(tree1a, &lck);
2963 CHECK_STATUS(status, NT_STATUS_OK);
2965 /* LEASE2 and LEASE3 should get broken to NONE. */
2966 torture_wait_for_lease_break(tctx);
2967 torture_wait_for_lease_break(tctx);
2968 torture_wait_for_lease_break(tctx);
2969 torture_wait_for_lease_break(tctx);
2971 CHECK_VAL(lease_break_info.failures, 0); \
2972 CHECK_VAL(lease_break_info.count, 2); \
2974 /* Get state of the H1 (LEASE1) */
2975 smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
2976 status = smb2_create(tree1a, mem_ctx, &io1);
2977 CHECK_STATUS(status, NT_STATUS_OK);
2978 /* Should still be RH. */
2979 CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
2980 smb2_util_close(tree1a, io1.out.file.handle);
2982 /* Get state of the H2 (LEASE2) */
2983 smb2_lease_create(&io2, &ls2, false, fname, LEASE2, smb2_util_lease_state(""));
2984 status = smb2_create(tree1b, mem_ctx, &io2);
2985 CHECK_STATUS(status, NT_STATUS_OK);
2986 CHECK_LEASE(&io2, "", true, LEASE2, 0);
2987 smb2_util_close(tree1b, io2.out.file.handle);
2989 /* Get state of the H3 (LEASE3) */
2990 smb2_lease_create(&io3, &ls3, false, fname, LEASE3, smb2_util_lease_state(""));
2991 status = smb2_create(tree2, mem_ctx, &io3);
2992 CHECK_STATUS(status, NT_STATUS_OK);
2993 CHECK_LEASE(&io3, "", true, LEASE3, 0);
2994 smb2_util_close(tree2, io3.out.file.handle);
2996 ZERO_STRUCT(lease_break_info);
2999 * Try and get get an exclusive byte
3000 * range lock on H3 (LEASE3).
3002 lck.in.lock_count = 1;
3003 lck.in.lock_sequence = 2;
3004 lck.in.file.handle = h3;
3008 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
3009 status = smb2_lock(tree2, &lck);
3010 CHECK_STATUS(status, NT_STATUS_OK);
3011 /* LEASE1 got broken to NONE. */
3012 CHECK_BREAK_INFO("RH", "", LEASE1);
3013 ZERO_STRUCT(lease_break_info);
3016 smb2_util_close(tree1a, h1);
3017 smb2_util_close(tree1b, h2);
3018 smb2_util_close(tree2, h3);
3020 smb2_util_unlink(tree1a, fname);
3021 talloc_free(mem_ctx);
3025 static bool test_lease_complex1(struct torture_context *tctx,
3026 struct smb2_tree *tree1a)
3028 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3029 struct smb2_create io1;
3030 struct smb2_create io2;
3031 struct smb2_lease ls1;
3032 struct smb2_lease ls2;
3033 struct smb2_handle h = {{0}};
3034 struct smb2_handle h2 = {{0}};
3035 struct smb2_handle h3 = {{0}};
3036 struct smb2_write w;
3038 const char *fname = "lease_complex1.dat";
3041 struct smb2_tree *tree1b = NULL;
3042 struct smbcli_options options1;
3044 options1 = tree1a->session->transport->options;
3046 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3047 if (!(caps & SMB2_CAP_LEASING)) {
3048 torture_skip(tctx, "leases are not supported");
3051 tree1a->session->transport->lease.handler = torture_lease_handler;
3052 tree1a->session->transport->lease.private_data = tree1a;
3053 tree1a->session->transport->oplock.handler = torture_oplock_handler;
3054 tree1a->session->transport->oplock.private_data = tree1a;
3056 /* create a new connection (same client_guid) */
3057 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
3058 torture_warning(tctx, "couldn't reconnect, bailing\n");
3063 tree1b->session->transport->lease.handler = torture_lease_handler;
3064 tree1b->session->transport->lease.private_data = tree1b;
3065 tree1b->session->transport->oplock.handler = torture_oplock_handler;
3066 tree1b->session->transport->oplock.private_data = tree1b;
3068 smb2_util_unlink(tree1a, fname);
3070 ZERO_STRUCT(lease_break_info);
3072 /* Grab R lease over connection 1a */
3073 smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
3074 status = smb2_create(tree1a, mem_ctx, &io1);
3075 CHECK_STATUS(status, NT_STATUS_OK);
3076 h = io1.out.file.handle;
3077 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3078 CHECK_LEASE(&io1, "R", true, LEASE1, 0);
3080 /* Upgrade to RWH over connection 1b */
3081 ls1.lease_state = smb2_util_lease_state("RWH");
3082 status = smb2_create(tree1b, mem_ctx, &io1);
3083 CHECK_STATUS(status, NT_STATUS_OK);
3084 h2 = io1.out.file.handle;
3085 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3086 CHECK_LEASE(&io1, "RHW", true, LEASE1, 0);
3088 /* close over connection 1b */
3089 status = smb2_util_close(tree1b, h2);
3090 CHECK_STATUS(status, NT_STATUS_OK);
3092 /* Contend with LEASE2. */
3093 smb2_lease_create(&io2, &ls2, false, fname, LEASE2, smb2_util_lease_state("R"));
3094 status = smb2_create(tree1b, mem_ctx, &io2);
3095 CHECK_STATUS(status, NT_STATUS_OK);
3096 h3 = io2.out.file.handle;
3097 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3098 CHECK_LEASE(&io2, "R", true, LEASE2, 0);
3100 /* Verify that we were only sent one break. */
3101 CHECK_BREAK_INFO("RHW", "RH", LEASE1);
3103 /* again RH over connection 1b doesn't change the epoch */
3104 ls1.lease_state = smb2_util_lease_state("RH");
3105 status = smb2_create(tree1b, mem_ctx, &io1);
3106 CHECK_STATUS(status, NT_STATUS_OK);
3107 h2 = io1.out.file.handle;
3108 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3109 CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
3111 /* close over connection 1b */
3112 status = smb2_util_close(tree1b, h2);
3113 CHECK_STATUS(status, NT_STATUS_OK);
3115 ZERO_STRUCT(lease_break_info);
3118 w.in.file.handle = h;
3120 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3121 memset(w.in.data.data, 'o', w.in.data.length);
3122 status = smb2_write(tree1a, &w);
3123 CHECK_STATUS(status, NT_STATUS_OK);
3125 ls2.lease_epoch += 1;
3126 CHECK_BREAK_INFO("R", "", LEASE2);
3128 ZERO_STRUCT(lease_break_info);
3131 w.in.file.handle = h3;
3133 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3134 memset(w.in.data.data, 'o', w.in.data.length);
3135 status = smb2_write(tree1b, &w);
3136 CHECK_STATUS(status, NT_STATUS_OK);
3138 ls1.lease_epoch += 1;
3139 CHECK_BREAK_INFO("RH", "", LEASE1);
3142 smb2_util_close(tree1a, h);
3143 smb2_util_close(tree1b, h2);
3144 smb2_util_close(tree1b, h3);
3146 smb2_util_unlink(tree1a, fname);
3148 talloc_free(mem_ctx);
3153 static bool test_lease_v2_complex1(struct torture_context *tctx,
3154 struct smb2_tree *tree1a)
3156 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3157 struct smb2_create io1;
3158 struct smb2_create io2;
3159 struct smb2_lease ls1;
3160 struct smb2_lease ls2;
3161 struct smb2_handle h = {{0}};
3162 struct smb2_handle h2 = {{0}};
3163 struct smb2_handle h3 = {{0}};
3164 struct smb2_write w;
3166 const char *fname = "lease_v2_complex1.dat";
3169 enum protocol_types protocol;
3170 struct smb2_tree *tree1b = NULL;
3171 struct smbcli_options options1;
3173 options1 = tree1a->session->transport->options;
3175 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3176 if (!(caps & SMB2_CAP_LEASING)) {
3177 torture_skip(tctx, "leases are not supported");
3180 protocol = smbXcli_conn_protocol(tree1a->session->transport->conn);
3181 if (protocol < PROTOCOL_SMB3_00) {
3182 torture_skip(tctx, "v2 leases are not supported");
3185 tree1a->session->transport->lease.handler = torture_lease_handler;
3186 tree1a->session->transport->lease.private_data = tree1a;
3187 tree1a->session->transport->oplock.handler = torture_oplock_handler;
3188 tree1a->session->transport->oplock.private_data = tree1a;
3190 /* create a new connection (same client_guid) */
3191 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
3192 torture_warning(tctx, "couldn't reconnect, bailing\n");
3197 tree1b->session->transport->lease.handler = torture_lease_handler;
3198 tree1b->session->transport->lease.private_data = tree1b;
3199 tree1b->session->transport->oplock.handler = torture_oplock_handler;
3200 tree1b->session->transport->oplock.private_data = tree1b;
3202 smb2_util_unlink(tree1a, fname);
3204 ZERO_STRUCT(lease_break_info);
3206 /* Grab R lease over connection 1a */
3207 smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
3208 smb2_util_lease_state("R"), 0x4711);
3209 status = smb2_create(tree1a, mem_ctx, &io1);
3210 CHECK_STATUS(status, NT_STATUS_OK);
3211 h = io1.out.file.handle;
3212 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3213 ls1.lease_epoch += 1;
3214 CHECK_LEASE_V2(&io1, "R", true, LEASE1,
3215 0, 0, ls1.lease_epoch);
3217 /* Upgrade to RWH over connection 1b */
3218 ls1.lease_state = smb2_util_lease_state("RWH");
3219 status = smb2_create(tree1b, mem_ctx, &io1);
3220 CHECK_STATUS(status, NT_STATUS_OK);
3221 h2 = io1.out.file.handle;
3222 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3223 ls1.lease_epoch += 1;
3224 CHECK_LEASE_V2(&io1, "RHW", true, LEASE1,
3225 0, 0, ls1.lease_epoch);
3227 /* close over connection 1b */
3228 status = smb2_util_close(tree1b, h2);
3229 CHECK_STATUS(status, NT_STATUS_OK);
3231 /* Contend with LEASE2. */
3232 smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
3233 smb2_util_lease_state("R"), 0x11);
3234 status = smb2_create(tree1b, mem_ctx, &io2);
3235 CHECK_STATUS(status, NT_STATUS_OK);
3236 h3 = io2.out.file.handle;
3237 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3238 ls2.lease_epoch += 1;
3239 CHECK_LEASE_V2(&io2, "R", true, LEASE2,
3240 0, 0, ls2.lease_epoch);
3242 /* Verify that we were only sent one break. */
3243 ls1.lease_epoch += 1;
3244 CHECK_BREAK_INFO_V2(tree1a->session->transport,
3245 "RHW", "RH", LEASE1, ls1.lease_epoch);
3247 /* again RH over connection 1b doesn't change the epoch */
3248 ls1.lease_state = smb2_util_lease_state("RH");
3249 status = smb2_create(tree1b, mem_ctx, &io1);
3250 CHECK_STATUS(status, NT_STATUS_OK);
3251 h2 = io1.out.file.handle;
3252 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3253 CHECK_LEASE_V2(&io1, "RH", true, LEASE1,
3254 0, 0, ls1.lease_epoch);
3256 /* close over connection 1b */
3257 status = smb2_util_close(tree1b, h2);
3258 CHECK_STATUS(status, NT_STATUS_OK);
3260 ZERO_STRUCT(lease_break_info);
3263 w.in.file.handle = h;
3265 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3266 memset(w.in.data.data, 'o', w.in.data.length);
3267 status = smb2_write(tree1a, &w);
3268 CHECK_STATUS(status, NT_STATUS_OK);
3270 ls2.lease_epoch += 1;
3271 CHECK_BREAK_INFO_V2(tree1a->session->transport,
3272 "R", "", LEASE2, ls2.lease_epoch);
3274 ZERO_STRUCT(lease_break_info);
3277 w.in.file.handle = h3;
3279 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3280 memset(w.in.data.data, 'o', w.in.data.length);
3281 status = smb2_write(tree1b, &w);
3282 CHECK_STATUS(status, NT_STATUS_OK);
3284 ls1.lease_epoch += 1;
3285 CHECK_BREAK_INFO_V2(tree1a->session->transport,
3286 "RH", "", LEASE1, ls1.lease_epoch);
3289 smb2_util_close(tree1a, h);
3290 smb2_util_close(tree1b, h2);
3291 smb2_util_close(tree1b, h3);
3293 smb2_util_unlink(tree1a, fname);
3295 talloc_free(mem_ctx);
3300 static bool test_lease_v2_complex2(struct torture_context *tctx,
3301 struct smb2_tree *tree1a)
3303 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3304 struct smb2_create io1;
3305 struct smb2_create io2;
3306 struct smb2_lease ls1;
3307 struct smb2_lease ls2;
3308 struct smb2_handle h = {{0}};
3309 struct smb2_handle h2 = {{0}};
3310 struct smb2_request *req2 = NULL;
3311 struct smb2_lease_break_ack ack = {};
3313 const char *fname = "lease_v2_complex2.dat";
3316 enum protocol_types protocol;
3317 struct smb2_tree *tree1b = NULL;
3318 struct smbcli_options options1;
3320 options1 = tree1a->session->transport->options;
3322 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3323 if (!(caps & SMB2_CAP_LEASING)) {
3324 torture_skip(tctx, "leases are not supported");
3327 protocol = smbXcli_conn_protocol(tree1a->session->transport->conn);
3328 if (protocol < PROTOCOL_SMB3_00) {
3329 torture_skip(tctx, "v2 leases are not supported");
3332 tree1a->session->transport->lease.handler = torture_lease_handler;
3333 tree1a->session->transport->lease.private_data = tree1a;
3334 tree1a->session->transport->oplock.handler = torture_oplock_handler;
3335 tree1a->session->transport->oplock.private_data = tree1a;
3337 /* create a new connection (same client_guid) */
3338 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
3339 torture_warning(tctx, "couldn't reconnect, bailing\n");
3344 tree1b->session->transport->lease.handler = torture_lease_handler;
3345 tree1b->session->transport->lease.private_data = tree1b;
3346 tree1b->session->transport->oplock.handler = torture_oplock_handler;
3347 tree1b->session->transport->oplock.private_data = tree1b;
3349 smb2_util_unlink(tree1a, fname);
3351 ZERO_STRUCT(lease_break_info);
3353 /* Grab RWH lease over connection 1a */
3354 smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
3355 smb2_util_lease_state("RWH"), 0x4711);
3356 status = smb2_create(tree1a, mem_ctx, &io1);
3357 CHECK_STATUS(status, NT_STATUS_OK);
3358 h = io1.out.file.handle;
3359 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3360 ls1.lease_epoch += 1;
3361 CHECK_LEASE_V2(&io1, "RWH", true, LEASE1,
3362 0, 0, ls1.lease_epoch);
3365 * we defer acking the lease break.
3367 ZERO_STRUCT(lease_break_info);
3368 lease_break_info.lease_skip_ack = true;
3370 /* Ask for RWH on connection 1b, different lease. */
3371 smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
3372 smb2_util_lease_state("RWH"), 0x11);
3373 req2 = smb2_create_send(tree1b, &io2);
3374 torture_assert(tctx, req2 != NULL, "smb2_create_send");
3376 ls1.lease_epoch += 1;
3378 CHECK_BREAK_INFO_V2(tree1a->session->transport,
3379 "RWH", "RH", LEASE1, ls1.lease_epoch);
3381 /* Send the break ACK on tree1b. */
3382 ack.in.lease.lease_key =
3383 lease_break_info.lease_break.current_lease.lease_key;
3384 ack.in.lease.lease_state = SMB2_LEASE_HANDLE|SMB2_LEASE_READ;
3386 status = smb2_lease_break_ack(tree1b, &ack);
3387 CHECK_STATUS(status, NT_STATUS_OK);
3388 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
3390 ZERO_STRUCT(lease_break_info);
3392 status = smb2_create_recv(req2, tctx, &io2);
3393 CHECK_STATUS(status, NT_STATUS_OK);
3394 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3395 CHECK_LEASE_V2(&io2, "RH", true, LEASE2,
3396 0, 0, ls2.lease_epoch+1);
3397 h2 = io2.out.file.handle;
3400 smb2_util_close(tree1a, h);
3401 smb2_util_close(tree1b, h2);
3403 smb2_util_unlink(tree1a, fname);
3405 talloc_free(mem_ctx);
3411 static bool test_lease_timeout(struct torture_context *tctx,
3412 struct smb2_tree *tree)
3414 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3415 struct smb2_create io;
3416 struct smb2_lease ls1;
3417 struct smb2_lease ls2;
3418 struct smb2_handle h = {{0}};
3419 struct smb2_handle hnew = {{0}};
3420 struct smb2_handle h1b = {{0}};
3422 const char *fname = "lease_timeout.dat";
3424 struct smb2_lease_break_ack ack = {};
3425 struct smb2_request *req2 = NULL;
3426 struct smb2_write w;
3429 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
3430 if (!(caps & SMB2_CAP_LEASING)) {
3431 torture_skip(tctx, "leases are not supported");
3434 smb2_util_unlink(tree, fname);
3436 /* Grab a RWH lease. */
3437 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3438 status = smb2_create(tree, mem_ctx, &io);
3439 CHECK_STATUS(status, NT_STATUS_OK);
3440 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3441 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3442 h = io.out.file.handle;
3444 tree->session->transport->lease.handler = torture_lease_handler;
3445 tree->session->transport->lease.private_data = tree;
3446 tree->session->transport->oplock.handler = torture_oplock_handler;
3447 tree->session->transport->oplock.private_data = tree;
3450 * Just don't ack the lease break.
3452 ZERO_STRUCT(lease_break_info);
3453 lease_break_info.lease_skip_ack = true;
3455 /* Break with a RWH request. */
3456 smb2_lease_create(&io, &ls2, false, fname, LEASE2, smb2_util_lease_state("RWH"));
3457 req2 = smb2_create_send(tree, &io);
3458 torture_assert(tctx, req2 != NULL, "smb2_create_send");
3459 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
3461 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
3463 /* Copy the break request. */
3464 ack.in.lease.lease_key =
3465 lease_break_info.lease_break.current_lease.lease_key;
3466 ack.in.lease.lease_state =
3467 lease_break_info.lease_break.new_lease_state;
3469 /* Now wait for the timeout and get the reply. */
3470 status = smb2_create_recv(req2, tctx, &io);
3471 CHECK_STATUS(status, NT_STATUS_OK);
3472 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3473 CHECK_LEASE(&io, "RH", true, LEASE2, 0);
3474 hnew = io.out.file.handle;
3476 /* Ack the break after the timeout... */
3477 status = smb2_lease_break_ack(tree, &ack);
3478 CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
3480 /* Get state of the original handle. */
3481 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
3482 status = smb2_create(tree, mem_ctx, &io);
3483 CHECK_STATUS(status, NT_STATUS_OK);
3484 CHECK_LEASE(&io, "", true, LEASE1, 0);
3485 smb2_util_close(tree, io.out.file.handle);
3487 /* Write on the original handle and make sure it's still valid. */
3488 ZERO_STRUCT(lease_break_info);
3490 w.in.file.handle = h;
3492 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3493 memset(w.in.data.data, '1', w.in.data.length);
3494 status = smb2_write(tree, &w);
3495 CHECK_STATUS(status, NT_STATUS_OK);
3497 /* Causes new handle to break to NONE. */
3498 CHECK_BREAK_INFO("RH", "", LEASE2);
3500 /* Write on the new handle. */
3501 ZERO_STRUCT(lease_break_info);
3503 w.in.file.handle = hnew;
3505 w.in.data = data_blob_talloc(mem_ctx, NULL, 1024);
3506 memset(w.in.data.data, '2', w.in.data.length);
3507 status = smb2_write(tree, &w);
3508 CHECK_STATUS(status, NT_STATUS_OK);
3509 /* No break - original handle was already NONE. */
3510 CHECK_NO_BREAK(tctx);
3511 smb2_util_close(tree, hnew);
3513 /* Upgrade to R on LEASE1. */
3514 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
3515 status = smb2_create(tree, mem_ctx, &io);
3516 CHECK_STATUS(status, NT_STATUS_OK);
3517 CHECK_LEASE(&io, "R", true, LEASE1, 0);
3518 h1b = io.out.file.handle;
3519 smb2_util_close(tree, h1b);
3521 /* Upgrade to RWH on LEASE1. */
3522 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3523 status = smb2_create(tree, mem_ctx, &io);
3524 CHECK_STATUS(status, NT_STATUS_OK);
3525 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3526 h1b = io.out.file.handle;
3527 smb2_util_close(tree, h1b);
3530 smb2_util_close(tree, h);
3531 smb2_util_close(tree, hnew);
3532 smb2_util_close(tree, h1b);
3534 smb2_util_unlink(tree, fname);
3536 talloc_free(mem_ctx);
3541 static bool test_lease_v2_rename(struct torture_context *tctx,
3542 struct smb2_tree *tree)
3544 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3545 struct smb2_create io;
3546 struct smb2_lease ls1;
3547 struct smb2_lease ls2;
3548 struct smb2_handle h = {{0}};
3549 struct smb2_handle h1 = {{0}};
3550 struct smb2_handle h2 = {{0}};
3551 union smb_setfileinfo sinfo;
3552 const char *fname = "lease_v2_rename_src.dat";
3553 const char *fname_dst = "lease_v2_rename_dst.dat";
3557 enum protocol_types protocol;
3559 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
3560 if (!(caps & SMB2_CAP_LEASING)) {
3561 torture_skip(tctx, "leases are not supported");
3564 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
3565 if (protocol < PROTOCOL_SMB3_00) {
3566 torture_skip(tctx, "v2 leases are not supported");
3569 smb2_util_unlink(tree, fname);
3570 smb2_util_unlink(tree, fname_dst);
3572 tree->session->transport->lease.handler = torture_lease_handler;
3573 tree->session->transport->lease.private_data = tree;
3574 tree->session->transport->oplock.handler = torture_oplock_handler;
3575 tree->session->transport->oplock.private_data = tree;
3577 ZERO_STRUCT(lease_break_info);
3580 smb2_lease_v2_create_share(&io, &ls1, false, fname,
3581 smb2_util_share_access("RWD"),
3583 smb2_util_lease_state("RHW"),
3585 status = smb2_create(tree, mem_ctx, &io);
3586 CHECK_STATUS(status, NT_STATUS_OK);
3587 h = io.out.file.handle;
3588 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3589 ls1.lease_epoch += 1;
3590 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
3592 /* Now rename - what happens ? */
3594 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
3595 sinfo.rename_information.in.file.handle = h;
3596 sinfo.rename_information.in.overwrite = true;
3597 sinfo.rename_information.in.new_name = fname_dst;
3598 status = smb2_setinfo_file(tree, &sinfo);
3599 CHECK_STATUS(status, NT_STATUS_OK);
3601 /* No lease break. */
3602 CHECK_NO_BREAK(tctx);
3604 /* Check we can open another handle on the new name. */
3605 smb2_lease_v2_create_share(&io, &ls1, false, fname_dst,
3606 smb2_util_share_access("RWD"),
3608 smb2_util_lease_state(""),
3610 status = smb2_create(tree, mem_ctx, &io);
3611 CHECK_STATUS(status, NT_STATUS_OK);
3612 h1 = io.out.file.handle;
3613 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3614 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
3615 smb2_util_close(tree, h1);
3617 /* Try another lease key. */
3618 smb2_lease_v2_create_share(&io, &ls2, false, fname_dst,
3619 smb2_util_share_access("RWD"),
3621 smb2_util_lease_state("RWH"),
3623 status = smb2_create(tree, mem_ctx, &io);
3624 CHECK_STATUS(status, NT_STATUS_OK);
3625 h2 = io.out.file.handle;
3626 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3627 ls2.lease_epoch += 1;
3628 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch );
3629 CHECK_BREAK_INFO_V2(tree->session->transport,
3630 "RWH", "RH", LEASE1, ls1.lease_epoch + 1);
3631 ls1.lease_epoch += 1;
3632 ZERO_STRUCT(lease_break_info);
3634 /* Now rename back. */
3636 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
3637 sinfo.rename_information.in.file.handle = h;
3638 sinfo.rename_information.in.overwrite = true;
3639 sinfo.rename_information.in.new_name = fname;
3640 status = smb2_setinfo_file(tree, &sinfo);
3641 CHECK_STATUS(status, NT_STATUS_OK);
3643 /* Breaks to R on LEASE2. */
3644 CHECK_BREAK_INFO_V2(tree->session->transport,
3645 "RH", "R", LEASE2, ls2.lease_epoch + 1);
3646 ls2.lease_epoch += 1;
3648 /* Check we can open another handle on the current name. */
3649 smb2_lease_v2_create_share(&io, &ls1, false, fname,
3650 smb2_util_share_access("RWD"),
3652 smb2_util_lease_state(""),
3654 status = smb2_create(tree, mem_ctx, &io);
3655 CHECK_STATUS(status, NT_STATUS_OK);
3656 h1 = io.out.file.handle;
3657 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3658 CHECK_LEASE_V2(&io, "RH", true, LEASE1, 0, 0, ls1.lease_epoch);
3659 smb2_util_close(tree, h1);
3663 smb2_util_close(tree, h);
3664 smb2_util_close(tree, h1);
3665 smb2_util_close(tree, h2);
3667 smb2_util_unlink(tree, fname);
3668 smb2_util_unlink(tree, fname_dst);
3670 smb2_util_unlink(tree, fname);
3671 talloc_free(mem_ctx);
3676 static bool test_lease_dynamic_share(struct torture_context *tctx,
3677 struct smb2_tree *tree1a)
3679 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3680 struct smb2_create io;
3681 struct smb2_lease ls1;
3682 struct smb2_handle h, h1, h2;
3683 struct smb2_write w;
3685 const char *fname = "dynamic_path.dat";
3688 struct smb2_tree *tree_2_1 = NULL;
3689 struct smb2_tree *tree_3_0 = NULL;
3690 struct smbcli_options options2_1;
3691 struct smbcli_options options3_0;
3692 const char *orig_share = NULL;
3694 if (!TARGET_IS_SAMBA3(tctx)) {
3695 torture_skip(tctx, "dynamic shares are not supported");
3699 options2_1 = tree1a->session->transport->options;
3700 options3_0 = tree1a->session->transport->options;
3702 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3703 if (!(caps & SMB2_CAP_LEASING)) {
3704 torture_skip(tctx, "leases are not supported");
3708 * Save off original share name and change it to dynamic_share.
3709 * This must have been pre-created with a dynamic path containing
3713 orig_share = lpcfg_parm_string(tctx->lp_ctx, NULL, "torture", "share");
3714 orig_share = talloc_strdup(tctx->lp_ctx, orig_share);
3715 if (orig_share == NULL) {
3716 torture_result(tctx, TORTURE_FAIL, __location__ "no memory\n");
3720 lpcfg_set_cmdline(tctx->lp_ctx, "torture:share", "dynamic_share");
3722 /* Set max protocol to SMB2.1 */
3723 options2_1.max_protocol = PROTOCOL_SMB2_10;
3724 /* create a new connection (same client_guid) */
3725 if (!torture_smb2_connection_ext(tctx, 0, &options2_1, &tree_2_1)) {
3726 torture_result(tctx, TORTURE_FAIL,
3727 __location__ "couldn't reconnect "
3728 "max protocol 2.1, bailing\n");
3733 tree_2_1->session->transport->lease.handler = torture_lease_handler;
3734 tree_2_1->session->transport->lease.private_data = tree_2_1;
3735 tree_2_1->session->transport->oplock.handler = torture_oplock_handler;
3736 tree_2_1->session->transport->oplock.private_data = tree_2_1;
3738 smb2_util_unlink(tree_2_1, fname);
3740 /* Set max protocol to SMB3.0 */
3741 options3_0.max_protocol = PROTOCOL_SMB3_00;
3742 /* create a new connection (same client_guid) */
3743 if (!torture_smb2_connection_ext(tctx, 0, &options3_0, &tree_3_0)) {
3744 torture_result(tctx, TORTURE_FAIL,
3745 __location__ "couldn't reconnect "
3746 "max protocol 3.0, bailing\n");
3751 tree_3_0->session->transport->lease.handler = torture_lease_handler;
3752 tree_3_0->session->transport->lease.private_data = tree_3_0;
3753 tree_3_0->session->transport->oplock.handler = torture_oplock_handler;
3754 tree_3_0->session->transport->oplock.private_data = tree_3_0;
3756 smb2_util_unlink(tree_3_0, fname);
3758 ZERO_STRUCT(lease_break_info);
3760 /* Get RWH lease over connection 2_1 */
3761 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3762 status = smb2_create(tree_2_1, mem_ctx, &io);
3763 CHECK_STATUS(status, NT_STATUS_OK);
3764 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3765 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3766 h = io.out.file.handle;
3768 /* Write some data into it. */
3769 w.in.file.handle = h;
3771 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3772 memset(w.in.data.data, '1', w.in.data.length);
3773 status = smb2_write(tree_2_1, &w);
3774 CHECK_STATUS(status, NT_STATUS_OK);
3776 /* Open the same name over connection 3_0. */
3777 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3778 status = smb2_create(tree_3_0, mem_ctx, &io);
3779 CHECK_STATUS(status, NT_STATUS_OK);
3780 h1 = io.out.file.handle;
3781 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3783 /* h1 should have replied with NONE. */
3784 CHECK_LEASE(&io, "", true, LEASE1, 0);
3786 /* We should have broken h to NONE. */
3787 CHECK_BREAK_INFO("RWH", "", LEASE1);
3789 /* Try to upgrade to RWH over connection 2_1 */
3790 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3791 status = smb2_create(tree_2_1, mem_ctx, &io);
3792 CHECK_STATUS(status, NT_STATUS_OK);
3793 h2 = io.out.file.handle;
3794 CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
3795 CHECK_VAL(io.out.size, 4096);
3796 CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
3797 /* Should have been denied. */
3798 CHECK_LEASE(&io, "", true, LEASE1, 0);
3799 smb2_util_close(tree_2_1, h2);
3801 /* Try to upgrade to RWH over connection 3_0 */
3802 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3803 status = smb2_create(tree_3_0, mem_ctx, &io);
3804 CHECK_STATUS(status, NT_STATUS_OK);
3805 h2 = io.out.file.handle;
3806 CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
3807 CHECK_VAL(io.out.size, 0);
3808 CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
3809 /* Should have been denied. */
3810 CHECK_LEASE(&io, "", true, LEASE1, 0);
3811 smb2_util_close(tree_3_0, h2);
3813 /* Write some data into it. */
3814 w.in.file.handle = h1;
3816 w.in.data = data_blob_talloc(mem_ctx, NULL, 1024);
3817 memset(w.in.data.data, '2', w.in.data.length);
3818 status = smb2_write(tree_3_0, &w);
3819 CHECK_STATUS(status, NT_STATUS_OK);
3821 /* Close everything.. */
3822 smb2_util_close(tree_2_1, h);
3823 smb2_util_close(tree_3_0, h1);
3825 /* And ensure we can get a lease ! */
3826 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3827 status = smb2_create(tree_2_1, mem_ctx, &io);
3828 CHECK_STATUS(status, NT_STATUS_OK);
3829 CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
3830 CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
3831 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3832 h = io.out.file.handle;
3833 /* And the file is the right size. */
3834 CHECK_VAL(io.out.size, 4096); \
3836 smb2_util_close(tree_2_1, h);
3838 /* And ensure we can get a lease ! */
3839 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3840 status = smb2_create(tree_3_0, mem_ctx, &io);
3841 CHECK_STATUS(status, NT_STATUS_OK);
3842 CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
3843 CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
3844 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3845 h = io.out.file.handle;
3846 /* And the file is the right size. */
3847 CHECK_VAL(io.out.size, 1024); \
3849 smb2_util_close(tree_3_0, h);
3853 if (tree_2_1 != NULL) {
3854 smb2_util_close(tree_2_1, h);
3855 smb2_util_unlink(tree_2_1, fname);
3857 if (tree_3_0 != NULL) {
3858 smb2_util_close(tree_3_0, h1);
3859 smb2_util_close(tree_3_0, h2);
3861 smb2_util_unlink(tree_3_0, fname);
3864 /* Set sharename back. */
3865 lpcfg_set_cmdline(tctx->lp_ctx, "torture:share", orig_share);
3867 talloc_free(mem_ctx);
3873 * Test identifies a bug where the Samba server will not trigger a lease break
3874 * for a handle caching lease held by a client when the underlying file is
3878 * open file in session1
3879 * session1 should have RWH lease.
3880 * open file in session2
3881 * lease break sent to session1 to downgrade lease to RH
3882 * close file in session 2
3883 * unlink file in session 2
3884 * lease break sent to session1 to downgrade lease to R
3887 static bool test_lease_unlink(struct torture_context *tctx,
3888 struct smb2_tree *tree1)
3890 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3893 struct smbcli_options transport2_options;
3894 struct smb2_tree *tree2 = NULL;
3895 struct smb2_transport *transport1 = tree1->session->transport;
3896 struct smb2_transport *transport2;
3897 struct smb2_handle h1 = {{ 0 }};
3898 struct smb2_handle h2 = {{ 0 }};
3899 const char *fname = "lease_unlink.dat";
3901 struct smb2_create io1;
3902 struct smb2_create io2;
3903 struct smb2_lease ls1;
3904 struct smb2_lease ls2;
3906 caps = smb2cli_conn_server_capabilities(
3907 tree1->session->transport->conn);
3908 if (!(caps & SMB2_CAP_LEASING)) {
3909 torture_skip(tctx, "leases are not supported");
3912 /* Connect 2nd connection */
3913 transport2_options = transport1->options;
3914 transport2_options.client_guid = GUID_random();
3915 if (!torture_smb2_connection_ext(tctx, 0, &transport2_options, &tree2)) {
3916 torture_warning(tctx, "couldn't reconnect, bailing\n");
3919 transport2 = tree2->session->transport;
3921 /* Set lease handlers */
3922 transport1->lease.handler = torture_lease_handler;
3923 transport1->lease.private_data = tree1;
3924 transport2->lease.handler = torture_lease_handler;
3925 transport2->lease.private_data = tree2;
3928 smb2_lease_create(&io1, &ls1, false, fname, LEASE1,
3929 smb2_util_lease_state("RHW"));
3930 smb2_lease_create(&io2, &ls2, false, fname, LEASE2,
3931 smb2_util_lease_state("RHW"));
3933 smb2_util_unlink(tree1, fname);
3935 torture_comment(tctx, "Client opens fname with session 1\n");
3936 torture_reset_lease_break_info(tctx, &lease_break_info);
3937 status = smb2_create(tree1, mem_ctx, &io1);
3938 CHECK_STATUS(status, NT_STATUS_OK);
3939 h1 = io1.out.file.handle;
3940 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3941 CHECK_LEASE(&io1, "RHW", true, LEASE1, 0);
3942 CHECK_VAL(lease_break_info.count, 0);
3944 torture_comment(tctx, "Client opens fname with session 2\n");
3945 torture_reset_lease_break_info(tctx, &lease_break_info);
3946 status = smb2_create(tree2, mem_ctx, &io2);
3947 CHECK_STATUS(status, NT_STATUS_OK);
3948 h2 = io2.out.file.handle;
3949 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3950 CHECK_LEASE(&io2, "RH", true, LEASE2, 0);
3951 CHECK_VAL(lease_break_info.count, 1);
3952 CHECK_BREAK_INFO("RHW", "RH", LEASE1);
3954 torture_comment(tctx,
3955 "Client closes and then unlinks fname with session 2\n");
3956 torture_reset_lease_break_info(tctx, &lease_break_info);
3957 smb2_util_close(tree2, h2);
3958 smb2_util_unlink(tree2, fname);
3959 CHECK_VAL(lease_break_info.count, 1);
3960 CHECK_BREAK_INFO("RH", "R", LEASE1);
3963 smb2_util_close(tree1, h1);
3964 smb2_util_close(tree2, h2);
3965 smb2_util_unlink(tree1, fname);
3970 struct torture_suite *torture_smb2_lease_init(TALLOC_CTX *ctx)
3972 struct torture_suite *suite =
3973 torture_suite_create(ctx, "lease");
3975 torture_suite_add_1smb2_test(suite, "request", test_lease_request);
3976 torture_suite_add_1smb2_test(suite, "break_twice",
3977 test_lease_break_twice);
3978 torture_suite_add_1smb2_test(suite, "nobreakself",
3979 test_lease_nobreakself);
3980 torture_suite_add_1smb2_test(suite, "statopen", test_lease_statopen);
3981 torture_suite_add_1smb2_test(suite, "statopen2", test_lease_statopen2);
3982 torture_suite_add_1smb2_test(suite, "statopen3", test_lease_statopen3);
3983 torture_suite_add_1smb2_test(suite, "upgrade", test_lease_upgrade);
3984 torture_suite_add_1smb2_test(suite, "upgrade2", test_lease_upgrade2);
3985 torture_suite_add_1smb2_test(suite, "upgrade3", test_lease_upgrade3);
3986 torture_suite_add_1smb2_test(suite, "break", test_lease_break);
3987 torture_suite_add_1smb2_test(suite, "oplock", test_lease_oplock);
3988 torture_suite_add_1smb2_test(suite, "multibreak", test_lease_multibreak);
3989 torture_suite_add_1smb2_test(suite, "breaking1", test_lease_breaking1);
3990 torture_suite_add_1smb2_test(suite, "breaking2", test_lease_breaking2);
3991 torture_suite_add_1smb2_test(suite, "breaking3", test_lease_breaking3);
3992 torture_suite_add_1smb2_test(suite, "v2_breaking3", test_lease_v2_breaking3);
3993 torture_suite_add_1smb2_test(suite, "breaking4", test_lease_breaking4);
3994 torture_suite_add_1smb2_test(suite, "breaking5", test_lease_breaking5);
3995 torture_suite_add_1smb2_test(suite, "breaking6", test_lease_breaking6);
3996 torture_suite_add_2smb2_test(suite, "lock1", test_lease_lock1);
3997 torture_suite_add_1smb2_test(suite, "complex1", test_lease_complex1);
3998 torture_suite_add_1smb2_test(suite, "v2_request_parent",
3999 test_lease_v2_request_parent);
4000 torture_suite_add_1smb2_test(suite, "v2_request", test_lease_v2_request);
4001 torture_suite_add_1smb2_test(suite, "v2_epoch1", test_lease_v2_epoch1);
4002 torture_suite_add_1smb2_test(suite, "v2_epoch2", test_lease_v2_epoch2);
4003 torture_suite_add_1smb2_test(suite, "v2_epoch3", test_lease_v2_epoch3);
4004 torture_suite_add_1smb2_test(suite, "v2_complex1", test_lease_v2_complex1);
4005 torture_suite_add_1smb2_test(suite, "v2_complex2", test_lease_v2_complex2);
4006 torture_suite_add_1smb2_test(suite, "v2_rename", test_lease_v2_rename);
4007 torture_suite_add_1smb2_test(suite, "dynamic_share", test_lease_dynamic_share);
4008 torture_suite_add_1smb2_test(suite, "timeout", test_lease_timeout);
4009 torture_suite_add_1smb2_test(suite, "unlink", test_lease_unlink);
4011 suite->description = talloc_strdup(suite, "SMB2-LEASE tests");