smbd: Fix cached dos attributes
[Samba.git] / source4 / torture / smb2 / lease.c
blob60c79e7666b8fb558a6b83791fa193bac9f715ec
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"
32 #include "lease_break_handler.h"
34 #define CHECK_VAL(v, correct) do { \
35 if ((v) != (correct)) { \
36 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
37 __location__, #v, (int)(v), (int)(correct)); \
38 ret = false; \
39 }} while (0)
41 #define CHECK_STATUS(status, correct) do { \
42 if (!NT_STATUS_EQUAL(status, correct)) { \
43 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
44 nt_errstr(status), nt_errstr(correct)); \
45 ret = false; \
46 goto done; \
47 }} while (0)
49 #define CHECK_CREATED(__io, __created, __attribute) \
50 do { \
51 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
52 CHECK_VAL((__io)->out.size, 0); \
53 CHECK_VAL((__io)->out.file_attr, (__attribute)); \
54 CHECK_VAL((__io)->out.reserved2, 0); \
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 = {
337 .data = {},
339 struct smb2_handle hnew = {
340 .data = {},
342 NTSTATUS status;
343 struct smb2_create io;
344 struct smb2_lease ls;
345 const char *fname = "lease_upgrade2.dat";
346 bool ret = true;
347 int i;
348 uint32_t caps;
350 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
351 if (!(caps & SMB2_CAP_LEASING)) {
352 torture_skip(tctx, "leases are not supported");
355 for (i = 0; i < NUM_UPGRADE_TESTS; i++) {
356 struct lease_upgrade2_test t = lease_upgrade2_tests[i];
358 smb2_util_unlink(tree, fname);
360 /* Grab a lease. */
361 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.initial));
362 status = smb2_create(tree, mem_ctx, &io);
363 CHECK_STATUS(status, NT_STATUS_OK);
364 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
365 CHECK_LEASE(&io, t.initial, true, LEASE1, 0);
366 h = io.out.file.handle;
368 /* Upgrade. */
369 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to));
370 status = smb2_create(tree, mem_ctx, &io);
371 CHECK_STATUS(status, NT_STATUS_OK);
372 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
373 CHECK_LEASE(&io, t.expected, true, LEASE1, 0);
374 hnew = io.out.file.handle;
376 smb2_util_close(tree, hnew);
377 smb2_util_close(tree, h);
380 done:
381 smb2_util_close(tree, h);
382 smb2_util_close(tree, hnew);
384 smb2_util_unlink(tree, fname);
386 talloc_free(mem_ctx);
388 return ret;
393 * upgrade3:
394 * full matrix of lease upgrade combinations
395 * (contended case)
397 * We start with 2 leases, and check how one can
398 * be upgraded
400 * The summary of the behaviour is this:
401 * -------------------------------------
403 * If we have two leases (lease1 and lease2) on the same file,
404 * then attempt to upgrade lease1 results in a change if and only
405 * if the requested lease state:
406 * - is valid,
407 * - is strictly a superset of lease1, and
408 * - can held together with lease2.
410 * In that case, the resulting lease state of the upgraded lease1
411 * is the state requested in the upgrade. lease2 is not broken
412 * and remains unchanged.
414 * Note that this contrasts the case of directly opening with
415 * an initial requested lease state, in which case you get that
416 * portion of the requested state that can be shared with the
417 * already existing leases (or the states that they get broken to).
419 struct lease_upgrade3_test {
420 const char *held1;
421 const char *held2;
422 const char *upgrade_to;
423 const char *upgraded_to;
426 #define NUM_UPGRADE3_TESTS ( 20 )
427 struct lease_upgrade3_test lease_upgrade3_tests[NUM_UPGRADE3_TESTS] = {
428 {"R", "R", "", "R" },
429 {"R", "R", "R", "R" },
430 {"R", "R", "RW", "R" },
431 {"R", "R", "RH", "RH" },
432 {"R", "R", "RHW", "R" },
434 {"R", "RH", "", "R" },
435 {"R", "RH", "R", "R" },
436 {"R", "RH", "RW", "R" },
437 {"R", "RH", "RH", "RH" },
438 {"R", "RH", "RHW", "R" },
440 {"RH", "R", "", "RH" },
441 {"RH", "R", "R", "RH" },
442 {"RH", "R", "RW", "RH" },
443 {"RH", "R", "RH", "RH" },
444 {"RH", "R", "RHW", "RH" },
446 {"RH", "RH", "", "RH" },
447 {"RH", "RH", "R", "RH" },
448 {"RH", "RH", "RW", "RH" },
449 {"RH", "RH", "RH", "RH" },
450 {"RH", "RH", "RHW", "RH" },
453 static bool test_lease_upgrade3(struct torture_context *tctx,
454 struct smb2_tree *tree)
456 TALLOC_CTX *mem_ctx = talloc_new(tctx);
457 struct smb2_handle h, h2, hnew;
458 NTSTATUS status;
459 struct smb2_create io;
460 struct smb2_lease ls;
461 const char *fname = "lease_upgrade3.dat";
462 bool ret = true;
463 int i;
464 uint32_t caps;
466 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
467 if (!(caps & SMB2_CAP_LEASING)) {
468 torture_skip(tctx, "leases are not supported");
471 tree->session->transport->lease.handler = torture_lease_handler;
472 tree->session->transport->lease.private_data = tree;
474 smb2_util_unlink(tree, fname);
476 for (i = 0; i < NUM_UPGRADE3_TESTS; i++) {
477 struct lease_upgrade3_test t = lease_upgrade3_tests[i];
479 smb2_util_unlink(tree, fname);
481 torture_reset_lease_break_info(tctx, &lease_break_info);
483 /* grab first lease */
484 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.held1));
485 status = smb2_create(tree, mem_ctx, &io);
486 CHECK_STATUS(status, NT_STATUS_OK);
487 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
488 CHECK_LEASE(&io, t.held1, true, LEASE1, 0);
489 h = io.out.file.handle;
491 /* grab second lease */
492 smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state(t.held2));
493 status = smb2_create(tree, mem_ctx, &io);
494 CHECK_STATUS(status, NT_STATUS_OK);
495 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
496 CHECK_LEASE(&io, t.held2, true, LEASE2, 0);
497 h2 = io.out.file.handle;
499 /* no break has happened */
500 CHECK_VAL(lease_break_info.count, 0);
501 CHECK_VAL(lease_break_info.failures, 0);
503 /* try to upgrade lease1 */
504 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to));
505 status = smb2_create(tree, mem_ctx, &io);
506 CHECK_STATUS(status, NT_STATUS_OK);
507 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
508 CHECK_LEASE(&io, t.upgraded_to, true, LEASE1, 0);
509 hnew = io.out.file.handle;
511 /* no break has happened */
512 CHECK_VAL(lease_break_info.count, 0);
513 CHECK_VAL(lease_break_info.failures, 0);
515 smb2_util_close(tree, hnew);
516 smb2_util_close(tree, h);
517 smb2_util_close(tree, h2);
520 done:
521 smb2_util_close(tree, h);
522 smb2_util_close(tree, hnew);
523 smb2_util_close(tree, h2);
525 smb2_util_unlink(tree, fname);
527 talloc_free(mem_ctx);
529 return ret;
535 break_results should be read as "held lease, new lease, hold broken to, new
536 grant", i.e. { "RH", "RW", "RH", "R" } means that if key1 holds RH and key2
537 tries for RW, key1 will be broken to RH (in this case, not broken at all)
538 and key2 will be granted R.
540 Note: break_results only includes things that Win7 will actually grant (see
541 request_results above).
543 #define NBREAK_RESULTS 16
544 static const char *break_results[NBREAK_RESULTS][4] = {
545 {"R", "R", "R", "R"},
546 {"R", "RH", "R", "RH"},
547 {"R", "RW", "R", "R"},
548 {"R", "RHW", "R", "RH"},
550 {"RH", "R", "RH", "R"},
551 {"RH", "RH", "RH", "RH"},
552 {"RH", "RW", "RH", "R"},
553 {"RH", "RHW", "RH", "RH"},
555 {"RW", "R", "R", "R"},
556 {"RW", "RH", "R", "RH"},
557 {"RW", "RW", "R", "R"},
558 {"RW", "RHW", "R", "RH"},
560 {"RHW", "R", "RH", "R"},
561 {"RHW", "RH", "RH", "RH"},
562 {"RHW", "RW", "RH", "R"},
563 {"RHW", "RHW", "RH", "RH"},
566 static bool test_lease_break(struct torture_context *tctx,
567 struct smb2_tree *tree)
569 TALLOC_CTX *mem_ctx = talloc_new(tctx);
570 struct smb2_create io;
571 struct smb2_lease ls;
572 struct smb2_handle h, h2, h3;
573 NTSTATUS status;
574 const char *fname = "lease_break.dat";
575 bool ret = true;
576 int i;
577 uint32_t caps;
579 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
580 if (!(caps & SMB2_CAP_LEASING)) {
581 torture_skip(tctx, "leases are not supported");
584 tree->session->transport->lease.handler = torture_lease_handler;
585 tree->session->transport->lease.private_data = tree;
587 smb2_util_unlink(tree, fname);
589 for (i = 0; i < NBREAK_RESULTS; i++) {
590 const char *held = break_results[i][0];
591 const char *contend = break_results[i][1];
592 const char *brokento = break_results[i][2];
593 const char *granted = break_results[i][3];
594 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
595 "expecting break to %s(%x) and grant of %s(%x)\n",
596 held, smb2_util_lease_state(held), contend, smb2_util_lease_state(contend),
597 brokento, smb2_util_lease_state(brokento), granted, smb2_util_lease_state(granted));
599 torture_reset_lease_break_info(tctx, &lease_break_info);
601 /* Grab lease. */
602 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held));
603 status = smb2_create(tree, mem_ctx, &io);
604 CHECK_STATUS(status, NT_STATUS_OK);
605 h = io.out.file.handle;
606 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
607 CHECK_LEASE(&io, held, true, LEASE1, 0);
609 /* Possibly contend lease. */
610 smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state(contend));
611 status = smb2_create(tree, mem_ctx, &io);
612 CHECK_STATUS(status, NT_STATUS_OK);
613 h2 = io.out.file.handle;
614 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
615 CHECK_LEASE(&io, granted, true, LEASE2, 0);
617 if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) {
618 CHECK_BREAK_INFO(held, brokento, LEASE1);
619 } else {
620 CHECK_NO_BREAK(tctx);
623 torture_reset_lease_break_info(tctx, &lease_break_info);
626 Now verify that an attempt to upgrade LEASE1 results in no
627 break and no change in LEASE1.
629 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
630 status = smb2_create(tree, mem_ctx, &io);
631 CHECK_STATUS(status, NT_STATUS_OK);
632 h3 = io.out.file.handle;
633 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
634 CHECK_LEASE(&io, brokento, true, LEASE1, 0);
635 CHECK_VAL(lease_break_info.count, 0);
636 CHECK_VAL(lease_break_info.failures, 0);
638 smb2_util_close(tree, h);
639 smb2_util_close(tree, h2);
640 smb2_util_close(tree, h3);
642 status = smb2_util_unlink(tree, fname);
643 CHECK_STATUS(status, NT_STATUS_OK);
646 done:
647 smb2_util_close(tree, h);
648 smb2_util_close(tree, h2);
650 smb2_util_unlink(tree, fname);
652 talloc_free(mem_ctx);
654 return ret;
657 static bool test_lease_nobreakself(struct torture_context *tctx,
658 struct smb2_tree *tree)
660 TALLOC_CTX *mem_ctx = talloc_new(tctx);
661 struct smb2_create io;
662 struct smb2_lease ls;
663 struct smb2_handle h1 = {{0}};
664 struct smb2_handle h2 = {{0}};
665 NTSTATUS status;
666 const char *fname = "lease_nobreakself.dat";
667 bool ret = true;
668 uint32_t caps;
669 char c = 0;
671 caps = smb2cli_conn_server_capabilities(
672 tree->session->transport->conn);
673 if (!(caps & SMB2_CAP_LEASING)) {
674 torture_skip(tctx, "leases are not supported");
677 smb2_util_unlink(tree, fname);
679 /* Win7 is happy to grant RHW leases on files. */
680 smb2_lease_create(&io, &ls, false, fname, LEASE1,
681 smb2_util_lease_state("R"));
682 status = smb2_create(tree, mem_ctx, &io);
683 CHECK_STATUS(status, NT_STATUS_OK);
684 h1 = io.out.file.handle;
685 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
686 CHECK_LEASE(&io, "R", true, LEASE1, 0);
688 smb2_lease_create(&io, &ls, false, fname, LEASE2,
689 smb2_util_lease_state("R"));
690 status = smb2_create(tree, mem_ctx, &io);
691 CHECK_STATUS(status, NT_STATUS_OK);
692 h2 = io.out.file.handle;
693 CHECK_LEASE(&io, "R", true, LEASE2, 0);
695 torture_reset_lease_break_info(tctx, &lease_break_info);
697 tree->session->transport->lease.handler = torture_lease_handler;
698 tree->session->transport->lease.private_data = tree;
700 /* Make sure we don't break ourselves on write */
702 status = smb2_util_write(tree, h1, &c, 0, 1);
703 CHECK_STATUS(status, NT_STATUS_OK);
704 CHECK_BREAK_INFO("R", "", LEASE2);
706 /* Try the other way round. First, upgrade LEASE2 to R again */
708 smb2_lease_create(&io, &ls, false, fname, LEASE2,
709 smb2_util_lease_state("R"));
710 status = smb2_create(tree, mem_ctx, &io);
711 CHECK_STATUS(status, NT_STATUS_OK);
712 CHECK_LEASE(&io, "R", true, LEASE2, 0);
713 smb2_util_close(tree, io.out.file.handle);
715 /* Now break LEASE1 via h2 */
717 torture_reset_lease_break_info(tctx, &lease_break_info);
718 status = smb2_util_write(tree, h2, &c, 0, 1);
719 CHECK_STATUS(status, NT_STATUS_OK);
720 CHECK_BREAK_INFO("R", "", LEASE1);
722 /* .. and break LEASE2 via h1 */
724 torture_reset_lease_break_info(tctx, &lease_break_info);
725 status = smb2_util_write(tree, h1, &c, 0, 1);
726 CHECK_STATUS(status, NT_STATUS_OK);
727 CHECK_BREAK_INFO("R", "", LEASE2);
729 done:
730 smb2_util_close(tree, h2);
731 smb2_util_close(tree, h1);
732 smb2_util_unlink(tree, fname);
733 talloc_free(mem_ctx);
734 return ret;
737 static bool test_lease_statopen(struct torture_context *tctx,
738 struct smb2_tree *tree)
740 TALLOC_CTX *mem_ctx = talloc_new(tctx);
741 struct smb2_create io;
742 struct smb2_lease ls;
743 struct smb2_handle h1 = {{0}};
744 struct smb2_handle h2 = {{0}};
745 NTSTATUS status;
746 const char *fname = "lease_statopen.dat";
747 bool ret = true;
748 uint32_t caps;
750 caps = smb2cli_conn_server_capabilities(
751 tree->session->transport->conn);
752 if (!(caps & SMB2_CAP_LEASING)) {
753 torture_skip(tctx, "leases are not supported");
756 smb2_util_unlink(tree, fname);
758 /* Create file. */
759 smb2_lease_create(&io, &ls, false, fname, LEASE1,
760 smb2_util_lease_state("RWH"));
761 status = smb2_create(tree, mem_ctx, &io);
762 CHECK_STATUS(status, NT_STATUS_OK);
763 h1 = io.out.file.handle;
764 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
765 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
766 smb2_util_close(tree, h1);
768 /* Stat open file with RWH lease. */
769 smb2_lease_create_share(&io, &ls, false, fname, 0, LEASE1,
770 smb2_util_lease_state("RWH"));
771 io.in.desired_access = FILE_READ_ATTRIBUTES;
772 status = smb2_create(tree, mem_ctx, &io);
773 CHECK_STATUS(status, NT_STATUS_OK);
774 h2 = io.out.file.handle;
775 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
777 torture_reset_lease_break_info(tctx, &lease_break_info);
779 tree->session->transport->lease.handler = torture_lease_handler;
780 tree->session->transport->lease.private_data = tree;
782 /* Ensure non-stat open doesn't break and gets same lease
783 state as existing stat open. */
784 smb2_lease_create(&io, &ls, false, fname, LEASE1,
785 smb2_util_lease_state(""));
786 status = smb2_create(tree, mem_ctx, &io);
787 CHECK_STATUS(status, NT_STATUS_OK);
788 h1 = io.out.file.handle;
789 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
790 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
792 CHECK_NO_BREAK(tctx);
793 smb2_util_close(tree, h1);
795 /* Open with conflicting lease. stat open should break down to RH */
796 smb2_lease_create(&io, &ls, false, fname, LEASE2,
797 smb2_util_lease_state("RWH"));
798 status = smb2_create(tree, mem_ctx, &io);
799 CHECK_STATUS(status, NT_STATUS_OK);
800 h1 = io.out.file.handle;
801 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
802 CHECK_LEASE(&io, "RH", true, LEASE2, 0);
804 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
806 done:
807 smb2_util_close(tree, h2);
808 smb2_util_close(tree, h1);
809 smb2_util_unlink(tree, fname);
810 talloc_free(mem_ctx);
811 return ret;
814 static bool test_lease_statopen2(struct torture_context *tctx,
815 struct smb2_tree *tree)
817 TALLOC_CTX *mem_ctx = talloc_new(tctx);
818 struct smb2_create io;
819 struct smb2_lease ls;
820 struct smb2_handle h1 = {{0}};
821 struct smb2_handle h2 = {{0}};
822 struct smb2_handle h3 = {{0}};
823 NTSTATUS status;
824 const char *fname = "lease_statopen2.dat";
825 bool ret = true;
826 uint32_t caps;
828 caps = smb2cli_conn_server_capabilities(
829 tree->session->transport->conn);
830 if (!(caps & SMB2_CAP_LEASING)) {
831 torture_skip(tctx, "leases are not supported");
834 smb2_util_unlink(tree, fname);
835 torture_reset_lease_break_info(tctx, &lease_break_info);
836 tree->session->transport->lease.handler = torture_lease_handler;
837 tree->session->transport->lease.private_data = tree;
839 status = torture_smb2_testfile(tree, fname, &h1);
840 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
841 "smb2_create failed\n");
842 smb2_util_close(tree, h1);
843 ZERO_STRUCT(h1);
845 /* Open file with RWH lease. */
846 smb2_lease_create_share(&io, &ls, false, fname,
847 smb2_util_share_access("RWD"),
848 LEASE1,
849 smb2_util_lease_state("RWH"));
850 io.in.desired_access = SEC_FILE_WRITE_DATA;
851 status = smb2_create(tree, mem_ctx, &io);
852 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
853 "smb2_create failed\n");
854 h1 = io.out.file.handle;
855 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
857 /* Stat open */
858 ZERO_STRUCT(io);
859 io.in.desired_access = FILE_READ_ATTRIBUTES;
860 io.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
861 io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
862 io.in.create_disposition = NTCREATEX_DISP_OPEN;
863 io.in.fname = fname;
864 status = smb2_create(tree, mem_ctx, &io);
865 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
866 "smb2_create failed\n");
867 h2 = io.out.file.handle;
869 /* Open file with RWH lease. */
870 smb2_lease_create_share(&io, &ls, false, fname,
871 smb2_util_share_access("RWD"),
872 LEASE1,
873 smb2_util_lease_state("RWH"));
874 io.in.desired_access = SEC_FILE_WRITE_DATA;
875 status = smb2_create(tree, mem_ctx, &io);
876 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
877 "smb2_create failed\n");
878 h3 = io.out.file.handle;
879 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
881 done:
882 if (!smb2_util_handle_empty(h3)) {
883 smb2_util_close(tree, h3);
885 if (!smb2_util_handle_empty(h2)) {
886 smb2_util_close(tree, h2);
888 if (!smb2_util_handle_empty(h1)) {
889 smb2_util_close(tree, h1);
891 smb2_util_unlink(tree, fname);
892 talloc_free(mem_ctx);
893 return ret;
896 static bool test_lease_statopen3(struct torture_context *tctx,
897 struct smb2_tree *tree)
899 TALLOC_CTX *mem_ctx = talloc_new(tctx);
900 struct smb2_create io;
901 struct smb2_lease ls;
902 struct smb2_handle h1 = {{0}};
903 struct smb2_handle h2 = {{0}};
904 NTSTATUS status;
905 const char *fname = "lease_statopen3.dat";
906 bool ret = true;
907 uint32_t caps;
909 caps = smb2cli_conn_server_capabilities(
910 tree->session->transport->conn);
911 if (!(caps & SMB2_CAP_LEASING)) {
912 torture_skip(tctx, "leases are not supported");
915 smb2_util_unlink(tree, fname);
916 torture_reset_lease_break_info(tctx, &lease_break_info);
917 tree->session->transport->lease.handler = torture_lease_handler;
918 tree->session->transport->lease.private_data = tree;
920 status = torture_smb2_testfile(tree, fname, &h1);
921 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
922 "smb2_create failed\n");
923 smb2_util_close(tree, h1);
924 ZERO_STRUCT(h1);
926 /* Stat open */
927 ZERO_STRUCT(io);
928 io.in.desired_access = FILE_READ_ATTRIBUTES;
929 io.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
930 io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
931 io.in.create_disposition = NTCREATEX_DISP_OPEN;
932 io.in.fname = fname;
933 status = smb2_create(tree, mem_ctx, &io);
934 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
935 "smb2_create failed\n");
936 h1 = io.out.file.handle;
938 /* Open file with RWH lease. */
939 smb2_lease_create_share(&io, &ls, false, fname,
940 smb2_util_share_access("RWD"),
941 LEASE1,
942 smb2_util_lease_state("RWH"));
943 io.in.desired_access = SEC_FILE_WRITE_DATA;
944 status = smb2_create(tree, mem_ctx, &io);
945 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
946 "smb2_create failed\n");
947 h2 = io.out.file.handle;
948 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
950 done:
951 if (!smb2_util_handle_empty(h1)) {
952 smb2_util_close(tree, h1);
954 if (!smb2_util_handle_empty(h2)) {
955 smb2_util_close(tree, h2);
957 smb2_util_unlink(tree, fname);
958 talloc_free(mem_ctx);
959 return ret;
962 static bool test_lease_statopen4_do(struct torture_context *tctx,
963 struct smb2_tree *tree,
964 uint32_t access_mask,
965 bool expect_stat_open)
967 TALLOC_CTX *mem_ctx = talloc_new(tctx);
968 struct smb2_create io;
969 struct smb2_lease ls;
970 struct smb2_handle h1 = {{0}};
971 struct smb2_handle h2 = {{0}};
972 struct smb2_handle h3 = {{0}};
973 NTSTATUS status;
974 const char *fname = "lease_statopen2.dat";
975 bool ret = true;
977 /* Open file with RWH lease. */
978 smb2_lease_create_share(&io, &ls, false, fname,
979 smb2_util_share_access("RWD"),
980 LEASE1,
981 smb2_util_lease_state("RWH"));
982 io.in.desired_access = SEC_FILE_ALL;
983 status = smb2_create(tree, mem_ctx, &io);
984 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
985 "smb2_create failed\n");
986 h1 = io.out.file.handle;
987 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
989 /* Stat open */
990 ZERO_STRUCT(io);
991 io.in.desired_access = access_mask;
992 io.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
993 io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
994 io.in.create_disposition = NTCREATEX_DISP_OPEN;
995 io.in.fname = fname;
996 status = smb2_create(tree, mem_ctx, &io);
997 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
998 "smb2_create failed\n");
999 h2 = io.out.file.handle;
1001 if (expect_stat_open) {
1002 CHECK_NO_BREAK(tctx);
1003 if (!ret) {
1004 goto done;
1006 } else {
1007 CHECK_VAL(lease_break_info.count, 1);
1008 if (!ret) {
1009 goto done;
1012 * Don't bother checking the lease state of an additional open
1013 * below...
1015 goto done;
1018 /* Open file with RWH lease. */
1019 smb2_lease_create_share(&io, &ls, false, fname,
1020 smb2_util_share_access("RWD"),
1021 LEASE1,
1022 smb2_util_lease_state("RWH"));
1023 io.in.desired_access = SEC_FILE_WRITE_DATA;
1024 status = smb2_create(tree, mem_ctx, &io);
1025 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1026 "smb2_create failed\n");
1027 h3 = io.out.file.handle;
1028 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
1030 done:
1031 if (!smb2_util_handle_empty(h3)) {
1032 smb2_util_close(tree, h3);
1034 if (!smb2_util_handle_empty(h2)) {
1035 smb2_util_close(tree, h2);
1037 if (!smb2_util_handle_empty(h1)) {
1038 smb2_util_close(tree, h1);
1040 talloc_free(mem_ctx);
1041 return ret;
1044 static bool test_lease_statopen4(struct torture_context *tctx,
1045 struct smb2_tree *tree)
1047 const char *fname = "lease_statopen4.dat";
1048 struct smb2_handle h1 = {{0}};
1049 uint32_t caps;
1050 size_t i;
1051 NTSTATUS status;
1052 bool ret = true;
1053 struct {
1054 uint32_t access_mask;
1055 bool expect_stat_open;
1056 } tests[] = {
1058 .access_mask = FILE_READ_DATA,
1059 .expect_stat_open = false,
1062 .access_mask = FILE_WRITE_DATA,
1063 .expect_stat_open = false,
1066 .access_mask = FILE_READ_EA,
1067 .expect_stat_open = false,
1070 .access_mask = FILE_WRITE_EA,
1071 .expect_stat_open = false,
1074 .access_mask = FILE_EXECUTE,
1075 .expect_stat_open = false,
1078 .access_mask = FILE_READ_ATTRIBUTES,
1079 .expect_stat_open = true,
1082 .access_mask = FILE_WRITE_ATTRIBUTES,
1083 .expect_stat_open = true,
1086 .access_mask = DELETE_ACCESS,
1087 .expect_stat_open = false,
1090 .access_mask = READ_CONTROL_ACCESS,
1091 .expect_stat_open = true,
1094 .access_mask = WRITE_DAC_ACCESS,
1095 .expect_stat_open = false,
1098 .access_mask = WRITE_OWNER_ACCESS,
1099 .expect_stat_open = false,
1102 .access_mask = SYNCHRONIZE_ACCESS,
1103 .expect_stat_open = true,
1107 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1108 if (!(caps & SMB2_CAP_LEASING)) {
1109 torture_skip(tctx, "leases are not supported");
1112 smb2_util_unlink(tree, fname);
1113 tree->session->transport->lease.handler = torture_lease_handler;
1114 tree->session->transport->lease.private_data = tree;
1116 status = torture_smb2_testfile(tree, fname, &h1);
1117 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1118 "smb2_create failed\n");
1119 smb2_util_close(tree, h1);
1120 ZERO_STRUCT(h1);
1122 for (i = 0; i < ARRAY_SIZE(tests); i++) {
1123 torture_reset_lease_break_info(tctx, &lease_break_info);
1125 ret = test_lease_statopen4_do(tctx,
1126 tree,
1127 tests[i].access_mask,
1128 tests[i].expect_stat_open);
1129 if (ret == true) {
1130 continue;
1132 torture_result(tctx, TORTURE_FAIL,
1133 "test %zu: access_mask: %s, "
1134 "expect_stat_open: %s\n",
1136 get_sec_mask_str(tree, tests[i].access_mask),
1137 tests[i].expect_stat_open ? "yes" : "no");
1138 goto done;
1141 done:
1142 smb2_util_unlink(tree, fname);
1143 return ret;
1146 static void torture_oplock_break_callback(struct smb2_request *req)
1148 NTSTATUS status;
1149 struct smb2_break br;
1151 ZERO_STRUCT(br);
1152 status = smb2_break_recv(req, &br);
1153 if (!NT_STATUS_IS_OK(status))
1154 lease_break_info.oplock_failures++;
1156 return;
1159 /* a oplock break request handler */
1160 static bool torture_oplock_handler(struct smb2_transport *transport,
1161 const struct smb2_handle *handle,
1162 uint8_t level, void *private_data)
1164 struct smb2_tree *tree = private_data;
1165 struct smb2_request *req;
1166 struct smb2_break br;
1168 lease_break_info.oplock_handle = *handle;
1169 lease_break_info.oplock_level = level;
1170 lease_break_info.oplock_count++;
1172 ZERO_STRUCT(br);
1173 br.in.file.handle = *handle;
1174 br.in.oplock_level = level;
1176 if (lease_break_info.held_oplock_level > SMB2_OPLOCK_LEVEL_II) {
1177 req = smb2_break_send(tree, &br);
1178 req->async.fn = torture_oplock_break_callback;
1179 req->async.private_data = NULL;
1181 lease_break_info.held_oplock_level = level;
1183 return true;
1186 #define NOPLOCK_RESULTS 12
1187 static const char *oplock_results[NOPLOCK_RESULTS][4] = {
1188 {"R", "s", "R", "s"},
1189 {"R", "x", "R", "s"},
1190 {"R", "b", "R", "s"},
1192 {"RH", "s", "RH", ""},
1193 {"RH", "x", "RH", ""},
1194 {"RH", "b", "RH", ""},
1196 {"RW", "s", "R", "s"},
1197 {"RW", "x", "R", "s"},
1198 {"RW", "b", "R", "s"},
1200 {"RHW", "s", "RH", ""},
1201 {"RHW", "x", "RH", ""},
1202 {"RHW", "b", "RH", ""},
1205 static const char *oplock_results_2[NOPLOCK_RESULTS][4] = {
1206 {"s", "R", "s", "R"},
1207 {"s", "RH", "s", "R"},
1208 {"s", "RW", "s", "R"},
1209 {"s", "RHW", "s", "R"},
1211 {"x", "R", "s", "R"},
1212 {"x", "RH", "s", "R"},
1213 {"x", "RW", "s", "R"},
1214 {"x", "RHW", "s", "R"},
1216 {"b", "R", "s", "R"},
1217 {"b", "RH", "s", "R"},
1218 {"b", "RW", "s", "R"},
1219 {"b", "RHW", "s", "R"},
1222 static bool test_lease_oplock(struct torture_context *tctx,
1223 struct smb2_tree *tree)
1225 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1226 struct smb2_create io;
1227 struct smb2_lease ls;
1228 struct smb2_handle h, h2;
1229 NTSTATUS status;
1230 const char *fname = "lease_oplock.dat";
1231 bool ret = true;
1232 int i;
1233 uint32_t caps;
1235 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1236 if (!(caps & SMB2_CAP_LEASING)) {
1237 torture_skip(tctx, "leases are not supported");
1240 tree->session->transport->lease.handler = torture_lease_handler;
1241 tree->session->transport->lease.private_data = tree;
1242 tree->session->transport->oplock.handler = torture_oplock_handler;
1243 tree->session->transport->oplock.private_data = tree;
1245 smb2_util_unlink(tree, fname);
1247 for (i = 0; i < NOPLOCK_RESULTS; i++) {
1248 const char *held = oplock_results[i][0];
1249 const char *contend = oplock_results[i][1];
1250 const char *brokento = oplock_results[i][2];
1251 const char *granted = oplock_results[i][3];
1252 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
1253 "expecting break to %s(%x) and grant of %s(%x)\n",
1254 held, smb2_util_lease_state(held), contend, smb2_util_oplock_level(contend),
1255 brokento, smb2_util_lease_state(brokento), granted, smb2_util_oplock_level(granted));
1257 torture_reset_lease_break_info(tctx, &lease_break_info);
1259 /* Grab lease. */
1260 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held));
1261 status = smb2_create(tree, mem_ctx, &io);
1262 CHECK_STATUS(status, NT_STATUS_OK);
1263 h = io.out.file.handle;
1264 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1265 CHECK_LEASE(&io, held, true, LEASE1, 0);
1267 /* Does an oplock contend the lease? */
1268 smb2_oplock_create(&io, fname, smb2_util_oplock_level(contend));
1269 status = smb2_create(tree, mem_ctx, &io);
1270 CHECK_STATUS(status, NT_STATUS_OK);
1271 h2 = io.out.file.handle;
1272 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1273 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(granted));
1274 lease_break_info.held_oplock_level = io.out.oplock_level;
1276 if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) {
1277 CHECK_BREAK_INFO(held, brokento, LEASE1);
1278 } else {
1279 CHECK_NO_BREAK(tctx);
1282 smb2_util_close(tree, h);
1283 smb2_util_close(tree, h2);
1285 status = smb2_util_unlink(tree, fname);
1286 CHECK_STATUS(status, NT_STATUS_OK);
1289 for (i = 0; i < NOPLOCK_RESULTS; i++) {
1290 const char *held = oplock_results_2[i][0];
1291 const char *contend = oplock_results_2[i][1];
1292 const char *brokento = oplock_results_2[i][2];
1293 const char *granted = oplock_results_2[i][3];
1294 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
1295 "expecting break to %s(%x) and grant of %s(%x)\n",
1296 held, smb2_util_oplock_level(held), contend, smb2_util_lease_state(contend),
1297 brokento, smb2_util_oplock_level(brokento), granted, smb2_util_lease_state(granted));
1299 torture_reset_lease_break_info(tctx, &lease_break_info);
1301 /* Grab an oplock. */
1302 smb2_oplock_create(&io, fname, smb2_util_oplock_level(held));
1303 status = smb2_create(tree, mem_ctx, &io);
1304 CHECK_STATUS(status, NT_STATUS_OK);
1305 h = io.out.file.handle;
1306 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1307 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(held));
1308 lease_break_info.held_oplock_level = io.out.oplock_level;
1310 /* Grab lease. */
1311 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(contend));
1312 status = smb2_create(tree, mem_ctx, &io);
1313 CHECK_STATUS(status, NT_STATUS_OK);
1314 h2 = io.out.file.handle;
1315 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1316 CHECK_LEASE(&io, granted, true, LEASE1, 0);
1318 if (smb2_util_oplock_level(held) != smb2_util_oplock_level(brokento)) {
1319 CHECK_OPLOCK_BREAK(brokento);
1320 } else {
1321 CHECK_NO_BREAK(tctx);
1324 smb2_util_close(tree, h);
1325 smb2_util_close(tree, h2);
1327 status = smb2_util_unlink(tree, fname);
1328 CHECK_STATUS(status, NT_STATUS_OK);
1331 done:
1332 smb2_util_close(tree, h);
1333 smb2_util_close(tree, h2);
1335 smb2_util_unlink(tree, fname);
1337 talloc_free(mem_ctx);
1339 return ret;
1342 static bool test_lease_multibreak(struct torture_context *tctx,
1343 struct smb2_tree *tree)
1345 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1346 struct smb2_create io;
1347 struct smb2_lease ls;
1348 struct smb2_handle h = {{0}};
1349 struct smb2_handle h2 = {{0}};
1350 struct smb2_handle h3 = {{0}};
1351 struct smb2_write w;
1352 NTSTATUS status;
1353 const char *fname = "lease_multibreak.dat";
1354 bool ret = true;
1355 uint32_t caps;
1357 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1358 if (!(caps & SMB2_CAP_LEASING)) {
1359 torture_skip(tctx, "leases are not supported");
1362 tree->session->transport->lease.handler = torture_lease_handler;
1363 tree->session->transport->lease.private_data = tree;
1364 tree->session->transport->oplock.handler = torture_oplock_handler;
1365 tree->session->transport->oplock.private_data = tree;
1367 smb2_util_unlink(tree, fname);
1369 torture_reset_lease_break_info(tctx, &lease_break_info);
1371 /* Grab lease, upgrade to RHW .. */
1372 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
1373 status = smb2_create(tree, mem_ctx, &io);
1374 CHECK_STATUS(status, NT_STATUS_OK);
1375 h = io.out.file.handle;
1376 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1377 CHECK_LEASE(&io, "RH", true, LEASE1, 0);
1379 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
1380 status = smb2_create(tree, mem_ctx, &io);
1381 CHECK_STATUS(status, NT_STATUS_OK);
1382 h2 = io.out.file.handle;
1383 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1384 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
1386 /* Contend with LEASE2. */
1387 smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state("RHW"));
1388 status = smb2_create(tree, mem_ctx, &io);
1389 CHECK_STATUS(status, NT_STATUS_OK);
1390 h3 = io.out.file.handle;
1391 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1392 CHECK_LEASE(&io, "RH", true, LEASE2, 0);
1394 /* Verify that we were only sent one break. */
1395 CHECK_BREAK_INFO("RHW", "RH", LEASE1);
1397 /* Drop LEASE1 / LEASE2 */
1398 status = smb2_util_close(tree, h);
1399 CHECK_STATUS(status, NT_STATUS_OK);
1400 status = smb2_util_close(tree, h2);
1401 CHECK_STATUS(status, NT_STATUS_OK);
1402 status = smb2_util_close(tree, h3);
1403 CHECK_STATUS(status, NT_STATUS_OK);
1405 torture_reset_lease_break_info(tctx, &lease_break_info);
1407 /* Grab an R lease. */
1408 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("R"));
1409 status = smb2_create(tree, mem_ctx, &io);
1410 CHECK_STATUS(status, NT_STATUS_OK);
1411 h = io.out.file.handle;
1412 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1413 CHECK_LEASE(&io, "R", true, LEASE1, 0);
1415 /* Grab a level-II oplock. */
1416 smb2_oplock_create(&io, fname, smb2_util_oplock_level("s"));
1417 status = smb2_create(tree, mem_ctx, &io);
1418 CHECK_STATUS(status, NT_STATUS_OK);
1419 h2 = io.out.file.handle;
1420 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1421 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
1422 lease_break_info.held_oplock_level = io.out.oplock_level;
1424 /* Verify no breaks. */
1425 CHECK_NO_BREAK(tctx);
1427 /* Open for truncate, force a break. */
1428 smb2_generic_create(&io, NULL, false, fname,
1429 NTCREATEX_DISP_OVERWRITE_IF, smb2_util_oplock_level(""), 0, 0);
1430 status = smb2_create(tree, mem_ctx, &io);
1431 CHECK_STATUS(status, NT_STATUS_OK);
1432 h3 = io.out.file.handle;
1433 CHECK_CREATED(&io, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
1434 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(""));
1435 lease_break_info.held_oplock_level = io.out.oplock_level;
1437 /* Sleep, use a write to clear the recv queue. */
1438 smb_msleep(250);
1439 ZERO_STRUCT(w);
1440 w.in.file.handle = h3;
1441 w.in.offset = 0;
1442 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
1443 memset(w.in.data.data, 'o', w.in.data.length);
1444 status = smb2_write(tree, &w);
1445 CHECK_STATUS(status, NT_STATUS_OK);
1447 /* Verify one oplock break, one lease break. */
1448 CHECK_OPLOCK_BREAK("");
1449 CHECK_BREAK_INFO("R", "", LEASE1);
1451 done:
1452 smb2_util_close(tree, h);
1453 smb2_util_close(tree, h2);
1454 smb2_util_close(tree, h3);
1456 smb2_util_unlink(tree, fname);
1458 talloc_free(mem_ctx);
1460 return ret;
1463 static bool test_lease_v2_request_parent(struct torture_context *tctx,
1464 struct smb2_tree *tree)
1466 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1467 struct smb2_create io;
1468 struct smb2_lease ls;
1469 struct smb2_handle h1 = {{0}};
1470 uint64_t parent = LEASE2;
1471 NTSTATUS status;
1472 const char *fname = "lease_v2_request_parent.dat";
1473 bool ret = true;
1474 uint32_t caps;
1475 enum protocol_types protocol;
1477 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1478 if (!(caps & SMB2_CAP_LEASING)) {
1479 torture_skip(tctx, "leases are not supported");
1481 if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
1482 torture_skip(tctx, "directory leases are not supported");
1485 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1486 if (protocol < PROTOCOL_SMB3_00) {
1487 torture_skip(tctx, "v2 leases are not supported");
1490 smb2_util_unlink(tree, fname);
1492 torture_reset_lease_break_info(tctx, &lease_break_info);
1494 ZERO_STRUCT(io);
1495 smb2_lease_v2_create_share(&io, &ls, false, fname,
1496 smb2_util_share_access("RWD"),
1497 LEASE1, &parent,
1498 smb2_util_lease_state("RHW"),
1499 0x11);
1501 status = smb2_create(tree, mem_ctx, &io);
1502 CHECK_STATUS(status, NT_STATUS_OK);
1503 h1 = io.out.file.handle;
1504 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1505 CHECK_LEASE_V2(&io, "RHW", true, LEASE1,
1506 SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2,
1507 ls.lease_epoch + 1);
1509 done:
1510 smb2_util_close(tree, h1);
1511 smb2_util_unlink(tree, fname);
1513 talloc_free(mem_ctx);
1515 return ret;
1518 static bool test_lease_break_twice(struct torture_context *tctx,
1519 struct smb2_tree *tree)
1521 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1522 struct smb2_create io;
1523 struct smb2_lease ls1;
1524 struct smb2_lease ls2;
1525 struct smb2_handle h1 = {{0}};
1526 NTSTATUS status;
1527 const char *fname = "lease_break_twice.dat";
1528 bool ret = true;
1529 uint32_t caps;
1530 enum protocol_types protocol;
1532 caps = smb2cli_conn_server_capabilities(
1533 tree->session->transport->conn);
1534 if (!(caps & SMB2_CAP_LEASING)) {
1535 torture_skip(tctx, "leases are not supported");
1538 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1539 if (protocol < PROTOCOL_SMB3_00) {
1540 torture_skip(tctx, "v2 leases are not supported");
1543 smb2_util_unlink(tree, fname);
1545 torture_reset_lease_break_info(tctx, &lease_break_info);
1546 ZERO_STRUCT(io);
1548 smb2_lease_v2_create_share(
1549 &io, &ls1, false, fname, smb2_util_share_access("RWD"),
1550 LEASE1, NULL, smb2_util_lease_state("RWH"), 0x11);
1552 status = smb2_create(tree, mem_ctx, &io);
1553 CHECK_STATUS(status, NT_STATUS_OK);
1554 h1 = io.out.file.handle;
1555 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1556 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch + 1);
1558 tree->session->transport->lease.handler = torture_lease_handler;
1559 tree->session->transport->lease.private_data = tree;
1561 torture_reset_lease_break_info(tctx, &lease_break_info);
1563 smb2_lease_v2_create_share(
1564 &io, &ls2, false, fname, smb2_util_share_access("R"),
1565 LEASE2, NULL, smb2_util_lease_state("RWH"), 0x22);
1567 status = smb2_create(tree, mem_ctx, &io);
1568 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
1569 CHECK_BREAK_INFO_V2(tree->session->transport,
1570 "RWH", "RW", LEASE1, ls1.lease_epoch + 2);
1572 smb2_lease_v2_create_share(
1573 &io, &ls2, false, fname, smb2_util_share_access("RWD"),
1574 LEASE2, NULL, smb2_util_lease_state("RWH"), 0x22);
1576 torture_reset_lease_break_info(tctx, &lease_break_info);
1578 status = smb2_create(tree, mem_ctx, &io);
1579 CHECK_STATUS(status, NT_STATUS_OK);
1580 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch + 1);
1581 CHECK_BREAK_INFO_V2(tree->session->transport,
1582 "RW", "R", LEASE1, ls1.lease_epoch + 3);
1584 done:
1585 smb2_util_close(tree, h1);
1586 smb2_util_unlink(tree, fname);
1587 talloc_free(mem_ctx);
1588 return ret;
1591 static bool test_lease_v2_request(struct torture_context *tctx,
1592 struct smb2_tree *tree)
1594 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1595 struct smb2_create io;
1596 struct smb2_lease ls1, ls2, ls2t, ls3, ls4;
1597 struct smb2_handle h1 = {{0}};
1598 struct smb2_handle h2 = {{0}};
1599 struct smb2_handle h3 = {{0}};
1600 struct smb2_handle h4 = {{0}};
1601 struct smb2_handle h5 = {{0}};
1602 struct smb2_write w;
1603 NTSTATUS status;
1604 const char *fname = "lease_v2_request.dat";
1605 const char *dname = "lease_v2_request.dir";
1606 const char *dnamefname = "lease_v2_request.dir\\lease.dat";
1607 const char *dnamefname2 = "lease_v2_request.dir\\lease2.dat";
1608 bool ret = true;
1609 uint32_t caps;
1610 enum protocol_types protocol;
1612 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1613 if (!(caps & SMB2_CAP_LEASING)) {
1614 torture_skip(tctx, "leases are not supported");
1616 if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
1617 torture_skip(tctx, "directory leases are not supported");
1620 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1621 if (protocol < PROTOCOL_SMB3_00) {
1622 torture_skip(tctx, "v2 leases are not supported");
1625 smb2_util_unlink(tree, fname);
1626 smb2_deltree(tree, dname);
1628 tree->session->transport->lease.handler = torture_lease_handler;
1629 tree->session->transport->lease.private_data = tree;
1630 tree->session->transport->oplock.handler = torture_oplock_handler;
1631 tree->session->transport->oplock.private_data = tree;
1633 torture_reset_lease_break_info(tctx, &lease_break_info);
1635 ZERO_STRUCT(io);
1636 smb2_lease_v2_create_share(&io, &ls1, false, fname,
1637 smb2_util_share_access("RWD"),
1638 LEASE1, NULL,
1639 smb2_util_lease_state("RHW"),
1640 0x11);
1642 status = smb2_create(tree, mem_ctx, &io);
1643 CHECK_STATUS(status, NT_STATUS_OK);
1644 h1 = io.out.file.handle;
1645 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1646 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch + 1);
1648 ZERO_STRUCT(io);
1649 smb2_lease_v2_create_share(&io, &ls2, true, dname,
1650 smb2_util_share_access("RWD"),
1651 LEASE2, NULL,
1652 smb2_util_lease_state("RHW"),
1653 0x22);
1654 status = smb2_create(tree, mem_ctx, &io);
1655 CHECK_STATUS(status, NT_STATUS_OK);
1656 h2 = io.out.file.handle;
1657 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
1658 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch + 1);
1660 ZERO_STRUCT(io);
1661 smb2_lease_v2_create_share(&io, &ls3, false, dnamefname,
1662 smb2_util_share_access("RWD"),
1663 LEASE3, &LEASE2,
1664 smb2_util_lease_state("RHW"),
1665 0x33);
1666 status = smb2_create(tree, mem_ctx, &io);
1667 CHECK_STATUS(status, NT_STATUS_OK);
1668 h3 = io.out.file.handle;
1669 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1670 CHECK_LEASE_V2(&io, "RHW", true, LEASE3,
1671 SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2,
1672 ls3.lease_epoch + 1);
1674 CHECK_NO_BREAK(tctx);
1676 ZERO_STRUCT(io);
1677 smb2_lease_v2_create_share(&io, &ls4, false, dnamefname2,
1678 smb2_util_share_access("RWD"),
1679 LEASE4, NULL,
1680 smb2_util_lease_state("RHW"),
1681 0x44);
1682 status = smb2_create(tree, mem_ctx, &io);
1683 CHECK_STATUS(status, NT_STATUS_OK);
1684 h4 = io.out.file.handle;
1685 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1686 CHECK_LEASE_V2(&io, "RHW", true, LEASE4, 0, 0, ls4.lease_epoch + 1);
1688 CHECK_BREAK_INFO_V2(tree->session->transport,
1689 "RH", "", LEASE2, ls2.lease_epoch + 2);
1691 torture_reset_lease_break_info(tctx, &lease_break_info);
1693 ZERO_STRUCT(io);
1694 smb2_lease_v2_create_share(&io, &ls2t, true, dname,
1695 smb2_util_share_access("RWD"),
1696 LEASE2, NULL,
1697 smb2_util_lease_state("RHW"),
1698 0x222);
1699 io.in.create_disposition = NTCREATEX_DISP_OPEN;
1700 status = smb2_create(tree, mem_ctx, &io);
1701 CHECK_STATUS(status, NT_STATUS_OK);
1702 h5 = io.out.file.handle;
1703 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_DIRECTORY);
1704 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch+3);
1705 smb2_util_close(tree, h5);
1707 ZERO_STRUCT(w);
1708 w.in.file.handle = h4;
1709 w.in.offset = 0;
1710 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
1711 memset(w.in.data.data, 'o', w.in.data.length);
1712 status = smb2_write(tree, &w);
1713 CHECK_STATUS(status, NT_STATUS_OK);
1716 * Wait 4 seconds in order to check if the write time
1717 * was updated (after 2 seconds).
1719 smb_msleep(4000);
1720 CHECK_NO_BREAK(tctx);
1723 * only the close on the modified file break the
1724 * directory lease.
1726 smb2_util_close(tree, h4);
1728 CHECK_BREAK_INFO_V2(tree->session->transport,
1729 "RH", "", LEASE2, ls2.lease_epoch+4);
1731 done:
1732 smb2_util_close(tree, h1);
1733 smb2_util_close(tree, h2);
1734 smb2_util_close(tree, h3);
1735 smb2_util_close(tree, h4);
1736 smb2_util_close(tree, h5);
1738 smb2_util_unlink(tree, fname);
1739 smb2_deltree(tree, dname);
1741 talloc_free(mem_ctx);
1743 return ret;
1746 static bool test_lease_v2_epoch1(struct torture_context *tctx,
1747 struct smb2_tree *tree)
1749 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1750 struct smb2_create io;
1751 struct smb2_lease ls;
1752 struct smb2_handle h;
1753 const char *fname = "lease_v2_epoch1.dat";
1754 bool ret = true;
1755 NTSTATUS status;
1756 uint32_t caps;
1757 enum protocol_types protocol;
1759 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1760 if (!(caps & SMB2_CAP_LEASING)) {
1761 torture_skip(tctx, "leases are not supported");
1764 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1765 if (protocol < PROTOCOL_SMB3_00) {
1766 torture_skip(tctx, "v2 leases are not supported");
1769 smb2_util_unlink(tree, fname);
1771 tree->session->transport->lease.handler = torture_lease_handler;
1772 tree->session->transport->lease.private_data = tree;
1773 tree->session->transport->oplock.handler = torture_oplock_handler;
1774 tree->session->transport->oplock.private_data = tree;
1776 torture_reset_lease_break_info(tctx, &lease_break_info);
1778 ZERO_STRUCT(io);
1779 smb2_lease_v2_create_share(&io, &ls, false, fname,
1780 smb2_util_share_access("RWD"),
1781 LEASE1, NULL,
1782 smb2_util_lease_state("RHW"),
1783 0x4711);
1784 status = smb2_create(tree, mem_ctx, &io);
1785 CHECK_STATUS(status, NT_STATUS_OK);
1786 h = io.out.file.handle;
1787 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1788 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls.lease_epoch + 1);
1789 smb2_util_close(tree, h);
1790 smb2_util_unlink(tree, fname);
1792 smb2_lease_v2_create_share(&io, &ls, false, fname,
1793 smb2_util_share_access("RWD"),
1794 LEASE1, NULL,
1795 smb2_util_lease_state("RHW"),
1796 0x11);
1798 status = smb2_create(tree, mem_ctx, &io);
1799 CHECK_STATUS(status, NT_STATUS_OK);
1800 h = io.out.file.handle;
1801 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1802 CHECK_LEASE_V2(&io, "RWH", true, LEASE1, 0, 0, ls.lease_epoch + 1);
1803 smb2_util_close(tree, h);
1805 done:
1806 smb2_util_unlink(tree, fname);
1807 talloc_free(mem_ctx);
1808 return ret;
1811 static bool test_lease_v2_epoch2(struct torture_context *tctx,
1812 struct smb2_tree *tree)
1814 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1815 struct smb2_create io;
1816 struct smb2_lease ls1v2, ls1v2t, ls1v1;
1817 struct smb2_handle hv2 = {}, hv1 = {};
1818 const char *fname = "lease_v2_epoch2.dat";
1819 bool ret = true;
1820 NTSTATUS status;
1821 uint32_t caps;
1822 enum protocol_types protocol;
1824 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1825 if (!(caps & SMB2_CAP_LEASING)) {
1826 torture_skip(tctx, "leases are not supported");
1829 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1830 if (protocol < PROTOCOL_SMB3_00) {
1831 torture_skip(tctx, "v2 leases are not supported");
1834 smb2_util_unlink(tree, fname);
1836 tree->session->transport->lease.handler = torture_lease_handler;
1837 tree->session->transport->lease.private_data = tree;
1838 tree->session->transport->oplock.handler = torture_oplock_handler;
1839 tree->session->transport->oplock.private_data = tree;
1841 torture_reset_lease_break_info(tctx, &lease_break_info);
1843 ZERO_STRUCT(io);
1844 smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
1845 smb2_util_share_access("RWD"),
1846 LEASE1, NULL,
1847 smb2_util_lease_state("R"),
1848 0x4711);
1849 status = smb2_create(tree, mem_ctx, &io);
1850 CHECK_STATUS(status, NT_STATUS_OK);
1851 hv2 = io.out.file.handle;
1852 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1853 CHECK_LEASE_V2(&io, "R", true, LEASE1, 0, 0, ls1v2.lease_epoch + 1);
1855 ZERO_STRUCT(io);
1856 smb2_lease_create_share(&io, &ls1v1, false, fname,
1857 smb2_util_share_access("RWD"),
1858 LEASE1,
1859 smb2_util_lease_state("RH"));
1860 status = smb2_create(tree, mem_ctx, &io);
1861 CHECK_STATUS(status, NT_STATUS_OK);
1862 hv1 = io.out.file.handle;
1863 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1864 CHECK_LEASE_V2(&io, "RH", true, LEASE1, 0, 0, ls1v2.lease_epoch + 2);
1866 smb2_util_close(tree, hv2);
1868 ZERO_STRUCT(io);
1869 smb2_lease_v2_create_share(&io, &ls1v2t, false, fname,
1870 smb2_util_share_access("RWD"),
1871 LEASE1, NULL,
1872 smb2_util_lease_state("RHW"),
1873 0x11);
1874 status = smb2_create(tree, mem_ctx, &io);
1875 CHECK_STATUS(status, NT_STATUS_OK);
1876 hv2 = io.out.file.handle;
1877 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1878 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1v2.lease_epoch + 3);
1880 smb2_util_close(tree, hv2);
1882 smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_NONE);
1883 status = smb2_create(tree, mem_ctx, &io);
1884 CHECK_STATUS(status, NT_STATUS_OK);
1885 hv2 = io.out.file.handle;
1886 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1887 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1889 CHECK_BREAK_INFO_V2(tree->session->transport,
1890 "RWH", "RH", LEASE1, ls1v2.lease_epoch + 4);
1892 smb2_util_close(tree, hv2);
1893 smb2_util_close(tree, hv1);
1895 ZERO_STRUCT(io);
1896 smb2_lease_create_share(&io, &ls1v1, false, fname,
1897 smb2_util_share_access("RWD"),
1898 LEASE1,
1899 smb2_util_lease_state("RHW"));
1900 status = smb2_create(tree, mem_ctx, &io);
1901 CHECK_STATUS(status, NT_STATUS_OK);
1902 hv1 = io.out.file.handle;
1903 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1904 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
1906 smb2_util_close(tree, hv1);
1908 done:
1909 smb2_util_close(tree, hv2);
1910 smb2_util_close(tree, hv1);
1911 smb2_util_unlink(tree, fname);
1912 talloc_free(mem_ctx);
1913 return ret;
1916 static bool test_lease_v2_epoch3(struct torture_context *tctx,
1917 struct smb2_tree *tree)
1919 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1920 struct smb2_create io;
1921 struct smb2_lease ls1v1 = {}, ls1v1t = {},ls1v2 = {};
1922 struct smb2_handle hv1 = {}, hv2 = {};
1923 const char *fname = "lease_v2_epoch3.dat";
1924 bool ret = true;
1925 NTSTATUS status;
1926 uint32_t caps;
1927 enum protocol_types protocol;
1929 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1930 if (!(caps & SMB2_CAP_LEASING)) {
1931 torture_skip(tctx, "leases are not supported");
1934 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1935 if (protocol < PROTOCOL_SMB3_00) {
1936 torture_skip(tctx, "v2 leases are not supported");
1939 smb2_util_unlink(tree, fname);
1941 tree->session->transport->lease.handler = torture_lease_handler;
1942 tree->session->transport->lease.private_data = tree;
1943 tree->session->transport->oplock.handler = torture_oplock_handler;
1944 tree->session->transport->oplock.private_data = tree;
1946 torture_reset_lease_break_info(tctx, &lease_break_info);
1948 ZERO_STRUCT(io);
1949 smb2_lease_create_share(&io, &ls1v1, false, fname,
1950 smb2_util_share_access("RWD"),
1951 LEASE1,
1952 smb2_util_lease_state("R"));
1953 status = smb2_create(tree, mem_ctx, &io);
1954 CHECK_STATUS(status, NT_STATUS_OK);
1955 hv1 = io.out.file.handle;
1956 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1957 CHECK_LEASE(&io, "R", true, LEASE1, 0);
1959 ZERO_STRUCT(io);
1960 smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
1961 smb2_util_share_access("RWD"),
1962 LEASE1, NULL,
1963 smb2_util_lease_state("RW"),
1964 0x4711);
1965 status = smb2_create(tree, mem_ctx, &io);
1966 CHECK_STATUS(status, NT_STATUS_OK);
1967 hv2 = io.out.file.handle;
1968 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1969 CHECK_LEASE(&io, "RW", true, LEASE1, 0);
1971 smb2_util_close(tree, hv1);
1973 ZERO_STRUCT(io);
1974 smb2_lease_create_share(&io, &ls1v1t, false, fname,
1975 smb2_util_share_access("RWD"),
1976 LEASE1,
1977 smb2_util_lease_state("RWH"));
1978 status = smb2_create(tree, mem_ctx, &io);
1979 CHECK_STATUS(status, NT_STATUS_OK);
1980 hv1 = io.out.file.handle;
1981 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1982 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
1984 smb2_util_close(tree, hv1);
1986 smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_NONE);
1987 status = smb2_create(tree, mem_ctx, &io);
1988 CHECK_STATUS(status, NT_STATUS_OK);
1989 hv1 = io.out.file.handle;
1990 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1991 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1993 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
1995 smb2_util_close(tree, hv1);
1996 smb2_util_close(tree, hv2);
1998 ZERO_STRUCT(io);
1999 smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
2000 smb2_util_share_access("RWD"),
2001 LEASE1, NULL,
2002 smb2_util_lease_state("RWH"),
2003 0x4711);
2004 status = smb2_create(tree, mem_ctx, &io);
2005 CHECK_STATUS(status, NT_STATUS_OK);
2006 hv2 = io.out.file.handle;
2007 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2008 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1v2.lease_epoch + 1);
2009 smb2_util_close(tree, hv2);
2011 done:
2012 smb2_util_close(tree, hv2);
2013 smb2_util_close(tree, hv1);
2014 smb2_util_unlink(tree, fname);
2015 talloc_free(mem_ctx);
2016 return ret;
2019 static bool test_lease_breaking1(struct torture_context *tctx,
2020 struct smb2_tree *tree)
2022 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2023 struct smb2_create io1 = {};
2024 struct smb2_create io2 = {};
2025 struct smb2_lease ls1 = {};
2026 struct smb2_handle h1a = {};
2027 struct smb2_handle h1b = {};
2028 struct smb2_handle h2 = {};
2029 struct smb2_request *req2 = NULL;
2030 struct smb2_lease_break_ack ack = {};
2031 const char *fname = "lease_breaking1.dat";
2032 bool ret = true;
2033 NTSTATUS status;
2034 uint32_t caps;
2036 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2037 if (!(caps & SMB2_CAP_LEASING)) {
2038 torture_skip(tctx, "leases are not supported");
2041 smb2_util_unlink(tree, fname);
2043 tree->session->transport->lease.handler = torture_lease_handler;
2044 tree->session->transport->lease.private_data = tree;
2045 tree->session->transport->oplock.handler = torture_oplock_handler;
2046 tree->session->transport->oplock.private_data = tree;
2049 * we defer acking the lease break.
2051 torture_reset_lease_break_info(tctx, &lease_break_info);
2052 lease_break_info.lease_skip_ack = true;
2054 smb2_lease_create_share(&io1, &ls1, false, fname,
2055 smb2_util_share_access("RWD"),
2056 LEASE1,
2057 smb2_util_lease_state("RWH"));
2058 status = smb2_create(tree, mem_ctx, &io1);
2059 CHECK_STATUS(status, NT_STATUS_OK);
2060 h1a = io1.out.file.handle;
2061 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2062 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2065 * a conflicting open is blocked until we ack the
2066 * lease break
2068 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2069 req2 = smb2_create_send(tree, &io2);
2070 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2073 * we got the lease break, but defer the ack.
2075 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2077 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2079 ack.in.lease.lease_key =
2080 lease_break_info.lease_break.current_lease.lease_key;
2081 ack.in.lease.lease_state =
2082 lease_break_info.lease_break.new_lease_state;
2083 torture_reset_lease_break_info(tctx, &lease_break_info);
2086 * a open using the same lease key is still works,
2087 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2089 status = smb2_create(tree, mem_ctx, &io1);
2090 CHECK_STATUS(status, NT_STATUS_OK);
2091 h1b = io1.out.file.handle;
2092 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2093 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2094 smb2_util_close(tree, h1b);
2096 CHECK_NO_BREAK(tctx);
2098 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2101 * We ack the lease break.
2103 status = smb2_lease_break_ack(tree, &ack);
2104 CHECK_STATUS(status, NT_STATUS_OK);
2105 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
2107 torture_assert(tctx, req2->cancel.can_cancel,
2108 "req2 can_cancel");
2110 status = smb2_create_recv(req2, tctx, &io2);
2111 CHECK_STATUS(status, NT_STATUS_OK);
2112 h2 = io2.out.file.handle;
2113 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2114 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2116 CHECK_NO_BREAK(tctx);
2117 done:
2118 smb2_util_close(tree, h1a);
2119 smb2_util_close(tree, h1b);
2120 smb2_util_close(tree, h2);
2121 smb2_util_unlink(tree, fname);
2122 talloc_free(mem_ctx);
2123 return ret;
2126 static bool test_lease_breaking2(struct torture_context *tctx,
2127 struct smb2_tree *tree)
2129 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2130 struct smb2_create io1 = {};
2131 struct smb2_create io2 = {};
2132 struct smb2_lease ls1 = {};
2133 struct smb2_handle h1a = {};
2134 struct smb2_handle h1b = {};
2135 struct smb2_handle h2 = {};
2136 struct smb2_request *req2 = NULL;
2137 struct smb2_lease_break_ack ack = {};
2138 const char *fname = "lease_breaking2.dat";
2139 bool ret = true;
2140 NTSTATUS status;
2141 uint32_t caps;
2143 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2144 if (!(caps & SMB2_CAP_LEASING)) {
2145 torture_skip(tctx, "leases are not supported");
2148 smb2_util_unlink(tree, fname);
2150 tree->session->transport->lease.handler = torture_lease_handler;
2151 tree->session->transport->lease.private_data = tree;
2152 tree->session->transport->oplock.handler = torture_oplock_handler;
2153 tree->session->transport->oplock.private_data = tree;
2156 * we defer acking the lease break.
2158 torture_reset_lease_break_info(tctx, &lease_break_info);
2159 lease_break_info.lease_skip_ack = true;
2161 smb2_lease_create_share(&io1, &ls1, false, fname,
2162 smb2_util_share_access("RWD"),
2163 LEASE1,
2164 smb2_util_lease_state("RWH"));
2165 status = smb2_create(tree, mem_ctx, &io1);
2166 CHECK_STATUS(status, NT_STATUS_OK);
2167 h1a = io1.out.file.handle;
2168 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2169 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2172 * a conflicting open is blocked until we ack the
2173 * lease break
2175 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2176 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2177 req2 = smb2_create_send(tree, &io2);
2178 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2181 * we got the lease break, but defer the ack.
2183 CHECK_BREAK_INFO("RWH", "", LEASE1);
2185 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2187 ack.in.lease.lease_key =
2188 lease_break_info.lease_break.current_lease.lease_key;
2189 torture_reset_lease_break_info(tctx, &lease_break_info);
2192 * a open using the same lease key is still works,
2193 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2195 status = smb2_create(tree, mem_ctx, &io1);
2196 CHECK_STATUS(status, NT_STATUS_OK);
2197 h1b = io1.out.file.handle;
2198 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2199 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2200 smb2_util_close(tree, h1b);
2202 CHECK_NO_BREAK(tctx);
2204 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2207 * We ack the lease break.
2209 ack.in.lease.lease_state =
2210 SMB2_LEASE_READ | SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE;
2211 status = smb2_lease_break_ack(tree, &ack);
2212 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2214 ack.in.lease.lease_state =
2215 SMB2_LEASE_READ | SMB2_LEASE_WRITE;
2216 status = smb2_lease_break_ack(tree, &ack);
2217 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2219 ack.in.lease.lease_state =
2220 SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE;
2221 status = smb2_lease_break_ack(tree, &ack);
2222 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2224 ack.in.lease.lease_state =
2225 SMB2_LEASE_READ | SMB2_LEASE_HANDLE;
2226 status = smb2_lease_break_ack(tree, &ack);
2227 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2229 ack.in.lease.lease_state = SMB2_LEASE_WRITE;
2230 status = smb2_lease_break_ack(tree, &ack);
2231 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2233 ack.in.lease.lease_state = SMB2_LEASE_HANDLE;
2234 status = smb2_lease_break_ack(tree, &ack);
2235 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2237 ack.in.lease.lease_state = SMB2_LEASE_READ;
2238 status = smb2_lease_break_ack(tree, &ack);
2239 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2241 /* Try again with the correct state this time. */
2242 ack.in.lease.lease_state = SMB2_LEASE_NONE;;
2243 status = smb2_lease_break_ack(tree, &ack);
2244 CHECK_STATUS(status, NT_STATUS_OK);
2245 CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
2247 status = smb2_lease_break_ack(tree, &ack);
2248 CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
2250 torture_assert(tctx, req2->cancel.can_cancel,
2251 "req2 can_cancel");
2253 status = smb2_create_recv(req2, tctx, &io2);
2254 CHECK_STATUS(status, NT_STATUS_OK);
2255 h2 = io2.out.file.handle;
2256 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2257 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2259 CHECK_NO_BREAK(tctx);
2261 /* Get state of the original handle. */
2262 smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
2263 status = smb2_create(tree, mem_ctx, &io1);
2264 CHECK_STATUS(status, NT_STATUS_OK);
2265 CHECK_LEASE(&io1, "", true, LEASE1, 0);
2266 smb2_util_close(tree, io1.out.file.handle);
2268 done:
2269 smb2_util_close(tree, h1a);
2270 smb2_util_close(tree, h1b);
2271 smb2_util_close(tree, h2);
2272 smb2_util_unlink(tree, fname);
2273 talloc_free(mem_ctx);
2274 return ret;
2277 static bool test_lease_breaking3(struct torture_context *tctx,
2278 struct smb2_tree *tree)
2280 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2281 struct smb2_create io1 = {};
2282 struct smb2_create io2 = {};
2283 struct smb2_create io3 = {};
2284 struct smb2_lease ls1 = {};
2285 struct smb2_handle h1a = {};
2286 struct smb2_handle h1b = {};
2287 struct smb2_handle h2 = {};
2288 struct smb2_handle h3 = {};
2289 struct smb2_request *req2 = NULL;
2290 struct smb2_request *req3 = NULL;
2291 struct lease_break_info lease_break_info_tmp = {};
2292 struct smb2_lease_break_ack ack = {};
2293 const char *fname = "lease_breaking3.dat";
2294 bool ret = true;
2295 NTSTATUS status;
2296 uint32_t caps;
2298 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2299 if (!(caps & SMB2_CAP_LEASING)) {
2300 torture_skip(tctx, "leases are not supported");
2303 smb2_util_unlink(tree, fname);
2305 tree->session->transport->lease.handler = torture_lease_handler;
2306 tree->session->transport->lease.private_data = tree;
2307 tree->session->transport->oplock.handler = torture_oplock_handler;
2308 tree->session->transport->oplock.private_data = tree;
2311 * we defer acking the lease break.
2313 torture_reset_lease_break_info(tctx, &lease_break_info);
2314 lease_break_info.lease_skip_ack = true;
2316 smb2_lease_create_share(&io1, &ls1, false, fname,
2317 smb2_util_share_access("RWD"),
2318 LEASE1,
2319 smb2_util_lease_state("RWH"));
2320 status = smb2_create(tree, mem_ctx, &io1);
2321 CHECK_STATUS(status, NT_STATUS_OK);
2322 h1a = io1.out.file.handle;
2323 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2324 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2327 * a conflicting open is blocked until we ack the
2328 * lease break
2330 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2331 req2 = smb2_create_send(tree, &io2);
2332 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2335 * we got the lease break, but defer the ack.
2337 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2339 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2342 * a open using the same lease key is still works,
2343 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2345 status = smb2_create(tree, mem_ctx, &io1);
2346 CHECK_STATUS(status, NT_STATUS_OK);
2347 h1b = io1.out.file.handle;
2348 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2349 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2350 smb2_util_close(tree, h1b);
2353 * a conflicting open with NTCREATEX_DISP_OVERWRITE
2354 * doesn't trigger an immediate lease break to none.
2356 lease_break_info_tmp = lease_break_info;
2357 torture_reset_lease_break_info(tctx, &lease_break_info);
2358 smb2_oplock_create(&io3, fname, SMB2_OPLOCK_LEVEL_NONE);
2359 io3.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2360 req3 = smb2_create_send(tree, &io3);
2361 torture_assert(tctx, req3 != NULL, "smb2_create_send");
2362 CHECK_NO_BREAK(tctx);
2363 lease_break_info = lease_break_info_tmp;
2365 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2367 ack.in.lease.lease_key =
2368 lease_break_info.lease_break.current_lease.lease_key;
2369 ack.in.lease.lease_state =
2370 lease_break_info.lease_break.new_lease_state;
2371 torture_reset_lease_break_info(tctx, &lease_break_info);
2374 * a open using the same lease key is still works,
2375 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2377 status = smb2_create(tree, mem_ctx, &io1);
2378 CHECK_STATUS(status, NT_STATUS_OK);
2379 h1b = io1.out.file.handle;
2380 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2381 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2382 smb2_util_close(tree, h1b);
2384 CHECK_NO_BREAK(tctx);
2387 * We ack the lease break, but defer acking the next break (to "R")
2389 lease_break_info.lease_skip_ack = true;
2390 status = smb2_lease_break_ack(tree, &ack);
2391 CHECK_STATUS(status, NT_STATUS_OK);
2392 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
2395 * We got an additional break downgrading to just "R"
2396 * while we defer the ack.
2398 CHECK_BREAK_INFO("RH", "R", LEASE1);
2400 ack.in.lease.lease_key =
2401 lease_break_info.lease_break.current_lease.lease_key;
2402 ack.in.lease.lease_state =
2403 lease_break_info.lease_break.new_lease_state;
2404 torture_reset_lease_break_info(tctx, &lease_break_info);
2407 * a open using the same lease key is still works,
2408 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2410 status = smb2_create(tree, mem_ctx, &io1);
2411 CHECK_STATUS(status, NT_STATUS_OK);
2412 h1b = io1.out.file.handle;
2413 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2414 CHECK_LEASE(&io1, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2415 smb2_util_close(tree, h1b);
2417 CHECK_NO_BREAK(tctx);
2419 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2420 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2423 * We ack the downgrade to "R" and get an immediate break to none
2425 status = smb2_lease_break_ack(tree, &ack);
2426 CHECK_STATUS(status, NT_STATUS_OK);
2427 CHECK_LEASE_BREAK_ACK(&ack, "R", LEASE1);
2430 * We get the downgrade to none.
2432 CHECK_BREAK_INFO("R", "", LEASE1);
2434 torture_assert(tctx, req2->cancel.can_cancel,
2435 "req2 can_cancel");
2436 torture_assert(tctx, req3->cancel.can_cancel,
2437 "req3 can_cancel");
2439 torture_reset_lease_break_info(tctx, &lease_break_info);
2441 status = smb2_create_recv(req2, tctx, &io2);
2442 CHECK_STATUS(status, NT_STATUS_OK);
2443 h2 = io2.out.file.handle;
2444 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2445 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2447 status = smb2_create_recv(req3, tctx, &io3);
2448 CHECK_STATUS(status, NT_STATUS_OK);
2449 h3 = io3.out.file.handle;
2450 CHECK_CREATED(&io3, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2451 CHECK_VAL(io3.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2453 CHECK_NO_BREAK(tctx);
2454 done:
2455 smb2_util_close(tree, h1a);
2456 smb2_util_close(tree, h1b);
2457 smb2_util_close(tree, h2);
2458 smb2_util_close(tree, h3);
2460 smb2_util_unlink(tree, fname);
2461 talloc_free(mem_ctx);
2462 return ret;
2465 static bool test_lease_v2_breaking3(struct torture_context *tctx,
2466 struct smb2_tree *tree)
2468 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2469 struct smb2_create io1 = {};
2470 struct smb2_create io2 = {};
2471 struct smb2_create io3 = {};
2472 struct smb2_lease ls1 = {};
2473 struct smb2_handle h1a = {};
2474 struct smb2_handle h1b = {};
2475 struct smb2_handle h2 = {};
2476 struct smb2_handle h3 = {};
2477 struct smb2_request *req2 = NULL;
2478 struct smb2_request *req3 = NULL;
2479 struct lease_break_info lease_break_info_tmp = {};
2480 struct smb2_lease_break_ack ack = {};
2481 const char *fname = "v2_lease_breaking3.dat";
2482 bool ret = true;
2483 NTSTATUS status;
2484 uint32_t caps;
2485 enum protocol_types protocol;
2487 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2488 if (!(caps & SMB2_CAP_LEASING)) {
2489 torture_skip(tctx, "leases are not supported");
2492 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
2493 if (protocol < PROTOCOL_SMB3_00) {
2494 torture_skip(tctx, "v2 leases are not supported");
2497 smb2_util_unlink(tree, fname);
2499 tree->session->transport->lease.handler = torture_lease_handler;
2500 tree->session->transport->lease.private_data = tree;
2501 tree->session->transport->oplock.handler = torture_oplock_handler;
2502 tree->session->transport->oplock.private_data = tree;
2505 * we defer acking the lease break.
2507 torture_reset_lease_break_info(tctx, &lease_break_info);
2508 lease_break_info.lease_skip_ack = true;
2510 smb2_lease_v2_create_share(&io1, &ls1, false, fname,
2511 smb2_util_share_access("RWD"),
2512 LEASE1, NULL,
2513 smb2_util_lease_state("RHW"),
2514 0x11);
2515 status = smb2_create(tree, mem_ctx, &io1);
2516 CHECK_STATUS(status, NT_STATUS_OK);
2517 h1a = io1.out.file.handle;
2518 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2519 /* Epoch increases on open. */
2520 ls1.lease_epoch += 1;
2521 CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
2524 * a conflicting open is blocked until we ack the
2525 * lease break
2527 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2528 req2 = smb2_create_send(tree, &io2);
2529 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2532 * we got the lease break, but defer the ack.
2534 CHECK_BREAK_INFO_V2(tree->session->transport,
2535 "RWH", "RH", LEASE1, ls1.lease_epoch + 1);
2537 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2539 /* On receiving a lease break, we must sync the new epoch. */
2540 ls1.lease_epoch = lease_break_info.lease_break.new_epoch;
2543 * a open using the same lease key is still works,
2544 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2546 status = smb2_create(tree, mem_ctx, &io1);
2547 CHECK_STATUS(status, NT_STATUS_OK);
2548 h1b = io1.out.file.handle;
2549 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2550 CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
2551 smb2_util_close(tree, h1b);
2554 * a conflicting open with NTCREATEX_DISP_OVERWRITE
2555 * doesn't trigger an immediate lease break to none.
2557 lease_break_info_tmp = lease_break_info;
2558 torture_reset_lease_break_info(tctx, &lease_break_info);
2559 smb2_oplock_create(&io3, fname, SMB2_OPLOCK_LEVEL_NONE);
2560 io3.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2561 req3 = smb2_create_send(tree, &io3);
2562 torture_assert(tctx, req3 != NULL, "smb2_create_send");
2563 CHECK_NO_BREAK(tctx);
2564 lease_break_info = lease_break_info_tmp;
2566 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2568 ack.in.lease.lease_key =
2569 lease_break_info.lease_break.current_lease.lease_key;
2570 ack.in.lease.lease_state =
2571 lease_break_info.lease_break.new_lease_state;
2572 torture_reset_lease_break_info(tctx, &lease_break_info);
2575 * a open using the same lease key is still works,
2576 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2578 status = smb2_create(tree, mem_ctx, &io1);
2579 CHECK_STATUS(status, NT_STATUS_OK);
2580 h1b = io1.out.file.handle;
2581 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2582 CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
2583 smb2_util_close(tree, h1b);
2585 CHECK_NO_BREAK(tctx);
2588 * We ack the lease break, but defer acking the next break (to "R")
2590 lease_break_info.lease_skip_ack = true;
2591 status = smb2_lease_break_ack(tree, &ack);
2592 CHECK_STATUS(status, NT_STATUS_OK);
2593 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
2596 * We got an additional break downgrading to just "R"
2597 * while we defer the ack.
2599 CHECK_BREAK_INFO_V2(tree->session->transport,
2600 "RH", "R", LEASE1, ls1.lease_epoch);
2601 /* On receiving a lease break, we must sync the new epoch. */
2602 ls1.lease_epoch = lease_break_info.lease_break.new_epoch;
2604 ack.in.lease.lease_key =
2605 lease_break_info.lease_break.current_lease.lease_key;
2606 ack.in.lease.lease_state =
2607 lease_break_info.lease_break.new_lease_state;
2608 torture_reset_lease_break_info(tctx, &lease_break_info);
2611 * a open using the same lease key is still works,
2612 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2614 status = smb2_create(tree, mem_ctx, &io1);
2615 CHECK_STATUS(status, NT_STATUS_OK);
2616 h1b = io1.out.file.handle;
2617 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2618 CHECK_LEASE_V2(&io1, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
2619 smb2_util_close(tree, h1b);
2621 CHECK_NO_BREAK(tctx);
2623 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2624 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2627 * We ack the downgrade to "R" and get an immediate break to none
2629 status = smb2_lease_break_ack(tree, &ack);
2630 CHECK_STATUS(status, NT_STATUS_OK);
2631 CHECK_LEASE_BREAK_ACK(&ack, "R", LEASE1);
2634 * We get the downgrade to none.
2636 CHECK_BREAK_INFO_V2(tree->session->transport,
2637 "R", "", LEASE1, ls1.lease_epoch);
2639 torture_assert(tctx, req2->cancel.can_cancel,
2640 "req2 can_cancel");
2641 torture_assert(tctx, req3->cancel.can_cancel,
2642 "req3 can_cancel");
2644 torture_reset_lease_break_info(tctx, &lease_break_info);
2646 status = smb2_create_recv(req2, tctx, &io2);
2647 CHECK_STATUS(status, NT_STATUS_OK);
2648 h2 = io2.out.file.handle;
2649 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2650 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2652 status = smb2_create_recv(req3, tctx, &io3);
2653 CHECK_STATUS(status, NT_STATUS_OK);
2654 h3 = io3.out.file.handle;
2655 CHECK_CREATED(&io3, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2656 CHECK_VAL(io3.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2658 CHECK_NO_BREAK(tctx);
2659 done:
2660 smb2_util_close(tree, h1a);
2661 smb2_util_close(tree, h1b);
2662 smb2_util_close(tree, h2);
2663 smb2_util_close(tree, h3);
2665 smb2_util_unlink(tree, fname);
2666 talloc_free(mem_ctx);
2667 return ret;
2671 static bool test_lease_breaking4(struct torture_context *tctx,
2672 struct smb2_tree *tree)
2674 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2675 struct smb2_create io1 = {};
2676 struct smb2_create io2 = {};
2677 struct smb2_create io3 = {};
2678 struct smb2_lease ls1 = {};
2679 struct smb2_lease ls1t = {};
2680 struct smb2_handle h1 = {};
2681 struct smb2_handle h2 = {};
2682 struct smb2_handle h3 = {};
2683 struct smb2_request *req2 = NULL;
2684 struct lease_break_info lease_break_info_tmp = {};
2685 struct smb2_lease_break_ack ack = {};
2686 const char *fname = "lease_breaking4.dat";
2687 bool ret = true;
2688 NTSTATUS status;
2689 uint32_t caps;
2691 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2692 if (!(caps & SMB2_CAP_LEASING)) {
2693 torture_skip(tctx, "leases are not supported");
2696 smb2_util_unlink(tree, fname);
2698 tree->session->transport->lease.handler = torture_lease_handler;
2699 tree->session->transport->lease.private_data = tree;
2700 tree->session->transport->oplock.handler = torture_oplock_handler;
2701 tree->session->transport->oplock.private_data = tree;
2704 * we defer acking the lease break.
2706 torture_reset_lease_break_info(tctx, &lease_break_info);
2707 lease_break_info.lease_skip_ack = true;
2709 smb2_lease_create_share(&io1, &ls1, false, fname,
2710 smb2_util_share_access("RWD"),
2711 LEASE1,
2712 smb2_util_lease_state("RH"));
2713 status = smb2_create(tree, mem_ctx, &io1);
2714 CHECK_STATUS(status, NT_STATUS_OK);
2715 h1 = io1.out.file.handle;
2716 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2717 CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
2719 CHECK_NO_BREAK(tctx);
2722 * a conflicting open is *not* blocked until we ack the
2723 * lease break
2725 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2726 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2727 req2 = smb2_create_send(tree, &io2);
2728 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2731 * We got a break from RH to NONE, we're supported to ack
2732 * this downgrade
2734 CHECK_BREAK_INFO("RH", "", LEASE1);
2736 lease_break_info_tmp = lease_break_info;
2737 torture_reset_lease_break_info(tctx, &lease_break_info);
2738 CHECK_NO_BREAK(tctx);
2740 torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2742 status = smb2_create_recv(req2, tctx, &io2);
2743 CHECK_STATUS(status, NT_STATUS_OK);
2744 h2 = io2.out.file.handle;
2745 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2746 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2747 smb2_util_close(tree, h2);
2749 CHECK_NO_BREAK(tctx);
2752 * a conflicting open is *not* blocked until we ack the
2753 * lease break, even if the lease is in breaking state.
2755 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2756 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2757 req2 = smb2_create_send(tree, &io2);
2758 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2760 CHECK_NO_BREAK(tctx);
2762 torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2764 status = smb2_create_recv(req2, tctx, &io2);
2765 CHECK_STATUS(status, NT_STATUS_OK);
2766 h2 = io2.out.file.handle;
2767 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2768 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2769 smb2_util_close(tree, h2);
2771 CHECK_NO_BREAK(tctx);
2774 * We now ask the server about the current lease state
2775 * which should still be "RH", but with
2776 * SMB2_LEASE_FLAG_BREAK_IN_PROGRESS.
2778 smb2_lease_create_share(&io3, &ls1t, false, fname,
2779 smb2_util_share_access("RWD"),
2780 LEASE1,
2781 smb2_util_lease_state(""));
2782 status = smb2_create(tree, mem_ctx, &io3);
2783 CHECK_STATUS(status, NT_STATUS_OK);
2784 h3 = io3.out.file.handle;
2785 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2786 CHECK_LEASE(&io3, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2789 * We finally ack the lease break...
2791 CHECK_NO_BREAK(tctx);
2792 lease_break_info = lease_break_info_tmp;
2793 ack.in.lease.lease_key =
2794 lease_break_info.lease_break.current_lease.lease_key;
2795 ack.in.lease.lease_state =
2796 lease_break_info.lease_break.new_lease_state;
2797 torture_reset_lease_break_info(tctx, &lease_break_info);
2798 lease_break_info.lease_skip_ack = true;
2800 status = smb2_lease_break_ack(tree, &ack);
2801 CHECK_STATUS(status, NT_STATUS_OK);
2802 CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
2804 CHECK_NO_BREAK(tctx);
2806 done:
2807 smb2_util_close(tree, h1);
2808 smb2_util_close(tree, h2);
2809 smb2_util_close(tree, h3);
2811 smb2_util_unlink(tree, fname);
2812 talloc_free(mem_ctx);
2813 return ret;
2816 static bool test_lease_breaking5(struct torture_context *tctx,
2817 struct smb2_tree *tree)
2819 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2820 struct smb2_create io1 = {};
2821 struct smb2_create io2 = {};
2822 struct smb2_create io3 = {};
2823 struct smb2_lease ls1 = {};
2824 struct smb2_lease ls1t = {};
2825 struct smb2_handle h1 = {};
2826 struct smb2_handle h2 = {};
2827 struct smb2_handle h3 = {};
2828 struct smb2_request *req2 = NULL;
2829 struct lease_break_info lease_break_info_tmp = {};
2830 struct smb2_lease_break_ack ack = {};
2831 const char *fname = "lease_breaking5.dat";
2832 bool ret = true;
2833 NTSTATUS status;
2834 uint32_t caps;
2836 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2837 if (!(caps & SMB2_CAP_LEASING)) {
2838 torture_skip(tctx, "leases are not supported");
2841 smb2_util_unlink(tree, fname);
2843 tree->session->transport->lease.handler = torture_lease_handler;
2844 tree->session->transport->lease.private_data = tree;
2845 tree->session->transport->oplock.handler = torture_oplock_handler;
2846 tree->session->transport->oplock.private_data = tree;
2849 * we defer acking the lease break.
2851 torture_reset_lease_break_info(tctx, &lease_break_info);
2852 lease_break_info.lease_skip_ack = true;
2854 smb2_lease_create_share(&io1, &ls1, false, fname,
2855 smb2_util_share_access("RWD"),
2856 LEASE1,
2857 smb2_util_lease_state("R"));
2858 status = smb2_create(tree, mem_ctx, &io1);
2859 CHECK_STATUS(status, NT_STATUS_OK);
2860 h1 = io1.out.file.handle;
2861 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2862 CHECK_LEASE(&io1, "R", true, LEASE1, 0);
2864 CHECK_NO_BREAK(tctx);
2867 * a conflicting open is *not* blocked until we ack the
2868 * lease break
2870 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2871 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2872 req2 = smb2_create_send(tree, &io2);
2873 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2876 * We got a break from RH to NONE, we're supported to ack
2877 * this downgrade
2879 CHECK_BREAK_INFO("R", "", LEASE1);
2881 lease_break_info_tmp = lease_break_info;
2882 torture_reset_lease_break_info(tctx, &lease_break_info);
2883 CHECK_NO_BREAK(tctx);
2885 torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2887 status = smb2_create_recv(req2, tctx, &io2);
2888 CHECK_STATUS(status, NT_STATUS_OK);
2889 h2 = io2.out.file.handle;
2890 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2891 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2893 CHECK_NO_BREAK(tctx);
2896 * We now ask the server about the current lease state
2897 * which should still be "RH", but with
2898 * SMB2_LEASE_FLAG_BREAK_IN_PROGRESS.
2900 smb2_lease_create_share(&io3, &ls1t, false, fname,
2901 smb2_util_share_access("RWD"),
2902 LEASE1,
2903 smb2_util_lease_state(""));
2904 status = smb2_create(tree, mem_ctx, &io3);
2905 CHECK_STATUS(status, NT_STATUS_OK);
2906 h3 = io3.out.file.handle;
2907 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2908 CHECK_LEASE(&io3, "", true, LEASE1, 0);
2911 * We send an ack without without being asked.
2913 CHECK_NO_BREAK(tctx);
2914 lease_break_info = lease_break_info_tmp;
2915 ack.in.lease.lease_key =
2916 lease_break_info.lease_break.current_lease.lease_key;
2917 ack.in.lease.lease_state =
2918 lease_break_info.lease_break.new_lease_state;
2919 torture_reset_lease_break_info(tctx, &lease_break_info);
2920 status = smb2_lease_break_ack(tree, &ack);
2921 CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
2923 CHECK_NO_BREAK(tctx);
2925 done:
2926 smb2_util_close(tree, h1);
2927 smb2_util_close(tree, h2);
2928 smb2_util_close(tree, h3);
2930 smb2_util_unlink(tree, fname);
2931 talloc_free(mem_ctx);
2932 return ret;
2935 static bool test_lease_breaking6(struct torture_context *tctx,
2936 struct smb2_tree *tree)
2938 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2939 struct smb2_create io1 = {};
2940 struct smb2_create io2 = {};
2941 struct smb2_lease ls1 = {};
2942 struct smb2_handle h1a = {};
2943 struct smb2_handle h1b = {};
2944 struct smb2_handle h2 = {};
2945 struct smb2_request *req2 = NULL;
2946 struct smb2_lease_break_ack ack = {};
2947 const char *fname = "lease_breaking6.dat";
2948 bool ret = true;
2949 NTSTATUS status;
2950 uint32_t caps;
2952 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2953 if (!(caps & SMB2_CAP_LEASING)) {
2954 torture_skip(tctx, "leases are not supported");
2957 smb2_util_unlink(tree, fname);
2959 tree->session->transport->lease.handler = torture_lease_handler;
2960 tree->session->transport->lease.private_data = tree;
2961 tree->session->transport->oplock.handler = torture_oplock_handler;
2962 tree->session->transport->oplock.private_data = tree;
2965 * we defer acking the lease break.
2967 torture_reset_lease_break_info(tctx, &lease_break_info);
2968 lease_break_info.lease_skip_ack = true;
2970 smb2_lease_create_share(&io1, &ls1, false, fname,
2971 smb2_util_share_access("RWD"),
2972 LEASE1,
2973 smb2_util_lease_state("RWH"));
2974 status = smb2_create(tree, mem_ctx, &io1);
2975 CHECK_STATUS(status, NT_STATUS_OK);
2976 h1a = io1.out.file.handle;
2977 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2978 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2981 * a conflicting open is blocked until we ack the
2982 * lease break
2984 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2985 req2 = smb2_create_send(tree, &io2);
2986 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2989 * we got the lease break, but defer the ack.
2991 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2993 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2995 ack.in.lease.lease_key =
2996 lease_break_info.lease_break.current_lease.lease_key;
2997 torture_reset_lease_break_info(tctx, &lease_break_info);
3000 * a open using the same lease key is still works,
3001 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
3003 status = smb2_create(tree, mem_ctx, &io1);
3004 CHECK_STATUS(status, NT_STATUS_OK);
3005 h1b = io1.out.file.handle;
3006 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3007 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
3008 smb2_util_close(tree, h1b);
3010 CHECK_NO_BREAK(tctx);
3012 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
3015 * We are asked to break to "RH", but we are allowed to
3016 * break to any of "RH", "R" or NONE.
3018 ack.in.lease.lease_state = SMB2_LEASE_NONE;
3019 status = smb2_lease_break_ack(tree, &ack);
3020 CHECK_STATUS(status, NT_STATUS_OK);
3021 CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
3023 torture_assert(tctx, req2->cancel.can_cancel,
3024 "req2 can_cancel");
3026 status = smb2_create_recv(req2, tctx, &io2);
3027 CHECK_STATUS(status, NT_STATUS_OK);
3028 h2 = io2.out.file.handle;
3029 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3030 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
3032 CHECK_NO_BREAK(tctx);
3033 done:
3034 smb2_util_close(tree, h1a);
3035 smb2_util_close(tree, h1b);
3036 smb2_util_close(tree, h2);
3037 smb2_util_unlink(tree, fname);
3038 talloc_free(mem_ctx);
3039 return ret;
3042 static bool test_lease_lock1(struct torture_context *tctx,
3043 struct smb2_tree *tree1a,
3044 struct smb2_tree *tree2)
3046 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3047 struct smb2_create io1 = {};
3048 struct smb2_create io2 = {};
3049 struct smb2_create io3 = {};
3050 struct smb2_lease ls1 = {};
3051 struct smb2_lease ls2 = {};
3052 struct smb2_lease ls3 = {};
3053 struct smb2_handle h1 = {};
3054 struct smb2_handle h2 = {};
3055 struct smb2_handle h3 = {};
3056 struct smb2_lock lck;
3057 struct smb2_lock_element el[1];
3058 const char *fname = "locktest.dat";
3059 bool ret = true;
3060 NTSTATUS status;
3061 uint32_t caps;
3062 struct smbcli_options options1;
3063 struct smb2_tree *tree1b = NULL;
3065 options1 = tree1a->session->transport->options;
3067 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3068 if (!(caps & SMB2_CAP_LEASING)) {
3069 torture_skip(tctx, "leases are not supported");
3072 /* Set up handlers. */
3073 tree2->session->transport->lease.handler = torture_lease_handler;
3074 tree2->session->transport->lease.private_data = tree2;
3075 tree2->session->transport->oplock.handler = torture_oplock_handler;
3076 tree2->session->transport->oplock.private_data = tree2;
3078 tree1a->session->transport->lease.handler = torture_lease_handler;
3079 tree1a->session->transport->lease.private_data = tree1a;
3080 tree1a->session->transport->oplock.handler = torture_oplock_handler;
3081 tree1a->session->transport->oplock.private_data = tree1a;
3083 /* create a new connection (same client_guid) */
3084 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
3085 torture_warning(tctx, "couldn't reconnect, bailing\n");
3086 ret = false;
3087 goto done;
3090 tree1b->session->transport->lease.handler = torture_lease_handler;
3091 tree1b->session->transport->lease.private_data = tree1b;
3092 tree1b->session->transport->oplock.handler = torture_oplock_handler;
3093 tree1b->session->transport->oplock.private_data = tree1b;
3095 smb2_util_unlink(tree1a, fname);
3097 torture_reset_lease_break_info(tctx, &lease_break_info);
3098 ZERO_STRUCT(lck);
3100 /* Open a handle on tree1a. */
3101 smb2_lease_create_share(&io1, &ls1, false, fname,
3102 smb2_util_share_access("RWD"),
3103 LEASE1,
3104 smb2_util_lease_state("RWH"));
3105 status = smb2_create(tree1a, mem_ctx, &io1);
3106 CHECK_STATUS(status, NT_STATUS_OK);
3107 h1 = io1.out.file.handle;
3108 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3109 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
3111 /* Open a second handle on tree1b. */
3112 smb2_lease_create_share(&io2, &ls2, false, fname,
3113 smb2_util_share_access("RWD"),
3114 LEASE2,
3115 smb2_util_lease_state("RWH"));
3116 status = smb2_create(tree1b, mem_ctx, &io2);
3117 CHECK_STATUS(status, NT_STATUS_OK);
3118 h2 = io2.out.file.handle;
3119 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3120 CHECK_LEASE(&io2, "RH", true, LEASE2, 0);
3121 /* And LEASE1 got broken to RH. */
3122 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
3123 torture_reset_lease_break_info(tctx, &lease_break_info);
3125 /* Now open a lease on a different client guid. */
3126 smb2_lease_create_share(&io3, &ls3, false, fname,
3127 smb2_util_share_access("RWD"),
3128 LEASE3,
3129 smb2_util_lease_state("RWH"));
3130 status = smb2_create(tree2, mem_ctx, &io3);
3131 CHECK_STATUS(status, NT_STATUS_OK);
3132 h3 = io3.out.file.handle;
3133 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3134 CHECK_LEASE(&io3, "RH", true, LEASE3, 0);
3135 /* Doesn't break. */
3136 CHECK_NO_BREAK(tctx);
3138 lck.in.locks = el;
3140 * Try and get get an exclusive byte
3141 * range lock on H1 (LEASE1).
3144 lck.in.lock_count = 1;
3145 lck.in.lock_sequence = 1;
3146 lck.in.file.handle = h1;
3147 el[0].offset = 0;
3148 el[0].length = 1;
3149 el[0].reserved = 0;
3150 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
3151 status = smb2_lock(tree1a, &lck);
3152 CHECK_STATUS(status, NT_STATUS_OK);
3154 /* LEASE2 and LEASE3 should get broken to NONE. */
3155 torture_wait_for_lease_break(tctx);
3156 torture_wait_for_lease_break(tctx);
3157 torture_wait_for_lease_break(tctx);
3158 torture_wait_for_lease_break(tctx);
3160 CHECK_VAL(lease_break_info.failures, 0); \
3161 CHECK_VAL(lease_break_info.count, 2); \
3163 /* Get state of the H1 (LEASE1) */
3164 smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
3165 status = smb2_create(tree1a, mem_ctx, &io1);
3166 CHECK_STATUS(status, NT_STATUS_OK);
3167 /* Should still be RH. */
3168 CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
3169 smb2_util_close(tree1a, io1.out.file.handle);
3171 /* Get state of the H2 (LEASE2) */
3172 smb2_lease_create(&io2, &ls2, false, fname, LEASE2, smb2_util_lease_state(""));
3173 status = smb2_create(tree1b, mem_ctx, &io2);
3174 CHECK_STATUS(status, NT_STATUS_OK);
3175 CHECK_LEASE(&io2, "", true, LEASE2, 0);
3176 smb2_util_close(tree1b, io2.out.file.handle);
3178 /* Get state of the H3 (LEASE3) */
3179 smb2_lease_create(&io3, &ls3, false, fname, LEASE3, smb2_util_lease_state(""));
3180 status = smb2_create(tree2, mem_ctx, &io3);
3181 CHECK_STATUS(status, NT_STATUS_OK);
3182 CHECK_LEASE(&io3, "", true, LEASE3, 0);
3183 smb2_util_close(tree2, io3.out.file.handle);
3185 torture_reset_lease_break_info(tctx, &lease_break_info);
3188 * Try and get get an exclusive byte
3189 * range lock on H3 (LEASE3).
3191 lck.in.lock_count = 1;
3192 lck.in.lock_sequence = 2;
3193 lck.in.file.handle = h3;
3194 el[0].offset = 100;
3195 el[0].length = 1;
3196 el[0].reserved = 0;
3197 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
3198 status = smb2_lock(tree2, &lck);
3199 CHECK_STATUS(status, NT_STATUS_OK);
3200 /* LEASE1 got broken to NONE. */
3201 CHECK_BREAK_INFO("RH", "", LEASE1);
3202 torture_reset_lease_break_info(tctx, &lease_break_info);
3204 done:
3205 smb2_util_close(tree1a, h1);
3206 smb2_util_close(tree1b, h2);
3207 smb2_util_close(tree2, h3);
3209 smb2_util_unlink(tree1a, fname);
3210 talloc_free(mem_ctx);
3211 return ret;
3214 static bool test_lease_complex1(struct torture_context *tctx,
3215 struct smb2_tree *tree1a)
3217 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3218 struct smb2_create io1;
3219 struct smb2_create io2;
3220 struct smb2_lease ls1;
3221 struct smb2_lease ls2;
3222 struct smb2_handle h = {{0}};
3223 struct smb2_handle h2 = {{0}};
3224 struct smb2_handle h3 = {{0}};
3225 struct smb2_write w;
3226 NTSTATUS status;
3227 const char *fname = "lease_complex1.dat";
3228 bool ret = true;
3229 uint32_t caps;
3230 struct smb2_tree *tree1b = NULL;
3231 struct smbcli_options options1;
3233 options1 = tree1a->session->transport->options;
3235 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3236 if (!(caps & SMB2_CAP_LEASING)) {
3237 torture_skip(tctx, "leases are not supported");
3240 tree1a->session->transport->lease.handler = torture_lease_handler;
3241 tree1a->session->transport->lease.private_data = tree1a;
3242 tree1a->session->transport->oplock.handler = torture_oplock_handler;
3243 tree1a->session->transport->oplock.private_data = tree1a;
3245 /* create a new connection (same client_guid) */
3246 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
3247 torture_warning(tctx, "couldn't reconnect, bailing\n");
3248 ret = false;
3249 goto done;
3252 tree1b->session->transport->lease.handler = torture_lease_handler;
3253 tree1b->session->transport->lease.private_data = tree1b;
3254 tree1b->session->transport->oplock.handler = torture_oplock_handler;
3255 tree1b->session->transport->oplock.private_data = tree1b;
3257 smb2_util_unlink(tree1a, fname);
3259 torture_reset_lease_break_info(tctx, &lease_break_info);
3261 /* Grab R lease over connection 1a */
3262 smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
3263 status = smb2_create(tree1a, mem_ctx, &io1);
3264 CHECK_STATUS(status, NT_STATUS_OK);
3265 h = io1.out.file.handle;
3266 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3267 CHECK_LEASE(&io1, "R", true, LEASE1, 0);
3269 /* Upgrade to RWH over connection 1b */
3270 ls1.lease_state = smb2_util_lease_state("RWH");
3271 status = smb2_create(tree1b, mem_ctx, &io1);
3272 CHECK_STATUS(status, NT_STATUS_OK);
3273 h2 = io1.out.file.handle;
3274 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3275 CHECK_LEASE(&io1, "RHW", true, LEASE1, 0);
3277 /* close over connection 1b */
3278 status = smb2_util_close(tree1b, h2);
3279 CHECK_STATUS(status, NT_STATUS_OK);
3281 /* Contend with LEASE2. */
3282 smb2_lease_create(&io2, &ls2, false, fname, LEASE2, smb2_util_lease_state("R"));
3283 status = smb2_create(tree1b, mem_ctx, &io2);
3284 CHECK_STATUS(status, NT_STATUS_OK);
3285 h3 = io2.out.file.handle;
3286 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3287 CHECK_LEASE(&io2, "R", true, LEASE2, 0);
3289 /* Verify that we were only sent one break. */
3290 CHECK_BREAK_INFO("RHW", "RH", LEASE1);
3292 /* again RH over connection 1b doesn't change the epoch */
3293 ls1.lease_state = smb2_util_lease_state("RH");
3294 status = smb2_create(tree1b, mem_ctx, &io1);
3295 CHECK_STATUS(status, NT_STATUS_OK);
3296 h2 = io1.out.file.handle;
3297 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3298 CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
3300 /* close over connection 1b */
3301 status = smb2_util_close(tree1b, h2);
3302 CHECK_STATUS(status, NT_STATUS_OK);
3304 torture_reset_lease_break_info(tctx, &lease_break_info);
3306 ZERO_STRUCT(w);
3307 w.in.file.handle = h;
3308 w.in.offset = 0;
3309 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3310 memset(w.in.data.data, 'o', w.in.data.length);
3311 status = smb2_write(tree1a, &w);
3312 CHECK_STATUS(status, NT_STATUS_OK);
3314 ls2.lease_epoch += 1;
3315 CHECK_BREAK_INFO("R", "", LEASE2);
3317 torture_reset_lease_break_info(tctx, &lease_break_info);
3319 ZERO_STRUCT(w);
3320 w.in.file.handle = h3;
3321 w.in.offset = 0;
3322 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3323 memset(w.in.data.data, 'o', w.in.data.length);
3324 status = smb2_write(tree1b, &w);
3325 CHECK_STATUS(status, NT_STATUS_OK);
3327 ls1.lease_epoch += 1;
3328 CHECK_BREAK_INFO("RH", "", LEASE1);
3330 done:
3331 smb2_util_close(tree1a, h);
3332 smb2_util_close(tree1b, h2);
3333 smb2_util_close(tree1b, h3);
3335 smb2_util_unlink(tree1a, fname);
3337 talloc_free(mem_ctx);
3339 return ret;
3342 static bool test_lease_v2_complex1(struct torture_context *tctx,
3343 struct smb2_tree *tree1a)
3345 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3346 struct smb2_create io1;
3347 struct smb2_create io2;
3348 struct smb2_lease ls1;
3349 struct smb2_lease ls2;
3350 struct smb2_handle h = {{0}};
3351 struct smb2_handle h2 = {{0}};
3352 struct smb2_handle h3 = {{0}};
3353 struct smb2_write w;
3354 NTSTATUS status;
3355 const char *fname = "lease_v2_complex1.dat";
3356 bool ret = true;
3357 uint32_t caps;
3358 enum protocol_types protocol;
3359 struct smb2_tree *tree1b = NULL;
3360 struct smbcli_options options1;
3362 options1 = tree1a->session->transport->options;
3364 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3365 if (!(caps & SMB2_CAP_LEASING)) {
3366 torture_skip(tctx, "leases are not supported");
3369 protocol = smbXcli_conn_protocol(tree1a->session->transport->conn);
3370 if (protocol < PROTOCOL_SMB3_00) {
3371 torture_skip(tctx, "v2 leases are not supported");
3374 tree1a->session->transport->lease.handler = torture_lease_handler;
3375 tree1a->session->transport->lease.private_data = tree1a;
3376 tree1a->session->transport->oplock.handler = torture_oplock_handler;
3377 tree1a->session->transport->oplock.private_data = tree1a;
3379 /* create a new connection (same client_guid) */
3380 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
3381 torture_warning(tctx, "couldn't reconnect, bailing\n");
3382 ret = false;
3383 goto done;
3386 tree1b->session->transport->lease.handler = torture_lease_handler;
3387 tree1b->session->transport->lease.private_data = tree1b;
3388 tree1b->session->transport->oplock.handler = torture_oplock_handler;
3389 tree1b->session->transport->oplock.private_data = tree1b;
3391 smb2_util_unlink(tree1a, fname);
3393 torture_reset_lease_break_info(tctx, &lease_break_info);
3395 /* Grab R lease over connection 1a */
3396 smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
3397 smb2_util_lease_state("R"), 0x4711);
3398 status = smb2_create(tree1a, mem_ctx, &io1);
3399 CHECK_STATUS(status, NT_STATUS_OK);
3400 h = io1.out.file.handle;
3401 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3402 ls1.lease_epoch += 1;
3403 CHECK_LEASE_V2(&io1, "R", true, LEASE1,
3404 0, 0, ls1.lease_epoch);
3406 /* Upgrade to RWH over connection 1b */
3407 ls1.lease_state = smb2_util_lease_state("RWH");
3408 status = smb2_create(tree1b, mem_ctx, &io1);
3409 CHECK_STATUS(status, NT_STATUS_OK);
3410 h2 = io1.out.file.handle;
3411 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3412 ls1.lease_epoch += 1;
3413 CHECK_LEASE_V2(&io1, "RHW", true, LEASE1,
3414 0, 0, ls1.lease_epoch);
3416 /* close over connection 1b */
3417 status = smb2_util_close(tree1b, h2);
3418 CHECK_STATUS(status, NT_STATUS_OK);
3420 /* Contend with LEASE2. */
3421 smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
3422 smb2_util_lease_state("R"), 0x11);
3423 status = smb2_create(tree1b, mem_ctx, &io2);
3424 CHECK_STATUS(status, NT_STATUS_OK);
3425 h3 = io2.out.file.handle;
3426 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3427 ls2.lease_epoch += 1;
3428 CHECK_LEASE_V2(&io2, "R", true, LEASE2,
3429 0, 0, ls2.lease_epoch);
3431 /* Verify that we were only sent one break. */
3432 ls1.lease_epoch += 1;
3433 CHECK_BREAK_INFO_V2(tree1a->session->transport,
3434 "RHW", "RH", LEASE1, ls1.lease_epoch);
3436 /* again RH over connection 1b doesn't change the epoch */
3437 ls1.lease_state = smb2_util_lease_state("RH");
3438 status = smb2_create(tree1b, mem_ctx, &io1);
3439 CHECK_STATUS(status, NT_STATUS_OK);
3440 h2 = io1.out.file.handle;
3441 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3442 CHECK_LEASE_V2(&io1, "RH", true, LEASE1,
3443 0, 0, ls1.lease_epoch);
3445 /* close over connection 1b */
3446 status = smb2_util_close(tree1b, h2);
3447 CHECK_STATUS(status, NT_STATUS_OK);
3449 torture_reset_lease_break_info(tctx, &lease_break_info);
3451 ZERO_STRUCT(w);
3452 w.in.file.handle = h;
3453 w.in.offset = 0;
3454 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3455 memset(w.in.data.data, 'o', w.in.data.length);
3456 status = smb2_write(tree1a, &w);
3457 CHECK_STATUS(status, NT_STATUS_OK);
3459 ls2.lease_epoch += 1;
3460 CHECK_BREAK_INFO_V2(tree1a->session->transport,
3461 "R", "", LEASE2, ls2.lease_epoch);
3463 torture_reset_lease_break_info(tctx, &lease_break_info);
3465 ZERO_STRUCT(w);
3466 w.in.file.handle = h3;
3467 w.in.offset = 0;
3468 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3469 memset(w.in.data.data, 'o', w.in.data.length);
3470 status = smb2_write(tree1b, &w);
3471 CHECK_STATUS(status, NT_STATUS_OK);
3473 ls1.lease_epoch += 1;
3474 CHECK_BREAK_INFO_V2(tree1a->session->transport,
3475 "RH", "", LEASE1, ls1.lease_epoch);
3477 done:
3478 smb2_util_close(tree1a, h);
3479 smb2_util_close(tree1b, h2);
3480 smb2_util_close(tree1b, h3);
3482 smb2_util_unlink(tree1a, fname);
3484 talloc_free(mem_ctx);
3486 return ret;
3489 static bool test_lease_v2_complex2(struct torture_context *tctx,
3490 struct smb2_tree *tree1a)
3492 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3493 struct smb2_create io1;
3494 struct smb2_create io2;
3495 struct smb2_lease ls1;
3496 struct smb2_lease ls2;
3497 struct smb2_handle h = {{0}};
3498 struct smb2_handle h2 = {{0}};
3499 struct smb2_request *req2 = NULL;
3500 struct smb2_lease_break_ack ack = {};
3501 NTSTATUS status;
3502 const char *fname = "lease_v2_complex2.dat";
3503 bool ret = true;
3504 uint32_t caps;
3505 enum protocol_types protocol;
3506 struct smb2_tree *tree1b = NULL;
3507 struct smbcli_options options1;
3509 options1 = tree1a->session->transport->options;
3511 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3512 if (!(caps & SMB2_CAP_LEASING)) {
3513 torture_skip(tctx, "leases are not supported");
3516 protocol = smbXcli_conn_protocol(tree1a->session->transport->conn);
3517 if (protocol < PROTOCOL_SMB3_00) {
3518 torture_skip(tctx, "v2 leases are not supported");
3521 tree1a->session->transport->lease.handler = torture_lease_handler;
3522 tree1a->session->transport->lease.private_data = tree1a;
3523 tree1a->session->transport->oplock.handler = torture_oplock_handler;
3524 tree1a->session->transport->oplock.private_data = tree1a;
3526 /* create a new connection (same client_guid) */
3527 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
3528 torture_warning(tctx, "couldn't reconnect, bailing\n");
3529 ret = false;
3530 goto done;
3533 tree1b->session->transport->lease.handler = torture_lease_handler;
3534 tree1b->session->transport->lease.private_data = tree1b;
3535 tree1b->session->transport->oplock.handler = torture_oplock_handler;
3536 tree1b->session->transport->oplock.private_data = tree1b;
3538 smb2_util_unlink(tree1a, fname);
3540 torture_reset_lease_break_info(tctx, &lease_break_info);
3542 /* Grab RWH lease over connection 1a */
3543 smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
3544 smb2_util_lease_state("RWH"), 0x4711);
3545 status = smb2_create(tree1a, mem_ctx, &io1);
3546 CHECK_STATUS(status, NT_STATUS_OK);
3547 h = io1.out.file.handle;
3548 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3549 ls1.lease_epoch += 1;
3550 CHECK_LEASE_V2(&io1, "RWH", true, LEASE1,
3551 0, 0, ls1.lease_epoch);
3554 * we defer acking the lease break.
3556 torture_reset_lease_break_info(tctx, &lease_break_info);
3557 lease_break_info.lease_skip_ack = true;
3559 /* Ask for RWH on connection 1b, different lease. */
3560 smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
3561 smb2_util_lease_state("RWH"), 0x11);
3562 req2 = smb2_create_send(tree1b, &io2);
3563 torture_assert(tctx, req2 != NULL, "smb2_create_send");
3565 ls1.lease_epoch += 1;
3567 CHECK_BREAK_INFO_V2(tree1a->session->transport,
3568 "RWH", "RH", LEASE1, ls1.lease_epoch);
3570 /* Send the break ACK on tree1b. */
3571 ack.in.lease.lease_key =
3572 lease_break_info.lease_break.current_lease.lease_key;
3573 ack.in.lease.lease_state = SMB2_LEASE_HANDLE|SMB2_LEASE_READ;
3575 status = smb2_lease_break_ack(tree1b, &ack);
3576 CHECK_STATUS(status, NT_STATUS_OK);
3577 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
3579 torture_reset_lease_break_info(tctx, &lease_break_info);
3581 status = smb2_create_recv(req2, tctx, &io2);
3582 CHECK_STATUS(status, NT_STATUS_OK);
3583 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3584 CHECK_LEASE_V2(&io2, "RH", true, LEASE2,
3585 0, 0, ls2.lease_epoch+1);
3586 h2 = io2.out.file.handle;
3588 done:
3589 smb2_util_close(tree1a, h);
3590 smb2_util_close(tree1b, h2);
3592 smb2_util_unlink(tree1a, fname);
3594 talloc_free(mem_ctx);
3596 return ret;
3600 static bool test_lease_timeout(struct torture_context *tctx,
3601 struct smb2_tree *tree)
3603 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3604 struct smb2_create io;
3605 struct smb2_lease ls1;
3606 struct smb2_lease ls2;
3607 struct smb2_handle h = {{0}};
3608 struct smb2_handle hnew = {{0}};
3609 struct smb2_handle h1b = {{0}};
3610 NTSTATUS status;
3611 const char *fname = "lease_timeout.dat";
3612 bool ret = true;
3613 struct smb2_lease_break_ack ack = {};
3614 struct smb2_request *req2 = NULL;
3615 struct smb2_write w;
3616 uint32_t caps;
3618 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
3619 if (!(caps & SMB2_CAP_LEASING)) {
3620 torture_skip(tctx, "leases are not supported");
3623 smb2_util_unlink(tree, fname);
3625 /* Grab a RWH lease. */
3626 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3627 status = smb2_create(tree, mem_ctx, &io);
3628 CHECK_STATUS(status, NT_STATUS_OK);
3629 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3630 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3631 h = io.out.file.handle;
3633 tree->session->transport->lease.handler = torture_lease_handler;
3634 tree->session->transport->lease.private_data = tree;
3635 tree->session->transport->oplock.handler = torture_oplock_handler;
3636 tree->session->transport->oplock.private_data = tree;
3639 * Just don't ack the lease break.
3641 torture_reset_lease_break_info(tctx, &lease_break_info);
3642 lease_break_info.lease_skip_ack = true;
3644 /* Break with a RWH request. */
3645 smb2_lease_create(&io, &ls2, false, fname, LEASE2, smb2_util_lease_state("RWH"));
3646 req2 = smb2_create_send(tree, &io);
3647 torture_assert(tctx, req2 != NULL, "smb2_create_send");
3648 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
3650 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
3652 /* Copy the break request. */
3653 ack.in.lease.lease_key =
3654 lease_break_info.lease_break.current_lease.lease_key;
3655 ack.in.lease.lease_state =
3656 lease_break_info.lease_break.new_lease_state;
3658 /* Now wait for the timeout and get the reply. */
3659 status = smb2_create_recv(req2, tctx, &io);
3660 CHECK_STATUS(status, NT_STATUS_OK);
3661 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3662 CHECK_LEASE(&io, "RH", true, LEASE2, 0);
3663 hnew = io.out.file.handle;
3665 /* Ack the break after the timeout... */
3666 status = smb2_lease_break_ack(tree, &ack);
3667 CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
3669 /* Get state of the original handle. */
3670 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
3671 status = smb2_create(tree, mem_ctx, &io);
3672 CHECK_STATUS(status, NT_STATUS_OK);
3673 CHECK_LEASE(&io, "", true, LEASE1, 0);
3674 smb2_util_close(tree, io.out.file.handle);
3676 /* Write on the original handle and make sure it's still valid. */
3677 torture_reset_lease_break_info(tctx, &lease_break_info);
3678 ZERO_STRUCT(w);
3679 w.in.file.handle = h;
3680 w.in.offset = 0;
3681 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3682 memset(w.in.data.data, '1', w.in.data.length);
3683 status = smb2_write(tree, &w);
3684 CHECK_STATUS(status, NT_STATUS_OK);
3686 /* Causes new handle to break to NONE. */
3687 CHECK_BREAK_INFO("RH", "", LEASE2);
3689 /* Write on the new handle. */
3690 torture_reset_lease_break_info(tctx, &lease_break_info);
3691 ZERO_STRUCT(w);
3692 w.in.file.handle = hnew;
3693 w.in.offset = 0;
3694 w.in.data = data_blob_talloc(mem_ctx, NULL, 1024);
3695 memset(w.in.data.data, '2', w.in.data.length);
3696 status = smb2_write(tree, &w);
3697 CHECK_STATUS(status, NT_STATUS_OK);
3698 /* No break - original handle was already NONE. */
3699 CHECK_NO_BREAK(tctx);
3700 smb2_util_close(tree, hnew);
3702 /* Upgrade to R on LEASE1. */
3703 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
3704 status = smb2_create(tree, mem_ctx, &io);
3705 CHECK_STATUS(status, NT_STATUS_OK);
3706 CHECK_LEASE(&io, "R", true, LEASE1, 0);
3707 h1b = io.out.file.handle;
3708 smb2_util_close(tree, h1b);
3710 /* Upgrade to RWH on LEASE1. */
3711 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3712 status = smb2_create(tree, mem_ctx, &io);
3713 CHECK_STATUS(status, NT_STATUS_OK);
3714 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3715 h1b = io.out.file.handle;
3716 smb2_util_close(tree, h1b);
3718 done:
3719 smb2_util_close(tree, h);
3720 smb2_util_close(tree, hnew);
3721 smb2_util_close(tree, h1b);
3723 smb2_util_unlink(tree, fname);
3725 talloc_free(mem_ctx);
3727 return ret;
3730 static bool test_lease_rename_wait(struct torture_context *tctx,
3731 struct smb2_tree *tree)
3733 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3734 struct smb2_create io;
3735 struct smb2_lease ls1;
3736 struct smb2_lease ls2;
3737 struct smb2_lease ls3;
3738 struct smb2_handle h1 = {{0}};
3739 struct smb2_handle h2 = {{0}};
3740 struct smb2_handle h3 = {{0}};
3741 union smb_setfileinfo sinfo;
3742 NTSTATUS status;
3743 const char *fname_src = "lease_rename_src.dat";
3744 const char *fname_dst = "lease_rename_dst.dat";
3745 bool ret = true;
3746 struct smb2_lease_break_ack ack = {};
3747 struct smb2_request *rename_req = NULL;
3748 uint32_t caps;
3749 unsigned int i;
3751 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
3752 if (!(caps & SMB2_CAP_LEASING)) {
3753 torture_skip(tctx, "leases are not supported");
3756 smb2_util_unlink(tree, fname_src);
3757 smb2_util_unlink(tree, fname_dst);
3759 /* Short timeout for fails. */
3760 tree->session->transport->options.request_timeout = 15;
3762 /* Grab a RH lease. */
3763 smb2_lease_create(&io,
3764 &ls1,
3765 false,
3766 fname_src,
3767 LEASE1,
3768 smb2_util_lease_state("RH"));
3769 status = smb2_create(tree, mem_ctx, &io);
3770 CHECK_STATUS(status, NT_STATUS_OK);
3771 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3772 CHECK_LEASE(&io, "RH", true, LEASE1, 0);
3773 h1 = io.out.file.handle;
3775 /* Second open with a RH lease. */
3776 smb2_lease_create(&io,
3777 &ls2,
3778 false,
3779 fname_src,
3780 LEASE2,
3781 smb2_util_lease_state("RH"));
3782 io.in.create_disposition = NTCREATEX_DISP_OPEN;
3783 io.in.desired_access = GENERIC_READ_ACCESS;
3784 status = smb2_create(tree, mem_ctx, &io);
3785 CHECK_STATUS(status, NT_STATUS_OK);
3786 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3787 CHECK_LEASE(&io, "RH", true, LEASE2, 0);
3788 h2 = io.out.file.handle;
3791 * Don't ack a lease break.
3793 tree->session->transport->lease.handler = torture_lease_handler;
3794 tree->session->transport->lease.private_data = tree;
3795 torture_reset_lease_break_info(tctx, &lease_break_info);
3796 lease_break_info.lease_skip_ack = true;
3798 /* Break with a rename. */
3799 ZERO_STRUCT(sinfo);
3800 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
3801 sinfo.rename_information.in.file.handle = h1;
3802 sinfo.rename_information.in.overwrite = true;
3803 sinfo.rename_information.in.new_name = fname_dst;
3804 rename_req = smb2_setinfo_file_send(tree, &sinfo);
3806 torture_assert(tctx,
3807 rename_req != NULL,
3808 "smb2_setinfo_file_send");
3809 torture_assert(tctx,
3810 rename_req->state == SMB2_REQUEST_RECV,
3811 "rename pending");
3813 /* Try and open the destination with a RH lease. */
3814 smb2_lease_create(&io,
3815 &ls3,
3816 false,
3817 fname_dst,
3818 LEASE3,
3819 smb2_util_lease_state("RH"));
3820 /* We want to open, not create. */
3821 io.in.create_disposition = NTCREATEX_DISP_OPEN;
3822 io.in.desired_access = GENERIC_READ_ACCESS;
3823 status = smb2_create(tree, mem_ctx, &io);
3824 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
3827 * The smb2_create() I/O should have picked up the break request
3828 * caused by the pending rename.
3831 /* Copy the break request. */
3832 ack.in.lease.lease_key =
3833 lease_break_info.lease_break.current_lease.lease_key;
3834 ack.in.lease.lease_state =
3835 lease_break_info.lease_break.new_lease_state;
3838 * Give the server 3 more chances to have renamed
3839 * the file. Better than doing a sleep.
3841 for (i = 0; i < 3; i++) {
3842 status = smb2_create(tree, mem_ctx, &io);
3843 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
3846 /* Ack the break. The server is now free to rename. */
3847 status = smb2_lease_break_ack(tree, &ack);
3848 CHECK_STATUS(status, NT_STATUS_OK);
3850 /* Get the rename reply. */
3851 status = smb2_setinfo_recv(rename_req);
3852 CHECK_STATUS(status, NT_STATUS_OK);
3854 /* The target should now exist. */
3855 status = smb2_create(tree, mem_ctx, &io);
3856 CHECK_STATUS(status, NT_STATUS_OK);
3857 h3 = io.out.file.handle;
3859 done:
3860 smb2_util_close(tree, h1);
3861 smb2_util_close(tree, h2);
3862 smb2_util_close(tree, h3);
3864 smb2_util_unlink(tree, fname_src);
3865 smb2_util_unlink(tree, fname_dst);
3867 talloc_free(mem_ctx);
3869 return ret;
3872 static bool test_lease_v2_rename(struct torture_context *tctx,
3873 struct smb2_tree *tree)
3875 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3876 struct smb2_create io;
3877 struct smb2_lease ls1;
3878 struct smb2_lease ls2;
3879 struct smb2_handle h = {{0}};
3880 struct smb2_handle h1 = {{0}};
3881 struct smb2_handle h2 = {{0}};
3882 union smb_setfileinfo sinfo;
3883 const char *fname = "lease_v2_rename_src.dat";
3884 const char *fname_dst = "lease_v2_rename_dst.dat";
3885 bool ret = true;
3886 NTSTATUS status;
3887 uint32_t caps;
3888 enum protocol_types protocol;
3890 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
3891 if (!(caps & SMB2_CAP_LEASING)) {
3892 torture_skip(tctx, "leases are not supported");
3895 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
3896 if (protocol < PROTOCOL_SMB3_00) {
3897 torture_skip(tctx, "v2 leases are not supported");
3900 smb2_util_unlink(tree, fname);
3901 smb2_util_unlink(tree, fname_dst);
3903 tree->session->transport->lease.handler = torture_lease_handler;
3904 tree->session->transport->lease.private_data = tree;
3905 tree->session->transport->oplock.handler = torture_oplock_handler;
3906 tree->session->transport->oplock.private_data = tree;
3908 torture_reset_lease_break_info(tctx, &lease_break_info);
3910 ZERO_STRUCT(io);
3911 smb2_lease_v2_create_share(&io, &ls1, false, fname,
3912 smb2_util_share_access("RWD"),
3913 LEASE1, NULL,
3914 smb2_util_lease_state("RHW"),
3915 0x4711);
3916 status = smb2_create(tree, mem_ctx, &io);
3917 CHECK_STATUS(status, NT_STATUS_OK);
3918 h = io.out.file.handle;
3919 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3920 ls1.lease_epoch += 1;
3921 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
3923 /* Now rename - what happens ? */
3924 ZERO_STRUCT(sinfo);
3925 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
3926 sinfo.rename_information.in.file.handle = h;
3927 sinfo.rename_information.in.overwrite = true;
3928 sinfo.rename_information.in.new_name = fname_dst;
3929 status = smb2_setinfo_file(tree, &sinfo);
3930 CHECK_STATUS(status, NT_STATUS_OK);
3932 /* No lease break. */
3933 CHECK_NO_BREAK(tctx);
3935 /* Check we can open another handle on the new name. */
3936 smb2_lease_v2_create_share(&io, &ls1, false, fname_dst,
3937 smb2_util_share_access("RWD"),
3938 LEASE1, NULL,
3939 smb2_util_lease_state(""),
3940 ls1.lease_epoch);
3941 status = smb2_create(tree, mem_ctx, &io);
3942 CHECK_STATUS(status, NT_STATUS_OK);
3943 h1 = io.out.file.handle;
3944 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3945 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
3946 smb2_util_close(tree, h1);
3948 /* Try another lease key. */
3949 smb2_lease_v2_create_share(&io, &ls2, false, fname_dst,
3950 smb2_util_share_access("RWD"),
3951 LEASE2, NULL,
3952 smb2_util_lease_state("RWH"),
3953 0x44);
3954 status = smb2_create(tree, mem_ctx, &io);
3955 CHECK_STATUS(status, NT_STATUS_OK);
3956 h2 = io.out.file.handle;
3957 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3958 ls2.lease_epoch += 1;
3959 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch );
3960 CHECK_BREAK_INFO_V2(tree->session->transport,
3961 "RWH", "RH", LEASE1, ls1.lease_epoch + 1);
3962 ls1.lease_epoch += 1;
3963 torture_reset_lease_break_info(tctx, &lease_break_info);
3965 /* Now rename back. */
3966 ZERO_STRUCT(sinfo);
3967 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
3968 sinfo.rename_information.in.file.handle = h;
3969 sinfo.rename_information.in.overwrite = true;
3970 sinfo.rename_information.in.new_name = fname;
3971 status = smb2_setinfo_file(tree, &sinfo);
3972 CHECK_STATUS(status, NT_STATUS_OK);
3974 /* Breaks to R on LEASE2. */
3975 CHECK_BREAK_INFO_V2(tree->session->transport,
3976 "RH", "R", LEASE2, ls2.lease_epoch + 1);
3977 ls2.lease_epoch += 1;
3979 /* Check we can open another handle on the current name. */
3980 smb2_lease_v2_create_share(&io, &ls1, false, fname,
3981 smb2_util_share_access("RWD"),
3982 LEASE1, NULL,
3983 smb2_util_lease_state(""),
3984 ls1.lease_epoch);
3985 status = smb2_create(tree, mem_ctx, &io);
3986 CHECK_STATUS(status, NT_STATUS_OK);
3987 h1 = io.out.file.handle;
3988 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3989 CHECK_LEASE_V2(&io, "RH", true, LEASE1, 0, 0, ls1.lease_epoch);
3990 smb2_util_close(tree, h1);
3992 done:
3994 smb2_util_close(tree, h);
3995 smb2_util_close(tree, h1);
3996 smb2_util_close(tree, h2);
3998 smb2_util_unlink(tree, fname);
3999 smb2_util_unlink(tree, fname_dst);
4001 smb2_util_unlink(tree, fname);
4002 talloc_free(mem_ctx);
4003 return ret;
4007 static bool test_lease_dynamic_share(struct torture_context *tctx,
4008 struct smb2_tree *tree1a)
4010 TALLOC_CTX *mem_ctx = talloc_new(tctx);
4011 struct smb2_create io;
4012 struct smb2_lease ls1;
4013 struct smb2_handle h, h1, h2;
4014 struct smb2_write w;
4015 NTSTATUS status;
4016 const char *fname = "dynamic_path.dat";
4017 bool ret = true;
4018 uint32_t caps;
4019 struct smb2_tree *tree_2 = NULL;
4020 struct smb2_tree *tree_3 = NULL;
4021 struct smbcli_options options;
4022 const char *orig_share = NULL;
4024 if (!TARGET_IS_SAMBA3(tctx)) {
4025 torture_skip(tctx, "dynamic shares are not supported");
4026 return true;
4029 options = tree1a->session->transport->options;
4030 options.client_guid = GUID_random();
4032 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
4033 if (!(caps & SMB2_CAP_LEASING)) {
4034 torture_skip(tctx, "leases are not supported");
4038 * Save off original share name and change it to dynamic_share.
4039 * This must have been pre-created with a dynamic path containing
4040 * %t. It means we'll sleep between the connects in order to
4041 * get a different timestamp for the share path.
4044 orig_share = lpcfg_parm_string(tctx->lp_ctx, NULL, "torture", "share");
4045 orig_share = talloc_strdup(tctx->lp_ctx, orig_share);
4046 if (orig_share == NULL) {
4047 torture_result(tctx, TORTURE_FAIL, __location__ "no memory\n");
4048 ret = false;
4049 goto done;
4051 lpcfg_set_cmdline(tctx->lp_ctx, "torture:share", "dynamic_share");
4053 /* create a new connection (same client_guid) */
4054 sleep(2);
4055 if (!torture_smb2_connection_ext(tctx, 0, &options, &tree_2)) {
4056 torture_result(tctx, TORTURE_FAIL,
4057 __location__ "couldn't reconnect "
4058 "max protocol 2.1, bailing\n");
4059 ret = false;
4060 goto done;
4063 tree_2->session->transport->lease.handler = torture_lease_handler;
4064 tree_2->session->transport->lease.private_data = tree_2;
4065 tree_2->session->transport->oplock.handler = torture_oplock_handler;
4066 tree_2->session->transport->oplock.private_data = tree_2;
4068 smb2_util_unlink(tree_2, fname);
4070 /* create a new connection (same client_guid) */
4071 sleep(2);
4072 if (!torture_smb2_connection_ext(tctx, 0, &options, &tree_3)) {
4073 torture_result(tctx, TORTURE_FAIL,
4074 __location__ "couldn't reconnect "
4075 "max protocol 3.0, bailing\n");
4076 ret = false;
4077 goto done;
4080 tree_3->session->transport->lease.handler = torture_lease_handler;
4081 tree_3->session->transport->lease.private_data = tree_3;
4082 tree_3->session->transport->oplock.handler = torture_oplock_handler;
4083 tree_3->session->transport->oplock.private_data = tree_3;
4085 smb2_util_unlink(tree_3, fname);
4087 torture_reset_lease_break_info(tctx, &lease_break_info);
4089 /* Get RWH lease over connection 2 */
4090 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
4091 status = smb2_create(tree_2, mem_ctx, &io);
4092 CHECK_STATUS(status, NT_STATUS_OK);
4093 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4094 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
4095 h = io.out.file.handle;
4097 /* Write some data into it. */
4098 w.in.file.handle = h;
4099 w.in.offset = 0;
4100 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
4101 memset(w.in.data.data, '1', w.in.data.length);
4102 status = smb2_write(tree_2, &w);
4103 CHECK_STATUS(status, NT_STATUS_OK);
4105 /* Open the same name over connection 3. */
4106 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
4107 status = smb2_create(tree_3, mem_ctx, &io);
4108 CHECK_STATUS(status, NT_STATUS_OK);
4109 h1 = io.out.file.handle;
4110 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4112 /* h1 should have replied with NONE. */
4113 CHECK_LEASE(&io, "", true, LEASE1, 0);
4115 /* We should have broken h to NONE. */
4116 CHECK_BREAK_INFO("RWH", "", LEASE1);
4118 /* Try to upgrade to RWH over connection 2 */
4119 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
4120 status = smb2_create(tree_2, mem_ctx, &io);
4121 CHECK_STATUS(status, NT_STATUS_OK);
4122 h2 = io.out.file.handle;
4123 CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
4124 CHECK_VAL(io.out.size, 4096);
4125 CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
4126 /* Should have been denied. */
4127 CHECK_LEASE(&io, "", true, LEASE1, 0);
4128 smb2_util_close(tree_2, h2);
4130 /* Try to upgrade to RWH over connection 3 */
4131 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
4132 status = smb2_create(tree_3, mem_ctx, &io);
4133 CHECK_STATUS(status, NT_STATUS_OK);
4134 h2 = io.out.file.handle;
4135 CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
4136 CHECK_VAL(io.out.size, 0);
4137 CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
4138 /* Should have been denied. */
4139 CHECK_LEASE(&io, "", true, LEASE1, 0);
4140 smb2_util_close(tree_3, h2);
4142 /* Write some data into it. */
4143 w.in.file.handle = h1;
4144 w.in.offset = 0;
4145 w.in.data = data_blob_talloc(mem_ctx, NULL, 1024);
4146 memset(w.in.data.data, '2', w.in.data.length);
4147 status = smb2_write(tree_3, &w);
4148 CHECK_STATUS(status, NT_STATUS_OK);
4150 /* Close everything.. */
4151 smb2_util_close(tree_2, h);
4152 smb2_util_close(tree_3, h1);
4154 /* And ensure we can get a lease ! */
4155 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
4156 status = smb2_create(tree_2, mem_ctx, &io);
4157 CHECK_STATUS(status, NT_STATUS_OK);
4158 CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
4159 CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
4160 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
4161 h = io.out.file.handle;
4162 /* And the file is the right size. */
4163 CHECK_VAL(io.out.size, 4096); \
4164 /* Close it. */
4165 smb2_util_close(tree_2, h);
4167 /* And ensure we can get a lease ! */
4168 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
4169 status = smb2_create(tree_3, mem_ctx, &io);
4170 CHECK_STATUS(status, NT_STATUS_OK);
4171 CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
4172 CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
4173 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
4174 h = io.out.file.handle;
4175 /* And the file is the right size. */
4176 CHECK_VAL(io.out.size, 1024); \
4177 /* Close it. */
4178 smb2_util_close(tree_3, h);
4180 done:
4182 if (tree_2 != NULL) {
4183 smb2_util_close(tree_2, h);
4184 smb2_util_unlink(tree_2, fname);
4186 if (tree_3 != NULL) {
4187 smb2_util_close(tree_3, h1);
4188 smb2_util_close(tree_3, h2);
4190 smb2_util_unlink(tree_3, fname);
4193 /* Set sharename back. */
4194 lpcfg_set_cmdline(tctx->lp_ctx, "torture:share", orig_share);
4196 talloc_free(mem_ctx);
4198 return ret;
4202 * Test identifies a bug where the Samba server will not trigger a lease break
4203 * for a handle caching lease held by a client when the underlying file is
4204 * deleted.
4205 * Test:
4206 * Connect session2.
4207 * open file in session1
4208 * session1 should have RWH lease.
4209 * open file in session2
4210 * lease break sent to session1 to downgrade lease to RH
4211 * close file in session 2
4212 * unlink file in session 2
4213 * lease break sent to session1 to downgrade lease to R
4214 * Cleanup
4216 static bool test_lease_unlink(struct torture_context *tctx,
4217 struct smb2_tree *tree1)
4219 TALLOC_CTX *mem_ctx = talloc_new(tctx);
4220 NTSTATUS status;
4221 bool ret = true;
4222 struct smbcli_options transport2_options;
4223 struct smb2_tree *tree2 = NULL;
4224 struct smb2_transport *transport1 = tree1->session->transport;
4225 struct smb2_transport *transport2;
4226 struct smb2_handle h1 = {{ 0 }};
4227 struct smb2_handle h2 = {{ 0 }};
4228 const char *fname = "lease_unlink.dat";
4229 uint32_t caps;
4230 struct smb2_create io1;
4231 struct smb2_create io2;
4232 struct smb2_lease ls1;
4233 struct smb2_lease ls2;
4235 caps = smb2cli_conn_server_capabilities(
4236 tree1->session->transport->conn);
4237 if (!(caps & SMB2_CAP_LEASING)) {
4238 torture_skip(tctx, "leases are not supported");
4241 /* Connect 2nd connection */
4242 transport2_options = transport1->options;
4243 transport2_options.client_guid = GUID_random();
4244 if (!torture_smb2_connection_ext(tctx, 0, &transport2_options, &tree2)) {
4245 torture_warning(tctx, "couldn't reconnect, bailing\n");
4246 return false;
4248 transport2 = tree2->session->transport;
4250 /* Set lease handlers */
4251 transport1->lease.handler = torture_lease_handler;
4252 transport1->lease.private_data = tree1;
4253 transport2->lease.handler = torture_lease_handler;
4254 transport2->lease.private_data = tree2;
4257 smb2_lease_create(&io1, &ls1, false, fname, LEASE1,
4258 smb2_util_lease_state("RHW"));
4259 smb2_lease_create(&io2, &ls2, false, fname, LEASE2,
4260 smb2_util_lease_state("RHW"));
4262 smb2_util_unlink(tree1, fname);
4264 torture_comment(tctx, "Client opens fname with session 1\n");
4265 torture_reset_lease_break_info(tctx, &lease_break_info);
4266 status = smb2_create(tree1, mem_ctx, &io1);
4267 CHECK_STATUS(status, NT_STATUS_OK);
4268 h1 = io1.out.file.handle;
4269 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4270 CHECK_LEASE(&io1, "RHW", true, LEASE1, 0);
4271 CHECK_VAL(lease_break_info.count, 0);
4273 torture_comment(tctx, "Client opens fname with session 2\n");
4274 torture_reset_lease_break_info(tctx, &lease_break_info);
4275 status = smb2_create(tree2, mem_ctx, &io2);
4276 CHECK_STATUS(status, NT_STATUS_OK);
4277 h2 = io2.out.file.handle;
4278 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
4279 CHECK_LEASE(&io2, "RH", true, LEASE2, 0);
4280 CHECK_VAL(lease_break_info.count, 1);
4281 CHECK_BREAK_INFO("RHW", "RH", LEASE1);
4283 torture_comment(tctx,
4284 "Client closes and then unlinks fname with session 2\n");
4285 torture_reset_lease_break_info(tctx, &lease_break_info);
4286 smb2_util_close(tree2, h2);
4287 smb2_util_unlink(tree2, fname);
4288 CHECK_VAL(lease_break_info.count, 1);
4289 CHECK_BREAK_INFO("RH", "R", LEASE1);
4291 done:
4292 smb2_util_close(tree1, h1);
4293 smb2_util_close(tree2, h2);
4294 smb2_util_unlink(tree1, fname);
4296 return ret;
4299 static bool test_lease_timeout_disconnect(struct torture_context *tctx,
4300 struct smb2_tree *tree1)
4302 TALLOC_CTX *mem_ctx = talloc_new(tctx);
4303 NTSTATUS status;
4304 bool ret = true;
4305 struct smbcli_options transport2_options;
4306 struct smbcli_options transport3_options;
4307 struct smb2_tree *tree2 = NULL;
4308 struct smb2_tree *tree3 = NULL;
4309 struct smb2_transport *transport1 = tree1->session->transport;
4310 struct smb2_transport *transport2;
4311 struct smb2_transport *transport3;
4312 const char *fname = "lease_timeout_logoff.dat" ;
4313 uint32_t caps;
4314 struct smb2_create io1;
4315 struct smb2_create io2;
4316 struct smb2_request *req2 = NULL;
4317 struct smb2_lease ls1;
4319 caps = smb2cli_conn_server_capabilities(
4320 tree1->session->transport->conn);
4321 if (!(caps & SMB2_CAP_LEASING)) {
4322 torture_skip(tctx, "leases are not supported");
4325 smb2_util_unlink(tree1, fname);
4327 /* Connect 2nd connection */
4328 torture_comment(tctx, "connect tree2 with the same client_guid\n");
4329 transport2_options = transport1->options;
4330 if (!torture_smb2_connection_ext(tctx, 0, &transport2_options, &tree2)) {
4331 torture_warning(tctx, "couldn't reconnect, bailing\n");
4332 return false;
4334 transport2 = tree2->session->transport;
4336 /* Connect 3rd connection */
4337 torture_comment(tctx, "connect tree3 with the same client_guid\n");
4338 transport3_options = transport1->options;
4339 if (!torture_smb2_connection_ext(tctx, 0, &transport3_options, &tree3)) {
4340 torture_warning(tctx, "couldn't reconnect, bailing\n");
4341 return false;
4343 transport3 = tree3->session->transport;
4345 /* Set lease handlers */
4346 transport1->lease.handler = torture_lease_handler;
4347 transport1->lease.private_data = tree1;
4348 transport2->lease.handler = torture_lease_handler;
4349 transport2->lease.private_data = tree2;
4350 transport3->lease.handler = torture_lease_handler;
4351 transport3->lease.private_data = tree3;
4353 smb2_lease_create_share(&io1, &ls1, false, fname,
4354 smb2_util_share_access(""),
4355 LEASE1,
4356 smb2_util_lease_state("RH"));
4357 io1.in.durable_open = true;
4358 smb2_generic_create(&io2, NULL, false, fname,
4359 NTCREATEX_DISP_OPEN_IF,
4360 SMB2_OPLOCK_LEVEL_NONE, 0, 0);
4362 torture_comment(tctx, "tree1: create file[%s] with durable RH lease (SHARE NONE)\n", fname);
4363 torture_reset_lease_break_info(tctx, &lease_break_info);
4364 lease_break_info.lease_skip_ack = true;
4365 status = smb2_create(tree1, mem_ctx, &io1);
4366 CHECK_STATUS(status, NT_STATUS_OK);
4367 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4368 CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
4369 CHECK_VAL(lease_break_info.count, 0);
4371 torture_comment(tctx, "tree1: skip lease acks\n");
4372 torture_reset_lease_break_info(tctx, &lease_break_info);
4373 lease_break_info.lease_skip_ack = true;
4374 torture_comment(tctx, "tree2: open file[%s] without lease (SHARE RWD)\n", fname);
4375 req2 = smb2_create_send(tree2, &io2);
4376 torture_assert(tctx, req2 != NULL, "req2 started");
4378 torture_comment(tctx, "tree1: wait for lease break\n");
4379 torture_wait_for_lease_break(tctx);
4380 CHECK_VAL(lease_break_info.count, 1);
4381 CHECK_BREAK_INFO("RH", "R", LEASE1);
4383 torture_comment(tctx, "tree1: reset lease handler\n");
4384 torture_reset_lease_break_info(tctx, &lease_break_info);
4385 lease_break_info.lease_skip_ack = true;
4386 CHECK_VAL(lease_break_info.count, 0);
4388 torture_comment(tctx, "tree2: check for SMB2_REQUEST_RECV\n");
4389 torture_assert_int_equal(tctx, req2->state,
4390 SMB2_REQUEST_RECV,
4391 "SMB2_REQUEST_RECV");
4393 torture_comment(tctx, "sleep 1\n");
4394 smb_msleep(1000);
4396 torture_comment(tctx, "transport1: keepalive\n");
4397 status = smb2_keepalive(transport1);
4398 CHECK_STATUS(status, NT_STATUS_OK);
4400 torture_comment(tctx, "transport2: keepalive\n");
4401 status = smb2_keepalive(transport2);
4402 CHECK_STATUS(status, NT_STATUS_OK);
4404 torture_comment(tctx, "transport3: keepalive\n");
4405 status = smb2_keepalive(transport3);
4406 CHECK_STATUS(status, NT_STATUS_OK);
4408 torture_comment(tctx, "tree2: check for SMB2_REQUEST_RECV\n");
4409 torture_assert_int_equal(tctx, req2->state,
4410 SMB2_REQUEST_RECV,
4411 "SMB2_REQUEST_RECV");
4412 torture_comment(tctx, "tree2: check for STATUS_PENDING\n");
4413 torture_assert(tctx, req2->cancel.can_cancel, "STATUS_PENDING");
4415 torture_comment(tctx, "sleep 1\n");
4416 smb_msleep(1000);
4417 torture_comment(tctx, "transport1: keepalive\n");
4418 status = smb2_keepalive(transport1);
4419 CHECK_STATUS(status, NT_STATUS_OK);
4420 torture_comment(tctx, "transport2: disconnect\n");
4421 TALLOC_FREE(tree2);
4423 torture_comment(tctx, "sleep 1\n");
4424 smb_msleep(1000);
4425 torture_comment(tctx, "transport1: keepalive\n");
4426 status = smb2_keepalive(transport1);
4427 CHECK_STATUS(status, NT_STATUS_OK);
4428 torture_comment(tctx, "transport1: disconnect\n");
4429 TALLOC_FREE(tree1);
4431 torture_comment(tctx, "sleep 1\n");
4432 smb_msleep(1000);
4433 torture_comment(tctx, "transport3: keepalive\n");
4434 status = smb2_keepalive(transport3);
4435 CHECK_STATUS(status, NT_STATUS_OK);
4436 torture_comment(tctx, "transport3: disconnect\n");
4437 TALLOC_FREE(tree3);
4439 done:
4441 return ret;
4444 static bool test_lease_duplicate_create(struct torture_context *tctx,
4445 struct smb2_tree *tree)
4447 TALLOC_CTX *mem_ctx = talloc_new(tctx);
4448 struct smb2_create io;
4449 struct smb2_lease ls;
4450 struct smb2_handle h1 = {{0}};
4451 struct smb2_handle h2 = {{0}};
4452 NTSTATUS status;
4453 const char *fname1 = "duplicate_create1.dat";
4454 const char *fname2 = "duplicate_create2.dat";
4455 bool ret = true;
4456 uint32_t caps;
4458 caps = smb2cli_conn_server_capabilities(
4459 tree->session->transport->conn);
4460 if (!(caps & SMB2_CAP_LEASING)) {
4461 torture_skip(tctx, "leases are not supported");
4464 /* Ensure files don't exist. */
4465 smb2_util_unlink(tree, fname1);
4466 smb2_util_unlink(tree, fname2);
4468 /* Create file1 - LEASE1 key. */
4469 smb2_lease_create(&io, &ls, false, fname1, LEASE1,
4470 smb2_util_lease_state("RWH"));
4471 status = smb2_create(tree, mem_ctx, &io);
4472 CHECK_STATUS(status, NT_STATUS_OK);
4473 h1 = io.out.file.handle;
4474 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4475 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
4478 * Create file2 with the same LEASE1 key - this should fail with.
4479 * INVALID_PARAMETER.
4481 smb2_lease_create(&io, &ls, false, fname2, LEASE1,
4482 smb2_util_lease_state("RWH"));
4483 status = smb2_create(tree, mem_ctx, &io);
4484 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
4485 smb2_util_close(tree, h1);
4487 done:
4488 smb2_util_close(tree, h2);
4489 smb2_util_close(tree, h1);
4490 smb2_util_unlink(tree, fname1);
4491 smb2_util_unlink(tree, fname2);
4492 talloc_free(mem_ctx);
4493 return ret;
4496 static bool test_lease_duplicate_open(struct torture_context *tctx,
4497 struct smb2_tree *tree)
4499 TALLOC_CTX *mem_ctx = talloc_new(tctx);
4500 struct smb2_create io;
4501 struct smb2_lease ls;
4502 struct smb2_handle h1 = {{0}};
4503 struct smb2_handle h2 = {{0}};
4504 NTSTATUS status;
4505 const char *fname1 = "duplicate_open1.dat";
4506 const char *fname2 = "duplicate_open2.dat";
4507 bool ret = true;
4508 uint32_t caps;
4510 caps = smb2cli_conn_server_capabilities(
4511 tree->session->transport->conn);
4512 if (!(caps & SMB2_CAP_LEASING)) {
4513 torture_skip(tctx, "leases are not supported");
4516 /* Ensure files don't exist. */
4517 smb2_util_unlink(tree, fname1);
4518 smb2_util_unlink(tree, fname2);
4520 /* Create file1 - LEASE1 key. */
4521 smb2_lease_create(&io, &ls, false, fname1, LEASE1,
4522 smb2_util_lease_state("RWH"));
4523 status = smb2_create(tree, mem_ctx, &io);
4524 CHECK_STATUS(status, NT_STATUS_OK);
4525 h1 = io.out.file.handle;
4526 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4527 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
4529 /* Leave file1 open and leased. */
4531 /* Create file2 - no lease. */
4532 smb2_lease_create(&io, NULL, false, fname2, 0,
4533 smb2_util_lease_state("RWH"));
4534 status = smb2_create(tree, mem_ctx, &io);
4535 CHECK_STATUS(status, NT_STATUS_OK);
4536 h2 = io.out.file.handle;
4537 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4538 /* Close it. */
4539 smb2_util_close(tree, h2);
4542 * Try and open file2 with the same LEASE1 key - this should fail with.
4543 * INVALID_PARAMETER.
4545 smb2_lease_create(&io, &ls, false, fname2, LEASE1,
4546 smb2_util_lease_state("RWH"));
4547 status = smb2_create(tree, mem_ctx, &io);
4548 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
4550 * If we did open this is an error, but save off
4551 * the handle so we close below.
4553 h2 = io.out.file.handle;
4555 done:
4556 smb2_util_close(tree, h2);
4557 smb2_util_close(tree, h1);
4558 smb2_util_unlink(tree, fname1);
4559 smb2_util_unlink(tree, fname2);
4560 talloc_free(mem_ctx);
4561 return ret;
4564 static bool test_lease_v1_bug_15148(struct torture_context *tctx,
4565 struct smb2_tree *tree)
4567 TALLOC_CTX *mem_ctx = talloc_new(tctx);
4568 struct smb2_create io1;
4569 struct smb2_create io2;
4570 struct smb2_lease ls1;
4571 struct smb2_lease ls2;
4572 struct smb2_handle h1 = {{0}};
4573 struct smb2_handle h2 = {{0}};
4574 struct smb2_write w;
4575 NTSTATUS status;
4576 const char *fname = "lease_v1_bug_15148.dat";
4577 bool ret = true;
4578 uint32_t caps;
4580 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
4581 if (!(caps & SMB2_CAP_LEASING)) {
4582 torture_skip(tctx, "leases are not supported");
4585 tree->session->transport->lease.handler = torture_lease_handler;
4586 tree->session->transport->lease.private_data = tree;
4587 tree->session->transport->oplock.handler = torture_oplock_handler;
4588 tree->session->transport->oplock.private_data = tree;
4590 smb2_util_unlink(tree, fname);
4592 torture_reset_lease_break_info(tctx, &lease_break_info);
4594 /* Grab R lease over connection 1a */
4595 smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
4596 status = smb2_create(tree, mem_ctx, &io1);
4597 CHECK_STATUS(status, NT_STATUS_OK);
4598 h1 = io1.out.file.handle;
4599 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4600 CHECK_LEASE(&io1, "R", true, LEASE1, 0);
4602 CHECK_NO_BREAK(tctx);
4604 /* Contend with LEASE2. */
4605 smb2_lease_create(&io2, &ls2, false, fname, LEASE2, smb2_util_lease_state("R"));
4606 status = smb2_create(tree, mem_ctx, &io2);
4607 CHECK_STATUS(status, NT_STATUS_OK);
4608 h2 = io2.out.file.handle;
4609 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
4610 CHECK_LEASE(&io2, "R", true, LEASE2, 0);
4612 CHECK_NO_BREAK(tctx);
4614 ZERO_STRUCT(w);
4615 w.in.file.handle = h1;
4616 w.in.offset = 0;
4617 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
4618 memset(w.in.data.data, 'o', w.in.data.length);
4619 status = smb2_write(tree, &w);
4620 CHECK_STATUS(status, NT_STATUS_OK);
4622 ls2.lease_epoch += 1;
4623 CHECK_BREAK_INFO("R", "", LEASE2);
4625 torture_reset_lease_break_info(tctx, &lease_break_info);
4627 ZERO_STRUCT(w);
4628 w.in.file.handle = h1;
4629 w.in.offset = 0;
4630 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
4631 memset(w.in.data.data, 'O', w.in.data.length);
4632 status = smb2_write(tree, &w);
4633 CHECK_STATUS(status, NT_STATUS_OK);
4635 CHECK_NO_BREAK(tctx);
4637 ZERO_STRUCT(w);
4638 w.in.file.handle = h2;
4639 w.in.offset = 0;
4640 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
4641 memset(w.in.data.data, 'o', w.in.data.length);
4642 status = smb2_write(tree, &w);
4643 CHECK_STATUS(status, NT_STATUS_OK);
4645 ls1.lease_epoch += 1;
4646 CHECK_BREAK_INFO("R", "", LEASE1);
4648 done:
4649 smb2_util_close(tree, h1);
4650 smb2_util_close(tree, h2);
4652 smb2_util_unlink(tree, fname);
4654 talloc_free(mem_ctx);
4656 return ret;
4659 static bool test_lease_v2_bug_15148(struct torture_context *tctx,
4660 struct smb2_tree *tree)
4662 TALLOC_CTX *mem_ctx = talloc_new(tctx);
4663 struct smb2_create io1;
4664 struct smb2_create io2;
4665 struct smb2_lease ls1;
4666 struct smb2_lease ls2;
4667 struct smb2_handle h1 = {{0}};
4668 struct smb2_handle h2 = {{0}};
4669 struct smb2_write w;
4670 NTSTATUS status;
4671 const char *fname = "lease_v2_bug_15148.dat";
4672 bool ret = true;
4673 uint32_t caps;
4674 enum protocol_types protocol;
4676 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
4677 if (!(caps & SMB2_CAP_LEASING)) {
4678 torture_skip(tctx, "leases are not supported");
4681 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
4682 if (protocol < PROTOCOL_SMB3_00) {
4683 torture_skip(tctx, "v2 leases are not supported");
4686 tree->session->transport->lease.handler = torture_lease_handler;
4687 tree->session->transport->lease.private_data = tree;
4688 tree->session->transport->oplock.handler = torture_oplock_handler;
4689 tree->session->transport->oplock.private_data = tree;
4691 smb2_util_unlink(tree, fname);
4693 torture_reset_lease_break_info(tctx, &lease_break_info);
4695 /* Grab R lease over connection 1a */
4696 smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
4697 smb2_util_lease_state("R"), 0x4711);
4698 status = smb2_create(tree, mem_ctx, &io1);
4699 CHECK_STATUS(status, NT_STATUS_OK);
4700 h1 = io1.out.file.handle;
4701 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
4702 ls1.lease_epoch += 1;
4703 CHECK_LEASE_V2(&io1, "R", true, LEASE1,
4704 0, 0, ls1.lease_epoch);
4706 CHECK_NO_BREAK(tctx);
4708 /* Contend with LEASE2. */
4709 smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
4710 smb2_util_lease_state("R"), 0x11);
4711 status = smb2_create(tree, mem_ctx, &io2);
4712 CHECK_STATUS(status, NT_STATUS_OK);
4713 h2 = io2.out.file.handle;
4714 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
4715 ls2.lease_epoch += 1;
4716 CHECK_LEASE_V2(&io2, "R", true, LEASE2,
4717 0, 0, ls2.lease_epoch);
4719 CHECK_NO_BREAK(tctx);
4721 ZERO_STRUCT(w);
4722 w.in.file.handle = h1;
4723 w.in.offset = 0;
4724 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
4725 memset(w.in.data.data, 'o', w.in.data.length);
4726 status = smb2_write(tree, &w);
4727 CHECK_STATUS(status, NT_STATUS_OK);
4729 ls2.lease_epoch += 1;
4730 CHECK_BREAK_INFO_V2(tree->session->transport,
4731 "R", "", LEASE2, ls2.lease_epoch);
4733 torture_reset_lease_break_info(tctx, &lease_break_info);
4735 ZERO_STRUCT(w);
4736 w.in.file.handle = h1;
4737 w.in.offset = 0;
4738 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
4739 memset(w.in.data.data, 'O', w.in.data.length);
4740 status = smb2_write(tree, &w);
4741 CHECK_STATUS(status, NT_STATUS_OK);
4743 CHECK_NO_BREAK(tctx);
4745 ZERO_STRUCT(w);
4746 w.in.file.handle = h2;
4747 w.in.offset = 0;
4748 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
4749 memset(w.in.data.data, 'o', w.in.data.length);
4750 status = smb2_write(tree, &w);
4751 CHECK_STATUS(status, NT_STATUS_OK);
4753 ls1.lease_epoch += 1;
4754 CHECK_BREAK_INFO_V2(tree->session->transport,
4755 "R", "", LEASE1, ls1.lease_epoch);
4757 done:
4758 smb2_util_close(tree, h1);
4759 smb2_util_close(tree, h2);
4761 smb2_util_unlink(tree, fname);
4763 talloc_free(mem_ctx);
4765 return ret;
4768 struct torture_suite *torture_smb2_lease_init(TALLOC_CTX *ctx)
4770 struct torture_suite *suite =
4771 torture_suite_create(ctx, "lease");
4773 torture_suite_add_1smb2_test(suite, "request", test_lease_request);
4774 torture_suite_add_1smb2_test(suite, "break_twice",
4775 test_lease_break_twice);
4776 torture_suite_add_1smb2_test(suite, "nobreakself",
4777 test_lease_nobreakself);
4778 torture_suite_add_1smb2_test(suite, "statopen", test_lease_statopen);
4779 torture_suite_add_1smb2_test(suite, "statopen2", test_lease_statopen2);
4780 torture_suite_add_1smb2_test(suite, "statopen3", test_lease_statopen3);
4781 torture_suite_add_1smb2_test(suite, "statopen4", test_lease_statopen4);
4782 torture_suite_add_1smb2_test(suite, "upgrade", test_lease_upgrade);
4783 torture_suite_add_1smb2_test(suite, "upgrade2", test_lease_upgrade2);
4784 torture_suite_add_1smb2_test(suite, "upgrade3", test_lease_upgrade3);
4785 torture_suite_add_1smb2_test(suite, "break", test_lease_break);
4786 torture_suite_add_1smb2_test(suite, "oplock", test_lease_oplock);
4787 torture_suite_add_1smb2_test(suite, "multibreak", test_lease_multibreak);
4788 torture_suite_add_1smb2_test(suite, "breaking1", test_lease_breaking1);
4789 torture_suite_add_1smb2_test(suite, "breaking2", test_lease_breaking2);
4790 torture_suite_add_1smb2_test(suite, "breaking3", test_lease_breaking3);
4791 torture_suite_add_1smb2_test(suite, "v2_breaking3", test_lease_v2_breaking3);
4792 torture_suite_add_1smb2_test(suite, "breaking4", test_lease_breaking4);
4793 torture_suite_add_1smb2_test(suite, "breaking5", test_lease_breaking5);
4794 torture_suite_add_1smb2_test(suite, "breaking6", test_lease_breaking6);
4795 torture_suite_add_2smb2_test(suite, "lock1", test_lease_lock1);
4796 torture_suite_add_1smb2_test(suite, "complex1", test_lease_complex1);
4797 torture_suite_add_1smb2_test(suite, "v2_request_parent",
4798 test_lease_v2_request_parent);
4799 torture_suite_add_1smb2_test(suite, "v2_request", test_lease_v2_request);
4800 torture_suite_add_1smb2_test(suite, "v2_epoch1", test_lease_v2_epoch1);
4801 torture_suite_add_1smb2_test(suite, "v2_epoch2", test_lease_v2_epoch2);
4802 torture_suite_add_1smb2_test(suite, "v2_epoch3", test_lease_v2_epoch3);
4803 torture_suite_add_1smb2_test(suite, "v2_complex1", test_lease_v2_complex1);
4804 torture_suite_add_1smb2_test(suite, "v2_complex2", test_lease_v2_complex2);
4805 torture_suite_add_1smb2_test(suite, "v2_rename", test_lease_v2_rename);
4806 torture_suite_add_1smb2_test(suite, "dynamic_share", test_lease_dynamic_share);
4807 torture_suite_add_1smb2_test(suite, "timeout", test_lease_timeout);
4808 torture_suite_add_1smb2_test(suite, "unlink", test_lease_unlink);
4809 torture_suite_add_1smb2_test(suite, "timeout-disconnect", test_lease_timeout_disconnect);
4810 torture_suite_add_1smb2_test(suite, "rename_wait",
4811 test_lease_rename_wait);
4812 torture_suite_add_1smb2_test(suite, "duplicate_create",
4813 test_lease_duplicate_create);
4814 torture_suite_add_1smb2_test(suite, "duplicate_open",
4815 test_lease_duplicate_open);
4816 torture_suite_add_1smb2_test(suite, "v1_bug15148",
4817 test_lease_v1_bug_15148);
4818 torture_suite_add_1smb2_test(suite, "v2_bug15148",
4819 test_lease_v2_bug_15148);
4821 suite->description = talloc_strdup(suite, "SMB2-LEASE tests");
4823 return suite;