torture: Fix uninitialized variables
[Samba.git] / source4 / torture / smb2 / lease.c
blob3ee915cc9522a0f605defbc96f4055b6823a84a4
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"
30 #include "libcli/security/security.h"
31 #include "lib/param/param.h"
33 #define CHECK_VAL(v, correct) do { \
34 if ((v) != (correct)) { \
35 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
36 __location__, #v, (int)(v), (int)(correct)); \
37 ret = false; \
38 }} while (0)
40 #define CHECK_STATUS(status, correct) do { \
41 if (!NT_STATUS_EQUAL(status, correct)) { \
42 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
43 nt_errstr(status), nt_errstr(correct)); \
44 ret = false; \
45 goto done; \
46 }} while (0)
48 #define CHECK_CREATED(__io, __created, __attribute) \
49 do { \
50 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
51 CHECK_VAL((__io)->out.alloc_size, 0); \
52 CHECK_VAL((__io)->out.size, 0); \
53 CHECK_VAL((__io)->out.file_attr, (__attribute)); \
54 CHECK_VAL((__io)->out.reserved2, 0); \
55 } while(0)
57 #define CHECK_LEASE(__io, __state, __oplevel, __key, __flags) \
58 do { \
59 CHECK_VAL((__io)->out.lease_response.lease_version, 1); \
60 if (__oplevel) { \
61 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
62 CHECK_VAL((__io)->out.lease_response.lease_key.data[0], (__key)); \
63 CHECK_VAL((__io)->out.lease_response.lease_key.data[1], ~(__key)); \
64 CHECK_VAL((__io)->out.lease_response.lease_state, smb2_util_lease_state(__state)); \
65 } else { \
66 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
67 CHECK_VAL((__io)->out.lease_response.lease_key.data[0], 0); \
68 CHECK_VAL((__io)->out.lease_response.lease_key.data[1], 0); \
69 CHECK_VAL((__io)->out.lease_response.lease_state, 0); \
70 } \
72 CHECK_VAL((__io)->out.lease_response.lease_flags, (__flags)); \
73 CHECK_VAL((__io)->out.lease_response.lease_duration, 0); \
74 CHECK_VAL((__io)->out.lease_response.lease_epoch, 0); \
75 } while(0)
77 #define CHECK_LEASE_V2(__io, __state, __oplevel, __key, __flags, __parent, __epoch) \
78 do { \
79 CHECK_VAL((__io)->out.lease_response_v2.lease_version, 2); \
80 if (__oplevel) { \
81 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
82 CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], (__key)); \
83 CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], ~(__key)); \
84 CHECK_VAL((__io)->out.lease_response_v2.lease_state, smb2_util_lease_state(__state)); \
85 } else { \
86 CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
87 CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], 0); \
88 CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], 0); \
89 CHECK_VAL((__io)->out.lease_response_v2.lease_state, 0); \
90 } \
92 CHECK_VAL((__io)->out.lease_response_v2.lease_flags, __flags); \
93 if (__flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET) { \
94 CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[0], (__parent)); \
95 CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[1], ~(__parent)); \
96 } \
97 CHECK_VAL((__io)->out.lease_response_v2.lease_duration, 0); \
98 CHECK_VAL((__io)->out.lease_response_v2.lease_epoch, (__epoch)); \
99 } while(0)
101 static const uint64_t LEASE1 = 0xBADC0FFEE0DDF00Dull;
102 static const uint64_t LEASE2 = 0xDEADBEEFFEEDBEADull;
103 static const uint64_t LEASE3 = 0xDAD0FFEDD00DF00Dull;
104 static const uint64_t LEASE4 = 0xBAD0FFEDD00DF00Dull;
106 #define NREQUEST_RESULTS 8
107 static const char *request_results[NREQUEST_RESULTS][2] = {
108 { "", "" },
109 { "R", "R" },
110 { "H", "" },
111 { "W", "" },
112 { "RH", "RH" },
113 { "RW", "RW" },
114 { "HW", "" },
115 { "RHW", "RHW" },
118 static bool test_lease_request(struct torture_context *tctx,
119 struct smb2_tree *tree)
121 TALLOC_CTX *mem_ctx = talloc_new(tctx);
122 struct smb2_create io;
123 struct smb2_lease ls;
124 struct smb2_handle h1 = {{0}};
125 struct smb2_handle h2 = {{0}};
126 NTSTATUS status;
127 const char *fname = "lease_request.dat";
128 const char *fname2 = "lease_request.2.dat";
129 const char *sname = "lease_request.dat:stream";
130 const char *dname = "lease_request.dir";
131 bool ret = true;
132 int i;
133 uint32_t caps;
135 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
136 if (!(caps & SMB2_CAP_LEASING)) {
137 torture_skip(tctx, "leases are not supported");
140 smb2_util_unlink(tree, fname);
141 smb2_util_unlink(tree, fname2);
142 smb2_util_rmdir(tree, dname);
144 /* Win7 is happy to grant RHW leases on files. */
145 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
146 status = smb2_create(tree, mem_ctx, &io);
147 CHECK_STATUS(status, NT_STATUS_OK);
148 h1 = io.out.file.handle;
149 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
150 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
152 /* But will reject leases on directories. */
153 if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
154 smb2_lease_create(&io, &ls, true, dname, LEASE2, smb2_util_lease_state("RHW"));
155 status = smb2_create(tree, mem_ctx, &io);
156 CHECK_STATUS(status, NT_STATUS_OK);
157 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
158 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
159 smb2_util_close(tree, io.out.file.handle);
162 /* Also rejects multiple files leased under the same key. */
163 smb2_lease_create(&io, &ls, true, fname2, LEASE1, smb2_util_lease_state("RHW"));
164 status = smb2_create(tree, mem_ctx, &io);
165 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
167 /* And grants leases on streams (with separate leasekey). */
168 smb2_lease_create(&io, &ls, false, sname, LEASE2, smb2_util_lease_state("RHW"));
169 status = smb2_create(tree, mem_ctx, &io);
170 h2 = io.out.file.handle;
171 CHECK_STATUS(status, NT_STATUS_OK);
172 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
173 CHECK_LEASE(&io, "RHW", true, LEASE2, 0);
174 smb2_util_close(tree, h2);
176 smb2_util_close(tree, h1);
178 /* Now see what combos are actually granted. */
179 for (i = 0; i < NREQUEST_RESULTS; i++) {
180 torture_comment(tctx, "Requesting lease type %s(%x),"
181 " expecting %s(%x)\n",
182 request_results[i][0], smb2_util_lease_state(request_results[i][0]),
183 request_results[i][1], smb2_util_lease_state(request_results[i][1]));
184 smb2_lease_create(&io, &ls, false, fname, LEASE1,
185 smb2_util_lease_state(request_results[i][0]));
186 status = smb2_create(tree, mem_ctx, &io);
187 h2 = io.out.file.handle;
188 CHECK_STATUS(status, NT_STATUS_OK);
189 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
190 CHECK_LEASE(&io, request_results[i][1], true, LEASE1, 0);
191 smb2_util_close(tree, io.out.file.handle);
194 done:
195 smb2_util_close(tree, h1);
196 smb2_util_close(tree, h2);
198 smb2_util_unlink(tree, fname);
199 smb2_util_unlink(tree, fname2);
200 smb2_util_rmdir(tree, dname);
202 talloc_free(mem_ctx);
204 return ret;
207 static bool test_lease_upgrade(struct torture_context *tctx,
208 struct smb2_tree *tree)
210 TALLOC_CTX *mem_ctx = talloc_new(tctx);
211 struct smb2_create io;
212 struct smb2_lease ls;
213 struct smb2_handle h = {{0}};
214 struct smb2_handle hnew = {{0}};
215 NTSTATUS status;
216 const char *fname = "lease_upgrade.dat";
217 bool ret = true;
218 uint32_t caps;
220 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
221 if (!(caps & SMB2_CAP_LEASING)) {
222 torture_skip(tctx, "leases are not supported");
225 smb2_util_unlink(tree, fname);
227 /* Grab a RH lease. */
228 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
229 status = smb2_create(tree, mem_ctx, &io);
230 CHECK_STATUS(status, NT_STATUS_OK);
231 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
232 CHECK_LEASE(&io, "RH", true, LEASE1, 0);
233 h = io.out.file.handle;
235 /* Upgrades (sidegrades?) to RW leave us with an RH. */
236 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RW"));
237 status = smb2_create(tree, mem_ctx, &io);
238 CHECK_STATUS(status, NT_STATUS_OK);
239 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
240 CHECK_LEASE(&io, "RH", true, LEASE1, 0);
241 hnew = io.out.file.handle;
243 smb2_util_close(tree, hnew);
245 /* Upgrade to RHW lease. */
246 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
247 status = smb2_create(tree, mem_ctx, &io);
248 CHECK_STATUS(status, NT_STATUS_OK);
249 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
250 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
251 hnew = io.out.file.handle;
253 smb2_util_close(tree, h);
254 h = hnew;
256 /* Attempt to downgrade - original lease state is maintained. */
257 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
258 status = smb2_create(tree, mem_ctx, &io);
259 CHECK_STATUS(status, NT_STATUS_OK);
260 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
261 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
262 hnew = io.out.file.handle;
264 smb2_util_close(tree, hnew);
266 done:
267 smb2_util_close(tree, h);
268 smb2_util_close(tree, hnew);
270 smb2_util_unlink(tree, fname);
272 talloc_free(mem_ctx);
274 return ret;
278 * upgrade2 test.
279 * full matrix of lease upgrade combinations
280 * (non-contended case)
282 * The summary of the behaviour is this:
283 * -------------------------------------
284 * An uncontended lease upgrade results in a change
285 * if and only if the requested lease state is
286 * - valid, and
287 * - strictly a superset of the lease state already held.
289 * In that case the resulting lease state is the one
290 * requested in the upgrade.
292 struct lease_upgrade2_test {
293 const char *initial;
294 const char *upgrade_to;
295 const char *expected;
298 #define NUM_LEASE_TYPES 5
299 #define NUM_UPGRADE_TESTS ( NUM_LEASE_TYPES * NUM_LEASE_TYPES )
300 struct lease_upgrade2_test lease_upgrade2_tests[NUM_UPGRADE_TESTS] = {
301 { "", "", "" },
302 { "", "R", "R" },
303 { "", "RH", "RH" },
304 { "", "RW", "RW" },
305 { "", "RWH", "RWH" },
307 { "R", "", "R" },
308 { "R", "R", "R" },
309 { "R", "RH", "RH" },
310 { "R", "RW", "RW" },
311 { "R", "RWH", "RWH" },
313 { "RH", "", "RH" },
314 { "RH", "R", "RH" },
315 { "RH", "RH", "RH" },
316 { "RH", "RW", "RH" },
317 { "RH", "RWH", "RWH" },
319 { "RW", "", "RW" },
320 { "RW", "R", "RW" },
321 { "RW", "RH", "RW" },
322 { "RW", "RW", "RW" },
323 { "RW", "RWH", "RWH" },
325 { "RWH", "", "RWH" },
326 { "RWH", "R", "RWH" },
327 { "RWH", "RH", "RWH" },
328 { "RWH", "RW", "RWH" },
329 { "RWH", "RWH", "RWH" },
332 static bool test_lease_upgrade2(struct torture_context *tctx,
333 struct smb2_tree *tree)
335 TALLOC_CTX *mem_ctx = talloc_new(tctx);
336 struct smb2_handle h, hnew;
337 NTSTATUS status;
338 struct smb2_create io;
339 struct smb2_lease ls;
340 const char *fname = "lease_upgrade2.dat";
341 bool ret = true;
342 int i;
343 uint32_t caps;
345 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
346 if (!(caps & SMB2_CAP_LEASING)) {
347 torture_skip(tctx, "leases are not supported");
350 for (i = 0; i < NUM_UPGRADE_TESTS; i++) {
351 struct lease_upgrade2_test t = lease_upgrade2_tests[i];
353 smb2_util_unlink(tree, fname);
355 /* Grab a lease. */
356 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.initial));
357 status = smb2_create(tree, mem_ctx, &io);
358 CHECK_STATUS(status, NT_STATUS_OK);
359 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
360 CHECK_LEASE(&io, t.initial, true, LEASE1, 0);
361 h = io.out.file.handle;
363 /* Upgrade. */
364 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to));
365 status = smb2_create(tree, mem_ctx, &io);
366 CHECK_STATUS(status, NT_STATUS_OK);
367 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
368 CHECK_LEASE(&io, t.expected, true, LEASE1, 0);
369 hnew = io.out.file.handle;
371 smb2_util_close(tree, hnew);
372 smb2_util_close(tree, h);
375 done:
376 smb2_util_close(tree, h);
377 smb2_util_close(tree, hnew);
379 smb2_util_unlink(tree, fname);
381 talloc_free(mem_ctx);
383 return ret;
387 #define CHECK_LEASE_BREAK(__lb, __oldstate, __state, __key) \
388 do { \
389 uint16_t __new = smb2_util_lease_state(__state); \
390 uint16_t __old = smb2_util_lease_state(__oldstate); \
391 CHECK_VAL((__lb)->new_lease_state, __new); \
392 CHECK_VAL((__lb)->current_lease.lease_state, __old); \
393 CHECK_VAL((__lb)->current_lease.lease_key.data[0], (__key)); \
394 CHECK_VAL((__lb)->current_lease.lease_key.data[1], ~(__key)); \
395 if (__old & (SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE)) { \
396 CHECK_VAL((__lb)->break_flags, \
397 SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED); \
398 } else { \
399 CHECK_VAL((__lb)->break_flags, 0); \
401 } while(0)
403 #define CHECK_LEASE_BREAK_ACK(__lba, __state, __key) \
404 do { \
405 CHECK_VAL((__lba)->out.reserved, 0); \
406 CHECK_VAL((__lba)->out.lease.lease_key.data[0], (__key)); \
407 CHECK_VAL((__lba)->out.lease.lease_key.data[1], ~(__key)); \
408 CHECK_VAL((__lba)->out.lease.lease_state, smb2_util_lease_state(__state)); \
409 CHECK_VAL((__lba)->out.lease.lease_flags, 0); \
410 CHECK_VAL((__lba)->out.lease.lease_duration, 0); \
411 } while(0)
413 static struct torture_lease_break {
414 struct smb2_lease_break lease_break;
415 struct smb2_transport *lease_transport;
416 bool lease_skip_ack;
417 struct smb2_lease_break_ack lease_break_ack;
418 int count;
419 int failures;
421 struct smb2_handle oplock_handle;
422 uint8_t held_oplock_level;
423 uint8_t oplock_level;
424 int oplock_count;
425 int oplock_failures;
426 } break_info;
428 #define CHECK_NO_BREAK(tctx) \
429 do { \
430 torture_wait_for_lease_break(tctx); \
431 CHECK_VAL(break_info.failures, 0); \
432 CHECK_VAL(break_info.count, 0); \
433 CHECK_VAL(break_info.oplock_failures, 0); \
434 CHECK_VAL(break_info.oplock_count, 0); \
435 } while(0)
437 #define CHECK_OPLOCK_BREAK(__brokento) \
438 do { \
439 torture_wait_for_lease_break(tctx); \
440 CHECK_VAL(break_info.oplock_count, 1); \
441 CHECK_VAL(break_info.oplock_failures, 0); \
442 CHECK_VAL(break_info.oplock_level, \
443 smb2_util_oplock_level(__brokento)); \
444 break_info.held_oplock_level = break_info.oplock_level; \
445 } while(0)
447 #define _CHECK_BREAK_INFO(__oldstate, __state, __key) \
448 do { \
449 torture_wait_for_lease_break(tctx); \
450 CHECK_VAL(break_info.failures, 0); \
451 CHECK_VAL(break_info.count, 1); \
452 CHECK_LEASE_BREAK(&break_info.lease_break, (__oldstate), \
453 (__state), (__key)); \
454 if (!break_info.lease_skip_ack && \
455 (break_info.lease_break.break_flags & \
456 SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED)) \
458 torture_wait_for_lease_break(tctx); \
459 CHECK_LEASE_BREAK_ACK(&break_info.lease_break_ack, \
460 (__state), (__key)); \
462 } while(0)
464 #define CHECK_BREAK_INFO(__oldstate, __state, __key) \
465 do { \
466 _CHECK_BREAK_INFO(__oldstate, __state, __key); \
467 CHECK_VAL(break_info.lease_break.new_epoch, 0); \
468 } while(0)
470 #define CHECK_BREAK_INFO_V2(__transport, __oldstate, __state, __key, __epoch) \
471 do { \
472 _CHECK_BREAK_INFO(__oldstate, __state, __key); \
473 CHECK_VAL(break_info.lease_break.new_epoch, __epoch); \
474 if (!TARGET_IS_SAMBA3(tctx)) { \
475 CHECK_VAL((uintptr_t)break_info.lease_transport, \
476 (uintptr_t)__transport); \
478 } while(0)
480 static void torture_lease_break_callback(struct smb2_request *req)
482 NTSTATUS status;
484 status = smb2_lease_break_ack_recv(req, &break_info.lease_break_ack);
485 if (!NT_STATUS_IS_OK(status))
486 break_info.failures++;
488 return;
491 /* a lease break request handler */
492 static bool torture_lease_handler(struct smb2_transport *transport,
493 const struct smb2_lease_break *lb,
494 void *private_data)
496 struct smb2_tree *tree = private_data;
497 struct smb2_lease_break_ack io;
498 struct smb2_request *req;
500 break_info.lease_transport = transport;
501 break_info.lease_break = *lb;
502 break_info.count++;
504 if (break_info.lease_skip_ack) {
505 return true;
508 if (lb->break_flags & SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED) {
509 ZERO_STRUCT(io);
510 io.in.lease.lease_key = lb->current_lease.lease_key;
511 io.in.lease.lease_state = lb->new_lease_state;
513 req = smb2_lease_break_ack_send(tree, &io);
514 req->async.fn = torture_lease_break_callback;
515 req->async.private_data = NULL;
518 return true;
522 * upgrade3:
523 * full matrix of lease upgrade combinations
524 * (contended case)
526 * We start with 2 leases, and check how one can
527 * be upgraded
529 * The summary of the behaviour is this:
530 * -------------------------------------
532 * If we have two leases (lease1 and lease2) on the same file,
533 * then attempt to upgrade lease1 results in a change if and only
534 * if the requested lease state:
535 * - is valid,
536 * - is strictly a superset of lease1, and
537 * - can held together with lease2.
539 * In that case, the resuling lease state of the upgraded lease1
540 * is the state requested in the upgrade. lease2 is not broken
541 * and remains unchanged.
543 * Note that this contrasts the case of directly opening with
544 * an initial requested lease state, in which case you get that
545 * portion of the requested state that can be shared with the
546 * already existing leases (or the states that they get broken to).
548 struct lease_upgrade3_test {
549 const char *held1;
550 const char *held2;
551 const char *upgrade_to;
552 const char *upgraded_to;
555 #define NUM_UPGRADE3_TESTS ( 20 )
556 struct lease_upgrade3_test lease_upgrade3_tests[NUM_UPGRADE3_TESTS] = {
557 {"R", "R", "", "R" },
558 {"R", "R", "R", "R" },
559 {"R", "R", "RW", "R" },
560 {"R", "R", "RH", "RH" },
561 {"R", "R", "RHW", "R" },
563 {"R", "RH", "", "R" },
564 {"R", "RH", "R", "R" },
565 {"R", "RH", "RW", "R" },
566 {"R", "RH", "RH", "RH" },
567 {"R", "RH", "RHW", "R" },
569 {"RH", "R", "", "RH" },
570 {"RH", "R", "R", "RH" },
571 {"RH", "R", "RW", "RH" },
572 {"RH", "R", "RH", "RH" },
573 {"RH", "R", "RHW", "RH" },
575 {"RH", "RH", "", "RH" },
576 {"RH", "RH", "R", "RH" },
577 {"RH", "RH", "RW", "RH" },
578 {"RH", "RH", "RH", "RH" },
579 {"RH", "RH", "RHW", "RH" },
582 static bool test_lease_upgrade3(struct torture_context *tctx,
583 struct smb2_tree *tree)
585 TALLOC_CTX *mem_ctx = talloc_new(tctx);
586 struct smb2_handle h, h2, hnew;
587 NTSTATUS status;
588 struct smb2_create io;
589 struct smb2_lease ls;
590 const char *fname = "lease_upgrade3.dat";
591 bool ret = true;
592 int i;
593 uint32_t caps;
595 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
596 if (!(caps & SMB2_CAP_LEASING)) {
597 torture_skip(tctx, "leases are not supported");
600 tree->session->transport->lease.handler = torture_lease_handler;
601 tree->session->transport->lease.private_data = tree;
603 smb2_util_unlink(tree, fname);
605 for (i = 0; i < NUM_UPGRADE3_TESTS; i++) {
606 struct lease_upgrade3_test t = lease_upgrade3_tests[i];
608 smb2_util_unlink(tree, fname);
610 ZERO_STRUCT(break_info);
612 /* grab first lease */
613 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.held1));
614 status = smb2_create(tree, mem_ctx, &io);
615 CHECK_STATUS(status, NT_STATUS_OK);
616 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
617 CHECK_LEASE(&io, t.held1, true, LEASE1, 0);
618 h = io.out.file.handle;
620 /* grab second lease */
621 smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state(t.held2));
622 status = smb2_create(tree, mem_ctx, &io);
623 CHECK_STATUS(status, NT_STATUS_OK);
624 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
625 CHECK_LEASE(&io, t.held2, true, LEASE2, 0);
626 h2 = io.out.file.handle;
628 /* no break has happened */
629 CHECK_VAL(break_info.count, 0);
630 CHECK_VAL(break_info.failures, 0);
632 /* try to upgrade lease1 */
633 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to));
634 status = smb2_create(tree, mem_ctx, &io);
635 CHECK_STATUS(status, NT_STATUS_OK);
636 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
637 CHECK_LEASE(&io, t.upgraded_to, true, LEASE1, 0);
638 hnew = io.out.file.handle;
640 /* no break has happened */
641 CHECK_VAL(break_info.count, 0);
642 CHECK_VAL(break_info.failures, 0);
644 smb2_util_close(tree, hnew);
645 smb2_util_close(tree, h);
646 smb2_util_close(tree, h2);
649 done:
650 smb2_util_close(tree, h);
651 smb2_util_close(tree, hnew);
652 smb2_util_close(tree, h2);
654 smb2_util_unlink(tree, fname);
656 talloc_free(mem_ctx);
658 return ret;
664 Timer handler function notifies the registering function that time is up
666 static void timeout_cb(struct tevent_context *ev,
667 struct tevent_timer *te,
668 struct timeval current_time,
669 void *private_data)
671 bool *timesup = (bool *)private_data;
672 *timesup = true;
673 return;
677 Wait a short period of time to receive a single oplock break request
679 static void torture_wait_for_lease_break(struct torture_context *tctx)
681 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
682 struct tevent_timer *te = NULL;
683 struct timeval ne;
684 bool timesup = false;
685 int old_count = break_info.count;
687 /* Wait .1 seconds for an lease break */
688 ne = tevent_timeval_current_ofs(0, 100000);
690 te = tevent_add_timer(tctx->ev, tmp_ctx, ne, timeout_cb, &timesup);
691 if (te == NULL) {
692 torture_comment(tctx, "Failed to wait for an oplock break. "
693 "test results may not be accurate.");
694 goto done;
697 while (!timesup && break_info.count < old_count + 1) {
698 if (tevent_loop_once(tctx->ev) != 0) {
699 torture_comment(tctx, "Failed to wait for an oplock "
700 "break. test results may not be "
701 "accurate.");
702 goto done;
706 done:
707 /* We don't know if the timed event fired and was freed, we received
708 * our oplock break, or some other event triggered the loop. Thus,
709 * we create a tmp_ctx to be able to safely free/remove the timed
710 * event in all 3 cases. */
711 talloc_free(tmp_ctx);
713 return;
717 break_results should be read as "held lease, new lease, hold broken to, new
718 grant", i.e. { "RH", "RW", "RH", "R" } means that if key1 holds RH and key2
719 tries for RW, key1 will be broken to RH (in this case, not broken at all)
720 and key2 will be granted R.
722 Note: break_results only includes things that Win7 will actually grant (see
723 request_results above).
725 #define NBREAK_RESULTS 16
726 static const char *break_results[NBREAK_RESULTS][4] = {
727 {"R", "R", "R", "R"},
728 {"R", "RH", "R", "RH"},
729 {"R", "RW", "R", "R"},
730 {"R", "RHW", "R", "RH"},
732 {"RH", "R", "RH", "R"},
733 {"RH", "RH", "RH", "RH"},
734 {"RH", "RW", "RH", "R"},
735 {"RH", "RHW", "RH", "RH"},
737 {"RW", "R", "R", "R"},
738 {"RW", "RH", "R", "RH"},
739 {"RW", "RW", "R", "R"},
740 {"RW", "RHW", "R", "RH"},
742 {"RHW", "R", "RH", "R"},
743 {"RHW", "RH", "RH", "RH"},
744 {"RHW", "RW", "RH", "R"},
745 {"RHW", "RHW", "RH", "RH"},
748 static bool test_lease_break(struct torture_context *tctx,
749 struct smb2_tree *tree)
751 TALLOC_CTX *mem_ctx = talloc_new(tctx);
752 struct smb2_create io;
753 struct smb2_lease ls;
754 struct smb2_handle h, h2, h3;
755 NTSTATUS status;
756 const char *fname = "lease_break.dat";
757 bool ret = true;
758 int i;
759 uint32_t caps;
761 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
762 if (!(caps & SMB2_CAP_LEASING)) {
763 torture_skip(tctx, "leases are not supported");
766 tree->session->transport->lease.handler = torture_lease_handler;
767 tree->session->transport->lease.private_data = tree;
769 smb2_util_unlink(tree, fname);
771 for (i = 0; i < NBREAK_RESULTS; i++) {
772 const char *held = break_results[i][0];
773 const char *contend = break_results[i][1];
774 const char *brokento = break_results[i][2];
775 const char *granted = break_results[i][3];
776 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
777 "expecting break to %s(%x) and grant of %s(%x)\n",
778 held, smb2_util_lease_state(held), contend, smb2_util_lease_state(contend),
779 brokento, smb2_util_lease_state(brokento), granted, smb2_util_lease_state(granted));
781 ZERO_STRUCT(break_info);
783 /* Grab lease. */
784 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held));
785 status = smb2_create(tree, mem_ctx, &io);
786 CHECK_STATUS(status, NT_STATUS_OK);
787 h = io.out.file.handle;
788 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
789 CHECK_LEASE(&io, held, true, LEASE1, 0);
791 /* Possibly contend lease. */
792 smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state(contend));
793 status = smb2_create(tree, mem_ctx, &io);
794 CHECK_STATUS(status, NT_STATUS_OK);
795 h2 = io.out.file.handle;
796 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
797 CHECK_LEASE(&io, granted, true, LEASE2, 0);
799 if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) {
800 CHECK_BREAK_INFO(held, brokento, LEASE1);
801 } else {
802 CHECK_NO_BREAK(tctx);
805 ZERO_STRUCT(break_info);
808 Now verify that an attempt to upgrade LEASE1 results in no
809 break and no change in LEASE1.
811 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
812 status = smb2_create(tree, mem_ctx, &io);
813 CHECK_STATUS(status, NT_STATUS_OK);
814 h3 = io.out.file.handle;
815 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
816 CHECK_LEASE(&io, brokento, true, LEASE1, 0);
817 CHECK_VAL(break_info.count, 0);
818 CHECK_VAL(break_info.failures, 0);
820 smb2_util_close(tree, h);
821 smb2_util_close(tree, h2);
822 smb2_util_close(tree, h3);
824 status = smb2_util_unlink(tree, fname);
825 CHECK_STATUS(status, NT_STATUS_OK);
828 done:
829 smb2_util_close(tree, h);
830 smb2_util_close(tree, h2);
832 smb2_util_unlink(tree, fname);
834 talloc_free(mem_ctx);
836 return ret;
839 static bool test_lease_nobreakself(struct torture_context *tctx,
840 struct smb2_tree *tree)
842 TALLOC_CTX *mem_ctx = talloc_new(tctx);
843 struct smb2_create io;
844 struct smb2_lease ls;
845 struct smb2_handle h1 = {{0}};
846 struct smb2_handle h2 = {{0}};
847 NTSTATUS status;
848 const char *fname = "lease_nobreakself.dat";
849 bool ret = true;
850 uint32_t caps;
851 char c = 0;
853 caps = smb2cli_conn_server_capabilities(
854 tree->session->transport->conn);
855 if (!(caps & SMB2_CAP_LEASING)) {
856 torture_skip(tctx, "leases are not supported");
859 smb2_util_unlink(tree, fname);
861 /* Win7 is happy to grant RHW leases on files. */
862 smb2_lease_create(&io, &ls, false, fname, LEASE1,
863 smb2_util_lease_state("R"));
864 status = smb2_create(tree, mem_ctx, &io);
865 CHECK_STATUS(status, NT_STATUS_OK);
866 h1 = io.out.file.handle;
867 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
868 CHECK_LEASE(&io, "R", true, LEASE1, 0);
870 smb2_lease_create(&io, &ls, false, fname, LEASE2,
871 smb2_util_lease_state("R"));
872 status = smb2_create(tree, mem_ctx, &io);
873 CHECK_STATUS(status, NT_STATUS_OK);
874 h2 = io.out.file.handle;
875 CHECK_LEASE(&io, "R", true, LEASE2, 0);
877 ZERO_STRUCT(break_info);
879 tree->session->transport->lease.handler = torture_lease_handler;
880 tree->session->transport->lease.private_data = tree;
882 /* Make sure we don't break ourselves on write */
884 status = smb2_util_write(tree, h1, &c, 0, 1);
885 CHECK_STATUS(status, NT_STATUS_OK);
886 CHECK_BREAK_INFO("R", "", LEASE2);
888 /* Try the other way round. First, upgrade LEASE2 to R again */
890 smb2_lease_create(&io, &ls, false, fname, LEASE2,
891 smb2_util_lease_state("R"));
892 status = smb2_create(tree, mem_ctx, &io);
893 CHECK_STATUS(status, NT_STATUS_OK);
894 CHECK_LEASE(&io, "R", true, LEASE2, 0);
895 smb2_util_close(tree, io.out.file.handle);
897 /* Now break LEASE1 via h2 */
899 ZERO_STRUCT(break_info);
900 status = smb2_util_write(tree, h2, &c, 0, 1);
901 CHECK_STATUS(status, NT_STATUS_OK);
902 CHECK_BREAK_INFO("R", "", LEASE1);
904 /* .. and break LEASE2 via h1 */
906 ZERO_STRUCT(break_info);
907 status = smb2_util_write(tree, h1, &c, 0, 1);
908 CHECK_STATUS(status, NT_STATUS_OK);
909 CHECK_BREAK_INFO("R", "", LEASE2);
911 done:
912 smb2_util_close(tree, h2);
913 smb2_util_close(tree, h1);
914 smb2_util_unlink(tree, fname);
915 talloc_free(mem_ctx);
916 return ret;
919 static bool test_lease_statopen(struct torture_context *tctx,
920 struct smb2_tree *tree)
922 TALLOC_CTX *mem_ctx = talloc_new(tctx);
923 struct smb2_create io;
924 struct smb2_lease ls;
925 struct smb2_handle h1 = {{0}};
926 struct smb2_handle h2 = {{0}};
927 NTSTATUS status;
928 const char *fname = "lease_statopen.dat";
929 bool ret = true;
930 uint32_t caps;
932 caps = smb2cli_conn_server_capabilities(
933 tree->session->transport->conn);
934 if (!(caps & SMB2_CAP_LEASING)) {
935 torture_skip(tctx, "leases are not supported");
938 smb2_util_unlink(tree, fname);
940 /* Create file. */
941 smb2_lease_create(&io, &ls, false, fname, LEASE1,
942 smb2_util_lease_state("RWH"));
943 status = smb2_create(tree, mem_ctx, &io);
944 CHECK_STATUS(status, NT_STATUS_OK);
945 h1 = io.out.file.handle;
946 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
947 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
948 smb2_util_close(tree, h1);
950 /* Stat open file with RWH lease. */
951 smb2_lease_create_share(&io, &ls, false, fname, 0, LEASE1,
952 smb2_util_lease_state("RWH"));
953 io.in.desired_access = FILE_READ_ATTRIBUTES;
954 status = smb2_create(tree, mem_ctx, &io);
955 CHECK_STATUS(status, NT_STATUS_OK);
956 h2 = io.out.file.handle;
957 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
959 ZERO_STRUCT(break_info);
961 tree->session->transport->lease.handler = torture_lease_handler;
962 tree->session->transport->lease.private_data = tree;
964 /* Ensure non-stat open doesn't break and gets same lease
965 state as existing stat open. */
966 smb2_lease_create(&io, &ls, false, fname, LEASE1,
967 smb2_util_lease_state(""));
968 status = smb2_create(tree, mem_ctx, &io);
969 CHECK_STATUS(status, NT_STATUS_OK);
970 h1 = io.out.file.handle;
971 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
972 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
974 CHECK_NO_BREAK(tctx);
975 smb2_util_close(tree, h1);
977 /* Open with conflicting lease. stat open should break down to RH */
978 smb2_lease_create(&io, &ls, false, fname, LEASE2,
979 smb2_util_lease_state("RWH"));
980 status = smb2_create(tree, mem_ctx, &io);
981 CHECK_STATUS(status, NT_STATUS_OK);
982 h1 = io.out.file.handle;
983 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
984 CHECK_LEASE(&io, "RH", true, LEASE2, 0);
986 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
988 done:
989 smb2_util_close(tree, h2);
990 smb2_util_close(tree, h1);
991 smb2_util_unlink(tree, fname);
992 talloc_free(mem_ctx);
993 return ret;
997 static void torture_oplock_break_callback(struct smb2_request *req)
999 NTSTATUS status;
1000 struct smb2_break br;
1002 ZERO_STRUCT(br);
1003 status = smb2_break_recv(req, &br);
1004 if (!NT_STATUS_IS_OK(status))
1005 break_info.oplock_failures++;
1007 return;
1010 /* a oplock break request handler */
1011 static bool torture_oplock_handler(struct smb2_transport *transport,
1012 const struct smb2_handle *handle,
1013 uint8_t level, void *private_data)
1015 struct smb2_tree *tree = private_data;
1016 struct smb2_request *req;
1017 struct smb2_break br;
1019 break_info.oplock_handle = *handle;
1020 break_info.oplock_level = level;
1021 break_info.oplock_count++;
1023 ZERO_STRUCT(br);
1024 br.in.file.handle = *handle;
1025 br.in.oplock_level = level;
1027 if (break_info.held_oplock_level > SMB2_OPLOCK_LEVEL_II) {
1028 req = smb2_break_send(tree, &br);
1029 req->async.fn = torture_oplock_break_callback;
1030 req->async.private_data = NULL;
1032 break_info.held_oplock_level = level;
1034 return true;
1037 #define NOPLOCK_RESULTS 12
1038 static const char *oplock_results[NOPLOCK_RESULTS][4] = {
1039 {"R", "s", "R", "s"},
1040 {"R", "x", "R", "s"},
1041 {"R", "b", "R", "s"},
1043 {"RH", "s", "RH", ""},
1044 {"RH", "x", "RH", ""},
1045 {"RH", "b", "RH", ""},
1047 {"RW", "s", "R", "s"},
1048 {"RW", "x", "R", "s"},
1049 {"RW", "b", "R", "s"},
1051 {"RHW", "s", "RH", ""},
1052 {"RHW", "x", "RH", ""},
1053 {"RHW", "b", "RH", ""},
1056 static const char *oplock_results_2[NOPLOCK_RESULTS][4] = {
1057 {"s", "R", "s", "R"},
1058 {"s", "RH", "s", "R"},
1059 {"s", "RW", "s", "R"},
1060 {"s", "RHW", "s", "R"},
1062 {"x", "R", "s", "R"},
1063 {"x", "RH", "s", "R"},
1064 {"x", "RW", "s", "R"},
1065 {"x", "RHW", "s", "R"},
1067 {"b", "R", "s", "R"},
1068 {"b", "RH", "s", "R"},
1069 {"b", "RW", "s", "R"},
1070 {"b", "RHW", "s", "R"},
1073 static bool test_lease_oplock(struct torture_context *tctx,
1074 struct smb2_tree *tree)
1076 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1077 struct smb2_create io;
1078 struct smb2_lease ls;
1079 struct smb2_handle h, h2;
1080 NTSTATUS status;
1081 const char *fname = "lease_oplock.dat";
1082 bool ret = true;
1083 int i;
1084 uint32_t caps;
1086 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1087 if (!(caps & SMB2_CAP_LEASING)) {
1088 torture_skip(tctx, "leases are not supported");
1091 tree->session->transport->lease.handler = torture_lease_handler;
1092 tree->session->transport->lease.private_data = tree;
1093 tree->session->transport->oplock.handler = torture_oplock_handler;
1094 tree->session->transport->oplock.private_data = tree;
1096 smb2_util_unlink(tree, fname);
1098 for (i = 0; i < NOPLOCK_RESULTS; i++) {
1099 const char *held = oplock_results[i][0];
1100 const char *contend = oplock_results[i][1];
1101 const char *brokento = oplock_results[i][2];
1102 const char *granted = oplock_results[i][3];
1103 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
1104 "expecting break to %s(%x) and grant of %s(%x)\n",
1105 held, smb2_util_lease_state(held), contend, smb2_util_oplock_level(contend),
1106 brokento, smb2_util_lease_state(brokento), granted, smb2_util_oplock_level(granted));
1108 ZERO_STRUCT(break_info);
1110 /* Grab lease. */
1111 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held));
1112 status = smb2_create(tree, mem_ctx, &io);
1113 CHECK_STATUS(status, NT_STATUS_OK);
1114 h = io.out.file.handle;
1115 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1116 CHECK_LEASE(&io, held, true, LEASE1, 0);
1118 /* Does an oplock contend the lease? */
1119 smb2_oplock_create(&io, fname, smb2_util_oplock_level(contend));
1120 status = smb2_create(tree, mem_ctx, &io);
1121 CHECK_STATUS(status, NT_STATUS_OK);
1122 h2 = io.out.file.handle;
1123 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1124 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(granted));
1125 break_info.held_oplock_level = io.out.oplock_level;
1127 if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) {
1128 CHECK_BREAK_INFO(held, brokento, LEASE1);
1129 } else {
1130 CHECK_NO_BREAK(tctx);
1133 smb2_util_close(tree, h);
1134 smb2_util_close(tree, h2);
1136 status = smb2_util_unlink(tree, fname);
1137 CHECK_STATUS(status, NT_STATUS_OK);
1140 for (i = 0; i < NOPLOCK_RESULTS; i++) {
1141 const char *held = oplock_results_2[i][0];
1142 const char *contend = oplock_results_2[i][1];
1143 const char *brokento = oplock_results_2[i][2];
1144 const char *granted = oplock_results_2[i][3];
1145 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
1146 "expecting break to %s(%x) and grant of %s(%x)\n",
1147 held, smb2_util_oplock_level(held), contend, smb2_util_lease_state(contend),
1148 brokento, smb2_util_oplock_level(brokento), granted, smb2_util_lease_state(granted));
1150 ZERO_STRUCT(break_info);
1152 /* Grab an oplock. */
1153 smb2_oplock_create(&io, fname, smb2_util_oplock_level(held));
1154 status = smb2_create(tree, mem_ctx, &io);
1155 CHECK_STATUS(status, NT_STATUS_OK);
1156 h = io.out.file.handle;
1157 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1158 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(held));
1159 break_info.held_oplock_level = io.out.oplock_level;
1161 /* Grab lease. */
1162 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(contend));
1163 status = smb2_create(tree, mem_ctx, &io);
1164 CHECK_STATUS(status, NT_STATUS_OK);
1165 h2 = io.out.file.handle;
1166 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1167 CHECK_LEASE(&io, granted, true, LEASE1, 0);
1169 if (smb2_util_oplock_level(held) != smb2_util_oplock_level(brokento)) {
1170 CHECK_OPLOCK_BREAK(brokento);
1171 } else {
1172 CHECK_NO_BREAK(tctx);
1175 smb2_util_close(tree, h);
1176 smb2_util_close(tree, h2);
1178 status = smb2_util_unlink(tree, fname);
1179 CHECK_STATUS(status, NT_STATUS_OK);
1182 done:
1183 smb2_util_close(tree, h);
1184 smb2_util_close(tree, h2);
1186 smb2_util_unlink(tree, fname);
1188 talloc_free(mem_ctx);
1190 return ret;
1193 static bool test_lease_multibreak(struct torture_context *tctx,
1194 struct smb2_tree *tree)
1196 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1197 struct smb2_create io;
1198 struct smb2_lease ls;
1199 struct smb2_handle h = {{0}};
1200 struct smb2_handle h2 = {{0}};
1201 struct smb2_handle h3 = {{0}};
1202 struct smb2_write w;
1203 NTSTATUS status;
1204 const char *fname = "lease_multibreak.dat";
1205 bool ret = true;
1206 uint32_t caps;
1208 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1209 if (!(caps & SMB2_CAP_LEASING)) {
1210 torture_skip(tctx, "leases are not supported");
1213 tree->session->transport->lease.handler = torture_lease_handler;
1214 tree->session->transport->lease.private_data = tree;
1215 tree->session->transport->oplock.handler = torture_oplock_handler;
1216 tree->session->transport->oplock.private_data = tree;
1218 smb2_util_unlink(tree, fname);
1220 ZERO_STRUCT(break_info);
1222 /* Grab lease, upgrade to RHW .. */
1223 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
1224 status = smb2_create(tree, mem_ctx, &io);
1225 CHECK_STATUS(status, NT_STATUS_OK);
1226 h = io.out.file.handle;
1227 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1228 CHECK_LEASE(&io, "RH", true, LEASE1, 0);
1230 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
1231 status = smb2_create(tree, mem_ctx, &io);
1232 CHECK_STATUS(status, NT_STATUS_OK);
1233 h2 = io.out.file.handle;
1234 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1235 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
1237 /* Contend with LEASE2. */
1238 smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state("RHW"));
1239 status = smb2_create(tree, mem_ctx, &io);
1240 CHECK_STATUS(status, NT_STATUS_OK);
1241 h3 = io.out.file.handle;
1242 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1243 CHECK_LEASE(&io, "RH", true, LEASE2, 0);
1245 /* Verify that we were only sent one break. */
1246 CHECK_BREAK_INFO("RHW", "RH", LEASE1);
1248 /* Drop LEASE1 / LEASE2 */
1249 status = smb2_util_close(tree, h);
1250 CHECK_STATUS(status, NT_STATUS_OK);
1251 status = smb2_util_close(tree, h2);
1252 CHECK_STATUS(status, NT_STATUS_OK);
1253 status = smb2_util_close(tree, h3);
1254 CHECK_STATUS(status, NT_STATUS_OK);
1256 ZERO_STRUCT(break_info);
1258 /* Grab an R lease. */
1259 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("R"));
1260 status = smb2_create(tree, mem_ctx, &io);
1261 CHECK_STATUS(status, NT_STATUS_OK);
1262 h = io.out.file.handle;
1263 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1264 CHECK_LEASE(&io, "R", true, LEASE1, 0);
1266 /* Grab a level-II oplock. */
1267 smb2_oplock_create(&io, fname, smb2_util_oplock_level("s"));
1268 status = smb2_create(tree, mem_ctx, &io);
1269 CHECK_STATUS(status, NT_STATUS_OK);
1270 h2 = io.out.file.handle;
1271 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1272 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
1273 break_info.held_oplock_level = io.out.oplock_level;
1275 /* Verify no breaks. */
1276 CHECK_NO_BREAK(tctx);
1278 /* Open for truncate, force a break. */
1279 smb2_generic_create(&io, NULL, false, fname,
1280 NTCREATEX_DISP_OVERWRITE_IF, smb2_util_oplock_level(""), 0, 0);
1281 status = smb2_create(tree, mem_ctx, &io);
1282 CHECK_STATUS(status, NT_STATUS_OK);
1283 h3 = io.out.file.handle;
1284 CHECK_CREATED(&io, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
1285 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(""));
1286 break_info.held_oplock_level = io.out.oplock_level;
1288 /* Sleep, use a write to clear the recv queue. */
1289 smb_msleep(250);
1290 ZERO_STRUCT(w);
1291 w.in.file.handle = h3;
1292 w.in.offset = 0;
1293 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
1294 memset(w.in.data.data, 'o', w.in.data.length);
1295 status = smb2_write(tree, &w);
1296 CHECK_STATUS(status, NT_STATUS_OK);
1298 /* Verify one oplock break, one lease break. */
1299 CHECK_OPLOCK_BREAK("");
1300 CHECK_BREAK_INFO("R", "", LEASE1);
1302 done:
1303 smb2_util_close(tree, h);
1304 smb2_util_close(tree, h2);
1305 smb2_util_close(tree, h3);
1307 smb2_util_unlink(tree, fname);
1309 talloc_free(mem_ctx);
1311 return ret;
1314 static bool test_lease_v2_request_parent(struct torture_context *tctx,
1315 struct smb2_tree *tree)
1317 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1318 struct smb2_create io;
1319 struct smb2_lease ls;
1320 struct smb2_handle h1 = {{0}};
1321 uint64_t parent = LEASE2;
1322 NTSTATUS status;
1323 const char *fname = "lease_v2_request_parent.dat";
1324 bool ret = true;
1325 uint32_t caps;
1326 enum protocol_types protocol;
1328 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1329 if (!(caps & SMB2_CAP_LEASING)) {
1330 torture_skip(tctx, "leases are not supported");
1332 if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
1333 torture_skip(tctx, "directory leases are not supported");
1336 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1337 if (protocol < PROTOCOL_SMB3_00) {
1338 torture_skip(tctx, "v2 leases are not supported");
1341 smb2_util_unlink(tree, fname);
1343 ZERO_STRUCT(break_info);
1345 ZERO_STRUCT(io);
1346 smb2_lease_v2_create_share(&io, &ls, false, fname,
1347 smb2_util_share_access("RWD"),
1348 LEASE1, &parent,
1349 smb2_util_lease_state("RHW"),
1350 0x11);
1352 status = smb2_create(tree, mem_ctx, &io);
1353 CHECK_STATUS(status, NT_STATUS_OK);
1354 h1 = io.out.file.handle;
1355 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1356 CHECK_LEASE_V2(&io, "RHW", true, LEASE1,
1357 SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2,
1358 ls.lease_epoch + 1);
1360 done:
1361 smb2_util_close(tree, h1);
1362 smb2_util_unlink(tree, fname);
1364 talloc_free(mem_ctx);
1366 return ret;
1369 static bool test_lease_break_twice(struct torture_context *tctx,
1370 struct smb2_tree *tree)
1372 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1373 struct smb2_create io;
1374 struct smb2_lease ls1;
1375 struct smb2_lease ls2;
1376 struct smb2_handle h1 = {{0}};
1377 NTSTATUS status;
1378 const char *fname = "lease_break_twice.dat";
1379 bool ret = true;
1380 uint32_t caps;
1381 enum protocol_types protocol;
1383 caps = smb2cli_conn_server_capabilities(
1384 tree->session->transport->conn);
1385 if (!(caps & SMB2_CAP_LEASING)) {
1386 torture_skip(tctx, "leases are not supported");
1389 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1390 if (protocol < PROTOCOL_SMB3_00) {
1391 torture_skip(tctx, "v2 leases are not supported");
1394 smb2_util_unlink(tree, fname);
1396 ZERO_STRUCT(break_info);
1397 ZERO_STRUCT(io);
1399 smb2_lease_v2_create_share(
1400 &io, &ls1, false, fname, smb2_util_share_access("RWD"),
1401 LEASE1, NULL, smb2_util_lease_state("RWH"), 0x11);
1403 status = smb2_create(tree, mem_ctx, &io);
1404 CHECK_STATUS(status, NT_STATUS_OK);
1405 h1 = io.out.file.handle;
1406 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1407 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch + 1);
1409 tree->session->transport->lease.handler = torture_lease_handler;
1410 tree->session->transport->lease.private_data = tree;
1412 ZERO_STRUCT(break_info);
1414 smb2_lease_v2_create_share(
1415 &io, &ls2, false, fname, smb2_util_share_access("R"),
1416 LEASE2, NULL, smb2_util_lease_state("RWH"), 0x22);
1418 status = smb2_create(tree, mem_ctx, &io);
1419 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
1420 CHECK_BREAK_INFO_V2(tree->session->transport,
1421 "RWH", "RW", LEASE1, ls1.lease_epoch + 2);
1423 smb2_lease_v2_create_share(
1424 &io, &ls2, false, fname, smb2_util_share_access("RWD"),
1425 LEASE2, NULL, smb2_util_lease_state("RWH"), 0x22);
1427 ZERO_STRUCT(break_info);
1429 status = smb2_create(tree, mem_ctx, &io);
1430 CHECK_STATUS(status, NT_STATUS_OK);
1431 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch + 1);
1432 CHECK_BREAK_INFO_V2(tree->session->transport,
1433 "RW", "R", LEASE1, ls1.lease_epoch + 3);
1435 done:
1436 smb2_util_close(tree, h1);
1437 smb2_util_unlink(tree, fname);
1438 talloc_free(mem_ctx);
1439 return ret;
1442 static bool test_lease_v2_request(struct torture_context *tctx,
1443 struct smb2_tree *tree)
1445 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1446 struct smb2_create io;
1447 struct smb2_lease ls1, ls2, ls2t, ls3, ls4;
1448 struct smb2_handle h1 = {{0}};
1449 struct smb2_handle h2 = {{0}};
1450 struct smb2_handle h3 = {{0}};
1451 struct smb2_handle h4 = {{0}};
1452 struct smb2_handle h5 = {{0}};
1453 struct smb2_write w;
1454 NTSTATUS status;
1455 const char *fname = "lease_v2_request.dat";
1456 const char *dname = "lease_v2_request.dir";
1457 const char *dnamefname = "lease_v2_request.dir\\lease.dat";
1458 const char *dnamefname2 = "lease_v2_request.dir\\lease2.dat";
1459 bool ret = true;
1460 uint32_t caps;
1461 enum protocol_types protocol;
1463 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1464 if (!(caps & SMB2_CAP_LEASING)) {
1465 torture_skip(tctx, "leases are not supported");
1467 if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
1468 torture_skip(tctx, "directory leases are not supported");
1471 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1472 if (protocol < PROTOCOL_SMB3_00) {
1473 torture_skip(tctx, "v2 leases are not supported");
1476 smb2_util_unlink(tree, fname);
1477 smb2_deltree(tree, dname);
1479 tree->session->transport->lease.handler = torture_lease_handler;
1480 tree->session->transport->lease.private_data = tree;
1481 tree->session->transport->oplock.handler = torture_oplock_handler;
1482 tree->session->transport->oplock.private_data = tree;
1484 ZERO_STRUCT(break_info);
1486 ZERO_STRUCT(io);
1487 smb2_lease_v2_create_share(&io, &ls1, false, fname,
1488 smb2_util_share_access("RWD"),
1489 LEASE1, NULL,
1490 smb2_util_lease_state("RHW"),
1491 0x11);
1493 status = smb2_create(tree, mem_ctx, &io);
1494 CHECK_STATUS(status, NT_STATUS_OK);
1495 h1 = io.out.file.handle;
1496 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1497 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch + 1);
1499 ZERO_STRUCT(io);
1500 smb2_lease_v2_create_share(&io, &ls2, true, dname,
1501 smb2_util_share_access("RWD"),
1502 LEASE2, NULL,
1503 smb2_util_lease_state("RHW"),
1504 0x22);
1505 status = smb2_create(tree, mem_ctx, &io);
1506 CHECK_STATUS(status, NT_STATUS_OK);
1507 h2 = io.out.file.handle;
1508 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
1509 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch + 1);
1511 ZERO_STRUCT(io);
1512 smb2_lease_v2_create_share(&io, &ls3, false, dnamefname,
1513 smb2_util_share_access("RWD"),
1514 LEASE3, &LEASE2,
1515 smb2_util_lease_state("RHW"),
1516 0x33);
1517 status = smb2_create(tree, mem_ctx, &io);
1518 CHECK_STATUS(status, NT_STATUS_OK);
1519 h3 = io.out.file.handle;
1520 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1521 CHECK_LEASE_V2(&io, "RHW", true, LEASE3,
1522 SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2,
1523 ls3.lease_epoch + 1);
1525 CHECK_NO_BREAK(tctx);
1527 ZERO_STRUCT(io);
1528 smb2_lease_v2_create_share(&io, &ls4, false, dnamefname2,
1529 smb2_util_share_access("RWD"),
1530 LEASE4, NULL,
1531 smb2_util_lease_state("RHW"),
1532 0x44);
1533 status = smb2_create(tree, mem_ctx, &io);
1534 CHECK_STATUS(status, NT_STATUS_OK);
1535 h4 = io.out.file.handle;
1536 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1537 CHECK_LEASE_V2(&io, "RHW", true, LEASE4, 0, 0, ls4.lease_epoch + 1);
1539 CHECK_BREAK_INFO_V2(tree->session->transport,
1540 "RH", "", LEASE2, ls2.lease_epoch + 2);
1542 ZERO_STRUCT(break_info);
1544 ZERO_STRUCT(io);
1545 smb2_lease_v2_create_share(&io, &ls2t, true, dname,
1546 smb2_util_share_access("RWD"),
1547 LEASE2, NULL,
1548 smb2_util_lease_state("RHW"),
1549 0x222);
1550 io.in.create_disposition = NTCREATEX_DISP_OPEN;
1551 status = smb2_create(tree, mem_ctx, &io);
1552 CHECK_STATUS(status, NT_STATUS_OK);
1553 h5 = io.out.file.handle;
1554 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_DIRECTORY);
1555 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch+3);
1556 smb2_util_close(tree, h5);
1558 ZERO_STRUCT(w);
1559 w.in.file.handle = h4;
1560 w.in.offset = 0;
1561 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
1562 memset(w.in.data.data, 'o', w.in.data.length);
1563 status = smb2_write(tree, &w);
1564 CHECK_STATUS(status, NT_STATUS_OK);
1567 * Wait 4 seconds in order to check if the write time
1568 * was updated (after 2 seconds).
1570 smb_msleep(4000);
1571 CHECK_NO_BREAK(tctx);
1574 * only the close on the modified file break the
1575 * directory lease.
1577 smb2_util_close(tree, h4);
1579 CHECK_BREAK_INFO_V2(tree->session->transport,
1580 "RH", "", LEASE2, ls2.lease_epoch+4);
1582 done:
1583 smb2_util_close(tree, h1);
1584 smb2_util_close(tree, h2);
1585 smb2_util_close(tree, h3);
1586 smb2_util_close(tree, h4);
1587 smb2_util_close(tree, h5);
1589 smb2_util_unlink(tree, fname);
1590 smb2_deltree(tree, dname);
1592 talloc_free(mem_ctx);
1594 return ret;
1597 static bool test_lease_v2_epoch1(struct torture_context *tctx,
1598 struct smb2_tree *tree)
1600 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1601 struct smb2_create io;
1602 struct smb2_lease ls;
1603 struct smb2_handle h;
1604 const char *fname = "lease_v2_epoch1.dat";
1605 bool ret = true;
1606 NTSTATUS status;
1607 uint32_t caps;
1608 enum protocol_types protocol;
1610 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1611 if (!(caps & SMB2_CAP_LEASING)) {
1612 torture_skip(tctx, "leases are not supported");
1615 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1616 if (protocol < PROTOCOL_SMB3_00) {
1617 torture_skip(tctx, "v2 leases are not supported");
1620 smb2_util_unlink(tree, fname);
1622 tree->session->transport->lease.handler = torture_lease_handler;
1623 tree->session->transport->lease.private_data = tree;
1624 tree->session->transport->oplock.handler = torture_oplock_handler;
1625 tree->session->transport->oplock.private_data = tree;
1627 ZERO_STRUCT(break_info);
1629 ZERO_STRUCT(io);
1630 smb2_lease_v2_create_share(&io, &ls, false, fname,
1631 smb2_util_share_access("RWD"),
1632 LEASE1, NULL,
1633 smb2_util_lease_state("RHW"),
1634 0x4711);
1635 status = smb2_create(tree, mem_ctx, &io);
1636 CHECK_STATUS(status, NT_STATUS_OK);
1637 h = io.out.file.handle;
1638 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1639 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls.lease_epoch + 1);
1640 smb2_util_close(tree, h);
1641 smb2_util_unlink(tree, fname);
1643 smb2_lease_v2_create_share(&io, &ls, false, fname,
1644 smb2_util_share_access("RWD"),
1645 LEASE1, NULL,
1646 smb2_util_lease_state("RHW"),
1647 0x11);
1649 status = smb2_create(tree, mem_ctx, &io);
1650 CHECK_STATUS(status, NT_STATUS_OK);
1651 h = io.out.file.handle;
1652 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1653 CHECK_LEASE_V2(&io, "RWH", true, LEASE1, 0, 0, ls.lease_epoch + 1);
1654 smb2_util_close(tree, h);
1656 done:
1657 smb2_util_unlink(tree, fname);
1658 talloc_free(mem_ctx);
1659 return ret;
1662 static bool test_lease_v2_epoch2(struct torture_context *tctx,
1663 struct smb2_tree *tree)
1665 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1666 struct smb2_create io;
1667 struct smb2_lease ls1v2, ls1v2t, ls1v1;
1668 struct smb2_handle hv2 = {}, hv1 = {};
1669 const char *fname = "lease_v2_epoch2.dat";
1670 bool ret = true;
1671 NTSTATUS status;
1672 uint32_t caps;
1673 enum protocol_types protocol;
1675 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1676 if (!(caps & SMB2_CAP_LEASING)) {
1677 torture_skip(tctx, "leases are not supported");
1680 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1681 if (protocol < PROTOCOL_SMB3_00) {
1682 torture_skip(tctx, "v2 leases are not supported");
1685 smb2_util_unlink(tree, fname);
1687 tree->session->transport->lease.handler = torture_lease_handler;
1688 tree->session->transport->lease.private_data = tree;
1689 tree->session->transport->oplock.handler = torture_oplock_handler;
1690 tree->session->transport->oplock.private_data = tree;
1692 ZERO_STRUCT(break_info);
1694 ZERO_STRUCT(io);
1695 smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
1696 smb2_util_share_access("RWD"),
1697 LEASE1, NULL,
1698 smb2_util_lease_state("R"),
1699 0x4711);
1700 status = smb2_create(tree, mem_ctx, &io);
1701 CHECK_STATUS(status, NT_STATUS_OK);
1702 hv2 = io.out.file.handle;
1703 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1704 CHECK_LEASE_V2(&io, "R", true, LEASE1, 0, 0, ls1v2.lease_epoch + 1);
1706 ZERO_STRUCT(io);
1707 smb2_lease_create_share(&io, &ls1v1, false, fname,
1708 smb2_util_share_access("RWD"),
1709 LEASE1,
1710 smb2_util_lease_state("RH"));
1711 status = smb2_create(tree, mem_ctx, &io);
1712 CHECK_STATUS(status, NT_STATUS_OK);
1713 hv1 = io.out.file.handle;
1714 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1715 CHECK_LEASE_V2(&io, "RH", true, LEASE1, 0, 0, ls1v2.lease_epoch + 2);
1717 smb2_util_close(tree, hv2);
1719 ZERO_STRUCT(io);
1720 smb2_lease_v2_create_share(&io, &ls1v2t, false, fname,
1721 smb2_util_share_access("RWD"),
1722 LEASE1, NULL,
1723 smb2_util_lease_state("RHW"),
1724 0x11);
1725 status = smb2_create(tree, mem_ctx, &io);
1726 CHECK_STATUS(status, NT_STATUS_OK);
1727 hv2 = io.out.file.handle;
1728 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1729 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1v2.lease_epoch + 3);
1731 smb2_util_close(tree, hv2);
1733 smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_NONE);
1734 status = smb2_create(tree, mem_ctx, &io);
1735 CHECK_STATUS(status, NT_STATUS_OK);
1736 hv2 = io.out.file.handle;
1737 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1738 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1740 CHECK_BREAK_INFO_V2(tree->session->transport,
1741 "RWH", "RH", LEASE1, ls1v2.lease_epoch + 4);
1743 smb2_util_close(tree, hv2);
1744 smb2_util_close(tree, hv1);
1746 ZERO_STRUCT(io);
1747 smb2_lease_create_share(&io, &ls1v1, false, fname,
1748 smb2_util_share_access("RWD"),
1749 LEASE1,
1750 smb2_util_lease_state("RHW"));
1751 status = smb2_create(tree, mem_ctx, &io);
1752 CHECK_STATUS(status, NT_STATUS_OK);
1753 hv1 = io.out.file.handle;
1754 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1755 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
1757 smb2_util_close(tree, hv1);
1759 done:
1760 smb2_util_close(tree, hv2);
1761 smb2_util_close(tree, hv1);
1762 smb2_util_unlink(tree, fname);
1763 talloc_free(mem_ctx);
1764 return ret;
1767 static bool test_lease_v2_epoch3(struct torture_context *tctx,
1768 struct smb2_tree *tree)
1770 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1771 struct smb2_create io;
1772 struct smb2_lease ls1v1 = {}, ls1v1t = {},ls1v2 = {};
1773 struct smb2_handle hv1 = {}, hv2 = {};
1774 const char *fname = "lease_v2_epoch3.dat";
1775 bool ret = true;
1776 NTSTATUS status;
1777 uint32_t caps;
1778 enum protocol_types protocol;
1780 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1781 if (!(caps & SMB2_CAP_LEASING)) {
1782 torture_skip(tctx, "leases are not supported");
1785 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1786 if (protocol < PROTOCOL_SMB3_00) {
1787 torture_skip(tctx, "v2 leases are not supported");
1790 smb2_util_unlink(tree, fname);
1792 tree->session->transport->lease.handler = torture_lease_handler;
1793 tree->session->transport->lease.private_data = tree;
1794 tree->session->transport->oplock.handler = torture_oplock_handler;
1795 tree->session->transport->oplock.private_data = tree;
1797 ZERO_STRUCT(break_info);
1799 ZERO_STRUCT(io);
1800 smb2_lease_create_share(&io, &ls1v1, false, fname,
1801 smb2_util_share_access("RWD"),
1802 LEASE1,
1803 smb2_util_lease_state("R"));
1804 status = smb2_create(tree, mem_ctx, &io);
1805 CHECK_STATUS(status, NT_STATUS_OK);
1806 hv1 = io.out.file.handle;
1807 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1808 CHECK_LEASE(&io, "R", true, LEASE1, 0);
1810 ZERO_STRUCT(io);
1811 smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
1812 smb2_util_share_access("RWD"),
1813 LEASE1, NULL,
1814 smb2_util_lease_state("RW"),
1815 0x4711);
1816 status = smb2_create(tree, mem_ctx, &io);
1817 CHECK_STATUS(status, NT_STATUS_OK);
1818 hv2 = io.out.file.handle;
1819 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1820 CHECK_LEASE(&io, "RW", true, LEASE1, 0);
1822 smb2_util_close(tree, hv1);
1824 ZERO_STRUCT(io);
1825 smb2_lease_create_share(&io, &ls1v1t, false, fname,
1826 smb2_util_share_access("RWD"),
1827 LEASE1,
1828 smb2_util_lease_state("RWH"));
1829 status = smb2_create(tree, mem_ctx, &io);
1830 CHECK_STATUS(status, NT_STATUS_OK);
1831 hv1 = io.out.file.handle;
1832 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1833 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
1835 smb2_util_close(tree, hv1);
1837 smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_NONE);
1838 status = smb2_create(tree, mem_ctx, &io);
1839 CHECK_STATUS(status, NT_STATUS_OK);
1840 hv1 = io.out.file.handle;
1841 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1842 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1844 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
1846 smb2_util_close(tree, hv1);
1847 smb2_util_close(tree, hv2);
1849 ZERO_STRUCT(io);
1850 smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
1851 smb2_util_share_access("RWD"),
1852 LEASE1, NULL,
1853 smb2_util_lease_state("RWH"),
1854 0x4711);
1855 status = smb2_create(tree, mem_ctx, &io);
1856 CHECK_STATUS(status, NT_STATUS_OK);
1857 hv2 = io.out.file.handle;
1858 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1859 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1v2.lease_epoch + 1);
1860 smb2_util_close(tree, hv2);
1862 done:
1863 smb2_util_close(tree, hv2);
1864 smb2_util_close(tree, hv1);
1865 smb2_util_unlink(tree, fname);
1866 talloc_free(mem_ctx);
1867 return ret;
1870 static bool test_lease_breaking1(struct torture_context *tctx,
1871 struct smb2_tree *tree)
1873 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1874 struct smb2_create io1 = {};
1875 struct smb2_create io2 = {};
1876 struct smb2_lease ls1 = {};
1877 struct smb2_handle h1a = {};
1878 struct smb2_handle h1b = {};
1879 struct smb2_handle h2 = {};
1880 struct smb2_request *req2 = NULL;
1881 struct smb2_lease_break_ack ack = {};
1882 const char *fname = "lease_breaking1.dat";
1883 bool ret = true;
1884 NTSTATUS status;
1885 uint32_t caps;
1887 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1888 if (!(caps & SMB2_CAP_LEASING)) {
1889 torture_skip(tctx, "leases are not supported");
1892 smb2_util_unlink(tree, fname);
1894 tree->session->transport->lease.handler = torture_lease_handler;
1895 tree->session->transport->lease.private_data = tree;
1896 tree->session->transport->oplock.handler = torture_oplock_handler;
1897 tree->session->transport->oplock.private_data = tree;
1900 * we defer acking the lease break.
1902 ZERO_STRUCT(break_info);
1903 break_info.lease_skip_ack = true;
1905 smb2_lease_create_share(&io1, &ls1, false, fname,
1906 smb2_util_share_access("RWD"),
1907 LEASE1,
1908 smb2_util_lease_state("RWH"));
1909 status = smb2_create(tree, mem_ctx, &io1);
1910 CHECK_STATUS(status, NT_STATUS_OK);
1911 h1a = io1.out.file.handle;
1912 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1913 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
1916 * a conflicting open is blocked until we ack the
1917 * lease break
1919 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
1920 req2 = smb2_create_send(tree, &io2);
1921 torture_assert(tctx, req2 != NULL, "smb2_create_send");
1924 * we got the lease break, but defer the ack.
1926 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
1928 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
1930 ack.in.lease.lease_key =
1931 break_info.lease_break.current_lease.lease_key;
1932 ack.in.lease.lease_state =
1933 break_info.lease_break.new_lease_state;
1934 ZERO_STRUCT(break_info);
1937 * a open using the same lease key is still works,
1938 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
1940 status = smb2_create(tree, mem_ctx, &io1);
1941 CHECK_STATUS(status, NT_STATUS_OK);
1942 h1b = io1.out.file.handle;
1943 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1944 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
1945 smb2_util_close(tree, h1b);
1947 CHECK_NO_BREAK(tctx);
1949 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
1952 * We ack the lease break.
1954 status = smb2_lease_break_ack(tree, &ack);
1955 CHECK_STATUS(status, NT_STATUS_OK);
1956 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
1958 torture_assert(tctx, req2->cancel.can_cancel,
1959 "req2 can_cancel");
1961 status = smb2_create_recv(req2, tctx, &io2);
1962 CHECK_STATUS(status, NT_STATUS_OK);
1963 h2 = io2.out.file.handle;
1964 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1965 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1967 CHECK_NO_BREAK(tctx);
1968 done:
1969 smb2_util_close(tree, h1a);
1970 smb2_util_close(tree, h1b);
1971 smb2_util_close(tree, h2);
1972 smb2_util_unlink(tree, fname);
1973 talloc_free(mem_ctx);
1974 return ret;
1977 static bool test_lease_breaking2(struct torture_context *tctx,
1978 struct smb2_tree *tree)
1980 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1981 struct smb2_create io1 = {};
1982 struct smb2_create io2 = {};
1983 struct smb2_lease ls1 = {};
1984 struct smb2_handle h1a = {};
1985 struct smb2_handle h1b = {};
1986 struct smb2_handle h2 = {};
1987 struct smb2_request *req2 = NULL;
1988 struct smb2_lease_break_ack ack = {};
1989 const char *fname = "lease_breaking2.dat";
1990 bool ret = true;
1991 NTSTATUS status;
1992 uint32_t caps;
1994 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1995 if (!(caps & SMB2_CAP_LEASING)) {
1996 torture_skip(tctx, "leases are not supported");
1999 smb2_util_unlink(tree, fname);
2001 tree->session->transport->lease.handler = torture_lease_handler;
2002 tree->session->transport->lease.private_data = tree;
2003 tree->session->transport->oplock.handler = torture_oplock_handler;
2004 tree->session->transport->oplock.private_data = tree;
2007 * we defer acking the lease break.
2009 ZERO_STRUCT(break_info);
2010 break_info.lease_skip_ack = true;
2012 smb2_lease_create_share(&io1, &ls1, false, fname,
2013 smb2_util_share_access("RWD"),
2014 LEASE1,
2015 smb2_util_lease_state("RWH"));
2016 status = smb2_create(tree, mem_ctx, &io1);
2017 CHECK_STATUS(status, NT_STATUS_OK);
2018 h1a = io1.out.file.handle;
2019 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2020 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2023 * a conflicting open is blocked until we ack the
2024 * lease break
2026 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2027 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2028 req2 = smb2_create_send(tree, &io2);
2029 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2032 * we got the lease break, but defer the ack.
2034 CHECK_BREAK_INFO("RWH", "", LEASE1);
2036 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2038 ack.in.lease.lease_key =
2039 break_info.lease_break.current_lease.lease_key;
2040 ZERO_STRUCT(break_info);
2043 * a open using the same lease key is still works,
2044 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2046 status = smb2_create(tree, mem_ctx, &io1);
2047 CHECK_STATUS(status, NT_STATUS_OK);
2048 h1b = io1.out.file.handle;
2049 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2050 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2051 smb2_util_close(tree, h1b);
2053 CHECK_NO_BREAK(tctx);
2055 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2058 * We ack the lease break.
2060 ack.in.lease.lease_state =
2061 SMB2_LEASE_READ | SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE;
2062 status = smb2_lease_break_ack(tree, &ack);
2063 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2065 ack.in.lease.lease_state =
2066 SMB2_LEASE_READ | SMB2_LEASE_WRITE;
2067 status = smb2_lease_break_ack(tree, &ack);
2068 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2070 ack.in.lease.lease_state =
2071 SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE;
2072 status = smb2_lease_break_ack(tree, &ack);
2073 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2075 ack.in.lease.lease_state =
2076 SMB2_LEASE_READ | SMB2_LEASE_HANDLE;
2077 status = smb2_lease_break_ack(tree, &ack);
2078 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2080 ack.in.lease.lease_state = SMB2_LEASE_WRITE;
2081 status = smb2_lease_break_ack(tree, &ack);
2082 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2084 ack.in.lease.lease_state = SMB2_LEASE_HANDLE;
2085 status = smb2_lease_break_ack(tree, &ack);
2086 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2088 ack.in.lease.lease_state = SMB2_LEASE_READ;
2089 status = smb2_lease_break_ack(tree, &ack);
2090 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2092 /* Try again with the correct state this time. */
2093 ack.in.lease.lease_state = SMB2_LEASE_NONE;;
2094 status = smb2_lease_break_ack(tree, &ack);
2095 CHECK_STATUS(status, NT_STATUS_OK);
2096 CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
2098 status = smb2_lease_break_ack(tree, &ack);
2099 CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
2101 torture_assert(tctx, req2->cancel.can_cancel,
2102 "req2 can_cancel");
2104 status = smb2_create_recv(req2, tctx, &io2);
2105 CHECK_STATUS(status, NT_STATUS_OK);
2106 h2 = io2.out.file.handle;
2107 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2108 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2110 CHECK_NO_BREAK(tctx);
2112 /* Get state of the original handle. */
2113 smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
2114 status = smb2_create(tree, mem_ctx, &io1);
2115 CHECK_STATUS(status, NT_STATUS_OK);
2116 CHECK_LEASE(&io1, "", true, LEASE1, 0);
2117 smb2_util_close(tree, io1.out.file.handle);
2119 done:
2120 smb2_util_close(tree, h1a);
2121 smb2_util_close(tree, h1b);
2122 smb2_util_close(tree, h2);
2123 smb2_util_unlink(tree, fname);
2124 talloc_free(mem_ctx);
2125 return ret;
2128 static bool test_lease_breaking3(struct torture_context *tctx,
2129 struct smb2_tree *tree)
2131 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2132 struct smb2_create io1 = {};
2133 struct smb2_create io2 = {};
2134 struct smb2_create io3 = {};
2135 struct smb2_lease ls1 = {};
2136 struct smb2_handle h1a = {};
2137 struct smb2_handle h1b = {};
2138 struct smb2_handle h2 = {};
2139 struct smb2_handle h3 = {};
2140 struct smb2_request *req2 = NULL;
2141 struct smb2_request *req3 = NULL;
2142 struct torture_lease_break break_info_tmp = {};
2143 struct smb2_lease_break_ack ack = {};
2144 const char *fname = "lease_breaking3.dat";
2145 bool ret = true;
2146 NTSTATUS status;
2147 uint32_t caps;
2149 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2150 if (!(caps & SMB2_CAP_LEASING)) {
2151 torture_skip(tctx, "leases are not supported");
2154 smb2_util_unlink(tree, fname);
2156 tree->session->transport->lease.handler = torture_lease_handler;
2157 tree->session->transport->lease.private_data = tree;
2158 tree->session->transport->oplock.handler = torture_oplock_handler;
2159 tree->session->transport->oplock.private_data = tree;
2162 * we defer acking the lease break.
2164 ZERO_STRUCT(break_info);
2165 break_info.lease_skip_ack = true;
2167 smb2_lease_create_share(&io1, &ls1, false, fname,
2168 smb2_util_share_access("RWD"),
2169 LEASE1,
2170 smb2_util_lease_state("RWH"));
2171 status = smb2_create(tree, mem_ctx, &io1);
2172 CHECK_STATUS(status, NT_STATUS_OK);
2173 h1a = io1.out.file.handle;
2174 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2175 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2178 * a conflicting open is blocked until we ack the
2179 * lease break
2181 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2182 req2 = smb2_create_send(tree, &io2);
2183 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2186 * we got the lease break, but defer the ack.
2188 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2190 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2193 * a open using the same lease key is still works,
2194 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2196 status = smb2_create(tree, mem_ctx, &io1);
2197 CHECK_STATUS(status, NT_STATUS_OK);
2198 h1b = io1.out.file.handle;
2199 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2200 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2201 smb2_util_close(tree, h1b);
2204 * a conflicting open with NTCREATEX_DISP_OVERWRITE
2205 * doesn't trigger an immediate lease break to none.
2207 break_info_tmp = break_info;
2208 ZERO_STRUCT(break_info);
2209 smb2_oplock_create(&io3, fname, SMB2_OPLOCK_LEVEL_NONE);
2210 io3.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2211 req3 = smb2_create_send(tree, &io3);
2212 torture_assert(tctx, req3 != NULL, "smb2_create_send");
2213 CHECK_NO_BREAK(tctx);
2214 break_info = break_info_tmp;
2216 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2218 ack.in.lease.lease_key =
2219 break_info.lease_break.current_lease.lease_key;
2220 ack.in.lease.lease_state =
2221 break_info.lease_break.new_lease_state;
2222 ZERO_STRUCT(break_info);
2225 * a open using the same lease key is still works,
2226 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2228 status = smb2_create(tree, mem_ctx, &io1);
2229 CHECK_STATUS(status, NT_STATUS_OK);
2230 h1b = io1.out.file.handle;
2231 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2232 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2233 smb2_util_close(tree, h1b);
2235 CHECK_NO_BREAK(tctx);
2238 * We ack the lease break, but defer acking the next break (to "R")
2240 break_info.lease_skip_ack = true;
2241 status = smb2_lease_break_ack(tree, &ack);
2242 CHECK_STATUS(status, NT_STATUS_OK);
2243 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
2246 * We got an additional break downgrading to just "R"
2247 * while we defer the ack.
2249 CHECK_BREAK_INFO("RH", "R", LEASE1);
2251 ack.in.lease.lease_key =
2252 break_info.lease_break.current_lease.lease_key;
2253 ack.in.lease.lease_state =
2254 break_info.lease_break.new_lease_state;
2255 ZERO_STRUCT(break_info);
2258 * a open using the same lease key is still works,
2259 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2261 status = smb2_create(tree, mem_ctx, &io1);
2262 CHECK_STATUS(status, NT_STATUS_OK);
2263 h1b = io1.out.file.handle;
2264 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2265 CHECK_LEASE(&io1, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2266 smb2_util_close(tree, h1b);
2268 CHECK_NO_BREAK(tctx);
2270 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2271 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2274 * We ack the downgrade to "R" and get an immediate break to none
2276 status = smb2_lease_break_ack(tree, &ack);
2277 CHECK_STATUS(status, NT_STATUS_OK);
2278 CHECK_LEASE_BREAK_ACK(&ack, "R", LEASE1);
2281 * We get the downgrade to none.
2283 CHECK_BREAK_INFO("R", "", LEASE1);
2285 torture_assert(tctx, req2->cancel.can_cancel,
2286 "req2 can_cancel");
2287 torture_assert(tctx, req3->cancel.can_cancel,
2288 "req3 can_cancel");
2290 ZERO_STRUCT(break_info);
2292 status = smb2_create_recv(req2, tctx, &io2);
2293 CHECK_STATUS(status, NT_STATUS_OK);
2294 h2 = io2.out.file.handle;
2295 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2296 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2298 status = smb2_create_recv(req3, tctx, &io3);
2299 CHECK_STATUS(status, NT_STATUS_OK);
2300 h3 = io3.out.file.handle;
2301 CHECK_CREATED(&io3, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2302 CHECK_VAL(io3.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2304 CHECK_NO_BREAK(tctx);
2305 done:
2306 smb2_util_close(tree, h1a);
2307 smb2_util_close(tree, h1b);
2308 smb2_util_close(tree, h2);
2309 smb2_util_close(tree, h3);
2311 smb2_util_unlink(tree, fname);
2312 talloc_free(mem_ctx);
2313 return ret;
2316 static bool test_lease_v2_breaking3(struct torture_context *tctx,
2317 struct smb2_tree *tree)
2319 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2320 struct smb2_create io1 = {};
2321 struct smb2_create io2 = {};
2322 struct smb2_create io3 = {};
2323 struct smb2_lease ls1 = {};
2324 struct smb2_handle h1a = {};
2325 struct smb2_handle h1b = {};
2326 struct smb2_handle h2 = {};
2327 struct smb2_handle h3 = {};
2328 struct smb2_request *req2 = NULL;
2329 struct smb2_request *req3 = NULL;
2330 struct torture_lease_break break_info_tmp = {};
2331 struct smb2_lease_break_ack ack = {};
2332 const char *fname = "v2_lease_breaking3.dat";
2333 bool ret = true;
2334 NTSTATUS status;
2335 uint32_t caps;
2336 enum protocol_types protocol;
2338 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2339 if (!(caps & SMB2_CAP_LEASING)) {
2340 torture_skip(tctx, "leases are not supported");
2343 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
2344 if (protocol < PROTOCOL_SMB3_00) {
2345 torture_skip(tctx, "v2 leases are not supported");
2348 smb2_util_unlink(tree, fname);
2350 tree->session->transport->lease.handler = torture_lease_handler;
2351 tree->session->transport->lease.private_data = tree;
2352 tree->session->transport->oplock.handler = torture_oplock_handler;
2353 tree->session->transport->oplock.private_data = tree;
2356 * we defer acking the lease break.
2358 ZERO_STRUCT(break_info);
2359 break_info.lease_skip_ack = true;
2361 smb2_lease_v2_create_share(&io1, &ls1, false, fname,
2362 smb2_util_share_access("RWD"),
2363 LEASE1, NULL,
2364 smb2_util_lease_state("RHW"),
2365 0x11);
2366 status = smb2_create(tree, mem_ctx, &io1);
2367 CHECK_STATUS(status, NT_STATUS_OK);
2368 h1a = io1.out.file.handle;
2369 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2370 /* Epoch increases on open. */
2371 ls1.lease_epoch += 1;
2372 CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
2375 * a conflicting open is blocked until we ack the
2376 * lease break
2378 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2379 req2 = smb2_create_send(tree, &io2);
2380 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2383 * we got the lease break, but defer the ack.
2385 CHECK_BREAK_INFO_V2(tree->session->transport,
2386 "RWH", "RH", LEASE1, ls1.lease_epoch + 1);
2388 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2390 /* On receiving a lease break, we must sync the new epoch. */
2391 ls1.lease_epoch = break_info.lease_break.new_epoch;
2394 * a open using the same lease key is still works,
2395 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2397 status = smb2_create(tree, mem_ctx, &io1);
2398 CHECK_STATUS(status, NT_STATUS_OK);
2399 h1b = io1.out.file.handle;
2400 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2401 CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
2402 smb2_util_close(tree, h1b);
2405 * a conflicting open with NTCREATEX_DISP_OVERWRITE
2406 * doesn't trigger an immediate lease break to none.
2408 break_info_tmp = break_info;
2409 ZERO_STRUCT(break_info);
2410 smb2_oplock_create(&io3, fname, SMB2_OPLOCK_LEVEL_NONE);
2411 io3.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2412 req3 = smb2_create_send(tree, &io3);
2413 torture_assert(tctx, req3 != NULL, "smb2_create_send");
2414 CHECK_NO_BREAK(tctx);
2415 break_info = break_info_tmp;
2417 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2419 ack.in.lease.lease_key =
2420 break_info.lease_break.current_lease.lease_key;
2421 ack.in.lease.lease_state =
2422 break_info.lease_break.new_lease_state;
2423 ZERO_STRUCT(break_info);
2426 * a open using the same lease key is still works,
2427 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2429 status = smb2_create(tree, mem_ctx, &io1);
2430 CHECK_STATUS(status, NT_STATUS_OK);
2431 h1b = io1.out.file.handle;
2432 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2433 CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
2434 smb2_util_close(tree, h1b);
2436 CHECK_NO_BREAK(tctx);
2439 * We ack the lease break, but defer acking the next break (to "R")
2441 break_info.lease_skip_ack = true;
2442 status = smb2_lease_break_ack(tree, &ack);
2443 CHECK_STATUS(status, NT_STATUS_OK);
2444 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
2447 * We got an additional break downgrading to just "R"
2448 * while we defer the ack.
2450 CHECK_BREAK_INFO_V2(tree->session->transport,
2451 "RH", "R", LEASE1, ls1.lease_epoch);
2452 /* On receiving a lease break, we must sync the new epoch. */
2453 ls1.lease_epoch = break_info.lease_break.new_epoch;
2455 ack.in.lease.lease_key =
2456 break_info.lease_break.current_lease.lease_key;
2457 ack.in.lease.lease_state =
2458 break_info.lease_break.new_lease_state;
2459 ZERO_STRUCT(break_info);
2462 * a open using the same lease key is still works,
2463 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2465 status = smb2_create(tree, mem_ctx, &io1);
2466 CHECK_STATUS(status, NT_STATUS_OK);
2467 h1b = io1.out.file.handle;
2468 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2469 CHECK_LEASE_V2(&io1, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
2470 smb2_util_close(tree, h1b);
2472 CHECK_NO_BREAK(tctx);
2474 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2475 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2478 * We ack the downgrade to "R" and get an immediate break to none
2480 status = smb2_lease_break_ack(tree, &ack);
2481 CHECK_STATUS(status, NT_STATUS_OK);
2482 CHECK_LEASE_BREAK_ACK(&ack, "R", LEASE1);
2485 * We get the downgrade to none.
2487 CHECK_BREAK_INFO_V2(tree->session->transport,
2488 "R", "", LEASE1, ls1.lease_epoch);
2490 torture_assert(tctx, req2->cancel.can_cancel,
2491 "req2 can_cancel");
2492 torture_assert(tctx, req3->cancel.can_cancel,
2493 "req3 can_cancel");
2495 ZERO_STRUCT(break_info);
2497 status = smb2_create_recv(req2, tctx, &io2);
2498 CHECK_STATUS(status, NT_STATUS_OK);
2499 h2 = io2.out.file.handle;
2500 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2501 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2503 status = smb2_create_recv(req3, tctx, &io3);
2504 CHECK_STATUS(status, NT_STATUS_OK);
2505 h3 = io3.out.file.handle;
2506 CHECK_CREATED(&io3, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2507 CHECK_VAL(io3.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2509 CHECK_NO_BREAK(tctx);
2510 done:
2511 smb2_util_close(tree, h1a);
2512 smb2_util_close(tree, h1b);
2513 smb2_util_close(tree, h2);
2514 smb2_util_close(tree, h3);
2516 smb2_util_unlink(tree, fname);
2517 talloc_free(mem_ctx);
2518 return ret;
2522 static bool test_lease_breaking4(struct torture_context *tctx,
2523 struct smb2_tree *tree)
2525 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2526 struct smb2_create io1 = {};
2527 struct smb2_create io2 = {};
2528 struct smb2_create io3 = {};
2529 struct smb2_lease ls1 = {};
2530 struct smb2_lease ls1t = {};
2531 struct smb2_handle h1 = {};
2532 struct smb2_handle h2 = {};
2533 struct smb2_handle h3 = {};
2534 struct smb2_request *req2 = NULL;
2535 struct torture_lease_break break_info_tmp = {};
2536 struct smb2_lease_break_ack ack = {};
2537 const char *fname = "lease_breaking4.dat";
2538 bool ret = true;
2539 NTSTATUS status;
2540 uint32_t caps;
2542 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2543 if (!(caps & SMB2_CAP_LEASING)) {
2544 torture_skip(tctx, "leases are not supported");
2547 smb2_util_unlink(tree, fname);
2549 tree->session->transport->lease.handler = torture_lease_handler;
2550 tree->session->transport->lease.private_data = tree;
2551 tree->session->transport->oplock.handler = torture_oplock_handler;
2552 tree->session->transport->oplock.private_data = tree;
2555 * we defer acking the lease break.
2557 ZERO_STRUCT(break_info);
2558 break_info.lease_skip_ack = true;
2560 smb2_lease_create_share(&io1, &ls1, false, fname,
2561 smb2_util_share_access("RWD"),
2562 LEASE1,
2563 smb2_util_lease_state("RH"));
2564 status = smb2_create(tree, mem_ctx, &io1);
2565 CHECK_STATUS(status, NT_STATUS_OK);
2566 h1 = io1.out.file.handle;
2567 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2568 CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
2570 CHECK_NO_BREAK(tctx);
2573 * a conflicting open is *not* blocked until we ack the
2574 * lease break
2576 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2577 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2578 req2 = smb2_create_send(tree, &io2);
2579 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2582 * We got a break from RH to NONE, we're supported to ack
2583 * this downgrade
2585 CHECK_BREAK_INFO("RH", "", LEASE1);
2587 break_info_tmp = break_info;
2588 ZERO_STRUCT(break_info);
2589 CHECK_NO_BREAK(tctx);
2591 torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2593 status = smb2_create_recv(req2, tctx, &io2);
2594 CHECK_STATUS(status, NT_STATUS_OK);
2595 h2 = io2.out.file.handle;
2596 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2597 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2598 smb2_util_close(tree, h2);
2600 CHECK_NO_BREAK(tctx);
2603 * a conflicting open is *not* blocked until we ack the
2604 * lease break, even if the lease is in breaking state.
2606 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2607 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2608 req2 = smb2_create_send(tree, &io2);
2609 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2611 CHECK_NO_BREAK(tctx);
2613 torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2615 status = smb2_create_recv(req2, tctx, &io2);
2616 CHECK_STATUS(status, NT_STATUS_OK);
2617 h2 = io2.out.file.handle;
2618 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2619 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2620 smb2_util_close(tree, h2);
2622 CHECK_NO_BREAK(tctx);
2625 * We now ask the server about the current lease state
2626 * which should still be "RH", but with
2627 * SMB2_LEASE_FLAG_BREAK_IN_PROGRESS.
2629 smb2_lease_create_share(&io3, &ls1t, false, fname,
2630 smb2_util_share_access("RWD"),
2631 LEASE1,
2632 smb2_util_lease_state(""));
2633 status = smb2_create(tree, mem_ctx, &io3);
2634 CHECK_STATUS(status, NT_STATUS_OK);
2635 h3 = io3.out.file.handle;
2636 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2637 CHECK_LEASE(&io3, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2640 * We finally ack the lease break...
2642 CHECK_NO_BREAK(tctx);
2643 break_info = break_info_tmp;
2644 ack.in.lease.lease_key =
2645 break_info.lease_break.current_lease.lease_key;
2646 ack.in.lease.lease_state =
2647 break_info.lease_break.new_lease_state;
2648 ZERO_STRUCT(break_info);
2649 break_info.lease_skip_ack = true;
2651 status = smb2_lease_break_ack(tree, &ack);
2652 CHECK_STATUS(status, NT_STATUS_OK);
2653 CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
2655 CHECK_NO_BREAK(tctx);
2657 done:
2658 smb2_util_close(tree, h1);
2659 smb2_util_close(tree, h2);
2660 smb2_util_close(tree, h3);
2662 smb2_util_unlink(tree, fname);
2663 talloc_free(mem_ctx);
2664 return ret;
2667 static bool test_lease_breaking5(struct torture_context *tctx,
2668 struct smb2_tree *tree)
2670 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2671 struct smb2_create io1 = {};
2672 struct smb2_create io2 = {};
2673 struct smb2_create io3 = {};
2674 struct smb2_lease ls1 = {};
2675 struct smb2_lease ls1t = {};
2676 struct smb2_handle h1 = {};
2677 struct smb2_handle h2 = {};
2678 struct smb2_handle h3 = {};
2679 struct smb2_request *req2 = NULL;
2680 struct torture_lease_break break_info_tmp = {};
2681 struct smb2_lease_break_ack ack = {};
2682 const char *fname = "lease_breaking5.dat";
2683 bool ret = true;
2684 NTSTATUS status;
2685 uint32_t caps;
2687 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2688 if (!(caps & SMB2_CAP_LEASING)) {
2689 torture_skip(tctx, "leases are not supported");
2692 smb2_util_unlink(tree, fname);
2694 tree->session->transport->lease.handler = torture_lease_handler;
2695 tree->session->transport->lease.private_data = tree;
2696 tree->session->transport->oplock.handler = torture_oplock_handler;
2697 tree->session->transport->oplock.private_data = tree;
2700 * we defer acking the lease break.
2702 ZERO_STRUCT(break_info);
2703 break_info.lease_skip_ack = true;
2705 smb2_lease_create_share(&io1, &ls1, false, fname,
2706 smb2_util_share_access("RWD"),
2707 LEASE1,
2708 smb2_util_lease_state("R"));
2709 status = smb2_create(tree, mem_ctx, &io1);
2710 CHECK_STATUS(status, NT_STATUS_OK);
2711 h1 = io1.out.file.handle;
2712 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2713 CHECK_LEASE(&io1, "R", true, LEASE1, 0);
2715 CHECK_NO_BREAK(tctx);
2718 * a conflicting open is *not* blocked until we ack the
2719 * lease break
2721 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2722 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2723 req2 = smb2_create_send(tree, &io2);
2724 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2727 * We got a break from RH to NONE, we're supported to ack
2728 * this downgrade
2730 CHECK_BREAK_INFO("R", "", LEASE1);
2732 break_info_tmp = break_info;
2733 ZERO_STRUCT(break_info);
2734 CHECK_NO_BREAK(tctx);
2736 torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2738 status = smb2_create_recv(req2, tctx, &io2);
2739 CHECK_STATUS(status, NT_STATUS_OK);
2740 h2 = io2.out.file.handle;
2741 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2742 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2744 CHECK_NO_BREAK(tctx);
2747 * We now ask the server about the current lease state
2748 * which should still be "RH", but with
2749 * SMB2_LEASE_FLAG_BREAK_IN_PROGRESS.
2751 smb2_lease_create_share(&io3, &ls1t, false, fname,
2752 smb2_util_share_access("RWD"),
2753 LEASE1,
2754 smb2_util_lease_state(""));
2755 status = smb2_create(tree, mem_ctx, &io3);
2756 CHECK_STATUS(status, NT_STATUS_OK);
2757 h3 = io3.out.file.handle;
2758 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2759 CHECK_LEASE(&io3, "", true, LEASE1, 0);
2762 * We send an ack without without being asked.
2764 CHECK_NO_BREAK(tctx);
2765 break_info = break_info_tmp;
2766 ack.in.lease.lease_key =
2767 break_info.lease_break.current_lease.lease_key;
2768 ack.in.lease.lease_state =
2769 break_info.lease_break.new_lease_state;
2770 ZERO_STRUCT(break_info);
2771 status = smb2_lease_break_ack(tree, &ack);
2772 CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
2774 CHECK_NO_BREAK(tctx);
2776 done:
2777 smb2_util_close(tree, h1);
2778 smb2_util_close(tree, h2);
2779 smb2_util_close(tree, h3);
2781 smb2_util_unlink(tree, fname);
2782 talloc_free(mem_ctx);
2783 return ret;
2786 static bool test_lease_breaking6(struct torture_context *tctx,
2787 struct smb2_tree *tree)
2789 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2790 struct smb2_create io1 = {};
2791 struct smb2_create io2 = {};
2792 struct smb2_lease ls1 = {};
2793 struct smb2_handle h1a = {};
2794 struct smb2_handle h1b = {};
2795 struct smb2_handle h2 = {};
2796 struct smb2_request *req2 = NULL;
2797 struct smb2_lease_break_ack ack = {};
2798 const char *fname = "lease_breaking6.dat";
2799 bool ret = true;
2800 NTSTATUS status;
2801 uint32_t caps;
2803 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2804 if (!(caps & SMB2_CAP_LEASING)) {
2805 torture_skip(tctx, "leases are not supported");
2808 smb2_util_unlink(tree, fname);
2810 tree->session->transport->lease.handler = torture_lease_handler;
2811 tree->session->transport->lease.private_data = tree;
2812 tree->session->transport->oplock.handler = torture_oplock_handler;
2813 tree->session->transport->oplock.private_data = tree;
2816 * we defer acking the lease break.
2818 ZERO_STRUCT(break_info);
2819 break_info.lease_skip_ack = true;
2821 smb2_lease_create_share(&io1, &ls1, false, fname,
2822 smb2_util_share_access("RWD"),
2823 LEASE1,
2824 smb2_util_lease_state("RWH"));
2825 status = smb2_create(tree, mem_ctx, &io1);
2826 CHECK_STATUS(status, NT_STATUS_OK);
2827 h1a = io1.out.file.handle;
2828 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2829 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2832 * a conflicting open is blocked until we ack the
2833 * lease break
2835 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2836 req2 = smb2_create_send(tree, &io2);
2837 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2840 * we got the lease break, but defer the ack.
2842 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2844 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2846 ack.in.lease.lease_key =
2847 break_info.lease_break.current_lease.lease_key;
2848 ZERO_STRUCT(break_info);
2851 * a open using the same lease key is still works,
2852 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2854 status = smb2_create(tree, mem_ctx, &io1);
2855 CHECK_STATUS(status, NT_STATUS_OK);
2856 h1b = io1.out.file.handle;
2857 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2858 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2859 smb2_util_close(tree, h1b);
2861 CHECK_NO_BREAK(tctx);
2863 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2866 * We are asked to break to "RH", but we are allowed to
2867 * break to any of "RH", "R" or NONE.
2869 ack.in.lease.lease_state = SMB2_LEASE_NONE;
2870 status = smb2_lease_break_ack(tree, &ack);
2871 CHECK_STATUS(status, NT_STATUS_OK);
2872 CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
2874 torture_assert(tctx, req2->cancel.can_cancel,
2875 "req2 can_cancel");
2877 status = smb2_create_recv(req2, tctx, &io2);
2878 CHECK_STATUS(status, NT_STATUS_OK);
2879 h2 = io2.out.file.handle;
2880 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2881 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2883 CHECK_NO_BREAK(tctx);
2884 done:
2885 smb2_util_close(tree, h1a);
2886 smb2_util_close(tree, h1b);
2887 smb2_util_close(tree, h2);
2888 smb2_util_unlink(tree, fname);
2889 talloc_free(mem_ctx);
2890 return ret;
2893 static bool test_lease_lock1(struct torture_context *tctx,
2894 struct smb2_tree *tree1a,
2895 struct smb2_tree *tree2)
2897 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2898 struct smb2_create io1 = {};
2899 struct smb2_create io2 = {};
2900 struct smb2_create io3 = {};
2901 struct smb2_lease ls1 = {};
2902 struct smb2_lease ls2 = {};
2903 struct smb2_lease ls3 = {};
2904 struct smb2_handle h1 = {};
2905 struct smb2_handle h2 = {};
2906 struct smb2_handle h3 = {};
2907 struct smb2_lock lck;
2908 struct smb2_lock_element el[1];
2909 const char *fname = "locktest.dat";
2910 bool ret = true;
2911 NTSTATUS status;
2912 uint32_t caps;
2913 struct smbcli_options options1;
2914 struct smb2_tree *tree1b = NULL;
2916 options1 = tree1a->session->transport->options;
2918 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
2919 if (!(caps & SMB2_CAP_LEASING)) {
2920 torture_skip(tctx, "leases are not supported");
2923 /* Set up handlers. */
2924 tree2->session->transport->lease.handler = torture_lease_handler;
2925 tree2->session->transport->lease.private_data = tree2;
2926 tree2->session->transport->oplock.handler = torture_oplock_handler;
2927 tree2->session->transport->oplock.private_data = tree2;
2929 tree1a->session->transport->lease.handler = torture_lease_handler;
2930 tree1a->session->transport->lease.private_data = tree1a;
2931 tree1a->session->transport->oplock.handler = torture_oplock_handler;
2932 tree1a->session->transport->oplock.private_data = tree1a;
2934 /* create a new connection (same client_guid) */
2935 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
2936 torture_warning(tctx, "couldn't reconnect, bailing\n");
2937 ret = false;
2938 goto done;
2941 tree1b->session->transport->lease.handler = torture_lease_handler;
2942 tree1b->session->transport->lease.private_data = tree1b;
2943 tree1b->session->transport->oplock.handler = torture_oplock_handler;
2944 tree1b->session->transport->oplock.private_data = tree1b;
2946 smb2_util_unlink(tree1a, fname);
2948 ZERO_STRUCT(break_info);
2949 ZERO_STRUCT(lck);
2951 /* Open a handle on tree1a. */
2952 smb2_lease_create_share(&io1, &ls1, false, fname,
2953 smb2_util_share_access("RWD"),
2954 LEASE1,
2955 smb2_util_lease_state("RWH"));
2956 status = smb2_create(tree1a, mem_ctx, &io1);
2957 CHECK_STATUS(status, NT_STATUS_OK);
2958 h1 = io1.out.file.handle;
2959 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2960 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2962 /* Open a second handle on tree1b. */
2963 smb2_lease_create_share(&io2, &ls2, false, fname,
2964 smb2_util_share_access("RWD"),
2965 LEASE2,
2966 smb2_util_lease_state("RWH"));
2967 status = smb2_create(tree1b, mem_ctx, &io2);
2968 CHECK_STATUS(status, NT_STATUS_OK);
2969 h2 = io2.out.file.handle;
2970 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2971 CHECK_LEASE(&io2, "RH", true, LEASE2, 0);
2972 /* And LEASE1 got broken to RH. */
2973 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2974 ZERO_STRUCT(break_info);
2976 /* Now open a lease on a different client guid. */
2977 smb2_lease_create_share(&io3, &ls3, false, fname,
2978 smb2_util_share_access("RWD"),
2979 LEASE3,
2980 smb2_util_lease_state("RWH"));
2981 status = smb2_create(tree2, mem_ctx, &io3);
2982 CHECK_STATUS(status, NT_STATUS_OK);
2983 h3 = io3.out.file.handle;
2984 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2985 CHECK_LEASE(&io3, "RH", true, LEASE3, 0);
2986 /* Doesn't break. */
2987 CHECK_NO_BREAK(tctx);
2989 lck.in.locks = el;
2991 * Try and get get an exclusive byte
2992 * range lock on H1 (LEASE1).
2995 lck.in.lock_count = 1;
2996 lck.in.lock_sequence = 1;
2997 lck.in.file.handle = h1;
2998 el[0].offset = 0;
2999 el[0].length = 1;
3000 el[0].reserved = 0;
3001 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
3002 status = smb2_lock(tree1a, &lck);
3003 CHECK_STATUS(status, NT_STATUS_OK);
3005 /* LEASE2 and LEASE3 should get broken to NONE. */
3006 torture_wait_for_lease_break(tctx);
3007 torture_wait_for_lease_break(tctx);
3008 torture_wait_for_lease_break(tctx);
3009 torture_wait_for_lease_break(tctx);
3011 CHECK_VAL(break_info.failures, 0); \
3012 CHECK_VAL(break_info.count, 2); \
3014 /* Get state of the H1 (LEASE1) */
3015 smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
3016 status = smb2_create(tree1a, mem_ctx, &io1);
3017 CHECK_STATUS(status, NT_STATUS_OK);
3018 /* Should still be RH. */
3019 CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
3020 smb2_util_close(tree1a, io1.out.file.handle);
3022 /* Get state of the H2 (LEASE2) */
3023 smb2_lease_create(&io2, &ls2, false, fname, LEASE2, smb2_util_lease_state(""));
3024 status = smb2_create(tree1b, mem_ctx, &io2);
3025 CHECK_STATUS(status, NT_STATUS_OK);
3026 CHECK_LEASE(&io2, "", true, LEASE2, 0);
3027 smb2_util_close(tree1b, io2.out.file.handle);
3029 /* Get state of the H3 (LEASE3) */
3030 smb2_lease_create(&io3, &ls3, false, fname, LEASE3, smb2_util_lease_state(""));
3031 status = smb2_create(tree2, mem_ctx, &io3);
3032 CHECK_STATUS(status, NT_STATUS_OK);
3033 CHECK_LEASE(&io3, "", true, LEASE3, 0);
3034 smb2_util_close(tree2, io3.out.file.handle);
3036 ZERO_STRUCT(break_info);
3039 * Try and get get an exclusive byte
3040 * range lock on H3 (LEASE3).
3042 lck.in.lock_count = 1;
3043 lck.in.lock_sequence = 2;
3044 lck.in.file.handle = h3;
3045 el[0].offset = 100;
3046 el[0].length = 1;
3047 el[0].reserved = 0;
3048 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
3049 status = smb2_lock(tree2, &lck);
3050 CHECK_STATUS(status, NT_STATUS_OK);
3051 /* LEASE1 got broken to NONE. */
3052 CHECK_BREAK_INFO("RH", "", LEASE1);
3053 ZERO_STRUCT(break_info);
3055 done:
3056 smb2_util_close(tree1a, h1);
3057 smb2_util_close(tree1b, h2);
3058 smb2_util_close(tree2, h3);
3060 smb2_util_unlink(tree1a, fname);
3061 talloc_free(mem_ctx);
3062 return ret;
3065 static bool test_lease_complex1(struct torture_context *tctx,
3066 struct smb2_tree *tree1a)
3068 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3069 struct smb2_create io1;
3070 struct smb2_create io2;
3071 struct smb2_lease ls1;
3072 struct smb2_lease ls2;
3073 struct smb2_handle h = {{0}};
3074 struct smb2_handle h2 = {{0}};
3075 struct smb2_handle h3 = {{0}};
3076 struct smb2_write w;
3077 NTSTATUS status;
3078 const char *fname = "lease_complex1.dat";
3079 bool ret = true;
3080 uint32_t caps;
3081 struct smb2_tree *tree1b = NULL;
3082 struct smbcli_options options1;
3084 options1 = tree1a->session->transport->options;
3086 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3087 if (!(caps & SMB2_CAP_LEASING)) {
3088 torture_skip(tctx, "leases are not supported");
3091 tree1a->session->transport->lease.handler = torture_lease_handler;
3092 tree1a->session->transport->lease.private_data = tree1a;
3093 tree1a->session->transport->oplock.handler = torture_oplock_handler;
3094 tree1a->session->transport->oplock.private_data = tree1a;
3096 /* create a new connection (same client_guid) */
3097 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
3098 torture_warning(tctx, "couldn't reconnect, bailing\n");
3099 ret = false;
3100 goto done;
3103 tree1b->session->transport->lease.handler = torture_lease_handler;
3104 tree1b->session->transport->lease.private_data = tree1b;
3105 tree1b->session->transport->oplock.handler = torture_oplock_handler;
3106 tree1b->session->transport->oplock.private_data = tree1b;
3108 smb2_util_unlink(tree1a, fname);
3110 ZERO_STRUCT(break_info);
3112 /* Grab R lease over connection 1a */
3113 smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
3114 status = smb2_create(tree1a, mem_ctx, &io1);
3115 CHECK_STATUS(status, NT_STATUS_OK);
3116 h = io1.out.file.handle;
3117 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3118 CHECK_LEASE(&io1, "R", true, LEASE1, 0);
3120 /* Upgrade to RWH over connection 1b */
3121 ls1.lease_state = smb2_util_lease_state("RWH");
3122 status = smb2_create(tree1b, mem_ctx, &io1);
3123 CHECK_STATUS(status, NT_STATUS_OK);
3124 h2 = io1.out.file.handle;
3125 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3126 CHECK_LEASE(&io1, "RHW", true, LEASE1, 0);
3128 /* close over connection 1b */
3129 status = smb2_util_close(tree1b, h2);
3130 CHECK_STATUS(status, NT_STATUS_OK);
3132 /* Contend with LEASE2. */
3133 smb2_lease_create(&io2, &ls2, false, fname, LEASE2, smb2_util_lease_state("R"));
3134 status = smb2_create(tree1b, mem_ctx, &io2);
3135 CHECK_STATUS(status, NT_STATUS_OK);
3136 h3 = io2.out.file.handle;
3137 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3138 CHECK_LEASE(&io2, "R", true, LEASE2, 0);
3140 /* Verify that we were only sent one break. */
3141 CHECK_BREAK_INFO("RHW", "RH", LEASE1);
3143 /* again RH over connection 1b doesn't change the epoch */
3144 ls1.lease_state = smb2_util_lease_state("RH");
3145 status = smb2_create(tree1b, mem_ctx, &io1);
3146 CHECK_STATUS(status, NT_STATUS_OK);
3147 h2 = io1.out.file.handle;
3148 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3149 CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
3151 /* close over connection 1b */
3152 status = smb2_util_close(tree1b, h2);
3153 CHECK_STATUS(status, NT_STATUS_OK);
3155 ZERO_STRUCT(break_info);
3157 ZERO_STRUCT(w);
3158 w.in.file.handle = h;
3159 w.in.offset = 0;
3160 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3161 memset(w.in.data.data, 'o', w.in.data.length);
3162 status = smb2_write(tree1a, &w);
3163 CHECK_STATUS(status, NT_STATUS_OK);
3165 ls2.lease_epoch += 1;
3166 CHECK_BREAK_INFO("R", "", LEASE2);
3168 ZERO_STRUCT(break_info);
3170 ZERO_STRUCT(w);
3171 w.in.file.handle = h3;
3172 w.in.offset = 0;
3173 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3174 memset(w.in.data.data, 'o', w.in.data.length);
3175 status = smb2_write(tree1b, &w);
3176 CHECK_STATUS(status, NT_STATUS_OK);
3178 ls1.lease_epoch += 1;
3179 CHECK_BREAK_INFO("RH", "", LEASE1);
3181 done:
3182 smb2_util_close(tree1a, h);
3183 smb2_util_close(tree1b, h2);
3184 smb2_util_close(tree1b, h3);
3186 smb2_util_unlink(tree1a, fname);
3188 talloc_free(mem_ctx);
3190 return ret;
3193 static bool test_lease_v2_complex1(struct torture_context *tctx,
3194 struct smb2_tree *tree1a)
3196 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3197 struct smb2_create io1;
3198 struct smb2_create io2;
3199 struct smb2_lease ls1;
3200 struct smb2_lease ls2;
3201 struct smb2_handle h = {{0}};
3202 struct smb2_handle h2 = {{0}};
3203 struct smb2_handle h3 = {{0}};
3204 struct smb2_write w;
3205 NTSTATUS status;
3206 const char *fname = "lease_v2_complex1.dat";
3207 bool ret = true;
3208 uint32_t caps;
3209 enum protocol_types protocol;
3210 struct smb2_tree *tree1b = NULL;
3211 struct smbcli_options options1;
3213 options1 = tree1a->session->transport->options;
3215 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3216 if (!(caps & SMB2_CAP_LEASING)) {
3217 torture_skip(tctx, "leases are not supported");
3220 protocol = smbXcli_conn_protocol(tree1a->session->transport->conn);
3221 if (protocol < PROTOCOL_SMB3_00) {
3222 torture_skip(tctx, "v2 leases are not supported");
3225 tree1a->session->transport->lease.handler = torture_lease_handler;
3226 tree1a->session->transport->lease.private_data = tree1a;
3227 tree1a->session->transport->oplock.handler = torture_oplock_handler;
3228 tree1a->session->transport->oplock.private_data = tree1a;
3230 /* create a new connection (same client_guid) */
3231 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
3232 torture_warning(tctx, "couldn't reconnect, bailing\n");
3233 ret = false;
3234 goto done;
3237 tree1b->session->transport->lease.handler = torture_lease_handler;
3238 tree1b->session->transport->lease.private_data = tree1b;
3239 tree1b->session->transport->oplock.handler = torture_oplock_handler;
3240 tree1b->session->transport->oplock.private_data = tree1b;
3242 smb2_util_unlink(tree1a, fname);
3244 ZERO_STRUCT(break_info);
3246 /* Grab R lease over connection 1a */
3247 smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
3248 smb2_util_lease_state("R"), 0x4711);
3249 status = smb2_create(tree1a, mem_ctx, &io1);
3250 CHECK_STATUS(status, NT_STATUS_OK);
3251 h = io1.out.file.handle;
3252 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3253 ls1.lease_epoch += 1;
3254 CHECK_LEASE_V2(&io1, "R", true, LEASE1,
3255 0, 0, ls1.lease_epoch);
3257 /* Upgrade to RWH over connection 1b */
3258 ls1.lease_state = smb2_util_lease_state("RWH");
3259 status = smb2_create(tree1b, mem_ctx, &io1);
3260 CHECK_STATUS(status, NT_STATUS_OK);
3261 h2 = io1.out.file.handle;
3262 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3263 ls1.lease_epoch += 1;
3264 CHECK_LEASE_V2(&io1, "RHW", true, LEASE1,
3265 0, 0, ls1.lease_epoch);
3267 /* close over connection 1b */
3268 status = smb2_util_close(tree1b, h2);
3269 CHECK_STATUS(status, NT_STATUS_OK);
3271 /* Contend with LEASE2. */
3272 smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
3273 smb2_util_lease_state("R"), 0x11);
3274 status = smb2_create(tree1b, mem_ctx, &io2);
3275 CHECK_STATUS(status, NT_STATUS_OK);
3276 h3 = io2.out.file.handle;
3277 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3278 ls2.lease_epoch += 1;
3279 CHECK_LEASE_V2(&io2, "R", true, LEASE2,
3280 0, 0, ls2.lease_epoch);
3282 /* Verify that we were only sent one break. */
3283 ls1.lease_epoch += 1;
3284 CHECK_BREAK_INFO_V2(tree1a->session->transport,
3285 "RHW", "RH", LEASE1, ls1.lease_epoch);
3287 /* again RH over connection 1b doesn't change the epoch */
3288 ls1.lease_state = smb2_util_lease_state("RH");
3289 status = smb2_create(tree1b, mem_ctx, &io1);
3290 CHECK_STATUS(status, NT_STATUS_OK);
3291 h2 = io1.out.file.handle;
3292 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3293 CHECK_LEASE_V2(&io1, "RH", true, LEASE1,
3294 0, 0, ls1.lease_epoch);
3296 /* close over connection 1b */
3297 status = smb2_util_close(tree1b, h2);
3298 CHECK_STATUS(status, NT_STATUS_OK);
3300 ZERO_STRUCT(break_info);
3302 ZERO_STRUCT(w);
3303 w.in.file.handle = h;
3304 w.in.offset = 0;
3305 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3306 memset(w.in.data.data, 'o', w.in.data.length);
3307 status = smb2_write(tree1a, &w);
3308 CHECK_STATUS(status, NT_STATUS_OK);
3310 ls2.lease_epoch += 1;
3311 CHECK_BREAK_INFO_V2(tree1a->session->transport,
3312 "R", "", LEASE2, ls2.lease_epoch);
3314 ZERO_STRUCT(break_info);
3316 ZERO_STRUCT(w);
3317 w.in.file.handle = h3;
3318 w.in.offset = 0;
3319 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3320 memset(w.in.data.data, 'o', w.in.data.length);
3321 status = smb2_write(tree1b, &w);
3322 CHECK_STATUS(status, NT_STATUS_OK);
3324 ls1.lease_epoch += 1;
3325 CHECK_BREAK_INFO_V2(tree1a->session->transport,
3326 "RH", "", LEASE1, ls1.lease_epoch);
3328 done:
3329 smb2_util_close(tree1a, h);
3330 smb2_util_close(tree1b, h2);
3331 smb2_util_close(tree1b, h3);
3333 smb2_util_unlink(tree1a, fname);
3335 talloc_free(mem_ctx);
3337 return ret;
3340 static bool test_lease_v2_complex2(struct torture_context *tctx,
3341 struct smb2_tree *tree1a)
3343 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3344 struct smb2_create io1;
3345 struct smb2_create io2;
3346 struct smb2_lease ls1;
3347 struct smb2_lease ls2;
3348 struct smb2_handle h = {{0}};
3349 struct smb2_handle h2 = {{0}};
3350 struct smb2_request *req2 = NULL;
3351 struct smb2_lease_break_ack ack = {};
3352 NTSTATUS status;
3353 const char *fname = "lease_v2_complex2.dat";
3354 bool ret = true;
3355 uint32_t caps;
3356 enum protocol_types protocol;
3357 struct smb2_tree *tree1b = NULL;
3358 struct smbcli_options options1;
3360 options1 = tree1a->session->transport->options;
3362 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3363 if (!(caps & SMB2_CAP_LEASING)) {
3364 torture_skip(tctx, "leases are not supported");
3367 protocol = smbXcli_conn_protocol(tree1a->session->transport->conn);
3368 if (protocol < PROTOCOL_SMB3_00) {
3369 torture_skip(tctx, "v2 leases are not supported");
3372 tree1a->session->transport->lease.handler = torture_lease_handler;
3373 tree1a->session->transport->lease.private_data = tree1a;
3374 tree1a->session->transport->oplock.handler = torture_oplock_handler;
3375 tree1a->session->transport->oplock.private_data = tree1a;
3377 /* create a new connection (same client_guid) */
3378 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
3379 torture_warning(tctx, "couldn't reconnect, bailing\n");
3380 ret = false;
3381 goto done;
3384 tree1b->session->transport->lease.handler = torture_lease_handler;
3385 tree1b->session->transport->lease.private_data = tree1b;
3386 tree1b->session->transport->oplock.handler = torture_oplock_handler;
3387 tree1b->session->transport->oplock.private_data = tree1b;
3389 smb2_util_unlink(tree1a, fname);
3391 ZERO_STRUCT(break_info);
3393 /* Grab RWH lease over connection 1a */
3394 smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
3395 smb2_util_lease_state("RWH"), 0x4711);
3396 status = smb2_create(tree1a, mem_ctx, &io1);
3397 CHECK_STATUS(status, NT_STATUS_OK);
3398 h = io1.out.file.handle;
3399 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3400 ls1.lease_epoch += 1;
3401 CHECK_LEASE_V2(&io1, "RWH", true, LEASE1,
3402 0, 0, ls1.lease_epoch);
3405 * we defer acking the lease break.
3407 ZERO_STRUCT(break_info);
3408 break_info.lease_skip_ack = true;
3410 /* Ask for RWH on connection 1b, different lease. */
3411 smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
3412 smb2_util_lease_state("RWH"), 0x11);
3413 req2 = smb2_create_send(tree1b, &io2);
3414 torture_assert(tctx, req2 != NULL, "smb2_create_send");
3416 ls1.lease_epoch += 1;
3418 CHECK_BREAK_INFO_V2(tree1a->session->transport,
3419 "RWH", "RH", LEASE1, ls1.lease_epoch);
3421 /* Send the break ACK on tree1b. */
3422 ack.in.lease.lease_key =
3423 break_info.lease_break.current_lease.lease_key;
3424 ack.in.lease.lease_state = SMB2_LEASE_HANDLE|SMB2_LEASE_READ;
3426 status = smb2_lease_break_ack(tree1b, &ack);
3427 CHECK_STATUS(status, NT_STATUS_OK);
3428 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
3430 ZERO_STRUCT(break_info);
3432 status = smb2_create_recv(req2, tctx, &io2);
3433 CHECK_STATUS(status, NT_STATUS_OK);
3434 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3435 CHECK_LEASE_V2(&io2, "RH", true, LEASE2,
3436 0, 0, ls2.lease_epoch+1);
3437 h2 = io2.out.file.handle;
3439 done:
3440 smb2_util_close(tree1a, h);
3441 smb2_util_close(tree1b, h2);
3443 smb2_util_unlink(tree1a, fname);
3445 talloc_free(mem_ctx);
3447 return ret;
3451 static bool test_lease_timeout(struct torture_context *tctx,
3452 struct smb2_tree *tree)
3454 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3455 struct smb2_create io;
3456 struct smb2_lease ls1;
3457 struct smb2_lease ls2;
3458 struct smb2_handle h = {{0}};
3459 struct smb2_handle hnew = {{0}};
3460 struct smb2_handle h1b = {{0}};
3461 NTSTATUS status;
3462 const char *fname = "lease_timeout.dat";
3463 bool ret = true;
3464 struct smb2_lease_break_ack ack = {};
3465 struct smb2_request *req2 = NULL;
3466 struct smb2_write w;
3467 uint32_t caps;
3469 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
3470 if (!(caps & SMB2_CAP_LEASING)) {
3471 torture_skip(tctx, "leases are not supported");
3474 smb2_util_unlink(tree, fname);
3476 /* Grab a RWH lease. */
3477 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3478 status = smb2_create(tree, mem_ctx, &io);
3479 CHECK_STATUS(status, NT_STATUS_OK);
3480 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3481 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3482 h = io.out.file.handle;
3484 tree->session->transport->lease.handler = torture_lease_handler;
3485 tree->session->transport->lease.private_data = tree;
3486 tree->session->transport->oplock.handler = torture_oplock_handler;
3487 tree->session->transport->oplock.private_data = tree;
3490 * Just don't ack the lease break.
3492 ZERO_STRUCT(break_info);
3493 break_info.lease_skip_ack = true;
3495 /* Break with a RWH request. */
3496 smb2_lease_create(&io, &ls2, false, fname, LEASE2, smb2_util_lease_state("RWH"));
3497 req2 = smb2_create_send(tree, &io);
3498 torture_assert(tctx, req2 != NULL, "smb2_create_send");
3499 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
3501 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
3503 /* Copy the break request. */
3504 ack.in.lease.lease_key =
3505 break_info.lease_break.current_lease.lease_key;
3506 ack.in.lease.lease_state =
3507 break_info.lease_break.new_lease_state;
3509 /* Now wait for the timeout and get the reply. */
3510 status = smb2_create_recv(req2, tctx, &io);
3511 CHECK_STATUS(status, NT_STATUS_OK);
3512 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3513 CHECK_LEASE(&io, "RH", true, LEASE2, 0);
3514 hnew = io.out.file.handle;
3516 /* Ack the break after the timeout... */
3517 status = smb2_lease_break_ack(tree, &ack);
3518 CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
3520 /* Get state of the original handle. */
3521 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
3522 status = smb2_create(tree, mem_ctx, &io);
3523 CHECK_STATUS(status, NT_STATUS_OK);
3524 CHECK_LEASE(&io, "", true, LEASE1, 0);
3525 smb2_util_close(tree, io.out.file.handle);
3527 /* Write on the original handle and make sure it's still valid. */
3528 ZERO_STRUCT(break_info);
3529 ZERO_STRUCT(w);
3530 w.in.file.handle = h;
3531 w.in.offset = 0;
3532 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3533 memset(w.in.data.data, '1', w.in.data.length);
3534 status = smb2_write(tree, &w);
3535 CHECK_STATUS(status, NT_STATUS_OK);
3537 /* Causes new handle to break to NONE. */
3538 CHECK_BREAK_INFO("RH", "", LEASE2);
3540 /* Write on the new handle. */
3541 ZERO_STRUCT(break_info);
3542 ZERO_STRUCT(w);
3543 w.in.file.handle = hnew;
3544 w.in.offset = 0;
3545 w.in.data = data_blob_talloc(mem_ctx, NULL, 1024);
3546 memset(w.in.data.data, '2', w.in.data.length);
3547 status = smb2_write(tree, &w);
3548 CHECK_STATUS(status, NT_STATUS_OK);
3549 /* No break - original handle was already NONE. */
3550 CHECK_NO_BREAK(tctx);
3551 smb2_util_close(tree, hnew);
3553 /* Upgrade to R on LEASE1. */
3554 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
3555 status = smb2_create(tree, mem_ctx, &io);
3556 CHECK_STATUS(status, NT_STATUS_OK);
3557 CHECK_LEASE(&io, "R", true, LEASE1, 0);
3558 h1b = io.out.file.handle;
3559 smb2_util_close(tree, h1b);
3561 /* Upgrade to RWH on LEASE1. */
3562 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3563 status = smb2_create(tree, mem_ctx, &io);
3564 CHECK_STATUS(status, NT_STATUS_OK);
3565 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3566 h1b = io.out.file.handle;
3567 smb2_util_close(tree, h1b);
3569 done:
3570 smb2_util_close(tree, h);
3571 smb2_util_close(tree, hnew);
3572 smb2_util_close(tree, h1b);
3574 smb2_util_unlink(tree, fname);
3576 talloc_free(mem_ctx);
3578 return ret;
3581 static bool test_lease_v2_rename(struct torture_context *tctx,
3582 struct smb2_tree *tree)
3584 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3585 struct smb2_create io;
3586 struct smb2_lease ls1;
3587 struct smb2_lease ls2;
3588 struct smb2_handle h = {{0}};
3589 struct smb2_handle h1 = {{0}};
3590 struct smb2_handle h2 = {{0}};
3591 union smb_setfileinfo sinfo;
3592 const char *fname = "lease_v2_rename_src.dat";
3593 const char *fname_dst = "lease_v2_rename_dst.dat";
3594 bool ret = true;
3595 NTSTATUS status;
3596 uint32_t caps;
3597 enum protocol_types protocol;
3599 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
3600 if (!(caps & SMB2_CAP_LEASING)) {
3601 torture_skip(tctx, "leases are not supported");
3604 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
3605 if (protocol < PROTOCOL_SMB3_00) {
3606 torture_skip(tctx, "v2 leases are not supported");
3609 smb2_util_unlink(tree, fname);
3610 smb2_util_unlink(tree, fname_dst);
3612 tree->session->transport->lease.handler = torture_lease_handler;
3613 tree->session->transport->lease.private_data = tree;
3614 tree->session->transport->oplock.handler = torture_oplock_handler;
3615 tree->session->transport->oplock.private_data = tree;
3617 ZERO_STRUCT(break_info);
3619 ZERO_STRUCT(io);
3620 smb2_lease_v2_create_share(&io, &ls1, false, fname,
3621 smb2_util_share_access("RWD"),
3622 LEASE1, NULL,
3623 smb2_util_lease_state("RHW"),
3624 0x4711);
3625 status = smb2_create(tree, mem_ctx, &io);
3626 CHECK_STATUS(status, NT_STATUS_OK);
3627 h = io.out.file.handle;
3628 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3629 ls1.lease_epoch += 1;
3630 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
3632 /* Now rename - what happens ? */
3633 ZERO_STRUCT(sinfo);
3634 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
3635 sinfo.rename_information.in.file.handle = h;
3636 sinfo.rename_information.in.overwrite = true;
3637 sinfo.rename_information.in.new_name = fname_dst;
3638 status = smb2_setinfo_file(tree, &sinfo);
3639 CHECK_STATUS(status, NT_STATUS_OK);
3641 /* No lease break. */
3642 CHECK_NO_BREAK(tctx);
3644 /* Check we can open another handle on the new name. */
3645 smb2_lease_v2_create_share(&io, &ls1, false, fname_dst,
3646 smb2_util_share_access("RWD"),
3647 LEASE1, NULL,
3648 smb2_util_lease_state(""),
3649 ls1.lease_epoch);
3650 status = smb2_create(tree, mem_ctx, &io);
3651 CHECK_STATUS(status, NT_STATUS_OK);
3652 h1 = io.out.file.handle;
3653 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3654 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
3655 smb2_util_close(tree, h1);
3657 /* Try another lease key. */
3658 smb2_lease_v2_create_share(&io, &ls2, false, fname_dst,
3659 smb2_util_share_access("RWD"),
3660 LEASE2, NULL,
3661 smb2_util_lease_state("RWH"),
3662 0x44);
3663 status = smb2_create(tree, mem_ctx, &io);
3664 CHECK_STATUS(status, NT_STATUS_OK);
3665 h2 = io.out.file.handle;
3666 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3667 ls2.lease_epoch += 1;
3668 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch );
3669 CHECK_BREAK_INFO_V2(tree->session->transport,
3670 "RWH", "RH", LEASE1, ls1.lease_epoch + 1);
3671 ls1.lease_epoch += 1;
3672 ZERO_STRUCT(break_info);
3674 /* Now rename back. */
3675 ZERO_STRUCT(sinfo);
3676 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
3677 sinfo.rename_information.in.file.handle = h;
3678 sinfo.rename_information.in.overwrite = true;
3679 sinfo.rename_information.in.new_name = fname;
3680 status = smb2_setinfo_file(tree, &sinfo);
3681 CHECK_STATUS(status, NT_STATUS_OK);
3683 /* Breaks to R on LEASE2. */
3684 CHECK_BREAK_INFO_V2(tree->session->transport,
3685 "RH", "R", LEASE2, ls2.lease_epoch + 1);
3686 ls2.lease_epoch += 1;
3688 /* Check we can open another handle on the current name. */
3689 smb2_lease_v2_create_share(&io, &ls1, false, fname,
3690 smb2_util_share_access("RWD"),
3691 LEASE1, NULL,
3692 smb2_util_lease_state(""),
3693 ls1.lease_epoch);
3694 status = smb2_create(tree, mem_ctx, &io);
3695 CHECK_STATUS(status, NT_STATUS_OK);
3696 h1 = io.out.file.handle;
3697 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3698 CHECK_LEASE_V2(&io, "RH", true, LEASE1, 0, 0, ls1.lease_epoch);
3699 smb2_util_close(tree, h1);
3701 done:
3703 smb2_util_close(tree, h);
3704 smb2_util_close(tree, h1);
3705 smb2_util_close(tree, h2);
3707 smb2_util_unlink(tree, fname);
3708 smb2_util_unlink(tree, fname_dst);
3710 smb2_util_unlink(tree, fname);
3711 talloc_free(mem_ctx);
3712 return ret;
3716 static bool test_lease_dynamic_share(struct torture_context *tctx,
3717 struct smb2_tree *tree1a)
3719 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3720 struct smb2_create io;
3721 struct smb2_lease ls1;
3722 struct smb2_handle h, h1, h2;
3723 struct smb2_write w;
3724 NTSTATUS status;
3725 const char *fname = "dynamic_path.dat";
3726 bool ret = true;
3727 uint32_t caps;
3728 struct smb2_tree *tree_2_1 = NULL;
3729 struct smb2_tree *tree_3_0 = NULL;
3730 struct smbcli_options options2_1;
3731 struct smbcli_options options3_0;
3732 const char *orig_share = NULL;
3734 if (!TARGET_IS_SAMBA3(tctx)) {
3735 torture_skip(tctx, "dynamic shares are not supported");
3736 return true;
3739 options2_1 = tree1a->session->transport->options;
3740 options3_0 = tree1a->session->transport->options;
3742 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3743 if (!(caps & SMB2_CAP_LEASING)) {
3744 torture_skip(tctx, "leases are not supported");
3748 * Save off original share name and change it to dynamic_share.
3749 * This must have been pre-created with a dynamic path containing
3750 * %R.
3753 orig_share = lpcfg_parm_string(tctx->lp_ctx, NULL, "torture", "share");
3754 orig_share = talloc_strdup(tctx->lp_ctx, orig_share);
3755 if (orig_share == NULL) {
3756 torture_result(tctx, TORTURE_FAIL, __location__ "no memory\n");
3757 ret = false;
3758 goto done;
3760 lpcfg_set_cmdline(tctx->lp_ctx, "torture:share", "dynamic_share");
3762 /* Set max protocol to SMB2.1 */
3763 options2_1.max_protocol = PROTOCOL_SMB2_10;
3764 /* create a new connection (same client_guid) */
3765 if (!torture_smb2_connection_ext(tctx, 0, &options2_1, &tree_2_1)) {
3766 torture_result(tctx, TORTURE_FAIL,
3767 __location__ "couldn't reconnect "
3768 "max protocol 2.1, bailing\n");
3769 ret = false;
3770 goto done;
3773 tree_2_1->session->transport->lease.handler = torture_lease_handler;
3774 tree_2_1->session->transport->lease.private_data = tree_2_1;
3775 tree_2_1->session->transport->oplock.handler = torture_oplock_handler;
3776 tree_2_1->session->transport->oplock.private_data = tree_2_1;
3778 smb2_util_unlink(tree_2_1, fname);
3780 /* Set max protocol to SMB3.0 */
3781 options3_0.max_protocol = PROTOCOL_SMB3_00;
3782 /* create a new connection (same client_guid) */
3783 if (!torture_smb2_connection_ext(tctx, 0, &options3_0, &tree_3_0)) {
3784 torture_result(tctx, TORTURE_FAIL,
3785 __location__ "couldn't reconnect "
3786 "max protocol 3.0, bailing\n");
3787 ret = false;
3788 goto done;
3791 tree_3_0->session->transport->lease.handler = torture_lease_handler;
3792 tree_3_0->session->transport->lease.private_data = tree_3_0;
3793 tree_3_0->session->transport->oplock.handler = torture_oplock_handler;
3794 tree_3_0->session->transport->oplock.private_data = tree_3_0;
3796 smb2_util_unlink(tree_3_0, fname);
3798 ZERO_STRUCT(break_info);
3800 /* Get RWH lease over connection 2_1 */
3801 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3802 status = smb2_create(tree_2_1, mem_ctx, &io);
3803 CHECK_STATUS(status, NT_STATUS_OK);
3804 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3805 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3806 h = io.out.file.handle;
3808 /* Write some data into it. */
3809 w.in.file.handle = h;
3810 w.in.offset = 0;
3811 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3812 memset(w.in.data.data, '1', w.in.data.length);
3813 status = smb2_write(tree_2_1, &w);
3814 CHECK_STATUS(status, NT_STATUS_OK);
3816 /* Open the same name over connection 3_0. */
3817 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3818 status = smb2_create(tree_3_0, mem_ctx, &io);
3819 CHECK_STATUS(status, NT_STATUS_OK);
3820 h1 = io.out.file.handle;
3821 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3823 /* h1 should have replied with NONE. */
3824 CHECK_LEASE(&io, "", true, LEASE1, 0);
3826 /* We should have broken h to NONE. */
3827 CHECK_BREAK_INFO("RWH", "", LEASE1);
3829 /* Try to upgrade to RWH over connection 2_1 */
3830 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3831 status = smb2_create(tree_2_1, mem_ctx, &io);
3832 CHECK_STATUS(status, NT_STATUS_OK);
3833 h2 = io.out.file.handle;
3834 CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
3835 CHECK_VAL(io.out.size, 4096);
3836 CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
3837 /* Should have been denied. */
3838 CHECK_LEASE(&io, "", true, LEASE1, 0);
3839 smb2_util_close(tree_2_1, h2);
3841 /* Try to upgrade to RWH over connection 3_0 */
3842 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3843 status = smb2_create(tree_3_0, mem_ctx, &io);
3844 CHECK_STATUS(status, NT_STATUS_OK);
3845 h2 = io.out.file.handle;
3846 CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
3847 CHECK_VAL(io.out.size, 0);
3848 CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
3849 /* Should have been denied. */
3850 CHECK_LEASE(&io, "", true, LEASE1, 0);
3851 smb2_util_close(tree_3_0, h2);
3853 /* Write some data into it. */
3854 w.in.file.handle = h1;
3855 w.in.offset = 0;
3856 w.in.data = data_blob_talloc(mem_ctx, NULL, 1024);
3857 memset(w.in.data.data, '2', w.in.data.length);
3858 status = smb2_write(tree_3_0, &w);
3859 CHECK_STATUS(status, NT_STATUS_OK);
3861 /* Close everything.. */
3862 smb2_util_close(tree_2_1, h);
3863 smb2_util_close(tree_3_0, h1);
3865 /* And ensure we can get a lease ! */
3866 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3867 status = smb2_create(tree_2_1, mem_ctx, &io);
3868 CHECK_STATUS(status, NT_STATUS_OK);
3869 CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
3870 CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
3871 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3872 h = io.out.file.handle;
3873 /* And the file is the right size. */
3874 CHECK_VAL(io.out.size, 4096); \
3875 /* Close it. */
3876 smb2_util_close(tree_2_1, h);
3878 /* And ensure we can get a lease ! */
3879 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3880 status = smb2_create(tree_3_0, mem_ctx, &io);
3881 CHECK_STATUS(status, NT_STATUS_OK);
3882 CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
3883 CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
3884 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3885 h = io.out.file.handle;
3886 /* And the file is the right size. */
3887 CHECK_VAL(io.out.size, 1024); \
3888 /* Close it. */
3889 smb2_util_close(tree_3_0, h);
3891 done:
3893 if (tree_2_1 != NULL) {
3894 smb2_util_close(tree_2_1, h);
3895 smb2_util_unlink(tree_2_1, fname);
3897 if (tree_3_0 != NULL) {
3898 smb2_util_close(tree_3_0, h1);
3899 smb2_util_close(tree_3_0, h2);
3901 smb2_util_unlink(tree_3_0, fname);
3904 /* Set sharename back. */
3905 lpcfg_set_cmdline(tctx->lp_ctx, "torture:share", orig_share);
3907 talloc_free(mem_ctx);
3909 return ret;
3912 struct torture_suite *torture_smb2_lease_init(void)
3914 struct torture_suite *suite =
3915 torture_suite_create(talloc_autofree_context(), "lease");
3917 torture_suite_add_1smb2_test(suite, "request", test_lease_request);
3918 torture_suite_add_1smb2_test(suite, "break_twice",
3919 test_lease_break_twice);
3920 torture_suite_add_1smb2_test(suite, "nobreakself",
3921 test_lease_nobreakself);
3922 torture_suite_add_1smb2_test(suite, "statopen", test_lease_statopen);
3923 torture_suite_add_1smb2_test(suite, "upgrade", test_lease_upgrade);
3924 torture_suite_add_1smb2_test(suite, "upgrade2", test_lease_upgrade2);
3925 torture_suite_add_1smb2_test(suite, "upgrade3", test_lease_upgrade3);
3926 torture_suite_add_1smb2_test(suite, "break", test_lease_break);
3927 torture_suite_add_1smb2_test(suite, "oplock", test_lease_oplock);
3928 torture_suite_add_1smb2_test(suite, "multibreak", test_lease_multibreak);
3929 torture_suite_add_1smb2_test(suite, "breaking1", test_lease_breaking1);
3930 torture_suite_add_1smb2_test(suite, "breaking2", test_lease_breaking2);
3931 torture_suite_add_1smb2_test(suite, "breaking3", test_lease_breaking3);
3932 torture_suite_add_1smb2_test(suite, "v2_breaking3", test_lease_v2_breaking3);
3933 torture_suite_add_1smb2_test(suite, "breaking4", test_lease_breaking4);
3934 torture_suite_add_1smb2_test(suite, "breaking5", test_lease_breaking5);
3935 torture_suite_add_1smb2_test(suite, "breaking6", test_lease_breaking6);
3936 torture_suite_add_2smb2_test(suite, "lock1", test_lease_lock1);
3937 torture_suite_add_1smb2_test(suite, "complex1", test_lease_complex1);
3938 torture_suite_add_1smb2_test(suite, "v2_request_parent",
3939 test_lease_v2_request_parent);
3940 torture_suite_add_1smb2_test(suite, "v2_request", test_lease_v2_request);
3941 torture_suite_add_1smb2_test(suite, "v2_epoch1", test_lease_v2_epoch1);
3942 torture_suite_add_1smb2_test(suite, "v2_epoch2", test_lease_v2_epoch2);
3943 torture_suite_add_1smb2_test(suite, "v2_epoch3", test_lease_v2_epoch3);
3944 torture_suite_add_1smb2_test(suite, "v2_complex1", test_lease_v2_complex1);
3945 torture_suite_add_1smb2_test(suite, "v2_complex2", test_lease_v2_complex2);
3946 torture_suite_add_1smb2_test(suite, "v2_rename", test_lease_v2_rename);
3947 torture_suite_add_1smb2_test(suite, "dynamic_share", test_lease_dynamic_share);
3948 torture_suite_add_1smb2_test(suite, "timeout", test_lease_timeout);
3950 suite->description = talloc_strdup(suite, "SMB2-LEASE tests");
3952 return suite;