s3: leases - torture test for timeout of responding to lease break request.
[Samba.git] / source4 / torture / smb2 / lease.c
blobe1bc9b3b653146f9d46e0d1892cf0c1a0315eb6c
1 /*
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/>.
22 #include "includes.h"
23 #include <tevent.h>
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"
31 #define CHECK_VAL(v, correct) do { \
32 if ((v) != (correct)) { \
33 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
34 __location__, #v, (int)(v), (int)(correct)); \
35 ret = false; \
36 }} while (0)
38 #define CHECK_STATUS(status, correct) do { \
39 if (!NT_STATUS_EQUAL(status, correct)) { \
40 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
41 nt_errstr(status), nt_errstr(correct)); \
42 ret = false; \
43 goto done; \
44 }} while (0)
46 #define CHECK_CREATED(__io, __created, __attribute) \
47 do { \
48 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
49 CHECK_VAL((__io)->out.alloc_size, 0); \
50 CHECK_VAL((__io)->out.size, 0); \
51 CHECK_VAL((__io)->out.file_attr, (__attribute)); \
52 CHECK_VAL((__io)->out.reserved2, 0); \
53 } while(0)
55 #define CHECK_LEASE(__io, __state, __oplevel, __key, __flags) \
56 do { \
57 CHECK_VAL((__io)->out.lease_response.lease_version, 1); \
58 if (__oplevel) { \
59 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
60 CHECK_VAL((__io)->out.lease_response.lease_key.data[0], (__key)); \
61 CHECK_VAL((__io)->out.lease_response.lease_key.data[1], ~(__key)); \
62 CHECK_VAL((__io)->out.lease_response.lease_state, smb2_util_lease_state(__state)); \
63 } else { \
64 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
65 CHECK_VAL((__io)->out.lease_response.lease_key.data[0], 0); \
66 CHECK_VAL((__io)->out.lease_response.lease_key.data[1], 0); \
67 CHECK_VAL((__io)->out.lease_response.lease_state, 0); \
68 } \
70 CHECK_VAL((__io)->out.lease_response.lease_flags, (__flags)); \
71 CHECK_VAL((__io)->out.lease_response.lease_duration, 0); \
72 CHECK_VAL((__io)->out.lease_response.lease_epoch, 0); \
73 } while(0)
75 #define CHECK_LEASE_V2(__io, __state, __oplevel, __key, __flags, __parent, __epoch) \
76 do { \
77 CHECK_VAL((__io)->out.lease_response_v2.lease_version, 2); \
78 if (__oplevel) { \
79 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
80 CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], (__key)); \
81 CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], ~(__key)); \
82 CHECK_VAL((__io)->out.lease_response_v2.lease_state, smb2_util_lease_state(__state)); \
83 } else { \
84 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
85 CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], 0); \
86 CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], 0); \
87 CHECK_VAL((__io)->out.lease_response_v2.lease_state, 0); \
88 } \
90 CHECK_VAL((__io)->out.lease_response_v2.lease_flags, __flags); \
91 if (__flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET) { \
92 CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[0], (__parent)); \
93 CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[1], ~(__parent)); \
94 } \
95 CHECK_VAL((__io)->out.lease_response_v2.lease_duration, 0); \
96 CHECK_VAL((__io)->out.lease_response_v2.lease_epoch, (__epoch)); \
97 } while(0)
99 static const uint64_t LEASE1 = 0xBADC0FFEE0DDF00Dull;
100 static const uint64_t LEASE2 = 0xDEADBEEFFEEDBEADull;
101 static const uint64_t LEASE3 = 0xDAD0FFEDD00DF00Dull;
102 static const uint64_t LEASE4 = 0xBAD0FFEDD00DF00Dull;
104 #define NREQUEST_RESULTS 8
105 static const char *request_results[NREQUEST_RESULTS][2] = {
106 { "", "" },
107 { "R", "R" },
108 { "H", "" },
109 { "W", "" },
110 { "RH", "RH" },
111 { "RW", "RW" },
112 { "HW", "" },
113 { "RHW", "RHW" },
116 static bool test_lease_request(struct torture_context *tctx,
117 struct smb2_tree *tree)
119 TALLOC_CTX *mem_ctx = talloc_new(tctx);
120 struct smb2_create io;
121 struct smb2_lease ls;
122 struct smb2_handle h1, h2;
123 NTSTATUS status;
124 const char *fname = "lease_request.dat";
125 const char *fname2 = "lease_request.2.dat";
126 const char *sname = "lease_request.dat:stream";
127 const char *dname = "lease_request.dir";
128 bool ret = true;
129 int i;
130 uint32_t caps;
132 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
133 if (!(caps & SMB2_CAP_LEASING)) {
134 torture_skip(tctx, "leases are not supported");
137 smb2_util_unlink(tree, fname);
138 smb2_util_unlink(tree, fname2);
139 smb2_util_rmdir(tree, dname);
141 /* Win7 is happy to grant RHW leases on files. */
142 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
143 status = smb2_create(tree, mem_ctx, &io);
144 CHECK_STATUS(status, NT_STATUS_OK);
145 h1 = io.out.file.handle;
146 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
147 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
149 /* But will reject leases on directories. */
150 if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
151 smb2_lease_create(&io, &ls, true, dname, LEASE2, smb2_util_lease_state("RHW"));
152 status = smb2_create(tree, mem_ctx, &io);
153 CHECK_STATUS(status, NT_STATUS_OK);
154 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
155 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
156 smb2_util_close(tree, io.out.file.handle);
159 /* Also rejects multiple files leased under the same key. */
160 smb2_lease_create(&io, &ls, true, fname2, LEASE1, smb2_util_lease_state("RHW"));
161 status = smb2_create(tree, mem_ctx, &io);
162 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
164 /* And grants leases on streams (with separate leasekey). */
165 smb2_lease_create(&io, &ls, false, sname, LEASE2, smb2_util_lease_state("RHW"));
166 status = smb2_create(tree, mem_ctx, &io);
167 h2 = io.out.file.handle;
168 CHECK_STATUS(status, NT_STATUS_OK);
169 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
170 CHECK_LEASE(&io, "RHW", true, LEASE2, 0);
171 smb2_util_close(tree, h2);
173 smb2_util_close(tree, h1);
175 /* Now see what combos are actually granted. */
176 for (i = 0; i < NREQUEST_RESULTS; i++) {
177 torture_comment(tctx, "Requesting lease type %s(%x),"
178 " expecting %s(%x)\n",
179 request_results[i][0], smb2_util_lease_state(request_results[i][0]),
180 request_results[i][1], smb2_util_lease_state(request_results[i][1]));
181 smb2_lease_create(&io, &ls, false, fname, LEASE1,
182 smb2_util_lease_state(request_results[i][0]));
183 status = smb2_create(tree, mem_ctx, &io);
184 h2 = io.out.file.handle;
185 CHECK_STATUS(status, NT_STATUS_OK);
186 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
187 CHECK_LEASE(&io, request_results[i][1], true, LEASE1, 0);
188 smb2_util_close(tree, io.out.file.handle);
191 done:
192 smb2_util_close(tree, h1);
193 smb2_util_close(tree, h2);
195 smb2_util_unlink(tree, fname);
196 smb2_util_unlink(tree, fname2);
197 smb2_util_rmdir(tree, dname);
199 talloc_free(mem_ctx);
201 return ret;
204 static bool test_lease_upgrade(struct torture_context *tctx,
205 struct smb2_tree *tree)
207 TALLOC_CTX *mem_ctx = talloc_new(tctx);
208 struct smb2_create io;
209 struct smb2_lease ls;
210 struct smb2_handle h, hnew;
211 NTSTATUS status;
212 const char *fname = "lease_upgrade.dat";
213 bool ret = true;
214 uint32_t caps;
216 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
217 if (!(caps & SMB2_CAP_LEASING)) {
218 torture_skip(tctx, "leases are not supported");
221 smb2_util_unlink(tree, fname);
223 /* Grab a RH lease. */
224 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
225 status = smb2_create(tree, mem_ctx, &io);
226 CHECK_STATUS(status, NT_STATUS_OK);
227 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
228 CHECK_LEASE(&io, "RH", true, LEASE1, 0);
229 h = io.out.file.handle;
231 /* Upgrades (sidegrades?) to RW leave us with an RH. */
232 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RW"));
233 status = smb2_create(tree, mem_ctx, &io);
234 CHECK_STATUS(status, NT_STATUS_OK);
235 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
236 CHECK_LEASE(&io, "RH", true, LEASE1, 0);
237 hnew = io.out.file.handle;
239 smb2_util_close(tree, hnew);
241 /* Upgrade to RHW lease. */
242 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
243 status = smb2_create(tree, mem_ctx, &io);
244 CHECK_STATUS(status, NT_STATUS_OK);
245 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
246 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
247 hnew = io.out.file.handle;
249 smb2_util_close(tree, h);
250 h = hnew;
252 /* Attempt to downgrade - original lease state is maintained. */
253 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
254 status = smb2_create(tree, mem_ctx, &io);
255 CHECK_STATUS(status, NT_STATUS_OK);
256 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
257 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
258 hnew = io.out.file.handle;
260 smb2_util_close(tree, hnew);
262 done:
263 smb2_util_close(tree, h);
264 smb2_util_close(tree, hnew);
266 smb2_util_unlink(tree, fname);
268 talloc_free(mem_ctx);
270 return ret;
274 * upgrade2 test.
275 * full matrix of lease upgrade combinations
276 * (non-contended case)
278 * The summary of the behaviour is this:
279 * -------------------------------------
280 * An uncontended lease upgrade results in a change
281 * if and only if the requested lease state is
282 * - valid, and
283 * - strictly a superset of the lease state already held.
285 * In that case the resulting lease state is the one
286 * requested in the upgrade.
288 struct lease_upgrade2_test {
289 const char *initial;
290 const char *upgrade_to;
291 const char *expected;
294 #define NUM_LEASE_TYPES 5
295 #define NUM_UPGRADE_TESTS ( NUM_LEASE_TYPES * NUM_LEASE_TYPES )
296 struct lease_upgrade2_test lease_upgrade2_tests[NUM_UPGRADE_TESTS] = {
297 { "", "", "" },
298 { "", "R", "R" },
299 { "", "RH", "RH" },
300 { "", "RW", "RW" },
301 { "", "RWH", "RWH" },
303 { "R", "", "R" },
304 { "R", "R", "R" },
305 { "R", "RH", "RH" },
306 { "R", "RW", "RW" },
307 { "R", "RWH", "RWH" },
309 { "RH", "", "RH" },
310 { "RH", "R", "RH" },
311 { "RH", "RH", "RH" },
312 { "RH", "RW", "RH" },
313 { "RH", "RWH", "RWH" },
315 { "RW", "", "RW" },
316 { "RW", "R", "RW" },
317 { "RW", "RH", "RW" },
318 { "RW", "RW", "RW" },
319 { "RW", "RWH", "RWH" },
321 { "RWH", "", "RWH" },
322 { "RWH", "R", "RWH" },
323 { "RWH", "RH", "RWH" },
324 { "RWH", "RW", "RWH" },
325 { "RWH", "RWH", "RWH" },
328 static bool test_lease_upgrade2(struct torture_context *tctx,
329 struct smb2_tree *tree)
331 TALLOC_CTX *mem_ctx = talloc_new(tctx);
332 struct smb2_handle h, hnew;
333 NTSTATUS status;
334 struct smb2_create io;
335 struct smb2_lease ls;
336 const char *fname = "lease_upgrade2.dat";
337 bool ret = true;
338 int i;
339 uint32_t caps;
341 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
342 if (!(caps & SMB2_CAP_LEASING)) {
343 torture_skip(tctx, "leases are not supported");
346 for (i = 0; i < NUM_UPGRADE_TESTS; i++) {
347 struct lease_upgrade2_test t = lease_upgrade2_tests[i];
349 smb2_util_unlink(tree, fname);
351 /* Grab a lease. */
352 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.initial));
353 status = smb2_create(tree, mem_ctx, &io);
354 CHECK_STATUS(status, NT_STATUS_OK);
355 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
356 CHECK_LEASE(&io, t.initial, true, LEASE1, 0);
357 h = io.out.file.handle;
359 /* Upgrade. */
360 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to));
361 status = smb2_create(tree, mem_ctx, &io);
362 CHECK_STATUS(status, NT_STATUS_OK);
363 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
364 CHECK_LEASE(&io, t.expected, true, LEASE1, 0);
365 hnew = io.out.file.handle;
367 smb2_util_close(tree, hnew);
368 smb2_util_close(tree, h);
371 done:
372 smb2_util_close(tree, h);
373 smb2_util_close(tree, hnew);
375 smb2_util_unlink(tree, fname);
377 talloc_free(mem_ctx);
379 return ret;
383 #define CHECK_LEASE_BREAK(__lb, __oldstate, __state, __key) \
384 do { \
385 uint16_t __new = smb2_util_lease_state(__state); \
386 uint16_t __old = smb2_util_lease_state(__oldstate); \
387 CHECK_VAL((__lb)->new_lease_state, __new); \
388 CHECK_VAL((__lb)->current_lease.lease_state, __old); \
389 CHECK_VAL((__lb)->current_lease.lease_key.data[0], (__key)); \
390 CHECK_VAL((__lb)->current_lease.lease_key.data[1], ~(__key)); \
391 if (__old & (SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE)) { \
392 CHECK_VAL((__lb)->break_flags, \
393 SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED); \
394 } else { \
395 CHECK_VAL((__lb)->break_flags, 0); \
397 } while(0)
399 #define CHECK_LEASE_BREAK_ACK(__lba, __state, __key) \
400 do { \
401 CHECK_VAL((__lba)->out.reserved, 0); \
402 CHECK_VAL((__lba)->out.lease.lease_key.data[0], (__key)); \
403 CHECK_VAL((__lba)->out.lease.lease_key.data[1], ~(__key)); \
404 CHECK_VAL((__lba)->out.lease.lease_state, smb2_util_lease_state(__state)); \
405 CHECK_VAL((__lba)->out.lease.lease_flags, 0); \
406 CHECK_VAL((__lba)->out.lease.lease_duration, 0); \
407 } while(0)
409 static struct torture_lease_break {
410 struct smb2_lease_break lease_break;
411 struct smb2_transport *lease_transport;
412 bool lease_skip_ack;
413 struct smb2_lease_break_ack lease_break_ack;
414 int count;
415 int failures;
417 struct smb2_handle oplock_handle;
418 uint8_t held_oplock_level;
419 uint8_t oplock_level;
420 int oplock_count;
421 int oplock_failures;
422 } break_info;
424 #define CHECK_NO_BREAK(tctx) \
425 do { \
426 torture_wait_for_lease_break(tctx); \
427 CHECK_VAL(break_info.failures, 0); \
428 CHECK_VAL(break_info.count, 0); \
429 CHECK_VAL(break_info.oplock_failures, 0); \
430 CHECK_VAL(break_info.oplock_count, 0); \
431 } while(0)
433 #define CHECK_OPLOCK_BREAK(__brokento) \
434 do { \
435 torture_wait_for_lease_break(tctx); \
436 CHECK_VAL(break_info.oplock_count, 1); \
437 CHECK_VAL(break_info.oplock_failures, 0); \
438 CHECK_VAL(break_info.oplock_level, \
439 smb2_util_oplock_level(__brokento)); \
440 break_info.held_oplock_level = break_info.oplock_level; \
441 } while(0)
443 #define _CHECK_BREAK_INFO(__oldstate, __state, __key) \
444 do { \
445 torture_wait_for_lease_break(tctx); \
446 CHECK_VAL(break_info.failures, 0); \
447 CHECK_VAL(break_info.count, 1); \
448 CHECK_LEASE_BREAK(&break_info.lease_break, (__oldstate), \
449 (__state), (__key)); \
450 if (!break_info.lease_skip_ack && \
451 (break_info.lease_break.break_flags & \
452 SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED)) \
454 torture_wait_for_lease_break(tctx); \
455 CHECK_LEASE_BREAK_ACK(&break_info.lease_break_ack, \
456 (__state), (__key)); \
458 } while(0)
460 #define CHECK_BREAK_INFO(__oldstate, __state, __key) \
461 do { \
462 _CHECK_BREAK_INFO(__oldstate, __state, __key); \
463 CHECK_VAL(break_info.lease_break.new_epoch, 0); \
464 } while(0)
466 #define CHECK_BREAK_INFO_V2(__transport, __oldstate, __state, __key, __epoch) \
467 do { \
468 _CHECK_BREAK_INFO(__oldstate, __state, __key); \
469 CHECK_VAL(break_info.lease_break.new_epoch, __epoch); \
470 if (!TARGET_IS_SAMBA3(tctx)) { \
471 CHECK_VAL((uintptr_t)break_info.lease_transport, \
472 (uintptr_t)__transport); \
474 } while(0)
476 static void torture_lease_break_callback(struct smb2_request *req)
478 NTSTATUS status;
480 status = smb2_lease_break_ack_recv(req, &break_info.lease_break_ack);
481 if (!NT_STATUS_IS_OK(status))
482 break_info.failures++;
484 return;
487 /* a lease break request handler */
488 static bool torture_lease_handler(struct smb2_transport *transport,
489 const struct smb2_lease_break *lb,
490 void *private_data)
492 struct smb2_tree *tree = private_data;
493 struct smb2_lease_break_ack io;
494 struct smb2_request *req;
496 break_info.lease_transport = transport;
497 break_info.lease_break = *lb;
498 break_info.count++;
500 if (break_info.lease_skip_ack) {
501 return true;
504 if (lb->break_flags & SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED) {
505 ZERO_STRUCT(io);
506 io.in.lease.lease_key = lb->current_lease.lease_key;
507 io.in.lease.lease_state = lb->new_lease_state;
509 req = smb2_lease_break_ack_send(tree, &io);
510 req->async.fn = torture_lease_break_callback;
511 req->async.private_data = NULL;
514 return true;
518 * upgrade3:
519 * full matrix of lease upgrade combinations
520 * (contended case)
522 * We start with 2 leases, and check how one can
523 * be upgraded
525 * The summary of the behaviour is this:
526 * -------------------------------------
528 * If we have two leases (lease1 and lease2) on the same file,
529 * then attempt to upgrade lease1 results in a change if and only
530 * if the requested lease state:
531 * - is valid,
532 * - is strictly a superset of lease1, and
533 * - can held together with lease2.
535 * In that case, the resuling lease state of the upgraded lease1
536 * is the state requested in the upgrade. lease2 is not broken
537 * and remains unchanged.
539 * Note that this contrasts the case of directly opening with
540 * an initial requested lease state, in which case you get that
541 * portion of the requested state that can be shared with the
542 * already existing leases (or the states that they get broken to).
544 struct lease_upgrade3_test {
545 const char *held1;
546 const char *held2;
547 const char *upgrade_to;
548 const char *upgraded_to;
551 #define NUM_UPGRADE3_TESTS ( 20 )
552 struct lease_upgrade3_test lease_upgrade3_tests[NUM_UPGRADE3_TESTS] = {
553 {"R", "R", "", "R" },
554 {"R", "R", "R", "R" },
555 {"R", "R", "RW", "R" },
556 {"R", "R", "RH", "RH" },
557 {"R", "R", "RHW", "R" },
559 {"R", "RH", "", "R" },
560 {"R", "RH", "R", "R" },
561 {"R", "RH", "RW", "R" },
562 {"R", "RH", "RH", "RH" },
563 {"R", "RH", "RHW", "R" },
565 {"RH", "R", "", "RH" },
566 {"RH", "R", "R", "RH" },
567 {"RH", "R", "RW", "RH" },
568 {"RH", "R", "RH", "RH" },
569 {"RH", "R", "RHW", "RH" },
571 {"RH", "RH", "", "RH" },
572 {"RH", "RH", "R", "RH" },
573 {"RH", "RH", "RW", "RH" },
574 {"RH", "RH", "RH", "RH" },
575 {"RH", "RH", "RHW", "RH" },
578 static bool test_lease_upgrade3(struct torture_context *tctx,
579 struct smb2_tree *tree)
581 TALLOC_CTX *mem_ctx = talloc_new(tctx);
582 struct smb2_handle h, h2, hnew;
583 NTSTATUS status;
584 struct smb2_create io;
585 struct smb2_lease ls;
586 const char *fname = "lease_upgrade3.dat";
587 bool ret = true;
588 int i;
589 uint32_t caps;
591 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
592 if (!(caps & SMB2_CAP_LEASING)) {
593 torture_skip(tctx, "leases are not supported");
596 tree->session->transport->lease.handler = torture_lease_handler;
597 tree->session->transport->lease.private_data = tree;
599 smb2_util_unlink(tree, fname);
601 for (i = 0; i < NUM_UPGRADE3_TESTS; i++) {
602 struct lease_upgrade3_test t = lease_upgrade3_tests[i];
604 smb2_util_unlink(tree, fname);
606 ZERO_STRUCT(break_info);
608 /* grab first lease */
609 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.held1));
610 status = smb2_create(tree, mem_ctx, &io);
611 CHECK_STATUS(status, NT_STATUS_OK);
612 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
613 CHECK_LEASE(&io, t.held1, true, LEASE1, 0);
614 h = io.out.file.handle;
616 /* grab second lease */
617 smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state(t.held2));
618 status = smb2_create(tree, mem_ctx, &io);
619 CHECK_STATUS(status, NT_STATUS_OK);
620 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
621 CHECK_LEASE(&io, t.held2, true, LEASE2, 0);
622 h2 = io.out.file.handle;
624 /* no break has happened */
625 CHECK_VAL(break_info.count, 0);
626 CHECK_VAL(break_info.failures, 0);
628 /* try to upgrade lease1 */
629 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to));
630 status = smb2_create(tree, mem_ctx, &io);
631 CHECK_STATUS(status, NT_STATUS_OK);
632 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
633 CHECK_LEASE(&io, t.upgraded_to, true, LEASE1, 0);
634 hnew = io.out.file.handle;
636 /* no break has happened */
637 CHECK_VAL(break_info.count, 0);
638 CHECK_VAL(break_info.failures, 0);
640 smb2_util_close(tree, hnew);
641 smb2_util_close(tree, h);
642 smb2_util_close(tree, h2);
645 done:
646 smb2_util_close(tree, h);
647 smb2_util_close(tree, hnew);
648 smb2_util_close(tree, h2);
650 smb2_util_unlink(tree, fname);
652 talloc_free(mem_ctx);
654 return ret;
660 Timer handler function notifies the registering function that time is up
662 static void timeout_cb(struct tevent_context *ev,
663 struct tevent_timer *te,
664 struct timeval current_time,
665 void *private_data)
667 bool *timesup = (bool *)private_data;
668 *timesup = true;
669 return;
673 Wait a short period of time to receive a single oplock break request
675 static void torture_wait_for_lease_break(struct torture_context *tctx)
677 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
678 struct tevent_timer *te = NULL;
679 struct timeval ne;
680 bool timesup = false;
681 int old_count = break_info.count;
683 /* Wait .1 seconds for an lease break */
684 ne = tevent_timeval_current_ofs(0, 100000);
686 te = tevent_add_timer(tctx->ev, tmp_ctx, ne, timeout_cb, &timesup);
687 if (te == NULL) {
688 torture_comment(tctx, "Failed to wait for an oplock break. "
689 "test results may not be accurate.");
690 goto done;
693 while (!timesup && break_info.count < old_count + 1) {
694 if (tevent_loop_once(tctx->ev) != 0) {
695 torture_comment(tctx, "Failed to wait for an oplock "
696 "break. test results may not be "
697 "accurate.");
698 goto done;
702 done:
703 /* We don't know if the timed event fired and was freed, we received
704 * our oplock break, or some other event triggered the loop. Thus,
705 * we create a tmp_ctx to be able to safely free/remove the timed
706 * event in all 3 cases. */
707 talloc_free(tmp_ctx);
709 return;
713 break_results should be read as "held lease, new lease, hold broken to, new
714 grant", i.e. { "RH", "RW", "RH", "R" } means that if key1 holds RH and key2
715 tries for RW, key1 will be broken to RH (in this case, not broken at all)
716 and key2 will be granted R.
718 Note: break_results only includes things that Win7 will actually grant (see
719 request_results above).
721 #define NBREAK_RESULTS 16
722 static const char *break_results[NBREAK_RESULTS][4] = {
723 {"R", "R", "R", "R"},
724 {"R", "RH", "R", "RH"},
725 {"R", "RW", "R", "R"},
726 {"R", "RHW", "R", "RH"},
728 {"RH", "R", "RH", "R"},
729 {"RH", "RH", "RH", "RH"},
730 {"RH", "RW", "RH", "R"},
731 {"RH", "RHW", "RH", "RH"},
733 {"RW", "R", "R", "R"},
734 {"RW", "RH", "R", "RH"},
735 {"RW", "RW", "R", "R"},
736 {"RW", "RHW", "R", "RH"},
738 {"RHW", "R", "RH", "R"},
739 {"RHW", "RH", "RH", "RH"},
740 {"RHW", "RW", "RH", "R"},
741 {"RHW", "RHW", "RH", "RH"},
744 static bool test_lease_break(struct torture_context *tctx,
745 struct smb2_tree *tree)
747 TALLOC_CTX *mem_ctx = talloc_new(tctx);
748 struct smb2_create io;
749 struct smb2_lease ls;
750 struct smb2_handle h, h2, h3;
751 NTSTATUS status;
752 const char *fname = "lease_break.dat";
753 bool ret = true;
754 int i;
755 uint32_t caps;
757 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
758 if (!(caps & SMB2_CAP_LEASING)) {
759 torture_skip(tctx, "leases are not supported");
762 tree->session->transport->lease.handler = torture_lease_handler;
763 tree->session->transport->lease.private_data = tree;
765 smb2_util_unlink(tree, fname);
767 for (i = 0; i < NBREAK_RESULTS; i++) {
768 const char *held = break_results[i][0];
769 const char *contend = break_results[i][1];
770 const char *brokento = break_results[i][2];
771 const char *granted = break_results[i][3];
772 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
773 "expecting break to %s(%x) and grant of %s(%x)\n",
774 held, smb2_util_lease_state(held), contend, smb2_util_lease_state(contend),
775 brokento, smb2_util_lease_state(brokento), granted, smb2_util_lease_state(granted));
777 ZERO_STRUCT(break_info);
779 /* Grab lease. */
780 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held));
781 status = smb2_create(tree, mem_ctx, &io);
782 CHECK_STATUS(status, NT_STATUS_OK);
783 h = io.out.file.handle;
784 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
785 CHECK_LEASE(&io, held, true, LEASE1, 0);
787 /* Possibly contend lease. */
788 smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state(contend));
789 status = smb2_create(tree, mem_ctx, &io);
790 CHECK_STATUS(status, NT_STATUS_OK);
791 h2 = io.out.file.handle;
792 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
793 CHECK_LEASE(&io, granted, true, LEASE2, 0);
795 if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) {
796 CHECK_BREAK_INFO(held, brokento, LEASE1);
797 } else {
798 CHECK_NO_BREAK(tctx);
801 ZERO_STRUCT(break_info);
804 Now verify that an attempt to upgrade LEASE1 results in no
805 break and no change in LEASE1.
807 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
808 status = smb2_create(tree, mem_ctx, &io);
809 CHECK_STATUS(status, NT_STATUS_OK);
810 h3 = io.out.file.handle;
811 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
812 CHECK_LEASE(&io, brokento, true, LEASE1, 0);
813 CHECK_VAL(break_info.count, 0);
814 CHECK_VAL(break_info.failures, 0);
816 smb2_util_close(tree, h);
817 smb2_util_close(tree, h2);
818 smb2_util_close(tree, h3);
820 status = smb2_util_unlink(tree, fname);
821 CHECK_STATUS(status, NT_STATUS_OK);
824 done:
825 smb2_util_close(tree, h);
826 smb2_util_close(tree, h2);
828 smb2_util_unlink(tree, fname);
830 talloc_free(mem_ctx);
832 return ret;
835 static bool test_lease_nobreakself(struct torture_context *tctx,
836 struct smb2_tree *tree)
838 TALLOC_CTX *mem_ctx = talloc_new(tctx);
839 struct smb2_create io;
840 struct smb2_lease ls;
841 struct smb2_handle h1, h2;
842 NTSTATUS status;
843 const char *fname = "lease_nobreakself.dat";
844 bool ret = true;
845 uint32_t caps;
846 char c = 0;
848 caps = smb2cli_conn_server_capabilities(
849 tree->session->transport->conn);
850 if (!(caps & SMB2_CAP_LEASING)) {
851 torture_skip(tctx, "leases are not supported");
854 smb2_util_unlink(tree, fname);
856 /* Win7 is happy to grant RHW leases on files. */
857 smb2_lease_create(&io, &ls, false, fname, LEASE1,
858 smb2_util_lease_state("R"));
859 status = smb2_create(tree, mem_ctx, &io);
860 CHECK_STATUS(status, NT_STATUS_OK);
861 h1 = io.out.file.handle;
862 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
863 CHECK_LEASE(&io, "R", true, LEASE1, 0);
865 smb2_lease_create(&io, &ls, false, fname, LEASE2,
866 smb2_util_lease_state("R"));
867 status = smb2_create(tree, mem_ctx, &io);
868 CHECK_STATUS(status, NT_STATUS_OK);
869 h2 = io.out.file.handle;
870 CHECK_LEASE(&io, "R", true, LEASE2, 0);
872 ZERO_STRUCT(break_info);
874 tree->session->transport->lease.handler = torture_lease_handler;
875 tree->session->transport->lease.private_data = tree;
877 /* Make sure we don't break ourselves on write */
879 status = smb2_util_write(tree, h1, &c, 0, 1);
880 CHECK_STATUS(status, NT_STATUS_OK);
881 CHECK_BREAK_INFO("R", "", LEASE2);
883 /* Try the other way round. First, upgrade LEASE2 to R again */
885 smb2_lease_create(&io, &ls, false, fname, LEASE2,
886 smb2_util_lease_state("R"));
887 status = smb2_create(tree, mem_ctx, &io);
888 CHECK_STATUS(status, NT_STATUS_OK);
889 CHECK_LEASE(&io, "R", true, LEASE2, 0);
890 smb2_util_close(tree, io.out.file.handle);
892 /* Now break LEASE1 via h2 */
894 ZERO_STRUCT(break_info);
895 status = smb2_util_write(tree, h2, &c, 0, 1);
896 CHECK_STATUS(status, NT_STATUS_OK);
897 CHECK_BREAK_INFO("R", "", LEASE1);
899 /* .. and break LEASE2 via h1 */
901 ZERO_STRUCT(break_info);
902 status = smb2_util_write(tree, h1, &c, 0, 1);
903 CHECK_STATUS(status, NT_STATUS_OK);
904 CHECK_BREAK_INFO("R", "", LEASE2);
906 done:
907 smb2_util_close(tree, h2);
908 smb2_util_close(tree, h1);
909 smb2_util_unlink(tree, fname);
910 talloc_free(mem_ctx);
911 return ret;
914 static void torture_oplock_break_callback(struct smb2_request *req)
916 NTSTATUS status;
917 struct smb2_break br;
919 ZERO_STRUCT(br);
920 status = smb2_break_recv(req, &br);
921 if (!NT_STATUS_IS_OK(status))
922 break_info.oplock_failures++;
924 return;
927 /* a oplock break request handler */
928 static bool torture_oplock_handler(struct smb2_transport *transport,
929 const struct smb2_handle *handle,
930 uint8_t level, void *private_data)
932 struct smb2_tree *tree = private_data;
933 struct smb2_request *req;
934 struct smb2_break br;
936 break_info.oplock_handle = *handle;
937 break_info.oplock_level = level;
938 break_info.oplock_count++;
940 ZERO_STRUCT(br);
941 br.in.file.handle = *handle;
942 br.in.oplock_level = level;
944 if (break_info.held_oplock_level > SMB2_OPLOCK_LEVEL_II) {
945 req = smb2_break_send(tree, &br);
946 req->async.fn = torture_oplock_break_callback;
947 req->async.private_data = NULL;
949 break_info.held_oplock_level = level;
951 return true;
954 #define NOPLOCK_RESULTS 12
955 static const char *oplock_results[NOPLOCK_RESULTS][4] = {
956 {"R", "s", "R", "s"},
957 {"R", "x", "R", "s"},
958 {"R", "b", "R", "s"},
960 {"RH", "s", "RH", ""},
961 {"RH", "x", "RH", ""},
962 {"RH", "b", "RH", ""},
964 {"RW", "s", "R", "s"},
965 {"RW", "x", "R", "s"},
966 {"RW", "b", "R", "s"},
968 {"RHW", "s", "RH", ""},
969 {"RHW", "x", "RH", ""},
970 {"RHW", "b", "RH", ""},
973 static const char *oplock_results_2[NOPLOCK_RESULTS][4] = {
974 {"s", "R", "s", "R"},
975 {"s", "RH", "s", "R"},
976 {"s", "RW", "s", "R"},
977 {"s", "RHW", "s", "R"},
979 {"x", "R", "s", "R"},
980 {"x", "RH", "s", "R"},
981 {"x", "RW", "s", "R"},
982 {"x", "RHW", "s", "R"},
984 {"b", "R", "s", "R"},
985 {"b", "RH", "s", "R"},
986 {"b", "RW", "s", "R"},
987 {"b", "RHW", "s", "R"},
990 static bool test_lease_oplock(struct torture_context *tctx,
991 struct smb2_tree *tree)
993 TALLOC_CTX *mem_ctx = talloc_new(tctx);
994 struct smb2_create io;
995 struct smb2_lease ls;
996 struct smb2_handle h, h2;
997 NTSTATUS status;
998 const char *fname = "lease_oplock.dat";
999 bool ret = true;
1000 int i;
1001 uint32_t caps;
1003 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1004 if (!(caps & SMB2_CAP_LEASING)) {
1005 torture_skip(tctx, "leases are not supported");
1008 tree->session->transport->lease.handler = torture_lease_handler;
1009 tree->session->transport->lease.private_data = tree;
1010 tree->session->transport->oplock.handler = torture_oplock_handler;
1011 tree->session->transport->oplock.private_data = tree;
1013 smb2_util_unlink(tree, fname);
1015 for (i = 0; i < NOPLOCK_RESULTS; i++) {
1016 const char *held = oplock_results[i][0];
1017 const char *contend = oplock_results[i][1];
1018 const char *brokento = oplock_results[i][2];
1019 const char *granted = oplock_results[i][3];
1020 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
1021 "expecting break to %s(%x) and grant of %s(%x)\n",
1022 held, smb2_util_lease_state(held), contend, smb2_util_oplock_level(contend),
1023 brokento, smb2_util_lease_state(brokento), granted, smb2_util_oplock_level(granted));
1025 ZERO_STRUCT(break_info);
1027 /* Grab lease. */
1028 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held));
1029 status = smb2_create(tree, mem_ctx, &io);
1030 CHECK_STATUS(status, NT_STATUS_OK);
1031 h = io.out.file.handle;
1032 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1033 CHECK_LEASE(&io, held, true, LEASE1, 0);
1035 /* Does an oplock contend the lease? */
1036 smb2_oplock_create(&io, fname, smb2_util_oplock_level(contend));
1037 status = smb2_create(tree, mem_ctx, &io);
1038 CHECK_STATUS(status, NT_STATUS_OK);
1039 h2 = io.out.file.handle;
1040 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1041 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(granted));
1042 break_info.held_oplock_level = io.out.oplock_level;
1044 if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) {
1045 CHECK_BREAK_INFO(held, brokento, LEASE1);
1046 } else {
1047 CHECK_NO_BREAK(tctx);
1050 smb2_util_close(tree, h);
1051 smb2_util_close(tree, h2);
1053 status = smb2_util_unlink(tree, fname);
1054 CHECK_STATUS(status, NT_STATUS_OK);
1057 for (i = 0; i < NOPLOCK_RESULTS; i++) {
1058 const char *held = oplock_results_2[i][0];
1059 const char *contend = oplock_results_2[i][1];
1060 const char *brokento = oplock_results_2[i][2];
1061 const char *granted = oplock_results_2[i][3];
1062 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
1063 "expecting break to %s(%x) and grant of %s(%x)\n",
1064 held, smb2_util_oplock_level(held), contend, smb2_util_lease_state(contend),
1065 brokento, smb2_util_oplock_level(brokento), granted, smb2_util_lease_state(granted));
1067 ZERO_STRUCT(break_info);
1069 /* Grab an oplock. */
1070 smb2_oplock_create(&io, fname, smb2_util_oplock_level(held));
1071 status = smb2_create(tree, mem_ctx, &io);
1072 CHECK_STATUS(status, NT_STATUS_OK);
1073 h = io.out.file.handle;
1074 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1075 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(held));
1076 break_info.held_oplock_level = io.out.oplock_level;
1078 /* Grab lease. */
1079 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(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_LEASE(&io, granted, true, LEASE1, 0);
1086 if (smb2_util_oplock_level(held) != smb2_util_oplock_level(brokento)) {
1087 CHECK_OPLOCK_BREAK(brokento);
1088 } else {
1089 CHECK_NO_BREAK(tctx);
1092 smb2_util_close(tree, h);
1093 smb2_util_close(tree, h2);
1095 status = smb2_util_unlink(tree, fname);
1096 CHECK_STATUS(status, NT_STATUS_OK);
1099 done:
1100 smb2_util_close(tree, h);
1101 smb2_util_close(tree, h2);
1103 smb2_util_unlink(tree, fname);
1105 talloc_free(mem_ctx);
1107 return ret;
1110 static bool test_lease_multibreak(struct torture_context *tctx,
1111 struct smb2_tree *tree)
1113 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1114 struct smb2_create io;
1115 struct smb2_lease ls;
1116 struct smb2_handle h, h2, h3;
1117 struct smb2_write w;
1118 NTSTATUS status;
1119 const char *fname = "lease_multibreak.dat";
1120 bool ret = true;
1121 uint32_t caps;
1123 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1124 if (!(caps & SMB2_CAP_LEASING)) {
1125 torture_skip(tctx, "leases are not supported");
1128 tree->session->transport->lease.handler = torture_lease_handler;
1129 tree->session->transport->lease.private_data = tree;
1130 tree->session->transport->oplock.handler = torture_oplock_handler;
1131 tree->session->transport->oplock.private_data = tree;
1133 smb2_util_unlink(tree, fname);
1135 ZERO_STRUCT(break_info);
1137 /* Grab lease, upgrade to RHW .. */
1138 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
1139 status = smb2_create(tree, mem_ctx, &io);
1140 CHECK_STATUS(status, NT_STATUS_OK);
1141 h = io.out.file.handle;
1142 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1143 CHECK_LEASE(&io, "RH", true, LEASE1, 0);
1145 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
1146 status = smb2_create(tree, mem_ctx, &io);
1147 CHECK_STATUS(status, NT_STATUS_OK);
1148 h2 = io.out.file.handle;
1149 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1150 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
1152 /* Contend with LEASE2. */
1153 smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state("RHW"));
1154 status = smb2_create(tree, mem_ctx, &io);
1155 CHECK_STATUS(status, NT_STATUS_OK);
1156 h3 = io.out.file.handle;
1157 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1158 CHECK_LEASE(&io, "RH", true, LEASE2, 0);
1160 /* Verify that we were only sent one break. */
1161 CHECK_BREAK_INFO("RHW", "RH", LEASE1);
1163 /* Drop LEASE1 / LEASE2 */
1164 status = smb2_util_close(tree, h);
1165 CHECK_STATUS(status, NT_STATUS_OK);
1166 status = smb2_util_close(tree, h2);
1167 CHECK_STATUS(status, NT_STATUS_OK);
1168 status = smb2_util_close(tree, h3);
1169 CHECK_STATUS(status, NT_STATUS_OK);
1171 ZERO_STRUCT(break_info);
1173 /* Grab an R lease. */
1174 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("R"));
1175 status = smb2_create(tree, mem_ctx, &io);
1176 CHECK_STATUS(status, NT_STATUS_OK);
1177 h = io.out.file.handle;
1178 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1179 CHECK_LEASE(&io, "R", true, LEASE1, 0);
1181 /* Grab a level-II oplock. */
1182 smb2_oplock_create(&io, fname, smb2_util_oplock_level("s"));
1183 status = smb2_create(tree, mem_ctx, &io);
1184 CHECK_STATUS(status, NT_STATUS_OK);
1185 h2 = io.out.file.handle;
1186 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1187 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
1188 break_info.held_oplock_level = io.out.oplock_level;
1190 /* Verify no breaks. */
1191 CHECK_NO_BREAK(tctx);
1193 /* Open for truncate, force a break. */
1194 smb2_generic_create(&io, NULL, false, fname,
1195 NTCREATEX_DISP_OVERWRITE_IF, smb2_util_oplock_level(""), 0, 0);
1196 status = smb2_create(tree, mem_ctx, &io);
1197 CHECK_STATUS(status, NT_STATUS_OK);
1198 h3 = io.out.file.handle;
1199 CHECK_CREATED(&io, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
1200 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(""));
1201 break_info.held_oplock_level = io.out.oplock_level;
1203 /* Sleep, use a write to clear the recv queue. */
1204 smb_msleep(250);
1205 ZERO_STRUCT(w);
1206 w.in.file.handle = h3;
1207 w.in.offset = 0;
1208 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
1209 memset(w.in.data.data, 'o', w.in.data.length);
1210 status = smb2_write(tree, &w);
1211 CHECK_STATUS(status, NT_STATUS_OK);
1213 /* Verify one oplock break, one lease break. */
1214 CHECK_OPLOCK_BREAK("");
1215 CHECK_BREAK_INFO("R", "", LEASE1);
1217 done:
1218 smb2_util_close(tree, h);
1219 smb2_util_close(tree, h2);
1220 smb2_util_close(tree, h3);
1222 smb2_util_unlink(tree, fname);
1224 talloc_free(mem_ctx);
1226 return ret;
1229 static bool test_lease_v2_request_parent(struct torture_context *tctx,
1230 struct smb2_tree *tree)
1232 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1233 struct smb2_create io;
1234 struct smb2_lease ls;
1235 struct smb2_handle h1;
1236 uint64_t parent = LEASE2;
1237 NTSTATUS status;
1238 const char *fname = "lease_v2_request_parent.dat";
1239 bool ret = true;
1240 uint32_t caps;
1241 enum protocol_types protocol;
1243 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1244 if (!(caps & SMB2_CAP_LEASING)) {
1245 torture_skip(tctx, "leases are not supported");
1247 if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
1248 torture_skip(tctx, "directory leases are not supported");
1251 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1252 if (protocol < PROTOCOL_SMB3_00) {
1253 torture_skip(tctx, "v2 leases are not supported");
1256 smb2_util_unlink(tree, fname);
1258 ZERO_STRUCT(break_info);
1260 ZERO_STRUCT(io);
1261 smb2_lease_v2_create_share(&io, &ls, false, fname,
1262 smb2_util_share_access("RWD"),
1263 LEASE1, &parent,
1264 smb2_util_lease_state("RHW"),
1265 0x11);
1267 status = smb2_create(tree, mem_ctx, &io);
1268 CHECK_STATUS(status, NT_STATUS_OK);
1269 h1 = io.out.file.handle;
1270 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1271 CHECK_LEASE_V2(&io, "RHW", true, LEASE1,
1272 SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2,
1273 ls.lease_epoch + 1);
1275 done:
1276 smb2_util_close(tree, h1);
1277 smb2_util_unlink(tree, fname);
1279 talloc_free(mem_ctx);
1281 return ret;
1284 static bool test_lease_break_twice(struct torture_context *tctx,
1285 struct smb2_tree *tree)
1287 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1288 struct smb2_create io;
1289 struct smb2_lease ls1;
1290 struct smb2_lease ls2;
1291 struct smb2_handle h1;
1292 NTSTATUS status;
1293 const char *fname = "lease_break_twice.dat";
1294 bool ret = true;
1295 uint32_t caps;
1296 enum protocol_types protocol;
1298 caps = smb2cli_conn_server_capabilities(
1299 tree->session->transport->conn);
1300 if (!(caps & SMB2_CAP_LEASING)) {
1301 torture_skip(tctx, "leases are not supported");
1304 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1305 if (protocol < PROTOCOL_SMB3_00) {
1306 torture_skip(tctx, "v2 leases are not supported");
1309 smb2_util_unlink(tree, fname);
1311 ZERO_STRUCT(break_info);
1312 ZERO_STRUCT(io);
1314 smb2_lease_v2_create_share(
1315 &io, &ls1, false, fname, smb2_util_share_access("RWD"),
1316 LEASE1, NULL, smb2_util_lease_state("RWH"), 0x11);
1318 status = smb2_create(tree, mem_ctx, &io);
1319 CHECK_STATUS(status, NT_STATUS_OK);
1320 h1 = io.out.file.handle;
1321 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1322 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch + 1);
1324 tree->session->transport->lease.handler = torture_lease_handler;
1325 tree->session->transport->lease.private_data = tree;
1327 ZERO_STRUCT(break_info);
1329 smb2_lease_v2_create_share(
1330 &io, &ls2, false, fname, smb2_util_share_access("R"),
1331 LEASE2, NULL, smb2_util_lease_state("RWH"), 0x22);
1333 status = smb2_create(tree, mem_ctx, &io);
1334 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
1335 CHECK_BREAK_INFO_V2(tree->session->transport,
1336 "RWH", "RW", LEASE1, ls1.lease_epoch + 2);
1338 smb2_lease_v2_create_share(
1339 &io, &ls2, false, fname, smb2_util_share_access("RWD"),
1340 LEASE2, NULL, smb2_util_lease_state("RWH"), 0x22);
1342 ZERO_STRUCT(break_info);
1344 status = smb2_create(tree, mem_ctx, &io);
1345 CHECK_STATUS(status, NT_STATUS_OK);
1346 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch + 1);
1347 CHECK_BREAK_INFO_V2(tree->session->transport,
1348 "RW", "R", LEASE1, ls1.lease_epoch + 3);
1350 done:
1351 smb2_util_close(tree, h1);
1352 smb2_util_unlink(tree, fname);
1353 talloc_free(mem_ctx);
1354 return ret;
1357 static bool test_lease_v2_request(struct torture_context *tctx,
1358 struct smb2_tree *tree)
1360 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1361 struct smb2_create io;
1362 struct smb2_lease ls1, ls2, ls2t, ls3, ls4;
1363 struct smb2_handle h1, h2, h3, h4, h5;
1364 struct smb2_write w;
1365 NTSTATUS status;
1366 const char *fname = "lease_v2_request.dat";
1367 const char *dname = "lease_v2_request.dir";
1368 const char *dnamefname = "lease_v2_request.dir\\lease.dat";
1369 const char *dnamefname2 = "lease_v2_request.dir\\lease2.dat";
1370 bool ret = true;
1371 uint32_t caps;
1372 enum protocol_types protocol;
1374 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1375 if (!(caps & SMB2_CAP_LEASING)) {
1376 torture_skip(tctx, "leases are not supported");
1378 if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
1379 torture_skip(tctx, "directory leases are not supported");
1382 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1383 if (protocol < PROTOCOL_SMB3_00) {
1384 torture_skip(tctx, "v2 leases are not supported");
1387 smb2_util_unlink(tree, fname);
1388 smb2_deltree(tree, dname);
1390 tree->session->transport->lease.handler = torture_lease_handler;
1391 tree->session->transport->lease.private_data = tree;
1392 tree->session->transport->oplock.handler = torture_oplock_handler;
1393 tree->session->transport->oplock.private_data = tree;
1395 ZERO_STRUCT(break_info);
1397 ZERO_STRUCT(io);
1398 smb2_lease_v2_create_share(&io, &ls1, false, fname,
1399 smb2_util_share_access("RWD"),
1400 LEASE1, NULL,
1401 smb2_util_lease_state("RHW"),
1402 0x11);
1404 status = smb2_create(tree, mem_ctx, &io);
1405 CHECK_STATUS(status, NT_STATUS_OK);
1406 h1 = io.out.file.handle;
1407 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1408 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch + 1);
1410 ZERO_STRUCT(io);
1411 smb2_lease_v2_create_share(&io, &ls2, true, dname,
1412 smb2_util_share_access("RWD"),
1413 LEASE2, NULL,
1414 smb2_util_lease_state("RHW"),
1415 0x22);
1416 status = smb2_create(tree, mem_ctx, &io);
1417 CHECK_STATUS(status, NT_STATUS_OK);
1418 h2 = io.out.file.handle;
1419 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
1420 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch + 1);
1422 ZERO_STRUCT(io);
1423 smb2_lease_v2_create_share(&io, &ls3, false, dnamefname,
1424 smb2_util_share_access("RWD"),
1425 LEASE3, &LEASE2,
1426 smb2_util_lease_state("RHW"),
1427 0x33);
1428 status = smb2_create(tree, mem_ctx, &io);
1429 CHECK_STATUS(status, NT_STATUS_OK);
1430 h3 = io.out.file.handle;
1431 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1432 CHECK_LEASE_V2(&io, "RHW", true, LEASE3,
1433 SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2,
1434 ls3.lease_epoch + 1);
1436 CHECK_NO_BREAK(tctx);
1438 ZERO_STRUCT(io);
1439 smb2_lease_v2_create_share(&io, &ls4, false, dnamefname2,
1440 smb2_util_share_access("RWD"),
1441 LEASE4, NULL,
1442 smb2_util_lease_state("RHW"),
1443 0x44);
1444 status = smb2_create(tree, mem_ctx, &io);
1445 CHECK_STATUS(status, NT_STATUS_OK);
1446 h4 = io.out.file.handle;
1447 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1448 CHECK_LEASE_V2(&io, "RHW", true, LEASE4, 0, 0, ls4.lease_epoch + 1);
1450 CHECK_BREAK_INFO_V2(tree->session->transport,
1451 "RH", "", LEASE2, ls2.lease_epoch + 2);
1453 ZERO_STRUCT(break_info);
1455 ZERO_STRUCT(io);
1456 smb2_lease_v2_create_share(&io, &ls2t, true, dname,
1457 smb2_util_share_access("RWD"),
1458 LEASE2, NULL,
1459 smb2_util_lease_state("RHW"),
1460 0x222);
1461 io.in.create_disposition = NTCREATEX_DISP_OPEN;
1462 status = smb2_create(tree, mem_ctx, &io);
1463 CHECK_STATUS(status, NT_STATUS_OK);
1464 h5 = io.out.file.handle;
1465 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_DIRECTORY);
1466 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch+3);
1467 smb2_util_close(tree, h5);
1469 ZERO_STRUCT(w);
1470 w.in.file.handle = h4;
1471 w.in.offset = 0;
1472 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
1473 memset(w.in.data.data, 'o', w.in.data.length);
1474 status = smb2_write(tree, &w);
1475 CHECK_STATUS(status, NT_STATUS_OK);
1478 * Wait 4 seconds in order to check if the write time
1479 * was updated (after 2 seconds).
1481 smb_msleep(4000);
1482 CHECK_NO_BREAK(tctx);
1485 * only the close on the modified file break the
1486 * directory lease.
1488 smb2_util_close(tree, h4);
1490 CHECK_BREAK_INFO_V2(tree->session->transport,
1491 "RH", "", LEASE2, ls2.lease_epoch+4);
1493 done:
1494 smb2_util_close(tree, h1);
1495 smb2_util_close(tree, h2);
1496 smb2_util_close(tree, h3);
1497 smb2_util_close(tree, h4);
1498 smb2_util_close(tree, h5);
1500 smb2_util_unlink(tree, fname);
1501 smb2_deltree(tree, dname);
1503 talloc_free(mem_ctx);
1505 return ret;
1508 static bool test_lease_v2_epoch1(struct torture_context *tctx,
1509 struct smb2_tree *tree)
1511 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1512 struct smb2_create io;
1513 struct smb2_lease ls;
1514 struct smb2_handle h;
1515 const char *fname = "lease_v2_epoch1.dat";
1516 bool ret = true;
1517 NTSTATUS status;
1518 uint32_t caps;
1519 enum protocol_types protocol;
1521 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1522 if (!(caps & SMB2_CAP_LEASING)) {
1523 torture_skip(tctx, "leases are not supported");
1526 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1527 if (protocol < PROTOCOL_SMB3_00) {
1528 torture_skip(tctx, "v2 leases are not supported");
1531 smb2_util_unlink(tree, fname);
1533 tree->session->transport->lease.handler = torture_lease_handler;
1534 tree->session->transport->lease.private_data = tree;
1535 tree->session->transport->oplock.handler = torture_oplock_handler;
1536 tree->session->transport->oplock.private_data = tree;
1538 ZERO_STRUCT(break_info);
1540 ZERO_STRUCT(io);
1541 smb2_lease_v2_create_share(&io, &ls, false, fname,
1542 smb2_util_share_access("RWD"),
1543 LEASE1, NULL,
1544 smb2_util_lease_state("RHW"),
1545 0x4711);
1546 status = smb2_create(tree, mem_ctx, &io);
1547 CHECK_STATUS(status, NT_STATUS_OK);
1548 h = io.out.file.handle;
1549 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1550 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls.lease_epoch + 1);
1551 smb2_util_close(tree, h);
1552 smb2_util_unlink(tree, fname);
1554 smb2_lease_v2_create_share(&io, &ls, false, fname,
1555 smb2_util_share_access("RWD"),
1556 LEASE1, NULL,
1557 smb2_util_lease_state("RHW"),
1558 0x11);
1560 status = smb2_create(tree, mem_ctx, &io);
1561 CHECK_STATUS(status, NT_STATUS_OK);
1562 h = io.out.file.handle;
1563 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1564 CHECK_LEASE_V2(&io, "RWH", true, LEASE1, 0, 0, ls.lease_epoch + 1);
1565 smb2_util_close(tree, h);
1567 done:
1568 smb2_util_unlink(tree, fname);
1569 talloc_free(mem_ctx);
1570 return ret;
1573 static bool test_lease_v2_epoch2(struct torture_context *tctx,
1574 struct smb2_tree *tree)
1576 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1577 struct smb2_create io;
1578 struct smb2_lease ls1v2, ls1v2t, ls1v1;
1579 struct smb2_handle hv2 = {}, hv1 = {};
1580 const char *fname = "lease_v2_epoch2.dat";
1581 bool ret = true;
1582 NTSTATUS status;
1583 uint32_t caps;
1584 enum protocol_types protocol;
1586 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1587 if (!(caps & SMB2_CAP_LEASING)) {
1588 torture_skip(tctx, "leases are not supported");
1591 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1592 if (protocol < PROTOCOL_SMB3_00) {
1593 torture_skip(tctx, "v2 leases are not supported");
1596 smb2_util_unlink(tree, fname);
1598 tree->session->transport->lease.handler = torture_lease_handler;
1599 tree->session->transport->lease.private_data = tree;
1600 tree->session->transport->oplock.handler = torture_oplock_handler;
1601 tree->session->transport->oplock.private_data = tree;
1603 ZERO_STRUCT(break_info);
1605 ZERO_STRUCT(io);
1606 smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
1607 smb2_util_share_access("RWD"),
1608 LEASE1, NULL,
1609 smb2_util_lease_state("R"),
1610 0x4711);
1611 status = smb2_create(tree, mem_ctx, &io);
1612 CHECK_STATUS(status, NT_STATUS_OK);
1613 hv2 = io.out.file.handle;
1614 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1615 CHECK_LEASE_V2(&io, "R", true, LEASE1, 0, 0, ls1v2.lease_epoch + 1);
1617 ZERO_STRUCT(io);
1618 smb2_lease_create_share(&io, &ls1v1, false, fname,
1619 smb2_util_share_access("RWD"),
1620 LEASE1,
1621 smb2_util_lease_state("RH"));
1622 status = smb2_create(tree, mem_ctx, &io);
1623 CHECK_STATUS(status, NT_STATUS_OK);
1624 hv1 = io.out.file.handle;
1625 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1626 CHECK_LEASE_V2(&io, "RH", true, LEASE1, 0, 0, ls1v2.lease_epoch + 2);
1628 smb2_util_close(tree, hv2);
1630 ZERO_STRUCT(io);
1631 smb2_lease_v2_create_share(&io, &ls1v2t, false, fname,
1632 smb2_util_share_access("RWD"),
1633 LEASE1, NULL,
1634 smb2_util_lease_state("RHW"),
1635 0x11);
1636 status = smb2_create(tree, mem_ctx, &io);
1637 CHECK_STATUS(status, NT_STATUS_OK);
1638 hv2 = io.out.file.handle;
1639 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1640 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1v2.lease_epoch + 3);
1642 smb2_util_close(tree, hv2);
1644 smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_NONE);
1645 status = smb2_create(tree, mem_ctx, &io);
1646 CHECK_STATUS(status, NT_STATUS_OK);
1647 hv2 = io.out.file.handle;
1648 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1649 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1651 CHECK_BREAK_INFO_V2(tree->session->transport,
1652 "RWH", "RH", LEASE1, ls1v2.lease_epoch + 4);
1654 smb2_util_close(tree, hv2);
1655 smb2_util_close(tree, hv1);
1657 ZERO_STRUCT(io);
1658 smb2_lease_create_share(&io, &ls1v1, false, fname,
1659 smb2_util_share_access("RWD"),
1660 LEASE1,
1661 smb2_util_lease_state("RHW"));
1662 status = smb2_create(tree, mem_ctx, &io);
1663 CHECK_STATUS(status, NT_STATUS_OK);
1664 hv1 = io.out.file.handle;
1665 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1666 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
1668 smb2_util_close(tree, hv1);
1670 done:
1671 smb2_util_close(tree, hv2);
1672 smb2_util_close(tree, hv1);
1673 smb2_util_unlink(tree, fname);
1674 talloc_free(mem_ctx);
1675 return ret;
1678 static bool test_lease_v2_epoch3(struct torture_context *tctx,
1679 struct smb2_tree *tree)
1681 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1682 struct smb2_create io;
1683 struct smb2_lease ls1v1 = {}, ls1v1t = {},ls1v2 = {};
1684 struct smb2_handle hv1 = {}, hv2 = {};
1685 const char *fname = "lease_v2_epoch3.dat";
1686 bool ret = true;
1687 NTSTATUS status;
1688 uint32_t caps;
1689 enum protocol_types protocol;
1691 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1692 if (!(caps & SMB2_CAP_LEASING)) {
1693 torture_skip(tctx, "leases are not supported");
1696 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1697 if (protocol < PROTOCOL_SMB3_00) {
1698 torture_skip(tctx, "v2 leases are not supported");
1701 smb2_util_unlink(tree, fname);
1703 tree->session->transport->lease.handler = torture_lease_handler;
1704 tree->session->transport->lease.private_data = tree;
1705 tree->session->transport->oplock.handler = torture_oplock_handler;
1706 tree->session->transport->oplock.private_data = tree;
1708 ZERO_STRUCT(break_info);
1710 ZERO_STRUCT(io);
1711 smb2_lease_create_share(&io, &ls1v1, false, fname,
1712 smb2_util_share_access("RWD"),
1713 LEASE1,
1714 smb2_util_lease_state("R"));
1715 status = smb2_create(tree, mem_ctx, &io);
1716 CHECK_STATUS(status, NT_STATUS_OK);
1717 hv1 = io.out.file.handle;
1718 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1719 CHECK_LEASE(&io, "R", true, LEASE1, 0);
1721 ZERO_STRUCT(io);
1722 smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
1723 smb2_util_share_access("RWD"),
1724 LEASE1, NULL,
1725 smb2_util_lease_state("RW"),
1726 0x4711);
1727 status = smb2_create(tree, mem_ctx, &io);
1728 CHECK_STATUS(status, NT_STATUS_OK);
1729 hv2 = io.out.file.handle;
1730 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1731 CHECK_LEASE(&io, "RW", true, LEASE1, 0);
1733 smb2_util_close(tree, hv1);
1735 ZERO_STRUCT(io);
1736 smb2_lease_create_share(&io, &ls1v1t, false, fname,
1737 smb2_util_share_access("RWD"),
1738 LEASE1,
1739 smb2_util_lease_state("RWH"));
1740 status = smb2_create(tree, mem_ctx, &io);
1741 CHECK_STATUS(status, NT_STATUS_OK);
1742 hv1 = io.out.file.handle;
1743 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1744 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
1746 smb2_util_close(tree, hv1);
1748 smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_NONE);
1749 status = smb2_create(tree, mem_ctx, &io);
1750 CHECK_STATUS(status, NT_STATUS_OK);
1751 hv1 = io.out.file.handle;
1752 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1753 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1755 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
1757 smb2_util_close(tree, hv1);
1758 smb2_util_close(tree, hv2);
1760 ZERO_STRUCT(io);
1761 smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
1762 smb2_util_share_access("RWD"),
1763 LEASE1, NULL,
1764 smb2_util_lease_state("RWH"),
1765 0x4711);
1766 status = smb2_create(tree, mem_ctx, &io);
1767 CHECK_STATUS(status, NT_STATUS_OK);
1768 hv2 = io.out.file.handle;
1769 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1770 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1v2.lease_epoch + 1);
1771 smb2_util_close(tree, hv2);
1773 done:
1774 smb2_util_close(tree, hv2);
1775 smb2_util_close(tree, hv1);
1776 smb2_util_unlink(tree, fname);
1777 talloc_free(mem_ctx);
1778 return ret;
1781 static bool test_lease_breaking1(struct torture_context *tctx,
1782 struct smb2_tree *tree)
1784 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1785 struct smb2_create io1 = {};
1786 struct smb2_create io2 = {};
1787 struct smb2_lease ls1 = {};
1788 struct smb2_handle h1a = {};
1789 struct smb2_handle h1b = {};
1790 struct smb2_handle h2 = {};
1791 struct smb2_request *req2 = NULL;
1792 struct smb2_lease_break_ack ack = {};
1793 const char *fname = "lease_breaking1.dat";
1794 bool ret = true;
1795 NTSTATUS status;
1796 uint32_t caps;
1798 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1799 if (!(caps & SMB2_CAP_LEASING)) {
1800 torture_skip(tctx, "leases are not supported");
1803 smb2_util_unlink(tree, fname);
1805 tree->session->transport->lease.handler = torture_lease_handler;
1806 tree->session->transport->lease.private_data = tree;
1807 tree->session->transport->oplock.handler = torture_oplock_handler;
1808 tree->session->transport->oplock.private_data = tree;
1811 * we defer acking the lease break.
1813 ZERO_STRUCT(break_info);
1814 break_info.lease_skip_ack = true;
1816 smb2_lease_create_share(&io1, &ls1, false, fname,
1817 smb2_util_share_access("RWD"),
1818 LEASE1,
1819 smb2_util_lease_state("RWH"));
1820 status = smb2_create(tree, mem_ctx, &io1);
1821 CHECK_STATUS(status, NT_STATUS_OK);
1822 h1a = io1.out.file.handle;
1823 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1824 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
1827 * a conflicting open is blocked until we ack the
1828 * lease break
1830 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
1831 req2 = smb2_create_send(tree, &io2);
1832 torture_assert(tctx, req2 != NULL, "smb2_create_send");
1835 * we got the lease break, but defer the ack.
1837 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
1839 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
1841 ack.in.lease.lease_key =
1842 break_info.lease_break.current_lease.lease_key;
1843 ack.in.lease.lease_state =
1844 break_info.lease_break.new_lease_state;
1845 ZERO_STRUCT(break_info);
1848 * a open using the same lease key is still works,
1849 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
1851 status = smb2_create(tree, mem_ctx, &io1);
1852 CHECK_STATUS(status, NT_STATUS_OK);
1853 h1b = io1.out.file.handle;
1854 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1855 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
1856 smb2_util_close(tree, h1b);
1858 CHECK_NO_BREAK(tctx);
1860 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
1863 * We ack the lease break.
1865 status = smb2_lease_break_ack(tree, &ack);
1866 CHECK_STATUS(status, NT_STATUS_OK);
1867 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
1869 torture_assert(tctx, req2->cancel.can_cancel,
1870 "req2 can_cancel");
1872 status = smb2_create_recv(req2, tctx, &io2);
1873 CHECK_STATUS(status, NT_STATUS_OK);
1874 h2 = io2.out.file.handle;
1875 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1876 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1878 CHECK_NO_BREAK(tctx);
1879 done:
1880 smb2_util_close(tree, h1a);
1881 smb2_util_close(tree, h1b);
1882 smb2_util_close(tree, h2);
1883 smb2_util_unlink(tree, fname);
1884 talloc_free(mem_ctx);
1885 return ret;
1888 static bool test_lease_breaking2(struct torture_context *tctx,
1889 struct smb2_tree *tree)
1891 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1892 struct smb2_create io1 = {};
1893 struct smb2_create io2 = {};
1894 struct smb2_lease ls1 = {};
1895 struct smb2_handle h1a = {};
1896 struct smb2_handle h1b = {};
1897 struct smb2_handle h2 = {};
1898 struct smb2_request *req2 = NULL;
1899 struct smb2_lease_break_ack ack = {};
1900 const char *fname = "lease_breaking2.dat";
1901 bool ret = true;
1902 NTSTATUS status;
1903 uint32_t caps;
1905 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1906 if (!(caps & SMB2_CAP_LEASING)) {
1907 torture_skip(tctx, "leases are not supported");
1910 smb2_util_unlink(tree, fname);
1912 tree->session->transport->lease.handler = torture_lease_handler;
1913 tree->session->transport->lease.private_data = tree;
1914 tree->session->transport->oplock.handler = torture_oplock_handler;
1915 tree->session->transport->oplock.private_data = tree;
1918 * we defer acking the lease break.
1920 ZERO_STRUCT(break_info);
1921 break_info.lease_skip_ack = true;
1923 smb2_lease_create_share(&io1, &ls1, false, fname,
1924 smb2_util_share_access("RWD"),
1925 LEASE1,
1926 smb2_util_lease_state("RWH"));
1927 status = smb2_create(tree, mem_ctx, &io1);
1928 CHECK_STATUS(status, NT_STATUS_OK);
1929 h1a = io1.out.file.handle;
1930 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1931 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
1934 * a conflicting open is blocked until we ack the
1935 * lease break
1937 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
1938 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
1939 req2 = smb2_create_send(tree, &io2);
1940 torture_assert(tctx, req2 != NULL, "smb2_create_send");
1943 * we got the lease break, but defer the ack.
1945 CHECK_BREAK_INFO("RWH", "", LEASE1);
1947 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
1949 ack.in.lease.lease_key =
1950 break_info.lease_break.current_lease.lease_key;
1951 ZERO_STRUCT(break_info);
1954 * a open using the same lease key is still works,
1955 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
1957 status = smb2_create(tree, mem_ctx, &io1);
1958 CHECK_STATUS(status, NT_STATUS_OK);
1959 h1b = io1.out.file.handle;
1960 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1961 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
1962 smb2_util_close(tree, h1b);
1964 CHECK_NO_BREAK(tctx);
1966 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
1969 * We ack the lease break.
1971 ack.in.lease.lease_state =
1972 SMB2_LEASE_READ | SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE;
1973 status = smb2_lease_break_ack(tree, &ack);
1974 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
1976 ack.in.lease.lease_state =
1977 SMB2_LEASE_READ | SMB2_LEASE_WRITE;
1978 status = smb2_lease_break_ack(tree, &ack);
1979 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
1981 ack.in.lease.lease_state =
1982 SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE;
1983 status = smb2_lease_break_ack(tree, &ack);
1984 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
1986 ack.in.lease.lease_state =
1987 SMB2_LEASE_READ | SMB2_LEASE_HANDLE;
1988 status = smb2_lease_break_ack(tree, &ack);
1989 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
1991 ack.in.lease.lease_state = SMB2_LEASE_WRITE;
1992 status = smb2_lease_break_ack(tree, &ack);
1993 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
1995 ack.in.lease.lease_state = SMB2_LEASE_HANDLE;
1996 status = smb2_lease_break_ack(tree, &ack);
1997 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
1999 ack.in.lease.lease_state = SMB2_LEASE_READ;
2000 status = smb2_lease_break_ack(tree, &ack);
2001 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2003 /* Try again with the correct state this time. */
2004 ack.in.lease.lease_state = SMB2_LEASE_NONE;;
2005 status = smb2_lease_break_ack(tree, &ack);
2006 CHECK_STATUS(status, NT_STATUS_OK);
2007 CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
2009 status = smb2_lease_break_ack(tree, &ack);
2010 CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
2012 torture_assert(tctx, req2->cancel.can_cancel,
2013 "req2 can_cancel");
2015 status = smb2_create_recv(req2, tctx, &io2);
2016 CHECK_STATUS(status, NT_STATUS_OK);
2017 h2 = io2.out.file.handle;
2018 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2019 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2021 CHECK_NO_BREAK(tctx);
2023 /* Get state of the original handle. */
2024 smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
2025 status = smb2_create(tree, mem_ctx, &io1);
2026 CHECK_STATUS(status, NT_STATUS_OK);
2027 CHECK_LEASE(&io1, "", true, LEASE1, 0);
2028 smb2_util_close(tree, io1.out.file.handle);
2030 done:
2031 smb2_util_close(tree, h1a);
2032 smb2_util_close(tree, h1b);
2033 smb2_util_close(tree, h2);
2034 smb2_util_unlink(tree, fname);
2035 talloc_free(mem_ctx);
2036 return ret;
2039 static bool test_lease_breaking3(struct torture_context *tctx,
2040 struct smb2_tree *tree)
2042 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2043 struct smb2_create io1 = {};
2044 struct smb2_create io2 = {};
2045 struct smb2_create io3 = {};
2046 struct smb2_lease ls1 = {};
2047 struct smb2_handle h1a = {};
2048 struct smb2_handle h1b = {};
2049 struct smb2_handle h2 = {};
2050 struct smb2_handle h3 = {};
2051 struct smb2_request *req2 = NULL;
2052 struct smb2_request *req3 = NULL;
2053 struct torture_lease_break break_info_tmp = {};
2054 struct smb2_lease_break_ack ack = {};
2055 const char *fname = "lease_breaking3.dat";
2056 bool ret = true;
2057 NTSTATUS status;
2058 uint32_t caps;
2060 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2061 if (!(caps & SMB2_CAP_LEASING)) {
2062 torture_skip(tctx, "leases are not supported");
2065 smb2_util_unlink(tree, fname);
2067 tree->session->transport->lease.handler = torture_lease_handler;
2068 tree->session->transport->lease.private_data = tree;
2069 tree->session->transport->oplock.handler = torture_oplock_handler;
2070 tree->session->transport->oplock.private_data = tree;
2073 * we defer acking the lease break.
2075 ZERO_STRUCT(break_info);
2076 break_info.lease_skip_ack = true;
2078 smb2_lease_create_share(&io1, &ls1, false, fname,
2079 smb2_util_share_access("RWD"),
2080 LEASE1,
2081 smb2_util_lease_state("RWH"));
2082 status = smb2_create(tree, mem_ctx, &io1);
2083 CHECK_STATUS(status, NT_STATUS_OK);
2084 h1a = io1.out.file.handle;
2085 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2086 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2089 * a conflicting open is blocked until we ack the
2090 * lease break
2092 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2093 req2 = smb2_create_send(tree, &io2);
2094 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2097 * we got the lease break, but defer the ack.
2099 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2101 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2104 * a open using the same lease key is still works,
2105 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2107 status = smb2_create(tree, mem_ctx, &io1);
2108 CHECK_STATUS(status, NT_STATUS_OK);
2109 h1b = io1.out.file.handle;
2110 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2111 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2112 smb2_util_close(tree, h1b);
2115 * a conflicting open with NTCREATEX_DISP_OVERWRITE
2116 * doesn't trigger an immediate lease break to none.
2118 break_info_tmp = break_info;
2119 ZERO_STRUCT(break_info);
2120 smb2_oplock_create(&io3, fname, SMB2_OPLOCK_LEVEL_NONE);
2121 io3.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2122 req3 = smb2_create_send(tree, &io3);
2123 torture_assert(tctx, req3 != NULL, "smb2_create_send");
2124 CHECK_NO_BREAK(tctx);
2125 break_info = break_info_tmp;
2127 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2129 ack.in.lease.lease_key =
2130 break_info.lease_break.current_lease.lease_key;
2131 ack.in.lease.lease_state =
2132 break_info.lease_break.new_lease_state;
2133 ZERO_STRUCT(break_info);
2136 * a open using the same lease key is still works,
2137 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2139 status = smb2_create(tree, mem_ctx, &io1);
2140 CHECK_STATUS(status, NT_STATUS_OK);
2141 h1b = io1.out.file.handle;
2142 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2143 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2144 smb2_util_close(tree, h1b);
2146 CHECK_NO_BREAK(tctx);
2149 * We ack the lease break, but defer acking the next break (to "R")
2151 break_info.lease_skip_ack = true;
2152 status = smb2_lease_break_ack(tree, &ack);
2153 CHECK_STATUS(status, NT_STATUS_OK);
2154 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
2157 * We got an additional break downgrading to just "R"
2158 * while we defer the ack.
2160 CHECK_BREAK_INFO("RH", "R", LEASE1);
2162 ack.in.lease.lease_key =
2163 break_info.lease_break.current_lease.lease_key;
2164 ack.in.lease.lease_state =
2165 break_info.lease_break.new_lease_state;
2166 ZERO_STRUCT(break_info);
2169 * a open using the same lease key is still works,
2170 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2172 status = smb2_create(tree, mem_ctx, &io1);
2173 CHECK_STATUS(status, NT_STATUS_OK);
2174 h1b = io1.out.file.handle;
2175 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2176 CHECK_LEASE(&io1, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2177 smb2_util_close(tree, h1b);
2179 CHECK_NO_BREAK(tctx);
2181 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2182 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2185 * We ack the downgrade to "R" and get an immediate break to none
2187 status = smb2_lease_break_ack(tree, &ack);
2188 CHECK_STATUS(status, NT_STATUS_OK);
2189 CHECK_LEASE_BREAK_ACK(&ack, "R", LEASE1);
2192 * We get the downgrade to none.
2194 CHECK_BREAK_INFO("R", "", LEASE1);
2196 torture_assert(tctx, req2->cancel.can_cancel,
2197 "req2 can_cancel");
2198 torture_assert(tctx, req3->cancel.can_cancel,
2199 "req3 can_cancel");
2201 ZERO_STRUCT(break_info);
2203 status = smb2_create_recv(req2, tctx, &io2);
2204 CHECK_STATUS(status, NT_STATUS_OK);
2205 h2 = io2.out.file.handle;
2206 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2207 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2209 status = smb2_create_recv(req3, tctx, &io3);
2210 CHECK_STATUS(status, NT_STATUS_OK);
2211 h3 = io3.out.file.handle;
2212 CHECK_CREATED(&io3, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2213 CHECK_VAL(io3.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2215 CHECK_NO_BREAK(tctx);
2216 done:
2217 smb2_util_close(tree, h1a);
2218 smb2_util_close(tree, h1b);
2219 smb2_util_close(tree, h2);
2220 smb2_util_close(tree, h3);
2222 smb2_util_unlink(tree, fname);
2223 talloc_free(mem_ctx);
2224 return ret;
2227 static bool test_lease_breaking4(struct torture_context *tctx,
2228 struct smb2_tree *tree)
2230 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2231 struct smb2_create io1 = {};
2232 struct smb2_create io2 = {};
2233 struct smb2_create io3 = {};
2234 struct smb2_lease ls1 = {};
2235 struct smb2_lease ls1t = {};
2236 struct smb2_handle h1 = {};
2237 struct smb2_handle h2 = {};
2238 struct smb2_handle h3 = {};
2239 struct smb2_request *req2 = NULL;
2240 struct torture_lease_break break_info_tmp = {};
2241 struct smb2_lease_break_ack ack = {};
2242 const char *fname = "lease_breaking4.dat";
2243 bool ret = true;
2244 NTSTATUS status;
2245 uint32_t caps;
2247 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2248 if (!(caps & SMB2_CAP_LEASING)) {
2249 torture_skip(tctx, "leases are not supported");
2252 smb2_util_unlink(tree, fname);
2254 tree->session->transport->lease.handler = torture_lease_handler;
2255 tree->session->transport->lease.private_data = tree;
2256 tree->session->transport->oplock.handler = torture_oplock_handler;
2257 tree->session->transport->oplock.private_data = tree;
2260 * we defer acking the lease break.
2262 ZERO_STRUCT(break_info);
2263 break_info.lease_skip_ack = true;
2265 smb2_lease_create_share(&io1, &ls1, false, fname,
2266 smb2_util_share_access("RWD"),
2267 LEASE1,
2268 smb2_util_lease_state("RH"));
2269 status = smb2_create(tree, mem_ctx, &io1);
2270 CHECK_STATUS(status, NT_STATUS_OK);
2271 h1 = io1.out.file.handle;
2272 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2273 CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
2275 CHECK_NO_BREAK(tctx);
2278 * a conflicting open is *not* blocked until we ack the
2279 * lease break
2281 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2282 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2283 req2 = smb2_create_send(tree, &io2);
2284 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2287 * We got a break from RH to NONE, we're supported to ack
2288 * this downgrade
2290 CHECK_BREAK_INFO("RH", "", LEASE1);
2292 break_info_tmp = break_info;
2293 ZERO_STRUCT(break_info);
2294 CHECK_NO_BREAK(tctx);
2296 torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2298 status = smb2_create_recv(req2, tctx, &io2);
2299 CHECK_STATUS(status, NT_STATUS_OK);
2300 h2 = io2.out.file.handle;
2301 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2302 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2303 smb2_util_close(tree, h2);
2305 CHECK_NO_BREAK(tctx);
2308 * a conflicting open is *not* blocked until we ack the
2309 * lease break, even if the lease is in breaking state.
2311 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2312 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2313 req2 = smb2_create_send(tree, &io2);
2314 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2316 CHECK_NO_BREAK(tctx);
2318 torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2320 status = smb2_create_recv(req2, tctx, &io2);
2321 CHECK_STATUS(status, NT_STATUS_OK);
2322 h2 = io2.out.file.handle;
2323 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2324 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2325 smb2_util_close(tree, h2);
2327 CHECK_NO_BREAK(tctx);
2330 * We now ask the server about the current lease state
2331 * which should still be "RH", but with
2332 * SMB2_LEASE_FLAG_BREAK_IN_PROGRESS.
2334 smb2_lease_create_share(&io3, &ls1t, false, fname,
2335 smb2_util_share_access("RWD"),
2336 LEASE1,
2337 smb2_util_lease_state(""));
2338 status = smb2_create(tree, mem_ctx, &io3);
2339 CHECK_STATUS(status, NT_STATUS_OK);
2340 h3 = io3.out.file.handle;
2341 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2342 CHECK_LEASE(&io3, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2345 * We finally ack the lease break...
2347 CHECK_NO_BREAK(tctx);
2348 break_info = break_info_tmp;
2349 ack.in.lease.lease_key =
2350 break_info.lease_break.current_lease.lease_key;
2351 ack.in.lease.lease_state =
2352 break_info.lease_break.new_lease_state;
2353 ZERO_STRUCT(break_info);
2354 break_info.lease_skip_ack = true;
2356 status = smb2_lease_break_ack(tree, &ack);
2357 CHECK_STATUS(status, NT_STATUS_OK);
2358 CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
2360 CHECK_NO_BREAK(tctx);
2362 done:
2363 smb2_util_close(tree, h1);
2364 smb2_util_close(tree, h2);
2365 smb2_util_close(tree, h3);
2367 smb2_util_unlink(tree, fname);
2368 talloc_free(mem_ctx);
2369 return ret;
2372 static bool test_lease_breaking5(struct torture_context *tctx,
2373 struct smb2_tree *tree)
2375 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2376 struct smb2_create io1 = {};
2377 struct smb2_create io2 = {};
2378 struct smb2_create io3 = {};
2379 struct smb2_lease ls1 = {};
2380 struct smb2_lease ls1t = {};
2381 struct smb2_handle h1 = {};
2382 struct smb2_handle h2 = {};
2383 struct smb2_handle h3 = {};
2384 struct smb2_request *req2 = NULL;
2385 struct torture_lease_break break_info_tmp = {};
2386 struct smb2_lease_break_ack ack = {};
2387 const char *fname = "lease_breaking5.dat";
2388 bool ret = true;
2389 NTSTATUS status;
2390 uint32_t caps;
2392 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2393 if (!(caps & SMB2_CAP_LEASING)) {
2394 torture_skip(tctx, "leases are not supported");
2397 smb2_util_unlink(tree, fname);
2399 tree->session->transport->lease.handler = torture_lease_handler;
2400 tree->session->transport->lease.private_data = tree;
2401 tree->session->transport->oplock.handler = torture_oplock_handler;
2402 tree->session->transport->oplock.private_data = tree;
2405 * we defer acking the lease break.
2407 ZERO_STRUCT(break_info);
2408 break_info.lease_skip_ack = true;
2410 smb2_lease_create_share(&io1, &ls1, false, fname,
2411 smb2_util_share_access("RWD"),
2412 LEASE1,
2413 smb2_util_lease_state("R"));
2414 status = smb2_create(tree, mem_ctx, &io1);
2415 CHECK_STATUS(status, NT_STATUS_OK);
2416 h1 = io1.out.file.handle;
2417 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2418 CHECK_LEASE(&io1, "R", true, LEASE1, 0);
2420 CHECK_NO_BREAK(tctx);
2423 * a conflicting open is *not* blocked until we ack the
2424 * lease break
2426 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2427 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2428 req2 = smb2_create_send(tree, &io2);
2429 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2432 * We got a break from RH to NONE, we're supported to ack
2433 * this downgrade
2435 CHECK_BREAK_INFO("R", "", LEASE1);
2437 break_info_tmp = break_info;
2438 ZERO_STRUCT(break_info);
2439 CHECK_NO_BREAK(tctx);
2441 torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2443 status = smb2_create_recv(req2, tctx, &io2);
2444 CHECK_STATUS(status, NT_STATUS_OK);
2445 h2 = io2.out.file.handle;
2446 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2447 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2449 CHECK_NO_BREAK(tctx);
2452 * We now ask the server about the current lease state
2453 * which should still be "RH", but with
2454 * SMB2_LEASE_FLAG_BREAK_IN_PROGRESS.
2456 smb2_lease_create_share(&io3, &ls1t, false, fname,
2457 smb2_util_share_access("RWD"),
2458 LEASE1,
2459 smb2_util_lease_state(""));
2460 status = smb2_create(tree, mem_ctx, &io3);
2461 CHECK_STATUS(status, NT_STATUS_OK);
2462 h3 = io3.out.file.handle;
2463 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2464 CHECK_LEASE(&io3, "", true, LEASE1, 0);
2467 * We send an ack without without being asked.
2469 CHECK_NO_BREAK(tctx);
2470 break_info = break_info_tmp;
2471 ack.in.lease.lease_key =
2472 break_info.lease_break.current_lease.lease_key;
2473 ack.in.lease.lease_state =
2474 break_info.lease_break.new_lease_state;
2475 ZERO_STRUCT(break_info);
2476 status = smb2_lease_break_ack(tree, &ack);
2477 CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
2479 CHECK_NO_BREAK(tctx);
2481 done:
2482 smb2_util_close(tree, h1);
2483 smb2_util_close(tree, h2);
2484 smb2_util_close(tree, h3);
2486 smb2_util_unlink(tree, fname);
2487 talloc_free(mem_ctx);
2488 return ret;
2491 static bool test_lease_breaking6(struct torture_context *tctx,
2492 struct smb2_tree *tree)
2494 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2495 struct smb2_create io1 = {};
2496 struct smb2_create io2 = {};
2497 struct smb2_lease ls1 = {};
2498 struct smb2_handle h1a = {};
2499 struct smb2_handle h1b = {};
2500 struct smb2_handle h2 = {};
2501 struct smb2_request *req2 = NULL;
2502 struct smb2_lease_break_ack ack = {};
2503 const char *fname = "lease_breaking6.dat";
2504 bool ret = true;
2505 NTSTATUS status;
2506 uint32_t caps;
2508 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2509 if (!(caps & SMB2_CAP_LEASING)) {
2510 torture_skip(tctx, "leases are not supported");
2513 smb2_util_unlink(tree, fname);
2515 tree->session->transport->lease.handler = torture_lease_handler;
2516 tree->session->transport->lease.private_data = tree;
2517 tree->session->transport->oplock.handler = torture_oplock_handler;
2518 tree->session->transport->oplock.private_data = tree;
2521 * we defer acking the lease break.
2523 ZERO_STRUCT(break_info);
2524 break_info.lease_skip_ack = true;
2526 smb2_lease_create_share(&io1, &ls1, false, fname,
2527 smb2_util_share_access("RWD"),
2528 LEASE1,
2529 smb2_util_lease_state("RWH"));
2530 status = smb2_create(tree, mem_ctx, &io1);
2531 CHECK_STATUS(status, NT_STATUS_OK);
2532 h1a = io1.out.file.handle;
2533 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2534 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2537 * a conflicting open is blocked until we ack the
2538 * lease break
2540 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2541 req2 = smb2_create_send(tree, &io2);
2542 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2545 * we got the lease break, but defer the ack.
2547 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2549 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2551 ack.in.lease.lease_key =
2552 break_info.lease_break.current_lease.lease_key;
2553 ZERO_STRUCT(break_info);
2556 * a open using the same lease key is still works,
2557 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2559 status = smb2_create(tree, mem_ctx, &io1);
2560 CHECK_STATUS(status, NT_STATUS_OK);
2561 h1b = io1.out.file.handle;
2562 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2563 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2564 smb2_util_close(tree, h1b);
2566 CHECK_NO_BREAK(tctx);
2568 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2571 * We are asked to break to "RH", but we are allowed to
2572 * break to any of "RH", "R" or NONE.
2574 ack.in.lease.lease_state = SMB2_LEASE_NONE;
2575 status = smb2_lease_break_ack(tree, &ack);
2576 CHECK_STATUS(status, NT_STATUS_OK);
2577 CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
2579 torture_assert(tctx, req2->cancel.can_cancel,
2580 "req2 can_cancel");
2582 status = smb2_create_recv(req2, tctx, &io2);
2583 CHECK_STATUS(status, NT_STATUS_OK);
2584 h2 = io2.out.file.handle;
2585 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2586 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2588 CHECK_NO_BREAK(tctx);
2589 done:
2590 smb2_util_close(tree, h1a);
2591 smb2_util_close(tree, h1b);
2592 smb2_util_close(tree, h2);
2593 smb2_util_unlink(tree, fname);
2594 talloc_free(mem_ctx);
2595 return ret;
2598 static bool test_lease_complex1(struct torture_context *tctx,
2599 struct smb2_tree *tree1a)
2601 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2602 struct smb2_create io1;
2603 struct smb2_create io2;
2604 struct smb2_lease ls1;
2605 struct smb2_lease ls2;
2606 struct smb2_handle h, h2, h3;
2607 struct smb2_write w;
2608 NTSTATUS status;
2609 const char *fname = "lease_complex1.dat";
2610 bool ret = true;
2611 uint32_t caps;
2612 struct smb2_tree *tree1b = NULL;
2613 struct smbcli_options options1;
2615 options1 = tree1a->session->transport->options;
2617 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
2618 if (!(caps & SMB2_CAP_LEASING)) {
2619 torture_skip(tctx, "leases are not supported");
2622 tree1a->session->transport->lease.handler = torture_lease_handler;
2623 tree1a->session->transport->lease.private_data = tree1a;
2624 tree1a->session->transport->oplock.handler = torture_oplock_handler;
2625 tree1a->session->transport->oplock.private_data = tree1a;
2627 /* create a new connection (same client_guid) */
2628 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
2629 torture_warning(tctx, "couldn't reconnect, bailing\n");
2630 ret = false;
2631 goto done;
2634 tree1b->session->transport->lease.handler = torture_lease_handler;
2635 tree1b->session->transport->lease.private_data = tree1b;
2636 tree1b->session->transport->oplock.handler = torture_oplock_handler;
2637 tree1b->session->transport->oplock.private_data = tree1b;
2639 smb2_util_unlink(tree1a, fname);
2641 ZERO_STRUCT(break_info);
2643 /* Grab R lease over connection 1a */
2644 smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
2645 status = smb2_create(tree1a, mem_ctx, &io1);
2646 CHECK_STATUS(status, NT_STATUS_OK);
2647 h = io1.out.file.handle;
2648 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2649 CHECK_LEASE(&io1, "R", true, LEASE1, 0);
2651 /* Upgrade to RWH over connection 1b */
2652 ls1.lease_state = smb2_util_lease_state("RWH");
2653 status = smb2_create(tree1b, mem_ctx, &io1);
2654 CHECK_STATUS(status, NT_STATUS_OK);
2655 h2 = io1.out.file.handle;
2656 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2657 CHECK_LEASE(&io1, "RHW", true, LEASE1, 0);
2659 /* close over connection 1b */
2660 status = smb2_util_close(tree1b, h2);
2661 CHECK_STATUS(status, NT_STATUS_OK);
2663 /* Contend with LEASE2. */
2664 smb2_lease_create(&io2, &ls2, false, fname, LEASE2, smb2_util_lease_state("RHW"));
2665 status = smb2_create(tree1b, mem_ctx, &io2);
2666 CHECK_STATUS(status, NT_STATUS_OK);
2667 h3 = io2.out.file.handle;
2668 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2669 CHECK_LEASE(&io2, "RH", true, LEASE2, 0);
2671 /* Verify that we were only sent one break. */
2672 CHECK_BREAK_INFO("RHW", "RH", LEASE1);
2674 /* again RH over connection 1b doesn't change the epoch */
2675 ls1.lease_state = smb2_util_lease_state("RH");
2676 status = smb2_create(tree1b, mem_ctx, &io1);
2677 CHECK_STATUS(status, NT_STATUS_OK);
2678 h2 = io1.out.file.handle;
2679 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2680 CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
2682 /* close over connection 1b */
2683 status = smb2_util_close(tree1b, h2);
2684 CHECK_STATUS(status, NT_STATUS_OK);
2686 ZERO_STRUCT(break_info);
2688 ZERO_STRUCT(w);
2689 w.in.file.handle = h;
2690 w.in.offset = 0;
2691 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
2692 memset(w.in.data.data, 'o', w.in.data.length);
2693 status = smb2_write(tree1a, &w);
2694 CHECK_STATUS(status, NT_STATUS_OK);
2696 ls2.lease_epoch += 1;
2697 CHECK_BREAK_INFO("RH", "", LEASE2);
2699 ZERO_STRUCT(break_info);
2701 ZERO_STRUCT(w);
2702 w.in.file.handle = h3;
2703 w.in.offset = 0;
2704 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
2705 memset(w.in.data.data, 'o', w.in.data.length);
2706 status = smb2_write(tree1b, &w);
2707 CHECK_STATUS(status, NT_STATUS_OK);
2709 ls1.lease_epoch += 1;
2710 CHECK_BREAK_INFO("RH", "", LEASE1);
2712 done:
2713 smb2_util_close(tree1a, h);
2714 smb2_util_close(tree1b, h2);
2715 smb2_util_close(tree1b, h3);
2717 smb2_util_unlink(tree1a, fname);
2719 talloc_free(mem_ctx);
2721 return ret;
2724 static bool test_lease_v2_complex1(struct torture_context *tctx,
2725 struct smb2_tree *tree1a)
2727 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2728 struct smb2_create io1;
2729 struct smb2_create io2;
2730 struct smb2_lease ls1;
2731 struct smb2_lease ls2;
2732 struct smb2_handle h, h2, h3;
2733 struct smb2_write w;
2734 NTSTATUS status;
2735 const char *fname = "lease_v2_complex1.dat";
2736 bool ret = true;
2737 uint32_t caps;
2738 enum protocol_types protocol;
2739 struct smb2_tree *tree1b = NULL;
2740 struct smbcli_options options1;
2742 options1 = tree1a->session->transport->options;
2744 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
2745 if (!(caps & SMB2_CAP_LEASING)) {
2746 torture_skip(tctx, "leases are not supported");
2749 protocol = smbXcli_conn_protocol(tree1a->session->transport->conn);
2750 if (protocol < PROTOCOL_SMB3_00) {
2751 torture_skip(tctx, "v2 leases are not supported");
2754 tree1a->session->transport->lease.handler = torture_lease_handler;
2755 tree1a->session->transport->lease.private_data = tree1a;
2756 tree1a->session->transport->oplock.handler = torture_oplock_handler;
2757 tree1a->session->transport->oplock.private_data = tree1a;
2759 /* create a new connection (same client_guid) */
2760 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
2761 torture_warning(tctx, "couldn't reconnect, bailing\n");
2762 ret = false;
2763 goto done;
2766 tree1b->session->transport->lease.handler = torture_lease_handler;
2767 tree1b->session->transport->lease.private_data = tree1b;
2768 tree1b->session->transport->oplock.handler = torture_oplock_handler;
2769 tree1b->session->transport->oplock.private_data = tree1b;
2771 smb2_util_unlink(tree1a, fname);
2773 ZERO_STRUCT(break_info);
2775 /* Grab R lease over connection 1a */
2776 smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
2777 smb2_util_lease_state("R"), 0x4711);
2778 status = smb2_create(tree1a, mem_ctx, &io1);
2779 CHECK_STATUS(status, NT_STATUS_OK);
2780 h = io1.out.file.handle;
2781 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2782 ls1.lease_epoch += 1;
2783 CHECK_LEASE_V2(&io1, "R", true, LEASE1,
2784 0, 0, ls1.lease_epoch);
2786 /* Upgrade to RWH over connection 1b */
2787 ls1.lease_state = smb2_util_lease_state("RWH");
2788 status = smb2_create(tree1b, mem_ctx, &io1);
2789 CHECK_STATUS(status, NT_STATUS_OK);
2790 h2 = io1.out.file.handle;
2791 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2792 ls1.lease_epoch += 1;
2793 CHECK_LEASE_V2(&io1, "RHW", true, LEASE1,
2794 0, 0, ls1.lease_epoch);
2796 /* close over connection 1b */
2797 status = smb2_util_close(tree1b, h2);
2798 CHECK_STATUS(status, NT_STATUS_OK);
2800 /* Contend with LEASE2. */
2801 smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
2802 smb2_util_lease_state("RWH"), 0x11);
2803 status = smb2_create(tree1b, mem_ctx, &io2);
2804 CHECK_STATUS(status, NT_STATUS_OK);
2805 h3 = io2.out.file.handle;
2806 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2807 ls2.lease_epoch += 1;
2808 CHECK_LEASE_V2(&io2, "RH", true, LEASE2,
2809 0, 0, ls2.lease_epoch);
2811 /* Verify that we were only sent one break. */
2812 ls1.lease_epoch += 1;
2813 CHECK_BREAK_INFO_V2(tree1a->session->transport,
2814 "RHW", "RH", LEASE1, ls1.lease_epoch);
2816 /* again RH over connection 1b doesn't change the epoch */
2817 ls1.lease_state = smb2_util_lease_state("RH");
2818 status = smb2_create(tree1b, mem_ctx, &io1);
2819 CHECK_STATUS(status, NT_STATUS_OK);
2820 h2 = io1.out.file.handle;
2821 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2822 CHECK_LEASE_V2(&io1, "RH", true, LEASE1,
2823 0, 0, ls1.lease_epoch);
2825 /* close over connection 1b */
2826 status = smb2_util_close(tree1b, h2);
2827 CHECK_STATUS(status, NT_STATUS_OK);
2829 ZERO_STRUCT(break_info);
2831 ZERO_STRUCT(w);
2832 w.in.file.handle = h;
2833 w.in.offset = 0;
2834 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
2835 memset(w.in.data.data, 'o', w.in.data.length);
2836 status = smb2_write(tree1a, &w);
2837 CHECK_STATUS(status, NT_STATUS_OK);
2839 ls2.lease_epoch += 1;
2840 CHECK_BREAK_INFO_V2(tree1a->session->transport,
2841 "RH", "", LEASE2, ls2.lease_epoch);
2843 ZERO_STRUCT(break_info);
2845 ZERO_STRUCT(w);
2846 w.in.file.handle = h3;
2847 w.in.offset = 0;
2848 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
2849 memset(w.in.data.data, 'o', w.in.data.length);
2850 status = smb2_write(tree1b, &w);
2851 CHECK_STATUS(status, NT_STATUS_OK);
2853 ls1.lease_epoch += 1;
2854 CHECK_BREAK_INFO_V2(tree1a->session->transport,
2855 "RH", "", LEASE1, ls1.lease_epoch);
2857 done:
2858 smb2_util_close(tree1a, h);
2859 smb2_util_close(tree1b, h2);
2860 smb2_util_close(tree1b, h3);
2862 smb2_util_unlink(tree1a, fname);
2864 talloc_free(mem_ctx);
2866 return ret;
2869 static bool test_lease_timeout(struct torture_context *tctx,
2870 struct smb2_tree *tree)
2872 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2873 struct smb2_create io;
2874 struct smb2_lease ls1;
2875 struct smb2_lease ls2;
2876 struct smb2_handle h, hnew, h1b;
2877 NTSTATUS status;
2878 const char *fname = "lease_timeout.dat";
2879 bool ret = true;
2880 struct smb2_lease_break_ack ack = {};
2881 struct smb2_request *req2 = NULL;
2882 struct smb2_write w;
2883 uint32_t caps;
2885 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2886 if (!(caps & SMB2_CAP_LEASING)) {
2887 torture_skip(tctx, "leases are not supported");
2890 smb2_util_unlink(tree, fname);
2892 /* Grab a RWH lease. */
2893 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
2894 status = smb2_create(tree, mem_ctx, &io);
2895 CHECK_STATUS(status, NT_STATUS_OK);
2896 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2897 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
2898 h = io.out.file.handle;
2900 tree->session->transport->lease.handler = torture_lease_handler;
2901 tree->session->transport->lease.private_data = tree;
2902 tree->session->transport->oplock.handler = torture_oplock_handler;
2903 tree->session->transport->oplock.private_data = tree;
2906 * Just don't ack the lease break.
2908 ZERO_STRUCT(break_info);
2909 break_info.lease_skip_ack = true;
2911 /* Break with a RWH request. */
2912 smb2_lease_create(&io, &ls2, false, fname, LEASE2, smb2_util_lease_state("RWH"));
2913 req2 = smb2_create_send(tree, &io);
2914 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2915 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2917 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2919 /* Copy the break request. */
2920 ack.in.lease.lease_key =
2921 break_info.lease_break.current_lease.lease_key;
2922 ack.in.lease.lease_state =
2923 break_info.lease_break.new_lease_state;
2925 /* Now wait for the timeout and get the reply. */
2926 status = smb2_create_recv(req2, tctx, &io);
2927 CHECK_STATUS(status, NT_STATUS_OK);
2928 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2929 CHECK_LEASE(&io, "RH", true, LEASE2, 0);
2930 hnew = io.out.file.handle;
2932 /* Ack the break after the timeout... */
2933 status = smb2_lease_break_ack(tree, &ack);
2934 CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
2936 /* Get state of the original handle. */
2937 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
2938 status = smb2_create(tree, mem_ctx, &io);
2939 CHECK_STATUS(status, NT_STATUS_OK);
2940 CHECK_LEASE(&io, "", true, LEASE1, 0);
2941 smb2_util_close(tree, io.out.file.handle);
2943 /* Write on the original handle and make sure it's still valid. */
2944 ZERO_STRUCT(break_info);
2945 ZERO_STRUCT(w);
2946 w.in.file.handle = h;
2947 w.in.offset = 0;
2948 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
2949 memset(w.in.data.data, '1', w.in.data.length);
2950 status = smb2_write(tree, &w);
2951 CHECK_STATUS(status, NT_STATUS_OK);
2953 /* Causes new handle to break to NONE. */
2954 CHECK_BREAK_INFO("RH", "", LEASE2);
2956 /* Write on the new handle. */
2957 ZERO_STRUCT(break_info);
2958 ZERO_STRUCT(w);
2959 w.in.file.handle = hnew;
2960 w.in.offset = 0;
2961 w.in.data = data_blob_talloc(mem_ctx, NULL, 1024);
2962 memset(w.in.data.data, '2', w.in.data.length);
2963 status = smb2_write(tree, &w);
2964 CHECK_STATUS(status, NT_STATUS_OK);
2965 /* No break - original handle was already NONE. */
2966 CHECK_NO_BREAK(tctx);
2967 smb2_util_close(tree, hnew);
2969 /* Upgrade to R on LEASE1. */
2970 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
2971 status = smb2_create(tree, mem_ctx, &io);
2972 CHECK_STATUS(status, NT_STATUS_OK);
2973 CHECK_LEASE(&io, "R", true, LEASE1, 0);
2974 h1b = io.out.file.handle;
2975 smb2_util_close(tree, h1b);
2977 /* Upgrade to RWH on LEASE1. */
2978 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
2979 status = smb2_create(tree, mem_ctx, &io);
2980 CHECK_STATUS(status, NT_STATUS_OK);
2981 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
2982 h1b = io.out.file.handle;
2983 smb2_util_close(tree, h1b);
2985 done:
2986 smb2_util_close(tree, h);
2987 smb2_util_close(tree, hnew);
2988 smb2_util_close(tree, h1b);
2990 smb2_util_unlink(tree, fname);
2992 talloc_free(mem_ctx);
2994 return ret;
2998 struct torture_suite *torture_smb2_lease_init(void)
3000 struct torture_suite *suite =
3001 torture_suite_create(talloc_autofree_context(), "lease");
3003 torture_suite_add_1smb2_test(suite, "request", test_lease_request);
3004 torture_suite_add_1smb2_test(suite, "break_twice",
3005 test_lease_break_twice);
3006 torture_suite_add_1smb2_test(suite, "nobreakself",
3007 test_lease_nobreakself);
3008 torture_suite_add_1smb2_test(suite, "upgrade", test_lease_upgrade);
3009 torture_suite_add_1smb2_test(suite, "upgrade2", test_lease_upgrade2);
3010 torture_suite_add_1smb2_test(suite, "upgrade3", test_lease_upgrade3);
3011 torture_suite_add_1smb2_test(suite, "break", test_lease_break);
3012 torture_suite_add_1smb2_test(suite, "oplock", test_lease_oplock);
3013 torture_suite_add_1smb2_test(suite, "multibreak", test_lease_multibreak);
3014 torture_suite_add_1smb2_test(suite, "breaking1", test_lease_breaking1);
3015 torture_suite_add_1smb2_test(suite, "breaking2", test_lease_breaking2);
3016 torture_suite_add_1smb2_test(suite, "breaking3", test_lease_breaking3);
3017 torture_suite_add_1smb2_test(suite, "breaking4", test_lease_breaking4);
3018 torture_suite_add_1smb2_test(suite, "breaking5", test_lease_breaking5);
3019 torture_suite_add_1smb2_test(suite, "breaking6", test_lease_breaking6);
3020 torture_suite_add_1smb2_test(suite, "complex1", test_lease_complex1);
3021 torture_suite_add_1smb2_test(suite, "v2_request_parent",
3022 test_lease_v2_request_parent);
3023 torture_suite_add_1smb2_test(suite, "v2_request", test_lease_v2_request);
3024 torture_suite_add_1smb2_test(suite, "v2_epoch1", test_lease_v2_epoch1);
3025 torture_suite_add_1smb2_test(suite, "v2_epoch2", test_lease_v2_epoch2);
3026 torture_suite_add_1smb2_test(suite, "v2_epoch3", test_lease_v2_epoch3);
3027 torture_suite_add_1smb2_test(suite, "v2_complex1", test_lease_v2_complex1);
3028 torture_suite_add_1smb2_test(suite, "timeout", test_lease_timeout);
3030 suite->description = talloc_strdup(suite, "SMB2-LEASE tests");
3032 return suite;