1 /*
2 Unix SMB/CIFS implementation.
3
4 test suite for SMB2 leases
5
6 Copyright (C) Zachary Loafman 2009
7
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.
12
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.
17
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/>.
20 */
21
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"
33
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)
40
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)
48
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)
56
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 } \
71 \
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)
76
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 } \
91 \
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)
100
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;
105
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" },
116 };
117
test_lease_request(struct torture_context * tctx,struct smb2_tree * tree)118 static bool test_lease_request(struct torture_context *tctx,
119 struct smb2_tree *tree)
120 {
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;
134
135 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
136 if (!(caps & SMB2_CAP_LEASING)) {
137 torture_skip(tctx, "leases are not supported");
138 }
139
140 smb2_util_unlink(tree, fname);
141 smb2_util_unlink(tree, fname2);
142 smb2_util_rmdir(tree, dname);
143
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);
151
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);
160 }
161
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);
166
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);
175
176 smb2_util_close(tree, h1);
177
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);
192 }
193
194 done:
195 smb2_util_close(tree, h1);
196 smb2_util_close(tree, h2);
197
198 smb2_util_unlink(tree, fname);
199 smb2_util_unlink(tree, fname2);
200 smb2_util_rmdir(tree, dname);
201
202 talloc_free(mem_ctx);
203
204 return ret;
205 }
206
test_lease_upgrade(struct torture_context * tctx,struct smb2_tree * tree)207 static bool test_lease_upgrade(struct torture_context *tctx,
208 struct smb2_tree *tree)
209 {
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;
219
220 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
221 if (!(caps & SMB2_CAP_LEASING)) {
222 torture_skip(tctx, "leases are not supported");
223 }
224
225 smb2_util_unlink(tree, fname);
226
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;
234
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;
242
243 smb2_util_close(tree, hnew);
244
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;
252
253 smb2_util_close(tree, h);
254 h = hnew;
255
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;
263
264 smb2_util_close(tree, hnew);
265
266 done:
267 smb2_util_close(tree, h);
268 smb2_util_close(tree, hnew);
269
270 smb2_util_unlink(tree, fname);
271
272 talloc_free(mem_ctx);
273
274 return ret;
275 }
276
277 /**
278 * upgrade2 test.
279 * full matrix of lease upgrade combinations
280 * (non-contended case)
281 *
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.
288 *
289 * In that case the resulting lease state is the one
290 * requested in the upgrade.
291 */
292 struct lease_upgrade2_test {
293 const char *initial;
294 const char *upgrade_to;
295 const char *expected;
296 };
297
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" },
306
307 { "R", "", "R" },
308 { "R", "R", "R" },
309 { "R", "RH", "RH" },
310 { "R", "RW", "RW" },
311 { "R", "RWH", "RWH" },
312
313 { "RH", "", "RH" },
314 { "RH", "R", "RH" },
315 { "RH", "RH", "RH" },
316 { "RH", "RW", "RH" },
317 { "RH", "RWH", "RWH" },
318
319 { "RW", "", "RW" },
320 { "RW", "R", "RW" },
321 { "RW", "RH", "RW" },
322 { "RW", "RW", "RW" },
323 { "RW", "RWH", "RWH" },
324
325 { "RWH", "", "RWH" },
326 { "RWH", "R", "RWH" },
327 { "RWH", "RH", "RWH" },
328 { "RWH", "RW", "RWH" },
329 { "RWH", "RWH", "RWH" },
330 };
331
test_lease_upgrade2(struct torture_context * tctx,struct smb2_tree * tree)332 static bool test_lease_upgrade2(struct torture_context *tctx,
333 struct smb2_tree *tree)
334 {
335 TALLOC_CTX *mem_ctx = talloc_new(tctx);
336 struct smb2_handle h, hnew;
337 NTSTATUS status;
338 struct smb2_create io;
339 struct smb2_lease ls;
340 const char *fname = "lease_upgrade2.dat";
341 bool ret = true;
342 int i;
343 uint32_t caps;
344
345 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
346 if (!(caps & SMB2_CAP_LEASING)) {
347 torture_skip(tctx, "leases are not supported");
348 }
349
350 for (i = 0; i < NUM_UPGRADE_TESTS; i++) {
351 struct lease_upgrade2_test t = lease_upgrade2_tests[i];
352
353 smb2_util_unlink(tree, fname);
354
355 /* Grab a lease. */
356 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.initial));
357 status = smb2_create(tree, mem_ctx, &io);
358 CHECK_STATUS(status, NT_STATUS_OK);
359 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
360 CHECK_LEASE(&io, t.initial, true, LEASE1, 0);
361 h = io.out.file.handle;
362
363 /* Upgrade. */
364 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to));
365 status = smb2_create(tree, mem_ctx, &io);
366 CHECK_STATUS(status, NT_STATUS_OK);
367 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
368 CHECK_LEASE(&io, t.expected, true, LEASE1, 0);
369 hnew = io.out.file.handle;
370
371 smb2_util_close(tree, hnew);
372 smb2_util_close(tree, h);
373 }
374
375 done:
376 smb2_util_close(tree, h);
377 smb2_util_close(tree, hnew);
378
379 smb2_util_unlink(tree, fname);
380
381 talloc_free(mem_ctx);
382
383 return ret;
384 }
385
386
387 /**
388 * upgrade3:
389 * full matrix of lease upgrade combinations
390 * (contended case)
391 *
392 * We start with 2 leases, and check how one can
393 * be upgraded
394 *
395 * The summary of the behaviour is this:
396 * -------------------------------------
397 *
398 * If we have two leases (lease1 and lease2) on the same file,
399 * then attempt to upgrade lease1 results in a change if and only
400 * if the requested lease state:
401 * - is valid,
402 * - is strictly a superset of lease1, and
403 * - can held together with lease2.
404 *
405 * In that case, the resuling lease state of the upgraded lease1
406 * is the state requested in the upgrade. lease2 is not broken
407 * and remains unchanged.
408 *
409 * Note that this contrasts the case of directly opening with
410 * an initial requested lease state, in which case you get that
411 * portion of the requested state that can be shared with the
412 * already existing leases (or the states that they get broken to).
413 */
414 struct lease_upgrade3_test {
415 const char *held1;
416 const char *held2;
417 const char *upgrade_to;
418 const char *upgraded_to;
419 };
420
421 #define NUM_UPGRADE3_TESTS ( 20 )
422 struct lease_upgrade3_test lease_upgrade3_tests[NUM_UPGRADE3_TESTS] = {
423 {"R", "R", "", "R" },
424 {"R", "R", "R", "R" },
425 {"R", "R", "RW", "R" },
426 {"R", "R", "RH", "RH" },
427 {"R", "R", "RHW", "R" },
428
429 {"R", "RH", "", "R" },
430 {"R", "RH", "R", "R" },
431 {"R", "RH", "RW", "R" },
432 {"R", "RH", "RH", "RH" },
433 {"R", "RH", "RHW", "R" },
434
435 {"RH", "R", "", "RH" },
436 {"RH", "R", "R", "RH" },
437 {"RH", "R", "RW", "RH" },
438 {"RH", "R", "RH", "RH" },
439 {"RH", "R", "RHW", "RH" },
440
441 {"RH", "RH", "", "RH" },
442 {"RH", "RH", "R", "RH" },
443 {"RH", "RH", "RW", "RH" },
444 {"RH", "RH", "RH", "RH" },
445 {"RH", "RH", "RHW", "RH" },
446 };
447
test_lease_upgrade3(struct torture_context * tctx,struct smb2_tree * tree)448 static bool test_lease_upgrade3(struct torture_context *tctx,
449 struct smb2_tree *tree)
450 {
451 TALLOC_CTX *mem_ctx = talloc_new(tctx);
452 struct smb2_handle h, h2, hnew;
453 NTSTATUS status;
454 struct smb2_create io;
455 struct smb2_lease ls;
456 const char *fname = "lease_upgrade3.dat";
457 bool ret = true;
458 int i;
459 uint32_t caps;
460
461 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
462 if (!(caps & SMB2_CAP_LEASING)) {
463 torture_skip(tctx, "leases are not supported");
464 }
465
466 tree->session->transport->lease.handler = torture_lease_handler;
467 tree->session->transport->lease.private_data = tree;
468
469 smb2_util_unlink(tree, fname);
470
471 for (i = 0; i < NUM_UPGRADE3_TESTS; i++) {
472 struct lease_upgrade3_test t = lease_upgrade3_tests[i];
473
474 smb2_util_unlink(tree, fname);
475
476 ZERO_STRUCT(lease_break_info);
477
478 /* grab first lease */
479 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.held1));
480 status = smb2_create(tree, mem_ctx, &io);
481 CHECK_STATUS(status, NT_STATUS_OK);
482 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
483 CHECK_LEASE(&io, t.held1, true, LEASE1, 0);
484 h = io.out.file.handle;
485
486 /* grab second lease */
487 smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state(t.held2));
488 status = smb2_create(tree, mem_ctx, &io);
489 CHECK_STATUS(status, NT_STATUS_OK);
490 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
491 CHECK_LEASE(&io, t.held2, true, LEASE2, 0);
492 h2 = io.out.file.handle;
493
494 /* no break has happened */
495 CHECK_VAL(lease_break_info.count, 0);
496 CHECK_VAL(lease_break_info.failures, 0);
497
498 /* try to upgrade lease1 */
499 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to));
500 status = smb2_create(tree, mem_ctx, &io);
501 CHECK_STATUS(status, NT_STATUS_OK);
502 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
503 CHECK_LEASE(&io, t.upgraded_to, true, LEASE1, 0);
504 hnew = io.out.file.handle;
505
506 /* no break has happened */
507 CHECK_VAL(lease_break_info.count, 0);
508 CHECK_VAL(lease_break_info.failures, 0);
509
510 smb2_util_close(tree, hnew);
511 smb2_util_close(tree, h);
512 smb2_util_close(tree, h2);
513 }
514
515 done:
516 smb2_util_close(tree, h);
517 smb2_util_close(tree, hnew);
518 smb2_util_close(tree, h2);
519
520 smb2_util_unlink(tree, fname);
521
522 talloc_free(mem_ctx);
523
524 return ret;
525 }
526
527
528
529 /*
530 break_results should be read as "held lease, new lease, hold broken to, new
531 grant", i.e. { "RH", "RW", "RH", "R" } means that if key1 holds RH and key2
532 tries for RW, key1 will be broken to RH (in this case, not broken at all)
533 and key2 will be granted R.
534
535 Note: break_results only includes things that Win7 will actually grant (see
536 request_results above).
537 */
538 #define NBREAK_RESULTS 16
539 static const char *break_results[NBREAK_RESULTS][4] = {
540 {"R", "R", "R", "R"},
541 {"R", "RH", "R", "RH"},
542 {"R", "RW", "R", "R"},
543 {"R", "RHW", "R", "RH"},
544
545 {"RH", "R", "RH", "R"},
546 {"RH", "RH", "RH", "RH"},
547 {"RH", "RW", "RH", "R"},
548 {"RH", "RHW", "RH", "RH"},
549
550 {"RW", "R", "R", "R"},
551 {"RW", "RH", "R", "RH"},
552 {"RW", "RW", "R", "R"},
553 {"RW", "RHW", "R", "RH"},
554
555 {"RHW", "R", "RH", "R"},
556 {"RHW", "RH", "RH", "RH"},
557 {"RHW", "RW", "RH", "R"},
558 {"RHW", "RHW", "RH", "RH"},
559 };
560
test_lease_break(struct torture_context * tctx,struct smb2_tree * tree)561 static bool test_lease_break(struct torture_context *tctx,
562 struct smb2_tree *tree)
563 {
564 TALLOC_CTX *mem_ctx = talloc_new(tctx);
565 struct smb2_create io;
566 struct smb2_lease ls;
567 struct smb2_handle h, h2, h3;
568 NTSTATUS status;
569 const char *fname = "lease_break.dat";
570 bool ret = true;
571 int i;
572 uint32_t caps;
573
574 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
575 if (!(caps & SMB2_CAP_LEASING)) {
576 torture_skip(tctx, "leases are not supported");
577 }
578
579 tree->session->transport->lease.handler = torture_lease_handler;
580 tree->session->transport->lease.private_data = tree;
581
582 smb2_util_unlink(tree, fname);
583
584 for (i = 0; i < NBREAK_RESULTS; i++) {
585 const char *held = break_results[i][0];
586 const char *contend = break_results[i][1];
587 const char *brokento = break_results[i][2];
588 const char *granted = break_results[i][3];
589 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
590 "expecting break to %s(%x) and grant of %s(%x)\n",
591 held, smb2_util_lease_state(held), contend, smb2_util_lease_state(contend),
592 brokento, smb2_util_lease_state(brokento), granted, smb2_util_lease_state(granted));
593
594 ZERO_STRUCT(lease_break_info);
595
596 /* Grab lease. */
597 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held));
598 status = smb2_create(tree, mem_ctx, &io);
599 CHECK_STATUS(status, NT_STATUS_OK);
600 h = io.out.file.handle;
601 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
602 CHECK_LEASE(&io, held, true, LEASE1, 0);
603
604 /* Possibly contend lease. */
605 smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state(contend));
606 status = smb2_create(tree, mem_ctx, &io);
607 CHECK_STATUS(status, NT_STATUS_OK);
608 h2 = io.out.file.handle;
609 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
610 CHECK_LEASE(&io, granted, true, LEASE2, 0);
611
612 if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) {
613 CHECK_BREAK_INFO(held, brokento, LEASE1);
614 } else {
615 CHECK_NO_BREAK(tctx);
616 }
617
618 ZERO_STRUCT(lease_break_info);
619
620 /*
621 Now verify that an attempt to upgrade LEASE1 results in no
622 break and no change in LEASE1.
623 */
624 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
625 status = smb2_create(tree, mem_ctx, &io);
626 CHECK_STATUS(status, NT_STATUS_OK);
627 h3 = io.out.file.handle;
628 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
629 CHECK_LEASE(&io, brokento, true, LEASE1, 0);
630 CHECK_VAL(lease_break_info.count, 0);
631 CHECK_VAL(lease_break_info.failures, 0);
632
633 smb2_util_close(tree, h);
634 smb2_util_close(tree, h2);
635 smb2_util_close(tree, h3);
636
637 status = smb2_util_unlink(tree, fname);
638 CHECK_STATUS(status, NT_STATUS_OK);
639 }
640
641 done:
642 smb2_util_close(tree, h);
643 smb2_util_close(tree, h2);
644
645 smb2_util_unlink(tree, fname);
646
647 talloc_free(mem_ctx);
648
649 return ret;
650 }
651
test_lease_nobreakself(struct torture_context * tctx,struct smb2_tree * tree)652 static bool test_lease_nobreakself(struct torture_context *tctx,
653 struct smb2_tree *tree)
654 {
655 TALLOC_CTX *mem_ctx = talloc_new(tctx);
656 struct smb2_create io;
657 struct smb2_lease ls;
658 struct smb2_handle h1 = {{0}};
659 struct smb2_handle h2 = {{0}};
660 NTSTATUS status;
661 const char *fname = "lease_nobreakself.dat";
662 bool ret = true;
663 uint32_t caps;
664 char c = 0;
665
666 caps = smb2cli_conn_server_capabilities(
667 tree->session->transport->conn);
668 if (!(caps & SMB2_CAP_LEASING)) {
669 torture_skip(tctx, "leases are not supported");
670 }
671
672 smb2_util_unlink(tree, fname);
673
674 /* Win7 is happy to grant RHW leases on files. */
675 smb2_lease_create(&io, &ls, false, fname, LEASE1,
676 smb2_util_lease_state("R"));
677 status = smb2_create(tree, mem_ctx, &io);
678 CHECK_STATUS(status, NT_STATUS_OK);
679 h1 = io.out.file.handle;
680 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
681 CHECK_LEASE(&io, "R", true, LEASE1, 0);
682
683 smb2_lease_create(&io, &ls, false, fname, LEASE2,
684 smb2_util_lease_state("R"));
685 status = smb2_create(tree, mem_ctx, &io);
686 CHECK_STATUS(status, NT_STATUS_OK);
687 h2 = io.out.file.handle;
688 CHECK_LEASE(&io, "R", true, LEASE2, 0);
689
690 ZERO_STRUCT(lease_break_info);
691
692 tree->session->transport->lease.handler = torture_lease_handler;
693 tree->session->transport->lease.private_data = tree;
694
695 /* Make sure we don't break ourselves on write */
696
697 status = smb2_util_write(tree, h1, &c, 0, 1);
698 CHECK_STATUS(status, NT_STATUS_OK);
699 CHECK_BREAK_INFO("R", "", LEASE2);
700
701 /* Try the other way round. First, upgrade LEASE2 to R again */
702
703 smb2_lease_create(&io, &ls, false, fname, LEASE2,
704 smb2_util_lease_state("R"));
705 status = smb2_create(tree, mem_ctx, &io);
706 CHECK_STATUS(status, NT_STATUS_OK);
707 CHECK_LEASE(&io, "R", true, LEASE2, 0);
708 smb2_util_close(tree, io.out.file.handle);
709
710 /* Now break LEASE1 via h2 */
711
712 ZERO_STRUCT(lease_break_info);
713 status = smb2_util_write(tree, h2, &c, 0, 1);
714 CHECK_STATUS(status, NT_STATUS_OK);
715 CHECK_BREAK_INFO("R", "", LEASE1);
716
717 /* .. and break LEASE2 via h1 */
718
719 ZERO_STRUCT(lease_break_info);
720 status = smb2_util_write(tree, h1, &c, 0, 1);
721 CHECK_STATUS(status, NT_STATUS_OK);
722 CHECK_BREAK_INFO("R", "", LEASE2);
723
724 done:
725 smb2_util_close(tree, h2);
726 smb2_util_close(tree, h1);
727 smb2_util_unlink(tree, fname);
728 talloc_free(mem_ctx);
729 return ret;
730 }
731
test_lease_statopen(struct torture_context * tctx,struct smb2_tree * tree)732 static bool test_lease_statopen(struct torture_context *tctx,
733 struct smb2_tree *tree)
734 {
735 TALLOC_CTX *mem_ctx = talloc_new(tctx);
736 struct smb2_create io;
737 struct smb2_lease ls;
738 struct smb2_handle h1 = {{0}};
739 struct smb2_handle h2 = {{0}};
740 NTSTATUS status;
741 const char *fname = "lease_statopen.dat";
742 bool ret = true;
743 uint32_t caps;
744
745 caps = smb2cli_conn_server_capabilities(
746 tree->session->transport->conn);
747 if (!(caps & SMB2_CAP_LEASING)) {
748 torture_skip(tctx, "leases are not supported");
749 }
750
751 smb2_util_unlink(tree, fname);
752
753 /* Create file. */
754 smb2_lease_create(&io, &ls, false, fname, LEASE1,
755 smb2_util_lease_state("RWH"));
756 status = smb2_create(tree, mem_ctx, &io);
757 CHECK_STATUS(status, NT_STATUS_OK);
758 h1 = io.out.file.handle;
759 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
760 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
761 smb2_util_close(tree, h1);
762
763 /* Stat open file with RWH lease. */
764 smb2_lease_create_share(&io, &ls, false, fname, 0, LEASE1,
765 smb2_util_lease_state("RWH"));
766 io.in.desired_access = FILE_READ_ATTRIBUTES;
767 status = smb2_create(tree, mem_ctx, &io);
768 CHECK_STATUS(status, NT_STATUS_OK);
769 h2 = io.out.file.handle;
770 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
771
772 ZERO_STRUCT(lease_break_info);
773
774 tree->session->transport->lease.handler = torture_lease_handler;
775 tree->session->transport->lease.private_data = tree;
776
777 /* Ensure non-stat open doesn't break and gets same lease
778 state as existing stat open. */
779 smb2_lease_create(&io, &ls, false, fname, LEASE1,
780 smb2_util_lease_state(""));
781 status = smb2_create(tree, mem_ctx, &io);
782 CHECK_STATUS(status, NT_STATUS_OK);
783 h1 = io.out.file.handle;
784 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
785 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
786
787 CHECK_NO_BREAK(tctx);
788 smb2_util_close(tree, h1);
789
790 /* Open with conflicting lease. stat open should break down to RH */
791 smb2_lease_create(&io, &ls, false, fname, LEASE2,
792 smb2_util_lease_state("RWH"));
793 status = smb2_create(tree, mem_ctx, &io);
794 CHECK_STATUS(status, NT_STATUS_OK);
795 h1 = io.out.file.handle;
796 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
797 CHECK_LEASE(&io, "RH", true, LEASE2, 0);
798
799 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
800
801 done:
802 smb2_util_close(tree, h2);
803 smb2_util_close(tree, h1);
804 smb2_util_unlink(tree, fname);
805 talloc_free(mem_ctx);
806 return ret;
807 }
808
test_lease_statopen2(struct torture_context * tctx,struct smb2_tree * tree)809 static bool test_lease_statopen2(struct torture_context *tctx,
810 struct smb2_tree *tree)
811 {
812 TALLOC_CTX *mem_ctx = talloc_new(tctx);
813 struct smb2_create io;
814 struct smb2_lease ls;
815 struct smb2_handle h1 = {{0}};
816 struct smb2_handle h2 = {{0}};
817 struct smb2_handle h3 = {{0}};
818 NTSTATUS status;
819 const char *fname = "lease_statopen2.dat";
820 bool ret = true;
821 uint32_t caps;
822
823 caps = smb2cli_conn_server_capabilities(
824 tree->session->transport->conn);
825 if (!(caps & SMB2_CAP_LEASING)) {
826 torture_skip(tctx, "leases are not supported");
827 }
828
829 smb2_util_unlink(tree, fname);
830 ZERO_STRUCT(lease_break_info);
831 tree->session->transport->lease.handler = torture_lease_handler;
832 tree->session->transport->lease.private_data = tree;
833
834 status = torture_smb2_testfile(tree, fname, &h1);
835 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
836 "smb2_create failed\n");
837 smb2_util_close(tree, h1);
838 ZERO_STRUCT(h1);
839
840 /* Open file with RWH lease. */
841 smb2_lease_create_share(&io, &ls, false, fname,
842 smb2_util_share_access("RWD"),
843 LEASE1,
844 smb2_util_lease_state("RWH"));
845 io.in.desired_access = SEC_FILE_WRITE_DATA;
846 status = smb2_create(tree, mem_ctx, &io);
847 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
848 "smb2_create failed\n");
849 h1 = io.out.file.handle;
850 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
851
852 /* Stat open */
853 ZERO_STRUCT(io);
854 io.in.desired_access = FILE_READ_ATTRIBUTES;
855 io.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
856 io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
857 io.in.create_disposition = NTCREATEX_DISP_OPEN;
858 io.in.fname = fname;
859 status = smb2_create(tree, mem_ctx, &io);
860 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
861 "smb2_create failed\n");
862 h2 = io.out.file.handle;
863
864 /* Open file with RWH lease. */
865 smb2_lease_create_share(&io, &ls, false, fname,
866 smb2_util_share_access("RWD"),
867 LEASE1,
868 smb2_util_lease_state("RWH"));
869 io.in.desired_access = SEC_FILE_WRITE_DATA;
870 status = smb2_create(tree, mem_ctx, &io);
871 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
872 "smb2_create failed\n");
873 h3 = io.out.file.handle;
874 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
875
876 done:
877 if (!smb2_util_handle_empty(h3)) {
878 smb2_util_close(tree, h3);
879 }
880 if (!smb2_util_handle_empty(h2)) {
881 smb2_util_close(tree, h2);
882 }
883 if (!smb2_util_handle_empty(h1)) {
884 smb2_util_close(tree, h1);
885 }
886 smb2_util_unlink(tree, fname);
887 talloc_free(mem_ctx);
888 return ret;
889 }
890
test_lease_statopen3(struct torture_context * tctx,struct smb2_tree * tree)891 static bool test_lease_statopen3(struct torture_context *tctx,
892 struct smb2_tree *tree)
893 {
894 TALLOC_CTX *mem_ctx = talloc_new(tctx);
895 struct smb2_create io;
896 struct smb2_lease ls;
897 struct smb2_handle h1 = {{0}};
898 struct smb2_handle h2 = {{0}};
899 NTSTATUS status;
900 const char *fname = "lease_statopen3.dat";
901 bool ret = true;
902 uint32_t caps;
903
904 caps = smb2cli_conn_server_capabilities(
905 tree->session->transport->conn);
906 if (!(caps & SMB2_CAP_LEASING)) {
907 torture_skip(tctx, "leases are not supported");
908 }
909
910 smb2_util_unlink(tree, fname);
911 ZERO_STRUCT(lease_break_info);
912 tree->session->transport->lease.handler = torture_lease_handler;
913 tree->session->transport->lease.private_data = tree;
914
915 status = torture_smb2_testfile(tree, fname, &h1);
916 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
917 "smb2_create failed\n");
918 smb2_util_close(tree, h1);
919 ZERO_STRUCT(h1);
920
921 /* Stat open */
922 ZERO_STRUCT(io);
923 io.in.desired_access = FILE_READ_ATTRIBUTES;
924 io.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
925 io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
926 io.in.create_disposition = NTCREATEX_DISP_OPEN;
927 io.in.fname = fname;
928 status = smb2_create(tree, mem_ctx, &io);
929 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
930 "smb2_create failed\n");
931 h1 = io.out.file.handle;
932
933 /* Open file with RWH lease. */
934 smb2_lease_create_share(&io, &ls, false, fname,
935 smb2_util_share_access("RWD"),
936 LEASE1,
937 smb2_util_lease_state("RWH"));
938 io.in.desired_access = SEC_FILE_WRITE_DATA;
939 status = smb2_create(tree, mem_ctx, &io);
940 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
941 "smb2_create failed\n");
942 h2 = io.out.file.handle;
943 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
944
945 done:
946 if (!smb2_util_handle_empty(h1)) {
947 smb2_util_close(tree, h1);
948 }
949 if (!smb2_util_handle_empty(h2)) {
950 smb2_util_close(tree, h2);
951 }
952 smb2_util_unlink(tree, fname);
953 talloc_free(mem_ctx);
954 return ret;
955 }
956
torture_oplock_break_callback(struct smb2_request * req)957 static void torture_oplock_break_callback(struct smb2_request *req)
958 {
959 NTSTATUS status;
960 struct smb2_break br;
961
962 ZERO_STRUCT(br);
963 status = smb2_break_recv(req, &br);
964 if (!NT_STATUS_IS_OK(status))
965 lease_break_info.oplock_failures++;
966
967 return;
968 }
969
970 /* a oplock break request handler */
torture_oplock_handler(struct smb2_transport * transport,const struct smb2_handle * handle,uint8_t level,void * private_data)971 static bool torture_oplock_handler(struct smb2_transport *transport,
972 const struct smb2_handle *handle,
973 uint8_t level, void *private_data)
974 {
975 struct smb2_tree *tree = private_data;
976 struct smb2_request *req;
977 struct smb2_break br;
978
979 lease_break_info.oplock_handle = *handle;
980 lease_break_info.oplock_level = level;
981 lease_break_info.oplock_count++;
982
983 ZERO_STRUCT(br);
984 br.in.file.handle = *handle;
985 br.in.oplock_level = level;
986
987 if (lease_break_info.held_oplock_level > SMB2_OPLOCK_LEVEL_II) {
988 req = smb2_break_send(tree, &br);
989 req->async.fn = torture_oplock_break_callback;
990 req->async.private_data = NULL;
991 }
992 lease_break_info.held_oplock_level = level;
993
994 return true;
995 }
996
997 #define NOPLOCK_RESULTS 12
998 static const char *oplock_results[NOPLOCK_RESULTS][4] = {
999 {"R", "s", "R", "s"},
1000 {"R", "x", "R", "s"},
1001 {"R", "b", "R", "s"},
1002
1003 {"RH", "s", "RH", ""},
1004 {"RH", "x", "RH", ""},
1005 {"RH", "b", "RH", ""},
1006
1007 {"RW", "s", "R", "s"},
1008 {"RW", "x", "R", "s"},
1009 {"RW", "b", "R", "s"},
1010
1011 {"RHW", "s", "RH", ""},
1012 {"RHW", "x", "RH", ""},
1013 {"RHW", "b", "RH", ""},
1014 };
1015
1016 static const char *oplock_results_2[NOPLOCK_RESULTS][4] = {
1017 {"s", "R", "s", "R"},
1018 {"s", "RH", "s", "R"},
1019 {"s", "RW", "s", "R"},
1020 {"s", "RHW", "s", "R"},
1021
1022 {"x", "R", "s", "R"},
1023 {"x", "RH", "s", "R"},
1024 {"x", "RW", "s", "R"},
1025 {"x", "RHW", "s", "R"},
1026
1027 {"b", "R", "s", "R"},
1028 {"b", "RH", "s", "R"},
1029 {"b", "RW", "s", "R"},
1030 {"b", "RHW", "s", "R"},
1031 };
1032
test_lease_oplock(struct torture_context * tctx,struct smb2_tree * tree)1033 static bool test_lease_oplock(struct torture_context *tctx,
1034 struct smb2_tree *tree)
1035 {
1036 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1037 struct smb2_create io;
1038 struct smb2_lease ls;
1039 struct smb2_handle h, h2;
1040 NTSTATUS status;
1041 const char *fname = "lease_oplock.dat";
1042 bool ret = true;
1043 int i;
1044 uint32_t caps;
1045
1046 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1047 if (!(caps & SMB2_CAP_LEASING)) {
1048 torture_skip(tctx, "leases are not supported");
1049 }
1050
1051 tree->session->transport->lease.handler = torture_lease_handler;
1052 tree->session->transport->lease.private_data = tree;
1053 tree->session->transport->oplock.handler = torture_oplock_handler;
1054 tree->session->transport->oplock.private_data = tree;
1055
1056 smb2_util_unlink(tree, fname);
1057
1058 for (i = 0; i < NOPLOCK_RESULTS; i++) {
1059 const char *held = oplock_results[i][0];
1060 const char *contend = oplock_results[i][1];
1061 const char *brokento = oplock_results[i][2];
1062 const char *granted = oplock_results[i][3];
1063 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
1064 "expecting break to %s(%x) and grant of %s(%x)\n",
1065 held, smb2_util_lease_state(held), contend, smb2_util_oplock_level(contend),
1066 brokento, smb2_util_lease_state(brokento), granted, smb2_util_oplock_level(granted));
1067
1068 ZERO_STRUCT(lease_break_info);
1069
1070 /* Grab lease. */
1071 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held));
1072 status = smb2_create(tree, mem_ctx, &io);
1073 CHECK_STATUS(status, NT_STATUS_OK);
1074 h = io.out.file.handle;
1075 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1076 CHECK_LEASE(&io, held, true, LEASE1, 0);
1077
1078 /* Does an oplock contend the lease? */
1079 smb2_oplock_create(&io, fname, smb2_util_oplock_level(contend));
1080 status = smb2_create(tree, mem_ctx, &io);
1081 CHECK_STATUS(status, NT_STATUS_OK);
1082 h2 = io.out.file.handle;
1083 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1084 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(granted));
1085 lease_break_info.held_oplock_level = io.out.oplock_level;
1086
1087 if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) {
1088 CHECK_BREAK_INFO(held, brokento, LEASE1);
1089 } else {
1090 CHECK_NO_BREAK(tctx);
1091 }
1092
1093 smb2_util_close(tree, h);
1094 smb2_util_close(tree, h2);
1095
1096 status = smb2_util_unlink(tree, fname);
1097 CHECK_STATUS(status, NT_STATUS_OK);
1098 }
1099
1100 for (i = 0; i < NOPLOCK_RESULTS; i++) {
1101 const char *held = oplock_results_2[i][0];
1102 const char *contend = oplock_results_2[i][1];
1103 const char *brokento = oplock_results_2[i][2];
1104 const char *granted = oplock_results_2[i][3];
1105 torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
1106 "expecting break to %s(%x) and grant of %s(%x)\n",
1107 held, smb2_util_oplock_level(held), contend, smb2_util_lease_state(contend),
1108 brokento, smb2_util_oplock_level(brokento), granted, smb2_util_lease_state(granted));
1109
1110 ZERO_STRUCT(lease_break_info);
1111
1112 /* Grab an oplock. */
1113 smb2_oplock_create(&io, fname, smb2_util_oplock_level(held));
1114 status = smb2_create(tree, mem_ctx, &io);
1115 CHECK_STATUS(status, NT_STATUS_OK);
1116 h = io.out.file.handle;
1117 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1118 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(held));
1119 lease_break_info.held_oplock_level = io.out.oplock_level;
1120
1121 /* Grab lease. */
1122 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(contend));
1123 status = smb2_create(tree, mem_ctx, &io);
1124 CHECK_STATUS(status, NT_STATUS_OK);
1125 h2 = io.out.file.handle;
1126 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1127 CHECK_LEASE(&io, granted, true, LEASE1, 0);
1128
1129 if (smb2_util_oplock_level(held) != smb2_util_oplock_level(brokento)) {
1130 CHECK_OPLOCK_BREAK(brokento);
1131 } else {
1132 CHECK_NO_BREAK(tctx);
1133 }
1134
1135 smb2_util_close(tree, h);
1136 smb2_util_close(tree, h2);
1137
1138 status = smb2_util_unlink(tree, fname);
1139 CHECK_STATUS(status, NT_STATUS_OK);
1140 }
1141
1142 done:
1143 smb2_util_close(tree, h);
1144 smb2_util_close(tree, h2);
1145
1146 smb2_util_unlink(tree, fname);
1147
1148 talloc_free(mem_ctx);
1149
1150 return ret;
1151 }
1152
test_lease_multibreak(struct torture_context * tctx,struct smb2_tree * tree)1153 static bool test_lease_multibreak(struct torture_context *tctx,
1154 struct smb2_tree *tree)
1155 {
1156 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1157 struct smb2_create io;
1158 struct smb2_lease ls;
1159 struct smb2_handle h = {{0}};
1160 struct smb2_handle h2 = {{0}};
1161 struct smb2_handle h3 = {{0}};
1162 struct smb2_write w;
1163 NTSTATUS status;
1164 const char *fname = "lease_multibreak.dat";
1165 bool ret = true;
1166 uint32_t caps;
1167
1168 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1169 if (!(caps & SMB2_CAP_LEASING)) {
1170 torture_skip(tctx, "leases are not supported");
1171 }
1172
1173 tree->session->transport->lease.handler = torture_lease_handler;
1174 tree->session->transport->lease.private_data = tree;
1175 tree->session->transport->oplock.handler = torture_oplock_handler;
1176 tree->session->transport->oplock.private_data = tree;
1177
1178 smb2_util_unlink(tree, fname);
1179
1180 ZERO_STRUCT(lease_break_info);
1181
1182 /* Grab lease, upgrade to RHW .. */
1183 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
1184 status = smb2_create(tree, mem_ctx, &io);
1185 CHECK_STATUS(status, NT_STATUS_OK);
1186 h = io.out.file.handle;
1187 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1188 CHECK_LEASE(&io, "RH", true, LEASE1, 0);
1189
1190 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
1191 status = smb2_create(tree, mem_ctx, &io);
1192 CHECK_STATUS(status, NT_STATUS_OK);
1193 h2 = io.out.file.handle;
1194 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1195 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
1196
1197 /* Contend with LEASE2. */
1198 smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state("RHW"));
1199 status = smb2_create(tree, mem_ctx, &io);
1200 CHECK_STATUS(status, NT_STATUS_OK);
1201 h3 = io.out.file.handle;
1202 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1203 CHECK_LEASE(&io, "RH", true, LEASE2, 0);
1204
1205 /* Verify that we were only sent one break. */
1206 CHECK_BREAK_INFO("RHW", "RH", LEASE1);
1207
1208 /* Drop LEASE1 / LEASE2 */
1209 status = smb2_util_close(tree, h);
1210 CHECK_STATUS(status, NT_STATUS_OK);
1211 status = smb2_util_close(tree, h2);
1212 CHECK_STATUS(status, NT_STATUS_OK);
1213 status = smb2_util_close(tree, h3);
1214 CHECK_STATUS(status, NT_STATUS_OK);
1215
1216 ZERO_STRUCT(lease_break_info);
1217
1218 /* Grab an R lease. */
1219 smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("R"));
1220 status = smb2_create(tree, mem_ctx, &io);
1221 CHECK_STATUS(status, NT_STATUS_OK);
1222 h = io.out.file.handle;
1223 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1224 CHECK_LEASE(&io, "R", true, LEASE1, 0);
1225
1226 /* Grab a level-II oplock. */
1227 smb2_oplock_create(&io, fname, smb2_util_oplock_level("s"));
1228 status = smb2_create(tree, mem_ctx, &io);
1229 CHECK_STATUS(status, NT_STATUS_OK);
1230 h2 = io.out.file.handle;
1231 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1232 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
1233 lease_break_info.held_oplock_level = io.out.oplock_level;
1234
1235 /* Verify no breaks. */
1236 CHECK_NO_BREAK(tctx);
1237
1238 /* Open for truncate, force a break. */
1239 smb2_generic_create(&io, NULL, false, fname,
1240 NTCREATEX_DISP_OVERWRITE_IF, smb2_util_oplock_level(""), 0, 0);
1241 status = smb2_create(tree, mem_ctx, &io);
1242 CHECK_STATUS(status, NT_STATUS_OK);
1243 h3 = io.out.file.handle;
1244 CHECK_CREATED(&io, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
1245 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(""));
1246 lease_break_info.held_oplock_level = io.out.oplock_level;
1247
1248 /* Sleep, use a write to clear the recv queue. */
1249 smb_msleep(250);
1250 ZERO_STRUCT(w);
1251 w.in.file.handle = h3;
1252 w.in.offset = 0;
1253 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
1254 memset(w.in.data.data, 'o', w.in.data.length);
1255 status = smb2_write(tree, &w);
1256 CHECK_STATUS(status, NT_STATUS_OK);
1257
1258 /* Verify one oplock break, one lease break. */
1259 CHECK_OPLOCK_BREAK("");
1260 CHECK_BREAK_INFO("R", "", LEASE1);
1261
1262 done:
1263 smb2_util_close(tree, h);
1264 smb2_util_close(tree, h2);
1265 smb2_util_close(tree, h3);
1266
1267 smb2_util_unlink(tree, fname);
1268
1269 talloc_free(mem_ctx);
1270
1271 return ret;
1272 }
1273
test_lease_v2_request_parent(struct torture_context * tctx,struct smb2_tree * tree)1274 static bool test_lease_v2_request_parent(struct torture_context *tctx,
1275 struct smb2_tree *tree)
1276 {
1277 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1278 struct smb2_create io;
1279 struct smb2_lease ls;
1280 struct smb2_handle h1 = {{0}};
1281 uint64_t parent = LEASE2;
1282 NTSTATUS status;
1283 const char *fname = "lease_v2_request_parent.dat";
1284 bool ret = true;
1285 uint32_t caps;
1286 enum protocol_types protocol;
1287
1288 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1289 if (!(caps & SMB2_CAP_LEASING)) {
1290 torture_skip(tctx, "leases are not supported");
1291 }
1292 if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
1293 torture_skip(tctx, "directory leases are not supported");
1294 }
1295
1296 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1297 if (protocol < PROTOCOL_SMB3_00) {
1298 torture_skip(tctx, "v2 leases are not supported");
1299 }
1300
1301 smb2_util_unlink(tree, fname);
1302
1303 ZERO_STRUCT(lease_break_info);
1304
1305 ZERO_STRUCT(io);
1306 smb2_lease_v2_create_share(&io, &ls, false, fname,
1307 smb2_util_share_access("RWD"),
1308 LEASE1, &parent,
1309 smb2_util_lease_state("RHW"),
1310 0x11);
1311
1312 status = smb2_create(tree, mem_ctx, &io);
1313 CHECK_STATUS(status, NT_STATUS_OK);
1314 h1 = io.out.file.handle;
1315 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1316 CHECK_LEASE_V2(&io, "RHW", true, LEASE1,
1317 SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2,
1318 ls.lease_epoch + 1);
1319
1320 done:
1321 smb2_util_close(tree, h1);
1322 smb2_util_unlink(tree, fname);
1323
1324 talloc_free(mem_ctx);
1325
1326 return ret;
1327 }
1328
test_lease_break_twice(struct torture_context * tctx,struct smb2_tree * tree)1329 static bool test_lease_break_twice(struct torture_context *tctx,
1330 struct smb2_tree *tree)
1331 {
1332 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1333 struct smb2_create io;
1334 struct smb2_lease ls1;
1335 struct smb2_lease ls2;
1336 struct smb2_handle h1 = {{0}};
1337 NTSTATUS status;
1338 const char *fname = "lease_break_twice.dat";
1339 bool ret = true;
1340 uint32_t caps;
1341 enum protocol_types protocol;
1342
1343 caps = smb2cli_conn_server_capabilities(
1344 tree->session->transport->conn);
1345 if (!(caps & SMB2_CAP_LEASING)) {
1346 torture_skip(tctx, "leases are not supported");
1347 }
1348
1349 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1350 if (protocol < PROTOCOL_SMB3_00) {
1351 torture_skip(tctx, "v2 leases are not supported");
1352 }
1353
1354 smb2_util_unlink(tree, fname);
1355
1356 ZERO_STRUCT(lease_break_info);
1357 ZERO_STRUCT(io);
1358
1359 smb2_lease_v2_create_share(
1360 &io, &ls1, false, fname, smb2_util_share_access("RWD"),
1361 LEASE1, NULL, smb2_util_lease_state("RWH"), 0x11);
1362
1363 status = smb2_create(tree, mem_ctx, &io);
1364 CHECK_STATUS(status, NT_STATUS_OK);
1365 h1 = io.out.file.handle;
1366 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1367 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch + 1);
1368
1369 tree->session->transport->lease.handler = torture_lease_handler;
1370 tree->session->transport->lease.private_data = tree;
1371
1372 ZERO_STRUCT(lease_break_info);
1373
1374 smb2_lease_v2_create_share(
1375 &io, &ls2, false, fname, smb2_util_share_access("R"),
1376 LEASE2, NULL, smb2_util_lease_state("RWH"), 0x22);
1377
1378 status = smb2_create(tree, mem_ctx, &io);
1379 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
1380 CHECK_BREAK_INFO_V2(tree->session->transport,
1381 "RWH", "RW", LEASE1, ls1.lease_epoch + 2);
1382
1383 smb2_lease_v2_create_share(
1384 &io, &ls2, false, fname, smb2_util_share_access("RWD"),
1385 LEASE2, NULL, smb2_util_lease_state("RWH"), 0x22);
1386
1387 ZERO_STRUCT(lease_break_info);
1388
1389 status = smb2_create(tree, mem_ctx, &io);
1390 CHECK_STATUS(status, NT_STATUS_OK);
1391 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch + 1);
1392 CHECK_BREAK_INFO_V2(tree->session->transport,
1393 "RW", "R", LEASE1, ls1.lease_epoch + 3);
1394
1395 done:
1396 smb2_util_close(tree, h1);
1397 smb2_util_unlink(tree, fname);
1398 talloc_free(mem_ctx);
1399 return ret;
1400 }
1401
test_lease_v2_request(struct torture_context * tctx,struct smb2_tree * tree)1402 static bool test_lease_v2_request(struct torture_context *tctx,
1403 struct smb2_tree *tree)
1404 {
1405 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1406 struct smb2_create io;
1407 struct smb2_lease ls1, ls2, ls2t, ls3, ls4;
1408 struct smb2_handle h1 = {{0}};
1409 struct smb2_handle h2 = {{0}};
1410 struct smb2_handle h3 = {{0}};
1411 struct smb2_handle h4 = {{0}};
1412 struct smb2_handle h5 = {{0}};
1413 struct smb2_write w;
1414 NTSTATUS status;
1415 const char *fname = "lease_v2_request.dat";
1416 const char *dname = "lease_v2_request.dir";
1417 const char *dnamefname = "lease_v2_request.dir\\lease.dat";
1418 const char *dnamefname2 = "lease_v2_request.dir\\lease2.dat";
1419 bool ret = true;
1420 uint32_t caps;
1421 enum protocol_types protocol;
1422
1423 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1424 if (!(caps & SMB2_CAP_LEASING)) {
1425 torture_skip(tctx, "leases are not supported");
1426 }
1427 if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
1428 torture_skip(tctx, "directory leases are not supported");
1429 }
1430
1431 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1432 if (protocol < PROTOCOL_SMB3_00) {
1433 torture_skip(tctx, "v2 leases are not supported");
1434 }
1435
1436 smb2_util_unlink(tree, fname);
1437 smb2_deltree(tree, dname);
1438
1439 tree->session->transport->lease.handler = torture_lease_handler;
1440 tree->session->transport->lease.private_data = tree;
1441 tree->session->transport->oplock.handler = torture_oplock_handler;
1442 tree->session->transport->oplock.private_data = tree;
1443
1444 ZERO_STRUCT(lease_break_info);
1445
1446 ZERO_STRUCT(io);
1447 smb2_lease_v2_create_share(&io, &ls1, false, fname,
1448 smb2_util_share_access("RWD"),
1449 LEASE1, NULL,
1450 smb2_util_lease_state("RHW"),
1451 0x11);
1452
1453 status = smb2_create(tree, mem_ctx, &io);
1454 CHECK_STATUS(status, NT_STATUS_OK);
1455 h1 = io.out.file.handle;
1456 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1457 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch + 1);
1458
1459 ZERO_STRUCT(io);
1460 smb2_lease_v2_create_share(&io, &ls2, true, dname,
1461 smb2_util_share_access("RWD"),
1462 LEASE2, NULL,
1463 smb2_util_lease_state("RHW"),
1464 0x22);
1465 status = smb2_create(tree, mem_ctx, &io);
1466 CHECK_STATUS(status, NT_STATUS_OK);
1467 h2 = io.out.file.handle;
1468 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
1469 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch + 1);
1470
1471 ZERO_STRUCT(io);
1472 smb2_lease_v2_create_share(&io, &ls3, false, dnamefname,
1473 smb2_util_share_access("RWD"),
1474 LEASE3, &LEASE2,
1475 smb2_util_lease_state("RHW"),
1476 0x33);
1477 status = smb2_create(tree, mem_ctx, &io);
1478 CHECK_STATUS(status, NT_STATUS_OK);
1479 h3 = io.out.file.handle;
1480 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1481 CHECK_LEASE_V2(&io, "RHW", true, LEASE3,
1482 SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2,
1483 ls3.lease_epoch + 1);
1484
1485 CHECK_NO_BREAK(tctx);
1486
1487 ZERO_STRUCT(io);
1488 smb2_lease_v2_create_share(&io, &ls4, false, dnamefname2,
1489 smb2_util_share_access("RWD"),
1490 LEASE4, NULL,
1491 smb2_util_lease_state("RHW"),
1492 0x44);
1493 status = smb2_create(tree, mem_ctx, &io);
1494 CHECK_STATUS(status, NT_STATUS_OK);
1495 h4 = io.out.file.handle;
1496 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1497 CHECK_LEASE_V2(&io, "RHW", true, LEASE4, 0, 0, ls4.lease_epoch + 1);
1498
1499 CHECK_BREAK_INFO_V2(tree->session->transport,
1500 "RH", "", LEASE2, ls2.lease_epoch + 2);
1501
1502 ZERO_STRUCT(lease_break_info);
1503
1504 ZERO_STRUCT(io);
1505 smb2_lease_v2_create_share(&io, &ls2t, true, dname,
1506 smb2_util_share_access("RWD"),
1507 LEASE2, NULL,
1508 smb2_util_lease_state("RHW"),
1509 0x222);
1510 io.in.create_disposition = NTCREATEX_DISP_OPEN;
1511 status = smb2_create(tree, mem_ctx, &io);
1512 CHECK_STATUS(status, NT_STATUS_OK);
1513 h5 = io.out.file.handle;
1514 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_DIRECTORY);
1515 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch+3);
1516 smb2_util_close(tree, h5);
1517
1518 ZERO_STRUCT(w);
1519 w.in.file.handle = h4;
1520 w.in.offset = 0;
1521 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
1522 memset(w.in.data.data, 'o', w.in.data.length);
1523 status = smb2_write(tree, &w);
1524 CHECK_STATUS(status, NT_STATUS_OK);
1525
1526 /*
1527 * Wait 4 seconds in order to check if the write time
1528 * was updated (after 2 seconds).
1529 */
1530 smb_msleep(4000);
1531 CHECK_NO_BREAK(tctx);
1532
1533 /*
1534 * only the close on the modified file break the
1535 * directory lease.
1536 */
1537 smb2_util_close(tree, h4);
1538
1539 CHECK_BREAK_INFO_V2(tree->session->transport,
1540 "RH", "", LEASE2, ls2.lease_epoch+4);
1541
1542 done:
1543 smb2_util_close(tree, h1);
1544 smb2_util_close(tree, h2);
1545 smb2_util_close(tree, h3);
1546 smb2_util_close(tree, h4);
1547 smb2_util_close(tree, h5);
1548
1549 smb2_util_unlink(tree, fname);
1550 smb2_deltree(tree, dname);
1551
1552 talloc_free(mem_ctx);
1553
1554 return ret;
1555 }
1556
test_lease_v2_epoch1(struct torture_context * tctx,struct smb2_tree * tree)1557 static bool test_lease_v2_epoch1(struct torture_context *tctx,
1558 struct smb2_tree *tree)
1559 {
1560 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1561 struct smb2_create io;
1562 struct smb2_lease ls;
1563 struct smb2_handle h;
1564 const char *fname = "lease_v2_epoch1.dat";
1565 bool ret = true;
1566 NTSTATUS status;
1567 uint32_t caps;
1568 enum protocol_types protocol;
1569
1570 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1571 if (!(caps & SMB2_CAP_LEASING)) {
1572 torture_skip(tctx, "leases are not supported");
1573 }
1574
1575 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1576 if (protocol < PROTOCOL_SMB3_00) {
1577 torture_skip(tctx, "v2 leases are not supported");
1578 }
1579
1580 smb2_util_unlink(tree, fname);
1581
1582 tree->session->transport->lease.handler = torture_lease_handler;
1583 tree->session->transport->lease.private_data = tree;
1584 tree->session->transport->oplock.handler = torture_oplock_handler;
1585 tree->session->transport->oplock.private_data = tree;
1586
1587 ZERO_STRUCT(lease_break_info);
1588
1589 ZERO_STRUCT(io);
1590 smb2_lease_v2_create_share(&io, &ls, false, fname,
1591 smb2_util_share_access("RWD"),
1592 LEASE1, NULL,
1593 smb2_util_lease_state("RHW"),
1594 0x4711);
1595 status = smb2_create(tree, mem_ctx, &io);
1596 CHECK_STATUS(status, NT_STATUS_OK);
1597 h = io.out.file.handle;
1598 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1599 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls.lease_epoch + 1);
1600 smb2_util_close(tree, h);
1601 smb2_util_unlink(tree, fname);
1602
1603 smb2_lease_v2_create_share(&io, &ls, false, fname,
1604 smb2_util_share_access("RWD"),
1605 LEASE1, NULL,
1606 smb2_util_lease_state("RHW"),
1607 0x11);
1608
1609 status = smb2_create(tree, mem_ctx, &io);
1610 CHECK_STATUS(status, NT_STATUS_OK);
1611 h = io.out.file.handle;
1612 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1613 CHECK_LEASE_V2(&io, "RWH", true, LEASE1, 0, 0, ls.lease_epoch + 1);
1614 smb2_util_close(tree, h);
1615
1616 done:
1617 smb2_util_unlink(tree, fname);
1618 talloc_free(mem_ctx);
1619 return ret;
1620 }
1621
test_lease_v2_epoch2(struct torture_context * tctx,struct smb2_tree * tree)1622 static bool test_lease_v2_epoch2(struct torture_context *tctx,
1623 struct smb2_tree *tree)
1624 {
1625 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1626 struct smb2_create io;
1627 struct smb2_lease ls1v2, ls1v2t, ls1v1;
1628 struct smb2_handle hv2 = {}, hv1 = {};
1629 const char *fname = "lease_v2_epoch2.dat";
1630 bool ret = true;
1631 NTSTATUS status;
1632 uint32_t caps;
1633 enum protocol_types protocol;
1634
1635 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1636 if (!(caps & SMB2_CAP_LEASING)) {
1637 torture_skip(tctx, "leases are not supported");
1638 }
1639
1640 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1641 if (protocol < PROTOCOL_SMB3_00) {
1642 torture_skip(tctx, "v2 leases are not supported");
1643 }
1644
1645 smb2_util_unlink(tree, fname);
1646
1647 tree->session->transport->lease.handler = torture_lease_handler;
1648 tree->session->transport->lease.private_data = tree;
1649 tree->session->transport->oplock.handler = torture_oplock_handler;
1650 tree->session->transport->oplock.private_data = tree;
1651
1652 ZERO_STRUCT(lease_break_info);
1653
1654 ZERO_STRUCT(io);
1655 smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
1656 smb2_util_share_access("RWD"),
1657 LEASE1, NULL,
1658 smb2_util_lease_state("R"),
1659 0x4711);
1660 status = smb2_create(tree, mem_ctx, &io);
1661 CHECK_STATUS(status, NT_STATUS_OK);
1662 hv2 = io.out.file.handle;
1663 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1664 CHECK_LEASE_V2(&io, "R", true, LEASE1, 0, 0, ls1v2.lease_epoch + 1);
1665
1666 ZERO_STRUCT(io);
1667 smb2_lease_create_share(&io, &ls1v1, false, fname,
1668 smb2_util_share_access("RWD"),
1669 LEASE1,
1670 smb2_util_lease_state("RH"));
1671 status = smb2_create(tree, mem_ctx, &io);
1672 CHECK_STATUS(status, NT_STATUS_OK);
1673 hv1 = io.out.file.handle;
1674 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1675 CHECK_LEASE_V2(&io, "RH", true, LEASE1, 0, 0, ls1v2.lease_epoch + 2);
1676
1677 smb2_util_close(tree, hv2);
1678
1679 ZERO_STRUCT(io);
1680 smb2_lease_v2_create_share(&io, &ls1v2t, false, fname,
1681 smb2_util_share_access("RWD"),
1682 LEASE1, NULL,
1683 smb2_util_lease_state("RHW"),
1684 0x11);
1685 status = smb2_create(tree, mem_ctx, &io);
1686 CHECK_STATUS(status, NT_STATUS_OK);
1687 hv2 = io.out.file.handle;
1688 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1689 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1v2.lease_epoch + 3);
1690
1691 smb2_util_close(tree, hv2);
1692
1693 smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_NONE);
1694 status = smb2_create(tree, mem_ctx, &io);
1695 CHECK_STATUS(status, NT_STATUS_OK);
1696 hv2 = io.out.file.handle;
1697 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1698 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1699
1700 CHECK_BREAK_INFO_V2(tree->session->transport,
1701 "RWH", "RH", LEASE1, ls1v2.lease_epoch + 4);
1702
1703 smb2_util_close(tree, hv2);
1704 smb2_util_close(tree, hv1);
1705
1706 ZERO_STRUCT(io);
1707 smb2_lease_create_share(&io, &ls1v1, false, fname,
1708 smb2_util_share_access("RWD"),
1709 LEASE1,
1710 smb2_util_lease_state("RHW"));
1711 status = smb2_create(tree, mem_ctx, &io);
1712 CHECK_STATUS(status, NT_STATUS_OK);
1713 hv1 = io.out.file.handle;
1714 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1715 CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
1716
1717 smb2_util_close(tree, hv1);
1718
1719 done:
1720 smb2_util_close(tree, hv2);
1721 smb2_util_close(tree, hv1);
1722 smb2_util_unlink(tree, fname);
1723 talloc_free(mem_ctx);
1724 return ret;
1725 }
1726
test_lease_v2_epoch3(struct torture_context * tctx,struct smb2_tree * tree)1727 static bool test_lease_v2_epoch3(struct torture_context *tctx,
1728 struct smb2_tree *tree)
1729 {
1730 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1731 struct smb2_create io;
1732 struct smb2_lease ls1v1 = {}, ls1v1t = {},ls1v2 = {};
1733 struct smb2_handle hv1 = {}, hv2 = {};
1734 const char *fname = "lease_v2_epoch3.dat";
1735 bool ret = true;
1736 NTSTATUS status;
1737 uint32_t caps;
1738 enum protocol_types protocol;
1739
1740 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1741 if (!(caps & SMB2_CAP_LEASING)) {
1742 torture_skip(tctx, "leases are not supported");
1743 }
1744
1745 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
1746 if (protocol < PROTOCOL_SMB3_00) {
1747 torture_skip(tctx, "v2 leases are not supported");
1748 }
1749
1750 smb2_util_unlink(tree, fname);
1751
1752 tree->session->transport->lease.handler = torture_lease_handler;
1753 tree->session->transport->lease.private_data = tree;
1754 tree->session->transport->oplock.handler = torture_oplock_handler;
1755 tree->session->transport->oplock.private_data = tree;
1756
1757 ZERO_STRUCT(lease_break_info);
1758
1759 ZERO_STRUCT(io);
1760 smb2_lease_create_share(&io, &ls1v1, false, fname,
1761 smb2_util_share_access("RWD"),
1762 LEASE1,
1763 smb2_util_lease_state("R"));
1764 status = smb2_create(tree, mem_ctx, &io);
1765 CHECK_STATUS(status, NT_STATUS_OK);
1766 hv1 = io.out.file.handle;
1767 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1768 CHECK_LEASE(&io, "R", true, LEASE1, 0);
1769
1770 ZERO_STRUCT(io);
1771 smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
1772 smb2_util_share_access("RWD"),
1773 LEASE1, NULL,
1774 smb2_util_lease_state("RW"),
1775 0x4711);
1776 status = smb2_create(tree, mem_ctx, &io);
1777 CHECK_STATUS(status, NT_STATUS_OK);
1778 hv2 = io.out.file.handle;
1779 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1780 CHECK_LEASE(&io, "RW", true, LEASE1, 0);
1781
1782 smb2_util_close(tree, hv1);
1783
1784 ZERO_STRUCT(io);
1785 smb2_lease_create_share(&io, &ls1v1t, false, fname,
1786 smb2_util_share_access("RWD"),
1787 LEASE1,
1788 smb2_util_lease_state("RWH"));
1789 status = smb2_create(tree, mem_ctx, &io);
1790 CHECK_STATUS(status, NT_STATUS_OK);
1791 hv1 = io.out.file.handle;
1792 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1793 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
1794
1795 smb2_util_close(tree, hv1);
1796
1797 smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_NONE);
1798 status = smb2_create(tree, mem_ctx, &io);
1799 CHECK_STATUS(status, NT_STATUS_OK);
1800 hv1 = io.out.file.handle;
1801 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1802 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1803
1804 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
1805
1806 smb2_util_close(tree, hv1);
1807 smb2_util_close(tree, hv2);
1808
1809 ZERO_STRUCT(io);
1810 smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
1811 smb2_util_share_access("RWD"),
1812 LEASE1, NULL,
1813 smb2_util_lease_state("RWH"),
1814 0x4711);
1815 status = smb2_create(tree, mem_ctx, &io);
1816 CHECK_STATUS(status, NT_STATUS_OK);
1817 hv2 = io.out.file.handle;
1818 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1819 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1v2.lease_epoch + 1);
1820 smb2_util_close(tree, hv2);
1821
1822 done:
1823 smb2_util_close(tree, hv2);
1824 smb2_util_close(tree, hv1);
1825 smb2_util_unlink(tree, fname);
1826 talloc_free(mem_ctx);
1827 return ret;
1828 }
1829
test_lease_breaking1(struct torture_context * tctx,struct smb2_tree * tree)1830 static bool test_lease_breaking1(struct torture_context *tctx,
1831 struct smb2_tree *tree)
1832 {
1833 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1834 struct smb2_create io1 = {};
1835 struct smb2_create io2 = {};
1836 struct smb2_lease ls1 = {};
1837 struct smb2_handle h1a = {};
1838 struct smb2_handle h1b = {};
1839 struct smb2_handle h2 = {};
1840 struct smb2_request *req2 = NULL;
1841 struct smb2_lease_break_ack ack = {};
1842 const char *fname = "lease_breaking1.dat";
1843 bool ret = true;
1844 NTSTATUS status;
1845 uint32_t caps;
1846
1847 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1848 if (!(caps & SMB2_CAP_LEASING)) {
1849 torture_skip(tctx, "leases are not supported");
1850 }
1851
1852 smb2_util_unlink(tree, fname);
1853
1854 tree->session->transport->lease.handler = torture_lease_handler;
1855 tree->session->transport->lease.private_data = tree;
1856 tree->session->transport->oplock.handler = torture_oplock_handler;
1857 tree->session->transport->oplock.private_data = tree;
1858
1859 /*
1860 * we defer acking the lease break.
1861 */
1862 ZERO_STRUCT(lease_break_info);
1863 lease_break_info.lease_skip_ack = true;
1864
1865 smb2_lease_create_share(&io1, &ls1, false, fname,
1866 smb2_util_share_access("RWD"),
1867 LEASE1,
1868 smb2_util_lease_state("RWH"));
1869 status = smb2_create(tree, mem_ctx, &io1);
1870 CHECK_STATUS(status, NT_STATUS_OK);
1871 h1a = io1.out.file.handle;
1872 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1873 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
1874
1875 /*
1876 * a conflicting open is blocked until we ack the
1877 * lease break
1878 */
1879 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
1880 req2 = smb2_create_send(tree, &io2);
1881 torture_assert(tctx, req2 != NULL, "smb2_create_send");
1882
1883 /*
1884 * we got the lease break, but defer the ack.
1885 */
1886 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
1887
1888 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
1889
1890 ack.in.lease.lease_key =
1891 lease_break_info.lease_break.current_lease.lease_key;
1892 ack.in.lease.lease_state =
1893 lease_break_info.lease_break.new_lease_state;
1894 ZERO_STRUCT(lease_break_info);
1895
1896 /*
1897 * a open using the same lease key is still works,
1898 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
1899 */
1900 status = smb2_create(tree, mem_ctx, &io1);
1901 CHECK_STATUS(status, NT_STATUS_OK);
1902 h1b = io1.out.file.handle;
1903 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1904 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
1905 smb2_util_close(tree, h1b);
1906
1907 CHECK_NO_BREAK(tctx);
1908
1909 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
1910
1911 /*
1912 * We ack the lease break.
1913 */
1914 status = smb2_lease_break_ack(tree, &ack);
1915 CHECK_STATUS(status, NT_STATUS_OK);
1916 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
1917
1918 torture_assert(tctx, req2->cancel.can_cancel,
1919 "req2 can_cancel");
1920
1921 status = smb2_create_recv(req2, tctx, &io2);
1922 CHECK_STATUS(status, NT_STATUS_OK);
1923 h2 = io2.out.file.handle;
1924 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
1925 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1926
1927 CHECK_NO_BREAK(tctx);
1928 done:
1929 smb2_util_close(tree, h1a);
1930 smb2_util_close(tree, h1b);
1931 smb2_util_close(tree, h2);
1932 smb2_util_unlink(tree, fname);
1933 talloc_free(mem_ctx);
1934 return ret;
1935 }
1936
test_lease_breaking2(struct torture_context * tctx,struct smb2_tree * tree)1937 static bool test_lease_breaking2(struct torture_context *tctx,
1938 struct smb2_tree *tree)
1939 {
1940 TALLOC_CTX *mem_ctx = talloc_new(tctx);
1941 struct smb2_create io1 = {};
1942 struct smb2_create io2 = {};
1943 struct smb2_lease ls1 = {};
1944 struct smb2_handle h1a = {};
1945 struct smb2_handle h1b = {};
1946 struct smb2_handle h2 = {};
1947 struct smb2_request *req2 = NULL;
1948 struct smb2_lease_break_ack ack = {};
1949 const char *fname = "lease_breaking2.dat";
1950 bool ret = true;
1951 NTSTATUS status;
1952 uint32_t caps;
1953
1954 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
1955 if (!(caps & SMB2_CAP_LEASING)) {
1956 torture_skip(tctx, "leases are not supported");
1957 }
1958
1959 smb2_util_unlink(tree, fname);
1960
1961 tree->session->transport->lease.handler = torture_lease_handler;
1962 tree->session->transport->lease.private_data = tree;
1963 tree->session->transport->oplock.handler = torture_oplock_handler;
1964 tree->session->transport->oplock.private_data = tree;
1965
1966 /*
1967 * we defer acking the lease break.
1968 */
1969 ZERO_STRUCT(lease_break_info);
1970 lease_break_info.lease_skip_ack = true;
1971
1972 smb2_lease_create_share(&io1, &ls1, false, fname,
1973 smb2_util_share_access("RWD"),
1974 LEASE1,
1975 smb2_util_lease_state("RWH"));
1976 status = smb2_create(tree, mem_ctx, &io1);
1977 CHECK_STATUS(status, NT_STATUS_OK);
1978 h1a = io1.out.file.handle;
1979 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
1980 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
1981
1982 /*
1983 * a conflicting open is blocked until we ack the
1984 * lease break
1985 */
1986 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
1987 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
1988 req2 = smb2_create_send(tree, &io2);
1989 torture_assert(tctx, req2 != NULL, "smb2_create_send");
1990
1991 /*
1992 * we got the lease break, but defer the ack.
1993 */
1994 CHECK_BREAK_INFO("RWH", "", LEASE1);
1995
1996 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
1997
1998 ack.in.lease.lease_key =
1999 lease_break_info.lease_break.current_lease.lease_key;
2000 ZERO_STRUCT(lease_break_info);
2001
2002 /*
2003 * a open using the same lease key is still works,
2004 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2005 */
2006 status = smb2_create(tree, mem_ctx, &io1);
2007 CHECK_STATUS(status, NT_STATUS_OK);
2008 h1b = io1.out.file.handle;
2009 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2010 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2011 smb2_util_close(tree, h1b);
2012
2013 CHECK_NO_BREAK(tctx);
2014
2015 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2016
2017 /*
2018 * We ack the lease break.
2019 */
2020 ack.in.lease.lease_state =
2021 SMB2_LEASE_READ | SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE;
2022 status = smb2_lease_break_ack(tree, &ack);
2023 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2024
2025 ack.in.lease.lease_state =
2026 SMB2_LEASE_READ | SMB2_LEASE_WRITE;
2027 status = smb2_lease_break_ack(tree, &ack);
2028 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2029
2030 ack.in.lease.lease_state =
2031 SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE;
2032 status = smb2_lease_break_ack(tree, &ack);
2033 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2034
2035 ack.in.lease.lease_state =
2036 SMB2_LEASE_READ | SMB2_LEASE_HANDLE;
2037 status = smb2_lease_break_ack(tree, &ack);
2038 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2039
2040 ack.in.lease.lease_state = SMB2_LEASE_WRITE;
2041 status = smb2_lease_break_ack(tree, &ack);
2042 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2043
2044 ack.in.lease.lease_state = SMB2_LEASE_HANDLE;
2045 status = smb2_lease_break_ack(tree, &ack);
2046 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2047
2048 ack.in.lease.lease_state = SMB2_LEASE_READ;
2049 status = smb2_lease_break_ack(tree, &ack);
2050 CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
2051
2052 /* Try again with the correct state this time. */
2053 ack.in.lease.lease_state = SMB2_LEASE_NONE;;
2054 status = smb2_lease_break_ack(tree, &ack);
2055 CHECK_STATUS(status, NT_STATUS_OK);
2056 CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
2057
2058 status = smb2_lease_break_ack(tree, &ack);
2059 CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
2060
2061 torture_assert(tctx, req2->cancel.can_cancel,
2062 "req2 can_cancel");
2063
2064 status = smb2_create_recv(req2, tctx, &io2);
2065 CHECK_STATUS(status, NT_STATUS_OK);
2066 h2 = io2.out.file.handle;
2067 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2068 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2069
2070 CHECK_NO_BREAK(tctx);
2071
2072 /* Get state of the original handle. */
2073 smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
2074 status = smb2_create(tree, mem_ctx, &io1);
2075 CHECK_STATUS(status, NT_STATUS_OK);
2076 CHECK_LEASE(&io1, "", true, LEASE1, 0);
2077 smb2_util_close(tree, io1.out.file.handle);
2078
2079 done:
2080 smb2_util_close(tree, h1a);
2081 smb2_util_close(tree, h1b);
2082 smb2_util_close(tree, h2);
2083 smb2_util_unlink(tree, fname);
2084 talloc_free(mem_ctx);
2085 return ret;
2086 }
2087
test_lease_breaking3(struct torture_context * tctx,struct smb2_tree * tree)2088 static bool test_lease_breaking3(struct torture_context *tctx,
2089 struct smb2_tree *tree)
2090 {
2091 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2092 struct smb2_create io1 = {};
2093 struct smb2_create io2 = {};
2094 struct smb2_create io3 = {};
2095 struct smb2_lease ls1 = {};
2096 struct smb2_handle h1a = {};
2097 struct smb2_handle h1b = {};
2098 struct smb2_handle h2 = {};
2099 struct smb2_handle h3 = {};
2100 struct smb2_request *req2 = NULL;
2101 struct smb2_request *req3 = NULL;
2102 struct lease_break_info lease_break_info_tmp = {};
2103 struct smb2_lease_break_ack ack = {};
2104 const char *fname = "lease_breaking3.dat";
2105 bool ret = true;
2106 NTSTATUS status;
2107 uint32_t caps;
2108
2109 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2110 if (!(caps & SMB2_CAP_LEASING)) {
2111 torture_skip(tctx, "leases are not supported");
2112 }
2113
2114 smb2_util_unlink(tree, fname);
2115
2116 tree->session->transport->lease.handler = torture_lease_handler;
2117 tree->session->transport->lease.private_data = tree;
2118 tree->session->transport->oplock.handler = torture_oplock_handler;
2119 tree->session->transport->oplock.private_data = tree;
2120
2121 /*
2122 * we defer acking the lease break.
2123 */
2124 ZERO_STRUCT(lease_break_info);
2125 lease_break_info.lease_skip_ack = true;
2126
2127 smb2_lease_create_share(&io1, &ls1, false, fname,
2128 smb2_util_share_access("RWD"),
2129 LEASE1,
2130 smb2_util_lease_state("RWH"));
2131 status = smb2_create(tree, mem_ctx, &io1);
2132 CHECK_STATUS(status, NT_STATUS_OK);
2133 h1a = io1.out.file.handle;
2134 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2135 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2136
2137 /*
2138 * a conflicting open is blocked until we ack the
2139 * lease break
2140 */
2141 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2142 req2 = smb2_create_send(tree, &io2);
2143 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2144
2145 /*
2146 * we got the lease break, but defer the ack.
2147 */
2148 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2149
2150 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2151
2152 /*
2153 * a open using the same lease key is still works,
2154 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2155 */
2156 status = smb2_create(tree, mem_ctx, &io1);
2157 CHECK_STATUS(status, NT_STATUS_OK);
2158 h1b = io1.out.file.handle;
2159 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2160 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2161 smb2_util_close(tree, h1b);
2162
2163 /*
2164 * a conflicting open with NTCREATEX_DISP_OVERWRITE
2165 * doesn't trigger an immediate lease break to none.
2166 */
2167 lease_break_info_tmp = lease_break_info;
2168 ZERO_STRUCT(lease_break_info);
2169 smb2_oplock_create(&io3, fname, SMB2_OPLOCK_LEVEL_NONE);
2170 io3.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2171 req3 = smb2_create_send(tree, &io3);
2172 torture_assert(tctx, req3 != NULL, "smb2_create_send");
2173 CHECK_NO_BREAK(tctx);
2174 lease_break_info = lease_break_info_tmp;
2175
2176 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2177
2178 ack.in.lease.lease_key =
2179 lease_break_info.lease_break.current_lease.lease_key;
2180 ack.in.lease.lease_state =
2181 lease_break_info.lease_break.new_lease_state;
2182 ZERO_STRUCT(lease_break_info);
2183
2184 /*
2185 * a open using the same lease key is still works,
2186 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2187 */
2188 status = smb2_create(tree, mem_ctx, &io1);
2189 CHECK_STATUS(status, NT_STATUS_OK);
2190 h1b = io1.out.file.handle;
2191 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2192 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2193 smb2_util_close(tree, h1b);
2194
2195 CHECK_NO_BREAK(tctx);
2196
2197 /*
2198 * We ack the lease break, but defer acking the next break (to "R")
2199 */
2200 lease_break_info.lease_skip_ack = true;
2201 status = smb2_lease_break_ack(tree, &ack);
2202 CHECK_STATUS(status, NT_STATUS_OK);
2203 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
2204
2205 /*
2206 * We got an additional break downgrading to just "R"
2207 * while we defer the ack.
2208 */
2209 CHECK_BREAK_INFO("RH", "R", LEASE1);
2210
2211 ack.in.lease.lease_key =
2212 lease_break_info.lease_break.current_lease.lease_key;
2213 ack.in.lease.lease_state =
2214 lease_break_info.lease_break.new_lease_state;
2215 ZERO_STRUCT(lease_break_info);
2216
2217 /*
2218 * a open using the same lease key is still works,
2219 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2220 */
2221 status = smb2_create(tree, mem_ctx, &io1);
2222 CHECK_STATUS(status, NT_STATUS_OK);
2223 h1b = io1.out.file.handle;
2224 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2225 CHECK_LEASE(&io1, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2226 smb2_util_close(tree, h1b);
2227
2228 CHECK_NO_BREAK(tctx);
2229
2230 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2231 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2232
2233 /*
2234 * We ack the downgrade to "R" and get an immediate break to none
2235 */
2236 status = smb2_lease_break_ack(tree, &ack);
2237 CHECK_STATUS(status, NT_STATUS_OK);
2238 CHECK_LEASE_BREAK_ACK(&ack, "R", LEASE1);
2239
2240 /*
2241 * We get the downgrade to none.
2242 */
2243 CHECK_BREAK_INFO("R", "", LEASE1);
2244
2245 torture_assert(tctx, req2->cancel.can_cancel,
2246 "req2 can_cancel");
2247 torture_assert(tctx, req3->cancel.can_cancel,
2248 "req3 can_cancel");
2249
2250 ZERO_STRUCT(lease_break_info);
2251
2252 status = smb2_create_recv(req2, tctx, &io2);
2253 CHECK_STATUS(status, NT_STATUS_OK);
2254 h2 = io2.out.file.handle;
2255 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2256 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2257
2258 status = smb2_create_recv(req3, tctx, &io3);
2259 CHECK_STATUS(status, NT_STATUS_OK);
2260 h3 = io3.out.file.handle;
2261 CHECK_CREATED(&io3, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2262 CHECK_VAL(io3.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2263
2264 CHECK_NO_BREAK(tctx);
2265 done:
2266 smb2_util_close(tree, h1a);
2267 smb2_util_close(tree, h1b);
2268 smb2_util_close(tree, h2);
2269 smb2_util_close(tree, h3);
2270
2271 smb2_util_unlink(tree, fname);
2272 talloc_free(mem_ctx);
2273 return ret;
2274 }
2275
test_lease_v2_breaking3(struct torture_context * tctx,struct smb2_tree * tree)2276 static bool test_lease_v2_breaking3(struct torture_context *tctx,
2277 struct smb2_tree *tree)
2278 {
2279 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2280 struct smb2_create io1 = {};
2281 struct smb2_create io2 = {};
2282 struct smb2_create io3 = {};
2283 struct smb2_lease ls1 = {};
2284 struct smb2_handle h1a = {};
2285 struct smb2_handle h1b = {};
2286 struct smb2_handle h2 = {};
2287 struct smb2_handle h3 = {};
2288 struct smb2_request *req2 = NULL;
2289 struct smb2_request *req3 = NULL;
2290 struct lease_break_info lease_break_info_tmp = {};
2291 struct smb2_lease_break_ack ack = {};
2292 const char *fname = "v2_lease_breaking3.dat";
2293 bool ret = true;
2294 NTSTATUS status;
2295 uint32_t caps;
2296 enum protocol_types protocol;
2297
2298 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2299 if (!(caps & SMB2_CAP_LEASING)) {
2300 torture_skip(tctx, "leases are not supported");
2301 }
2302
2303 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
2304 if (protocol < PROTOCOL_SMB3_00) {
2305 torture_skip(tctx, "v2 leases are not supported");
2306 }
2307
2308 smb2_util_unlink(tree, fname);
2309
2310 tree->session->transport->lease.handler = torture_lease_handler;
2311 tree->session->transport->lease.private_data = tree;
2312 tree->session->transport->oplock.handler = torture_oplock_handler;
2313 tree->session->transport->oplock.private_data = tree;
2314
2315 /*
2316 * we defer acking the lease break.
2317 */
2318 ZERO_STRUCT(lease_break_info);
2319 lease_break_info.lease_skip_ack = true;
2320
2321 smb2_lease_v2_create_share(&io1, &ls1, false, fname,
2322 smb2_util_share_access("RWD"),
2323 LEASE1, NULL,
2324 smb2_util_lease_state("RHW"),
2325 0x11);
2326 status = smb2_create(tree, mem_ctx, &io1);
2327 CHECK_STATUS(status, NT_STATUS_OK);
2328 h1a = io1.out.file.handle;
2329 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2330 /* Epoch increases on open. */
2331 ls1.lease_epoch += 1;
2332 CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
2333
2334 /*
2335 * a conflicting open is blocked until we ack the
2336 * lease break
2337 */
2338 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2339 req2 = smb2_create_send(tree, &io2);
2340 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2341
2342 /*
2343 * we got the lease break, but defer the ack.
2344 */
2345 CHECK_BREAK_INFO_V2(tree->session->transport,
2346 "RWH", "RH", LEASE1, ls1.lease_epoch + 1);
2347
2348 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2349
2350 /* On receiving a lease break, we must sync the new epoch. */
2351 ls1.lease_epoch = lease_break_info.lease_break.new_epoch;
2352
2353 /*
2354 * a open using the same lease key is still works,
2355 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2356 */
2357 status = smb2_create(tree, mem_ctx, &io1);
2358 CHECK_STATUS(status, NT_STATUS_OK);
2359 h1b = io1.out.file.handle;
2360 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2361 CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
2362 smb2_util_close(tree, h1b);
2363
2364 /*
2365 * a conflicting open with NTCREATEX_DISP_OVERWRITE
2366 * doesn't trigger an immediate lease break to none.
2367 */
2368 lease_break_info_tmp = lease_break_info;
2369 ZERO_STRUCT(lease_break_info);
2370 smb2_oplock_create(&io3, fname, SMB2_OPLOCK_LEVEL_NONE);
2371 io3.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2372 req3 = smb2_create_send(tree, &io3);
2373 torture_assert(tctx, req3 != NULL, "smb2_create_send");
2374 CHECK_NO_BREAK(tctx);
2375 lease_break_info = lease_break_info_tmp;
2376
2377 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2378
2379 ack.in.lease.lease_key =
2380 lease_break_info.lease_break.current_lease.lease_key;
2381 ack.in.lease.lease_state =
2382 lease_break_info.lease_break.new_lease_state;
2383 ZERO_STRUCT(lease_break_info);
2384
2385 /*
2386 * a open using the same lease key is still works,
2387 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2388 */
2389 status = smb2_create(tree, mem_ctx, &io1);
2390 CHECK_STATUS(status, NT_STATUS_OK);
2391 h1b = io1.out.file.handle;
2392 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2393 CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
2394 smb2_util_close(tree, h1b);
2395
2396 CHECK_NO_BREAK(tctx);
2397
2398 /*
2399 * We ack the lease break, but defer acking the next break (to "R")
2400 */
2401 lease_break_info.lease_skip_ack = true;
2402 status = smb2_lease_break_ack(tree, &ack);
2403 CHECK_STATUS(status, NT_STATUS_OK);
2404 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
2405
2406 /*
2407 * We got an additional break downgrading to just "R"
2408 * while we defer the ack.
2409 */
2410 CHECK_BREAK_INFO_V2(tree->session->transport,
2411 "RH", "R", LEASE1, ls1.lease_epoch);
2412 /* On receiving a lease break, we must sync the new epoch. */
2413 ls1.lease_epoch = lease_break_info.lease_break.new_epoch;
2414
2415 ack.in.lease.lease_key =
2416 lease_break_info.lease_break.current_lease.lease_key;
2417 ack.in.lease.lease_state =
2418 lease_break_info.lease_break.new_lease_state;
2419 ZERO_STRUCT(lease_break_info);
2420
2421 /*
2422 * a open using the same lease key is still works,
2423 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2424 */
2425 status = smb2_create(tree, mem_ctx, &io1);
2426 CHECK_STATUS(status, NT_STATUS_OK);
2427 h1b = io1.out.file.handle;
2428 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2429 CHECK_LEASE_V2(&io1, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
2430 smb2_util_close(tree, h1b);
2431
2432 CHECK_NO_BREAK(tctx);
2433
2434 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2435 torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
2436
2437 /*
2438 * We ack the downgrade to "R" and get an immediate break to none
2439 */
2440 status = smb2_lease_break_ack(tree, &ack);
2441 CHECK_STATUS(status, NT_STATUS_OK);
2442 CHECK_LEASE_BREAK_ACK(&ack, "R", LEASE1);
2443
2444 /*
2445 * We get the downgrade to none.
2446 */
2447 CHECK_BREAK_INFO_V2(tree->session->transport,
2448 "R", "", LEASE1, ls1.lease_epoch);
2449
2450 torture_assert(tctx, req2->cancel.can_cancel,
2451 "req2 can_cancel");
2452 torture_assert(tctx, req3->cancel.can_cancel,
2453 "req3 can_cancel");
2454
2455 ZERO_STRUCT(lease_break_info);
2456
2457 status = smb2_create_recv(req2, tctx, &io2);
2458 CHECK_STATUS(status, NT_STATUS_OK);
2459 h2 = io2.out.file.handle;
2460 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2461 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2462
2463 status = smb2_create_recv(req3, tctx, &io3);
2464 CHECK_STATUS(status, NT_STATUS_OK);
2465 h3 = io3.out.file.handle;
2466 CHECK_CREATED(&io3, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2467 CHECK_VAL(io3.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2468
2469 CHECK_NO_BREAK(tctx);
2470 done:
2471 smb2_util_close(tree, h1a);
2472 smb2_util_close(tree, h1b);
2473 smb2_util_close(tree, h2);
2474 smb2_util_close(tree, h3);
2475
2476 smb2_util_unlink(tree, fname);
2477 talloc_free(mem_ctx);
2478 return ret;
2479 }
2480
2481
test_lease_breaking4(struct torture_context * tctx,struct smb2_tree * tree)2482 static bool test_lease_breaking4(struct torture_context *tctx,
2483 struct smb2_tree *tree)
2484 {
2485 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2486 struct smb2_create io1 = {};
2487 struct smb2_create io2 = {};
2488 struct smb2_create io3 = {};
2489 struct smb2_lease ls1 = {};
2490 struct smb2_lease ls1t = {};
2491 struct smb2_handle h1 = {};
2492 struct smb2_handle h2 = {};
2493 struct smb2_handle h3 = {};
2494 struct smb2_request *req2 = NULL;
2495 struct lease_break_info lease_break_info_tmp = {};
2496 struct smb2_lease_break_ack ack = {};
2497 const char *fname = "lease_breaking4.dat";
2498 bool ret = true;
2499 NTSTATUS status;
2500 uint32_t caps;
2501
2502 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2503 if (!(caps & SMB2_CAP_LEASING)) {
2504 torture_skip(tctx, "leases are not supported");
2505 }
2506
2507 smb2_util_unlink(tree, fname);
2508
2509 tree->session->transport->lease.handler = torture_lease_handler;
2510 tree->session->transport->lease.private_data = tree;
2511 tree->session->transport->oplock.handler = torture_oplock_handler;
2512 tree->session->transport->oplock.private_data = tree;
2513
2514 /*
2515 * we defer acking the lease break.
2516 */
2517 ZERO_STRUCT(lease_break_info);
2518 lease_break_info.lease_skip_ack = true;
2519
2520 smb2_lease_create_share(&io1, &ls1, false, fname,
2521 smb2_util_share_access("RWD"),
2522 LEASE1,
2523 smb2_util_lease_state("RH"));
2524 status = smb2_create(tree, mem_ctx, &io1);
2525 CHECK_STATUS(status, NT_STATUS_OK);
2526 h1 = io1.out.file.handle;
2527 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2528 CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
2529
2530 CHECK_NO_BREAK(tctx);
2531
2532 /*
2533 * a conflicting open is *not* blocked until we ack the
2534 * lease break
2535 */
2536 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2537 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2538 req2 = smb2_create_send(tree, &io2);
2539 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2540
2541 /*
2542 * We got a break from RH to NONE, we're supported to ack
2543 * this downgrade
2544 */
2545 CHECK_BREAK_INFO("RH", "", LEASE1);
2546
2547 lease_break_info_tmp = lease_break_info;
2548 ZERO_STRUCT(lease_break_info);
2549 CHECK_NO_BREAK(tctx);
2550
2551 torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2552
2553 status = smb2_create_recv(req2, tctx, &io2);
2554 CHECK_STATUS(status, NT_STATUS_OK);
2555 h2 = io2.out.file.handle;
2556 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2557 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2558 smb2_util_close(tree, h2);
2559
2560 CHECK_NO_BREAK(tctx);
2561
2562 /*
2563 * a conflicting open is *not* blocked until we ack the
2564 * lease break, even if the lease is in breaking state.
2565 */
2566 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2567 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2568 req2 = smb2_create_send(tree, &io2);
2569 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2570
2571 CHECK_NO_BREAK(tctx);
2572
2573 torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2574
2575 status = smb2_create_recv(req2, tctx, &io2);
2576 CHECK_STATUS(status, NT_STATUS_OK);
2577 h2 = io2.out.file.handle;
2578 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2579 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2580 smb2_util_close(tree, h2);
2581
2582 CHECK_NO_BREAK(tctx);
2583
2584 /*
2585 * We now ask the server about the current lease state
2586 * which should still be "RH", but with
2587 * SMB2_LEASE_FLAG_BREAK_IN_PROGRESS.
2588 */
2589 smb2_lease_create_share(&io3, &ls1t, false, fname,
2590 smb2_util_share_access("RWD"),
2591 LEASE1,
2592 smb2_util_lease_state(""));
2593 status = smb2_create(tree, mem_ctx, &io3);
2594 CHECK_STATUS(status, NT_STATUS_OK);
2595 h3 = io3.out.file.handle;
2596 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2597 CHECK_LEASE(&io3, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2598
2599 /*
2600 * We finally ack the lease break...
2601 */
2602 CHECK_NO_BREAK(tctx);
2603 lease_break_info = lease_break_info_tmp;
2604 ack.in.lease.lease_key =
2605 lease_break_info.lease_break.current_lease.lease_key;
2606 ack.in.lease.lease_state =
2607 lease_break_info.lease_break.new_lease_state;
2608 ZERO_STRUCT(lease_break_info);
2609 lease_break_info.lease_skip_ack = true;
2610
2611 status = smb2_lease_break_ack(tree, &ack);
2612 CHECK_STATUS(status, NT_STATUS_OK);
2613 CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
2614
2615 CHECK_NO_BREAK(tctx);
2616
2617 done:
2618 smb2_util_close(tree, h1);
2619 smb2_util_close(tree, h2);
2620 smb2_util_close(tree, h3);
2621
2622 smb2_util_unlink(tree, fname);
2623 talloc_free(mem_ctx);
2624 return ret;
2625 }
2626
test_lease_breaking5(struct torture_context * tctx,struct smb2_tree * tree)2627 static bool test_lease_breaking5(struct torture_context *tctx,
2628 struct smb2_tree *tree)
2629 {
2630 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2631 struct smb2_create io1 = {};
2632 struct smb2_create io2 = {};
2633 struct smb2_create io3 = {};
2634 struct smb2_lease ls1 = {};
2635 struct smb2_lease ls1t = {};
2636 struct smb2_handle h1 = {};
2637 struct smb2_handle h2 = {};
2638 struct smb2_handle h3 = {};
2639 struct smb2_request *req2 = NULL;
2640 struct lease_break_info lease_break_info_tmp = {};
2641 struct smb2_lease_break_ack ack = {};
2642 const char *fname = "lease_breaking5.dat";
2643 bool ret = true;
2644 NTSTATUS status;
2645 uint32_t caps;
2646
2647 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2648 if (!(caps & SMB2_CAP_LEASING)) {
2649 torture_skip(tctx, "leases are not supported");
2650 }
2651
2652 smb2_util_unlink(tree, fname);
2653
2654 tree->session->transport->lease.handler = torture_lease_handler;
2655 tree->session->transport->lease.private_data = tree;
2656 tree->session->transport->oplock.handler = torture_oplock_handler;
2657 tree->session->transport->oplock.private_data = tree;
2658
2659 /*
2660 * we defer acking the lease break.
2661 */
2662 ZERO_STRUCT(lease_break_info);
2663 lease_break_info.lease_skip_ack = true;
2664
2665 smb2_lease_create_share(&io1, &ls1, false, fname,
2666 smb2_util_share_access("RWD"),
2667 LEASE1,
2668 smb2_util_lease_state("R"));
2669 status = smb2_create(tree, mem_ctx, &io1);
2670 CHECK_STATUS(status, NT_STATUS_OK);
2671 h1 = io1.out.file.handle;
2672 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2673 CHECK_LEASE(&io1, "R", true, LEASE1, 0);
2674
2675 CHECK_NO_BREAK(tctx);
2676
2677 /*
2678 * a conflicting open is *not* blocked until we ack the
2679 * lease break
2680 */
2681 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2682 io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2683 req2 = smb2_create_send(tree, &io2);
2684 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2685
2686 /*
2687 * We got a break from RH to NONE, we're supported to ack
2688 * this downgrade
2689 */
2690 CHECK_BREAK_INFO("R", "", LEASE1);
2691
2692 lease_break_info_tmp = lease_break_info;
2693 ZERO_STRUCT(lease_break_info);
2694 CHECK_NO_BREAK(tctx);
2695
2696 torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
2697
2698 status = smb2_create_recv(req2, tctx, &io2);
2699 CHECK_STATUS(status, NT_STATUS_OK);
2700 h2 = io2.out.file.handle;
2701 CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
2702 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2703
2704 CHECK_NO_BREAK(tctx);
2705
2706 /*
2707 * We now ask the server about the current lease state
2708 * which should still be "RH", but with
2709 * SMB2_LEASE_FLAG_BREAK_IN_PROGRESS.
2710 */
2711 smb2_lease_create_share(&io3, &ls1t, false, fname,
2712 smb2_util_share_access("RWD"),
2713 LEASE1,
2714 smb2_util_lease_state(""));
2715 status = smb2_create(tree, mem_ctx, &io3);
2716 CHECK_STATUS(status, NT_STATUS_OK);
2717 h3 = io3.out.file.handle;
2718 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2719 CHECK_LEASE(&io3, "", true, LEASE1, 0);
2720
2721 /*
2722 * We send an ack without without being asked.
2723 */
2724 CHECK_NO_BREAK(tctx);
2725 lease_break_info = lease_break_info_tmp;
2726 ack.in.lease.lease_key =
2727 lease_break_info.lease_break.current_lease.lease_key;
2728 ack.in.lease.lease_state =
2729 lease_break_info.lease_break.new_lease_state;
2730 ZERO_STRUCT(lease_break_info);
2731 status = smb2_lease_break_ack(tree, &ack);
2732 CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
2733
2734 CHECK_NO_BREAK(tctx);
2735
2736 done:
2737 smb2_util_close(tree, h1);
2738 smb2_util_close(tree, h2);
2739 smb2_util_close(tree, h3);
2740
2741 smb2_util_unlink(tree, fname);
2742 talloc_free(mem_ctx);
2743 return ret;
2744 }
2745
test_lease_breaking6(struct torture_context * tctx,struct smb2_tree * tree)2746 static bool test_lease_breaking6(struct torture_context *tctx,
2747 struct smb2_tree *tree)
2748 {
2749 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2750 struct smb2_create io1 = {};
2751 struct smb2_create io2 = {};
2752 struct smb2_lease ls1 = {};
2753 struct smb2_handle h1a = {};
2754 struct smb2_handle h1b = {};
2755 struct smb2_handle h2 = {};
2756 struct smb2_request *req2 = NULL;
2757 struct smb2_lease_break_ack ack = {};
2758 const char *fname = "lease_breaking6.dat";
2759 bool ret = true;
2760 NTSTATUS status;
2761 uint32_t caps;
2762
2763 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
2764 if (!(caps & SMB2_CAP_LEASING)) {
2765 torture_skip(tctx, "leases are not supported");
2766 }
2767
2768 smb2_util_unlink(tree, fname);
2769
2770 tree->session->transport->lease.handler = torture_lease_handler;
2771 tree->session->transport->lease.private_data = tree;
2772 tree->session->transport->oplock.handler = torture_oplock_handler;
2773 tree->session->transport->oplock.private_data = tree;
2774
2775 /*
2776 * we defer acking the lease break.
2777 */
2778 ZERO_STRUCT(lease_break_info);
2779 lease_break_info.lease_skip_ack = true;
2780
2781 smb2_lease_create_share(&io1, &ls1, false, fname,
2782 smb2_util_share_access("RWD"),
2783 LEASE1,
2784 smb2_util_lease_state("RWH"));
2785 status = smb2_create(tree, mem_ctx, &io1);
2786 CHECK_STATUS(status, NT_STATUS_OK);
2787 h1a = io1.out.file.handle;
2788 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2789 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2790
2791 /*
2792 * a conflicting open is blocked until we ack the
2793 * lease break
2794 */
2795 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
2796 req2 = smb2_create_send(tree, &io2);
2797 torture_assert(tctx, req2 != NULL, "smb2_create_send");
2798
2799 /*
2800 * we got the lease break, but defer the ack.
2801 */
2802 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2803
2804 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2805
2806 ack.in.lease.lease_key =
2807 lease_break_info.lease_break.current_lease.lease_key;
2808 ZERO_STRUCT(lease_break_info);
2809
2810 /*
2811 * a open using the same lease key is still works,
2812 * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
2813 */
2814 status = smb2_create(tree, mem_ctx, &io1);
2815 CHECK_STATUS(status, NT_STATUS_OK);
2816 h1b = io1.out.file.handle;
2817 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2818 CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
2819 smb2_util_close(tree, h1b);
2820
2821 CHECK_NO_BREAK(tctx);
2822
2823 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
2824
2825 /*
2826 * We are asked to break to "RH", but we are allowed to
2827 * break to any of "RH", "R" or NONE.
2828 */
2829 ack.in.lease.lease_state = SMB2_LEASE_NONE;
2830 status = smb2_lease_break_ack(tree, &ack);
2831 CHECK_STATUS(status, NT_STATUS_OK);
2832 CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
2833
2834 torture_assert(tctx, req2->cancel.can_cancel,
2835 "req2 can_cancel");
2836
2837 status = smb2_create_recv(req2, tctx, &io2);
2838 CHECK_STATUS(status, NT_STATUS_OK);
2839 h2 = io2.out.file.handle;
2840 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2841 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
2842
2843 CHECK_NO_BREAK(tctx);
2844 done:
2845 smb2_util_close(tree, h1a);
2846 smb2_util_close(tree, h1b);
2847 smb2_util_close(tree, h2);
2848 smb2_util_unlink(tree, fname);
2849 talloc_free(mem_ctx);
2850 return ret;
2851 }
2852
test_lease_lock1(struct torture_context * tctx,struct smb2_tree * tree1a,struct smb2_tree * tree2)2853 static bool test_lease_lock1(struct torture_context *tctx,
2854 struct smb2_tree *tree1a,
2855 struct smb2_tree *tree2)
2856 {
2857 TALLOC_CTX *mem_ctx = talloc_new(tctx);
2858 struct smb2_create io1 = {};
2859 struct smb2_create io2 = {};
2860 struct smb2_create io3 = {};
2861 struct smb2_lease ls1 = {};
2862 struct smb2_lease ls2 = {};
2863 struct smb2_lease ls3 = {};
2864 struct smb2_handle h1 = {};
2865 struct smb2_handle h2 = {};
2866 struct smb2_handle h3 = {};
2867 struct smb2_lock lck;
2868 struct smb2_lock_element el[1];
2869 const char *fname = "locktest.dat";
2870 bool ret = true;
2871 NTSTATUS status;
2872 uint32_t caps;
2873 struct smbcli_options options1;
2874 struct smb2_tree *tree1b = NULL;
2875
2876 options1 = tree1a->session->transport->options;
2877
2878 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
2879 if (!(caps & SMB2_CAP_LEASING)) {
2880 torture_skip(tctx, "leases are not supported");
2881 }
2882
2883 /* Set up handlers. */
2884 tree2->session->transport->lease.handler = torture_lease_handler;
2885 tree2->session->transport->lease.private_data = tree2;
2886 tree2->session->transport->oplock.handler = torture_oplock_handler;
2887 tree2->session->transport->oplock.private_data = tree2;
2888
2889 tree1a->session->transport->lease.handler = torture_lease_handler;
2890 tree1a->session->transport->lease.private_data = tree1a;
2891 tree1a->session->transport->oplock.handler = torture_oplock_handler;
2892 tree1a->session->transport->oplock.private_data = tree1a;
2893
2894 /* create a new connection (same client_guid) */
2895 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
2896 torture_warning(tctx, "couldn't reconnect, bailing\n");
2897 ret = false;
2898 goto done;
2899 }
2900
2901 tree1b->session->transport->lease.handler = torture_lease_handler;
2902 tree1b->session->transport->lease.private_data = tree1b;
2903 tree1b->session->transport->oplock.handler = torture_oplock_handler;
2904 tree1b->session->transport->oplock.private_data = tree1b;
2905
2906 smb2_util_unlink(tree1a, fname);
2907
2908 ZERO_STRUCT(lease_break_info);
2909 ZERO_STRUCT(lck);
2910
2911 /* Open a handle on tree1a. */
2912 smb2_lease_create_share(&io1, &ls1, false, fname,
2913 smb2_util_share_access("RWD"),
2914 LEASE1,
2915 smb2_util_lease_state("RWH"));
2916 status = smb2_create(tree1a, mem_ctx, &io1);
2917 CHECK_STATUS(status, NT_STATUS_OK);
2918 h1 = io1.out.file.handle;
2919 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
2920 CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
2921
2922 /* Open a second handle on tree1b. */
2923 smb2_lease_create_share(&io2, &ls2, false, fname,
2924 smb2_util_share_access("RWD"),
2925 LEASE2,
2926 smb2_util_lease_state("RWH"));
2927 status = smb2_create(tree1b, mem_ctx, &io2);
2928 CHECK_STATUS(status, NT_STATUS_OK);
2929 h2 = io2.out.file.handle;
2930 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2931 CHECK_LEASE(&io2, "RH", true, LEASE2, 0);
2932 /* And LEASE1 got broken to RH. */
2933 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
2934 ZERO_STRUCT(lease_break_info);
2935
2936 /* Now open a lease on a different client guid. */
2937 smb2_lease_create_share(&io3, &ls3, false, fname,
2938 smb2_util_share_access("RWD"),
2939 LEASE3,
2940 smb2_util_lease_state("RWH"));
2941 status = smb2_create(tree2, mem_ctx, &io3);
2942 CHECK_STATUS(status, NT_STATUS_OK);
2943 h3 = io3.out.file.handle;
2944 CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
2945 CHECK_LEASE(&io3, "RH", true, LEASE3, 0);
2946 /* Doesn't break. */
2947 CHECK_NO_BREAK(tctx);
2948
2949 lck.in.locks = el;
2950 /*
2951 * Try and get get an exclusive byte
2952 * range lock on H1 (LEASE1).
2953 */
2954
2955 lck.in.lock_count = 1;
2956 lck.in.lock_sequence = 1;
2957 lck.in.file.handle = h1;
2958 el[0].offset = 0;
2959 el[0].length = 1;
2960 el[0].reserved = 0;
2961 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
2962 status = smb2_lock(tree1a, &lck);
2963 CHECK_STATUS(status, NT_STATUS_OK);
2964
2965 /* LEASE2 and LEASE3 should get broken to NONE. */
2966 torture_wait_for_lease_break(tctx);
2967 torture_wait_for_lease_break(tctx);
2968 torture_wait_for_lease_break(tctx);
2969 torture_wait_for_lease_break(tctx);
2970
2971 CHECK_VAL(lease_break_info.failures, 0); \
2972 CHECK_VAL(lease_break_info.count, 2); \
2973
2974 /* Get state of the H1 (LEASE1) */
2975 smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
2976 status = smb2_create(tree1a, mem_ctx, &io1);
2977 CHECK_STATUS(status, NT_STATUS_OK);
2978 /* Should still be RH. */
2979 CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
2980 smb2_util_close(tree1a, io1.out.file.handle);
2981
2982 /* Get state of the H2 (LEASE2) */
2983 smb2_lease_create(&io2, &ls2, false, fname, LEASE2, smb2_util_lease_state(""));
2984 status = smb2_create(tree1b, mem_ctx, &io2);
2985 CHECK_STATUS(status, NT_STATUS_OK);
2986 CHECK_LEASE(&io2, "", true, LEASE2, 0);
2987 smb2_util_close(tree1b, io2.out.file.handle);
2988
2989 /* Get state of the H3 (LEASE3) */
2990 smb2_lease_create(&io3, &ls3, false, fname, LEASE3, smb2_util_lease_state(""));
2991 status = smb2_create(tree2, mem_ctx, &io3);
2992 CHECK_STATUS(status, NT_STATUS_OK);
2993 CHECK_LEASE(&io3, "", true, LEASE3, 0);
2994 smb2_util_close(tree2, io3.out.file.handle);
2995
2996 ZERO_STRUCT(lease_break_info);
2997
2998 /*
2999 * Try and get get an exclusive byte
3000 * range lock on H3 (LEASE3).
3001 */
3002 lck.in.lock_count = 1;
3003 lck.in.lock_sequence = 2;
3004 lck.in.file.handle = h3;
3005 el[0].offset = 100;
3006 el[0].length = 1;
3007 el[0].reserved = 0;
3008 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
3009 status = smb2_lock(tree2, &lck);
3010 CHECK_STATUS(status, NT_STATUS_OK);
3011 /* LEASE1 got broken to NONE. */
3012 CHECK_BREAK_INFO("RH", "", LEASE1);
3013 ZERO_STRUCT(lease_break_info);
3014
3015 done:
3016 smb2_util_close(tree1a, h1);
3017 smb2_util_close(tree1b, h2);
3018 smb2_util_close(tree2, h3);
3019
3020 smb2_util_unlink(tree1a, fname);
3021 talloc_free(mem_ctx);
3022 return ret;
3023 }
3024
test_lease_complex1(struct torture_context * tctx,struct smb2_tree * tree1a)3025 static bool test_lease_complex1(struct torture_context *tctx,
3026 struct smb2_tree *tree1a)
3027 {
3028 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3029 struct smb2_create io1;
3030 struct smb2_create io2;
3031 struct smb2_lease ls1;
3032 struct smb2_lease ls2;
3033 struct smb2_handle h = {{0}};
3034 struct smb2_handle h2 = {{0}};
3035 struct smb2_handle h3 = {{0}};
3036 struct smb2_write w;
3037 NTSTATUS status;
3038 const char *fname = "lease_complex1.dat";
3039 bool ret = true;
3040 uint32_t caps;
3041 struct smb2_tree *tree1b = NULL;
3042 struct smbcli_options options1;
3043
3044 options1 = tree1a->session->transport->options;
3045
3046 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3047 if (!(caps & SMB2_CAP_LEASING)) {
3048 torture_skip(tctx, "leases are not supported");
3049 }
3050
3051 tree1a->session->transport->lease.handler = torture_lease_handler;
3052 tree1a->session->transport->lease.private_data = tree1a;
3053 tree1a->session->transport->oplock.handler = torture_oplock_handler;
3054 tree1a->session->transport->oplock.private_data = tree1a;
3055
3056 /* create a new connection (same client_guid) */
3057 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
3058 torture_warning(tctx, "couldn't reconnect, bailing\n");
3059 ret = false;
3060 goto done;
3061 }
3062
3063 tree1b->session->transport->lease.handler = torture_lease_handler;
3064 tree1b->session->transport->lease.private_data = tree1b;
3065 tree1b->session->transport->oplock.handler = torture_oplock_handler;
3066 tree1b->session->transport->oplock.private_data = tree1b;
3067
3068 smb2_util_unlink(tree1a, fname);
3069
3070 ZERO_STRUCT(lease_break_info);
3071
3072 /* Grab R lease over connection 1a */
3073 smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
3074 status = smb2_create(tree1a, mem_ctx, &io1);
3075 CHECK_STATUS(status, NT_STATUS_OK);
3076 h = io1.out.file.handle;
3077 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3078 CHECK_LEASE(&io1, "R", true, LEASE1, 0);
3079
3080 /* Upgrade to RWH over connection 1b */
3081 ls1.lease_state = smb2_util_lease_state("RWH");
3082 status = smb2_create(tree1b, mem_ctx, &io1);
3083 CHECK_STATUS(status, NT_STATUS_OK);
3084 h2 = io1.out.file.handle;
3085 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3086 CHECK_LEASE(&io1, "RHW", true, LEASE1, 0);
3087
3088 /* close over connection 1b */
3089 status = smb2_util_close(tree1b, h2);
3090 CHECK_STATUS(status, NT_STATUS_OK);
3091
3092 /* Contend with LEASE2. */
3093 smb2_lease_create(&io2, &ls2, false, fname, LEASE2, smb2_util_lease_state("R"));
3094 status = smb2_create(tree1b, mem_ctx, &io2);
3095 CHECK_STATUS(status, NT_STATUS_OK);
3096 h3 = io2.out.file.handle;
3097 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3098 CHECK_LEASE(&io2, "R", true, LEASE2, 0);
3099
3100 /* Verify that we were only sent one break. */
3101 CHECK_BREAK_INFO("RHW", "RH", LEASE1);
3102
3103 /* again RH over connection 1b doesn't change the epoch */
3104 ls1.lease_state = smb2_util_lease_state("RH");
3105 status = smb2_create(tree1b, mem_ctx, &io1);
3106 CHECK_STATUS(status, NT_STATUS_OK);
3107 h2 = io1.out.file.handle;
3108 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3109 CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
3110
3111 /* close over connection 1b */
3112 status = smb2_util_close(tree1b, h2);
3113 CHECK_STATUS(status, NT_STATUS_OK);
3114
3115 ZERO_STRUCT(lease_break_info);
3116
3117 ZERO_STRUCT(w);
3118 w.in.file.handle = h;
3119 w.in.offset = 0;
3120 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3121 memset(w.in.data.data, 'o', w.in.data.length);
3122 status = smb2_write(tree1a, &w);
3123 CHECK_STATUS(status, NT_STATUS_OK);
3124
3125 ls2.lease_epoch += 1;
3126 CHECK_BREAK_INFO("R", "", LEASE2);
3127
3128 ZERO_STRUCT(lease_break_info);
3129
3130 ZERO_STRUCT(w);
3131 w.in.file.handle = h3;
3132 w.in.offset = 0;
3133 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3134 memset(w.in.data.data, 'o', w.in.data.length);
3135 status = smb2_write(tree1b, &w);
3136 CHECK_STATUS(status, NT_STATUS_OK);
3137
3138 ls1.lease_epoch += 1;
3139 CHECK_BREAK_INFO("RH", "", LEASE1);
3140
3141 done:
3142 smb2_util_close(tree1a, h);
3143 smb2_util_close(tree1b, h2);
3144 smb2_util_close(tree1b, h3);
3145
3146 smb2_util_unlink(tree1a, fname);
3147
3148 talloc_free(mem_ctx);
3149
3150 return ret;
3151 }
3152
test_lease_v2_complex1(struct torture_context * tctx,struct smb2_tree * tree1a)3153 static bool test_lease_v2_complex1(struct torture_context *tctx,
3154 struct smb2_tree *tree1a)
3155 {
3156 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3157 struct smb2_create io1;
3158 struct smb2_create io2;
3159 struct smb2_lease ls1;
3160 struct smb2_lease ls2;
3161 struct smb2_handle h = {{0}};
3162 struct smb2_handle h2 = {{0}};
3163 struct smb2_handle h3 = {{0}};
3164 struct smb2_write w;
3165 NTSTATUS status;
3166 const char *fname = "lease_v2_complex1.dat";
3167 bool ret = true;
3168 uint32_t caps;
3169 enum protocol_types protocol;
3170 struct smb2_tree *tree1b = NULL;
3171 struct smbcli_options options1;
3172
3173 options1 = tree1a->session->transport->options;
3174
3175 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3176 if (!(caps & SMB2_CAP_LEASING)) {
3177 torture_skip(tctx, "leases are not supported");
3178 }
3179
3180 protocol = smbXcli_conn_protocol(tree1a->session->transport->conn);
3181 if (protocol < PROTOCOL_SMB3_00) {
3182 torture_skip(tctx, "v2 leases are not supported");
3183 }
3184
3185 tree1a->session->transport->lease.handler = torture_lease_handler;
3186 tree1a->session->transport->lease.private_data = tree1a;
3187 tree1a->session->transport->oplock.handler = torture_oplock_handler;
3188 tree1a->session->transport->oplock.private_data = tree1a;
3189
3190 /* create a new connection (same client_guid) */
3191 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
3192 torture_warning(tctx, "couldn't reconnect, bailing\n");
3193 ret = false;
3194 goto done;
3195 }
3196
3197 tree1b->session->transport->lease.handler = torture_lease_handler;
3198 tree1b->session->transport->lease.private_data = tree1b;
3199 tree1b->session->transport->oplock.handler = torture_oplock_handler;
3200 tree1b->session->transport->oplock.private_data = tree1b;
3201
3202 smb2_util_unlink(tree1a, fname);
3203
3204 ZERO_STRUCT(lease_break_info);
3205
3206 /* Grab R lease over connection 1a */
3207 smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
3208 smb2_util_lease_state("R"), 0x4711);
3209 status = smb2_create(tree1a, mem_ctx, &io1);
3210 CHECK_STATUS(status, NT_STATUS_OK);
3211 h = io1.out.file.handle;
3212 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3213 ls1.lease_epoch += 1;
3214 CHECK_LEASE_V2(&io1, "R", true, LEASE1,
3215 0, 0, ls1.lease_epoch);
3216
3217 /* Upgrade to RWH over connection 1b */
3218 ls1.lease_state = smb2_util_lease_state("RWH");
3219 status = smb2_create(tree1b, mem_ctx, &io1);
3220 CHECK_STATUS(status, NT_STATUS_OK);
3221 h2 = io1.out.file.handle;
3222 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3223 ls1.lease_epoch += 1;
3224 CHECK_LEASE_V2(&io1, "RHW", true, LEASE1,
3225 0, 0, ls1.lease_epoch);
3226
3227 /* close over connection 1b */
3228 status = smb2_util_close(tree1b, h2);
3229 CHECK_STATUS(status, NT_STATUS_OK);
3230
3231 /* Contend with LEASE2. */
3232 smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
3233 smb2_util_lease_state("R"), 0x11);
3234 status = smb2_create(tree1b, mem_ctx, &io2);
3235 CHECK_STATUS(status, NT_STATUS_OK);
3236 h3 = io2.out.file.handle;
3237 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3238 ls2.lease_epoch += 1;
3239 CHECK_LEASE_V2(&io2, "R", true, LEASE2,
3240 0, 0, ls2.lease_epoch);
3241
3242 /* Verify that we were only sent one break. */
3243 ls1.lease_epoch += 1;
3244 CHECK_BREAK_INFO_V2(tree1a->session->transport,
3245 "RHW", "RH", LEASE1, ls1.lease_epoch);
3246
3247 /* again RH over connection 1b doesn't change the epoch */
3248 ls1.lease_state = smb2_util_lease_state("RH");
3249 status = smb2_create(tree1b, mem_ctx, &io1);
3250 CHECK_STATUS(status, NT_STATUS_OK);
3251 h2 = io1.out.file.handle;
3252 CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3253 CHECK_LEASE_V2(&io1, "RH", true, LEASE1,
3254 0, 0, ls1.lease_epoch);
3255
3256 /* close over connection 1b */
3257 status = smb2_util_close(tree1b, h2);
3258 CHECK_STATUS(status, NT_STATUS_OK);
3259
3260 ZERO_STRUCT(lease_break_info);
3261
3262 ZERO_STRUCT(w);
3263 w.in.file.handle = h;
3264 w.in.offset = 0;
3265 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3266 memset(w.in.data.data, 'o', w.in.data.length);
3267 status = smb2_write(tree1a, &w);
3268 CHECK_STATUS(status, NT_STATUS_OK);
3269
3270 ls2.lease_epoch += 1;
3271 CHECK_BREAK_INFO_V2(tree1a->session->transport,
3272 "R", "", LEASE2, ls2.lease_epoch);
3273
3274 ZERO_STRUCT(lease_break_info);
3275
3276 ZERO_STRUCT(w);
3277 w.in.file.handle = h3;
3278 w.in.offset = 0;
3279 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3280 memset(w.in.data.data, 'o', w.in.data.length);
3281 status = smb2_write(tree1b, &w);
3282 CHECK_STATUS(status, NT_STATUS_OK);
3283
3284 ls1.lease_epoch += 1;
3285 CHECK_BREAK_INFO_V2(tree1a->session->transport,
3286 "RH", "", LEASE1, ls1.lease_epoch);
3287
3288 done:
3289 smb2_util_close(tree1a, h);
3290 smb2_util_close(tree1b, h2);
3291 smb2_util_close(tree1b, h3);
3292
3293 smb2_util_unlink(tree1a, fname);
3294
3295 talloc_free(mem_ctx);
3296
3297 return ret;
3298 }
3299
test_lease_v2_complex2(struct torture_context * tctx,struct smb2_tree * tree1a)3300 static bool test_lease_v2_complex2(struct torture_context *tctx,
3301 struct smb2_tree *tree1a)
3302 {
3303 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3304 struct smb2_create io1;
3305 struct smb2_create io2;
3306 struct smb2_lease ls1;
3307 struct smb2_lease ls2;
3308 struct smb2_handle h = {{0}};
3309 struct smb2_handle h2 = {{0}};
3310 struct smb2_request *req2 = NULL;
3311 struct smb2_lease_break_ack ack = {};
3312 NTSTATUS status;
3313 const char *fname = "lease_v2_complex2.dat";
3314 bool ret = true;
3315 uint32_t caps;
3316 enum protocol_types protocol;
3317 struct smb2_tree *tree1b = NULL;
3318 struct smbcli_options options1;
3319
3320 options1 = tree1a->session->transport->options;
3321
3322 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3323 if (!(caps & SMB2_CAP_LEASING)) {
3324 torture_skip(tctx, "leases are not supported");
3325 }
3326
3327 protocol = smbXcli_conn_protocol(tree1a->session->transport->conn);
3328 if (protocol < PROTOCOL_SMB3_00) {
3329 torture_skip(tctx, "v2 leases are not supported");
3330 }
3331
3332 tree1a->session->transport->lease.handler = torture_lease_handler;
3333 tree1a->session->transport->lease.private_data = tree1a;
3334 tree1a->session->transport->oplock.handler = torture_oplock_handler;
3335 tree1a->session->transport->oplock.private_data = tree1a;
3336
3337 /* create a new connection (same client_guid) */
3338 if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
3339 torture_warning(tctx, "couldn't reconnect, bailing\n");
3340 ret = false;
3341 goto done;
3342 }
3343
3344 tree1b->session->transport->lease.handler = torture_lease_handler;
3345 tree1b->session->transport->lease.private_data = tree1b;
3346 tree1b->session->transport->oplock.handler = torture_oplock_handler;
3347 tree1b->session->transport->oplock.private_data = tree1b;
3348
3349 smb2_util_unlink(tree1a, fname);
3350
3351 ZERO_STRUCT(lease_break_info);
3352
3353 /* Grab RWH lease over connection 1a */
3354 smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
3355 smb2_util_lease_state("RWH"), 0x4711);
3356 status = smb2_create(tree1a, mem_ctx, &io1);
3357 CHECK_STATUS(status, NT_STATUS_OK);
3358 h = io1.out.file.handle;
3359 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3360 ls1.lease_epoch += 1;
3361 CHECK_LEASE_V2(&io1, "RWH", true, LEASE1,
3362 0, 0, ls1.lease_epoch);
3363
3364 /*
3365 * we defer acking the lease break.
3366 */
3367 ZERO_STRUCT(lease_break_info);
3368 lease_break_info.lease_skip_ack = true;
3369
3370 /* Ask for RWH on connection 1b, different lease. */
3371 smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
3372 smb2_util_lease_state("RWH"), 0x11);
3373 req2 = smb2_create_send(tree1b, &io2);
3374 torture_assert(tctx, req2 != NULL, "smb2_create_send");
3375
3376 ls1.lease_epoch += 1;
3377
3378 CHECK_BREAK_INFO_V2(tree1a->session->transport,
3379 "RWH", "RH", LEASE1, ls1.lease_epoch);
3380
3381 /* Send the break ACK on tree1b. */
3382 ack.in.lease.lease_key =
3383 lease_break_info.lease_break.current_lease.lease_key;
3384 ack.in.lease.lease_state = SMB2_LEASE_HANDLE|SMB2_LEASE_READ;
3385
3386 status = smb2_lease_break_ack(tree1b, &ack);
3387 CHECK_STATUS(status, NT_STATUS_OK);
3388 CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
3389
3390 ZERO_STRUCT(lease_break_info);
3391
3392 status = smb2_create_recv(req2, tctx, &io2);
3393 CHECK_STATUS(status, NT_STATUS_OK);
3394 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3395 CHECK_LEASE_V2(&io2, "RH", true, LEASE2,
3396 0, 0, ls2.lease_epoch+1);
3397 h2 = io2.out.file.handle;
3398
3399 done:
3400 smb2_util_close(tree1a, h);
3401 smb2_util_close(tree1b, h2);
3402
3403 smb2_util_unlink(tree1a, fname);
3404
3405 talloc_free(mem_ctx);
3406
3407 return ret;
3408 }
3409
3410
test_lease_timeout(struct torture_context * tctx,struct smb2_tree * tree)3411 static bool test_lease_timeout(struct torture_context *tctx,
3412 struct smb2_tree *tree)
3413 {
3414 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3415 struct smb2_create io;
3416 struct smb2_lease ls1;
3417 struct smb2_lease ls2;
3418 struct smb2_handle h = {{0}};
3419 struct smb2_handle hnew = {{0}};
3420 struct smb2_handle h1b = {{0}};
3421 NTSTATUS status;
3422 const char *fname = "lease_timeout.dat";
3423 bool ret = true;
3424 struct smb2_lease_break_ack ack = {};
3425 struct smb2_request *req2 = NULL;
3426 struct smb2_write w;
3427 uint32_t caps;
3428
3429 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
3430 if (!(caps & SMB2_CAP_LEASING)) {
3431 torture_skip(tctx, "leases are not supported");
3432 }
3433
3434 smb2_util_unlink(tree, fname);
3435
3436 /* Grab a RWH lease. */
3437 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3438 status = smb2_create(tree, mem_ctx, &io);
3439 CHECK_STATUS(status, NT_STATUS_OK);
3440 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3441 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3442 h = io.out.file.handle;
3443
3444 tree->session->transport->lease.handler = torture_lease_handler;
3445 tree->session->transport->lease.private_data = tree;
3446 tree->session->transport->oplock.handler = torture_oplock_handler;
3447 tree->session->transport->oplock.private_data = tree;
3448
3449 /*
3450 * Just don't ack the lease break.
3451 */
3452 ZERO_STRUCT(lease_break_info);
3453 lease_break_info.lease_skip_ack = true;
3454
3455 /* Break with a RWH request. */
3456 smb2_lease_create(&io, &ls2, false, fname, LEASE2, smb2_util_lease_state("RWH"));
3457 req2 = smb2_create_send(tree, &io);
3458 torture_assert(tctx, req2 != NULL, "smb2_create_send");
3459 torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
3460
3461 CHECK_BREAK_INFO("RWH", "RH", LEASE1);
3462
3463 /* Copy the break request. */
3464 ack.in.lease.lease_key =
3465 lease_break_info.lease_break.current_lease.lease_key;
3466 ack.in.lease.lease_state =
3467 lease_break_info.lease_break.new_lease_state;
3468
3469 /* Now wait for the timeout and get the reply. */
3470 status = smb2_create_recv(req2, tctx, &io);
3471 CHECK_STATUS(status, NT_STATUS_OK);
3472 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3473 CHECK_LEASE(&io, "RH", true, LEASE2, 0);
3474 hnew = io.out.file.handle;
3475
3476 /* Ack the break after the timeout... */
3477 status = smb2_lease_break_ack(tree, &ack);
3478 CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
3479
3480 /* Get state of the original handle. */
3481 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
3482 status = smb2_create(tree, mem_ctx, &io);
3483 CHECK_STATUS(status, NT_STATUS_OK);
3484 CHECK_LEASE(&io, "", true, LEASE1, 0);
3485 smb2_util_close(tree, io.out.file.handle);
3486
3487 /* Write on the original handle and make sure it's still valid. */
3488 ZERO_STRUCT(lease_break_info);
3489 ZERO_STRUCT(w);
3490 w.in.file.handle = h;
3491 w.in.offset = 0;
3492 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3493 memset(w.in.data.data, '1', w.in.data.length);
3494 status = smb2_write(tree, &w);
3495 CHECK_STATUS(status, NT_STATUS_OK);
3496
3497 /* Causes new handle to break to NONE. */
3498 CHECK_BREAK_INFO("RH", "", LEASE2);
3499
3500 /* Write on the new handle. */
3501 ZERO_STRUCT(lease_break_info);
3502 ZERO_STRUCT(w);
3503 w.in.file.handle = hnew;
3504 w.in.offset = 0;
3505 w.in.data = data_blob_talloc(mem_ctx, NULL, 1024);
3506 memset(w.in.data.data, '2', w.in.data.length);
3507 status = smb2_write(tree, &w);
3508 CHECK_STATUS(status, NT_STATUS_OK);
3509 /* No break - original handle was already NONE. */
3510 CHECK_NO_BREAK(tctx);
3511 smb2_util_close(tree, hnew);
3512
3513 /* Upgrade to R on LEASE1. */
3514 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
3515 status = smb2_create(tree, mem_ctx, &io);
3516 CHECK_STATUS(status, NT_STATUS_OK);
3517 CHECK_LEASE(&io, "R", true, LEASE1, 0);
3518 h1b = io.out.file.handle;
3519 smb2_util_close(tree, h1b);
3520
3521 /* Upgrade to RWH on LEASE1. */
3522 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3523 status = smb2_create(tree, mem_ctx, &io);
3524 CHECK_STATUS(status, NT_STATUS_OK);
3525 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3526 h1b = io.out.file.handle;
3527 smb2_util_close(tree, h1b);
3528
3529 done:
3530 smb2_util_close(tree, h);
3531 smb2_util_close(tree, hnew);
3532 smb2_util_close(tree, h1b);
3533
3534 smb2_util_unlink(tree, fname);
3535
3536 talloc_free(mem_ctx);
3537
3538 return ret;
3539 }
3540
test_lease_v2_rename(struct torture_context * tctx,struct smb2_tree * tree)3541 static bool test_lease_v2_rename(struct torture_context *tctx,
3542 struct smb2_tree *tree)
3543 {
3544 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3545 struct smb2_create io;
3546 struct smb2_lease ls1;
3547 struct smb2_lease ls2;
3548 struct smb2_handle h = {{0}};
3549 struct smb2_handle h1 = {{0}};
3550 struct smb2_handle h2 = {{0}};
3551 union smb_setfileinfo sinfo;
3552 const char *fname = "lease_v2_rename_src.dat";
3553 const char *fname_dst = "lease_v2_rename_dst.dat";
3554 bool ret = true;
3555 NTSTATUS status;
3556 uint32_t caps;
3557 enum protocol_types protocol;
3558
3559 caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
3560 if (!(caps & SMB2_CAP_LEASING)) {
3561 torture_skip(tctx, "leases are not supported");
3562 }
3563
3564 protocol = smbXcli_conn_protocol(tree->session->transport->conn);
3565 if (protocol < PROTOCOL_SMB3_00) {
3566 torture_skip(tctx, "v2 leases are not supported");
3567 }
3568
3569 smb2_util_unlink(tree, fname);
3570 smb2_util_unlink(tree, fname_dst);
3571
3572 tree->session->transport->lease.handler = torture_lease_handler;
3573 tree->session->transport->lease.private_data = tree;
3574 tree->session->transport->oplock.handler = torture_oplock_handler;
3575 tree->session->transport->oplock.private_data = tree;
3576
3577 ZERO_STRUCT(lease_break_info);
3578
3579 ZERO_STRUCT(io);
3580 smb2_lease_v2_create_share(&io, &ls1, false, fname,
3581 smb2_util_share_access("RWD"),
3582 LEASE1, NULL,
3583 smb2_util_lease_state("RHW"),
3584 0x4711);
3585 status = smb2_create(tree, mem_ctx, &io);
3586 CHECK_STATUS(status, NT_STATUS_OK);
3587 h = io.out.file.handle;
3588 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3589 ls1.lease_epoch += 1;
3590 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
3591
3592 /* Now rename - what happens ? */
3593 ZERO_STRUCT(sinfo);
3594 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
3595 sinfo.rename_information.in.file.handle = h;
3596 sinfo.rename_information.in.overwrite = true;
3597 sinfo.rename_information.in.new_name = fname_dst;
3598 status = smb2_setinfo_file(tree, &sinfo);
3599 CHECK_STATUS(status, NT_STATUS_OK);
3600
3601 /* No lease break. */
3602 CHECK_NO_BREAK(tctx);
3603
3604 /* Check we can open another handle on the new name. */
3605 smb2_lease_v2_create_share(&io, &ls1, false, fname_dst,
3606 smb2_util_share_access("RWD"),
3607 LEASE1, NULL,
3608 smb2_util_lease_state(""),
3609 ls1.lease_epoch);
3610 status = smb2_create(tree, mem_ctx, &io);
3611 CHECK_STATUS(status, NT_STATUS_OK);
3612 h1 = io.out.file.handle;
3613 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3614 CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
3615 smb2_util_close(tree, h1);
3616
3617 /* Try another lease key. */
3618 smb2_lease_v2_create_share(&io, &ls2, false, fname_dst,
3619 smb2_util_share_access("RWD"),
3620 LEASE2, NULL,
3621 smb2_util_lease_state("RWH"),
3622 0x44);
3623 status = smb2_create(tree, mem_ctx, &io);
3624 CHECK_STATUS(status, NT_STATUS_OK);
3625 h2 = io.out.file.handle;
3626 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3627 ls2.lease_epoch += 1;
3628 CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch );
3629 CHECK_BREAK_INFO_V2(tree->session->transport,
3630 "RWH", "RH", LEASE1, ls1.lease_epoch + 1);
3631 ls1.lease_epoch += 1;
3632 ZERO_STRUCT(lease_break_info);
3633
3634 /* Now rename back. */
3635 ZERO_STRUCT(sinfo);
3636 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
3637 sinfo.rename_information.in.file.handle = h;
3638 sinfo.rename_information.in.overwrite = true;
3639 sinfo.rename_information.in.new_name = fname;
3640 status = smb2_setinfo_file(tree, &sinfo);
3641 CHECK_STATUS(status, NT_STATUS_OK);
3642
3643 /* Breaks to R on LEASE2. */
3644 CHECK_BREAK_INFO_V2(tree->session->transport,
3645 "RH", "R", LEASE2, ls2.lease_epoch + 1);
3646 ls2.lease_epoch += 1;
3647
3648 /* Check we can open another handle on the current name. */
3649 smb2_lease_v2_create_share(&io, &ls1, false, fname,
3650 smb2_util_share_access("RWD"),
3651 LEASE1, NULL,
3652 smb2_util_lease_state(""),
3653 ls1.lease_epoch);
3654 status = smb2_create(tree, mem_ctx, &io);
3655 CHECK_STATUS(status, NT_STATUS_OK);
3656 h1 = io.out.file.handle;
3657 CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3658 CHECK_LEASE_V2(&io, "RH", true, LEASE1, 0, 0, ls1.lease_epoch);
3659 smb2_util_close(tree, h1);
3660
3661 done:
3662
3663 smb2_util_close(tree, h);
3664 smb2_util_close(tree, h1);
3665 smb2_util_close(tree, h2);
3666
3667 smb2_util_unlink(tree, fname);
3668 smb2_util_unlink(tree, fname_dst);
3669
3670 smb2_util_unlink(tree, fname);
3671 talloc_free(mem_ctx);
3672 return ret;
3673 }
3674
3675
test_lease_dynamic_share(struct torture_context * tctx,struct smb2_tree * tree1a)3676 static bool test_lease_dynamic_share(struct torture_context *tctx,
3677 struct smb2_tree *tree1a)
3678 {
3679 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3680 struct smb2_create io;
3681 struct smb2_lease ls1;
3682 struct smb2_handle h, h1, h2;
3683 struct smb2_write w;
3684 NTSTATUS status;
3685 const char *fname = "dynamic_path.dat";
3686 bool ret = true;
3687 uint32_t caps;
3688 struct smb2_tree *tree_2_1 = NULL;
3689 struct smb2_tree *tree_3_0 = NULL;
3690 struct smbcli_options options2_1;
3691 struct smbcli_options options3_0;
3692 const char *orig_share = NULL;
3693
3694 if (!TARGET_IS_SAMBA3(tctx)) {
3695 torture_skip(tctx, "dynamic shares are not supported");
3696 return true;
3697 }
3698
3699 options2_1 = tree1a->session->transport->options;
3700 options3_0 = tree1a->session->transport->options;
3701
3702 caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
3703 if (!(caps & SMB2_CAP_LEASING)) {
3704 torture_skip(tctx, "leases are not supported");
3705 }
3706
3707 /*
3708 * Save off original share name and change it to dynamic_share.
3709 * This must have been pre-created with a dynamic path containing
3710 * %R.
3711 */
3712
3713 orig_share = lpcfg_parm_string(tctx->lp_ctx, NULL, "torture", "share");
3714 orig_share = talloc_strdup(tctx->lp_ctx, orig_share);
3715 if (orig_share == NULL) {
3716 torture_result(tctx, TORTURE_FAIL, __location__ "no memory\n");
3717 ret = false;
3718 goto done;
3719 }
3720 lpcfg_set_cmdline(tctx->lp_ctx, "torture:share", "dynamic_share");
3721
3722 /* Set max protocol to SMB2.1 */
3723 options2_1.max_protocol = PROTOCOL_SMB2_10;
3724 /* create a new connection (same client_guid) */
3725 if (!torture_smb2_connection_ext(tctx, 0, &options2_1, &tree_2_1)) {
3726 torture_result(tctx, TORTURE_FAIL,
3727 __location__ "couldn't reconnect "
3728 "max protocol 2.1, bailing\n");
3729 ret = false;
3730 goto done;
3731 }
3732
3733 tree_2_1->session->transport->lease.handler = torture_lease_handler;
3734 tree_2_1->session->transport->lease.private_data = tree_2_1;
3735 tree_2_1->session->transport->oplock.handler = torture_oplock_handler;
3736 tree_2_1->session->transport->oplock.private_data = tree_2_1;
3737
3738 smb2_util_unlink(tree_2_1, fname);
3739
3740 /* Set max protocol to SMB3.0 */
3741 options3_0.max_protocol = PROTOCOL_SMB3_00;
3742 /* create a new connection (same client_guid) */
3743 if (!torture_smb2_connection_ext(tctx, 0, &options3_0, &tree_3_0)) {
3744 torture_result(tctx, TORTURE_FAIL,
3745 __location__ "couldn't reconnect "
3746 "max protocol 3.0, bailing\n");
3747 ret = false;
3748 goto done;
3749 }
3750
3751 tree_3_0->session->transport->lease.handler = torture_lease_handler;
3752 tree_3_0->session->transport->lease.private_data = tree_3_0;
3753 tree_3_0->session->transport->oplock.handler = torture_oplock_handler;
3754 tree_3_0->session->transport->oplock.private_data = tree_3_0;
3755
3756 smb2_util_unlink(tree_3_0, fname);
3757
3758 ZERO_STRUCT(lease_break_info);
3759
3760 /* Get RWH lease over connection 2_1 */
3761 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3762 status = smb2_create(tree_2_1, mem_ctx, &io);
3763 CHECK_STATUS(status, NT_STATUS_OK);
3764 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3765 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3766 h = io.out.file.handle;
3767
3768 /* Write some data into it. */
3769 w.in.file.handle = h;
3770 w.in.offset = 0;
3771 w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
3772 memset(w.in.data.data, '1', w.in.data.length);
3773 status = smb2_write(tree_2_1, &w);
3774 CHECK_STATUS(status, NT_STATUS_OK);
3775
3776 /* Open the same name over connection 3_0. */
3777 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3778 status = smb2_create(tree_3_0, mem_ctx, &io);
3779 CHECK_STATUS(status, NT_STATUS_OK);
3780 h1 = io.out.file.handle;
3781 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3782
3783 /* h1 should have replied with NONE. */
3784 CHECK_LEASE(&io, "", true, LEASE1, 0);
3785
3786 /* We should have broken h to NONE. */
3787 CHECK_BREAK_INFO("RWH", "", LEASE1);
3788
3789 /* Try to upgrade to RWH over connection 2_1 */
3790 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3791 status = smb2_create(tree_2_1, mem_ctx, &io);
3792 CHECK_STATUS(status, NT_STATUS_OK);
3793 h2 = io.out.file.handle;
3794 CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
3795 CHECK_VAL(io.out.size, 4096);
3796 CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
3797 /* Should have been denied. */
3798 CHECK_LEASE(&io, "", true, LEASE1, 0);
3799 smb2_util_close(tree_2_1, h2);
3800
3801 /* Try to upgrade to RWH over connection 3_0 */
3802 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3803 status = smb2_create(tree_3_0, mem_ctx, &io);
3804 CHECK_STATUS(status, NT_STATUS_OK);
3805 h2 = io.out.file.handle;
3806 CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
3807 CHECK_VAL(io.out.size, 0);
3808 CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
3809 /* Should have been denied. */
3810 CHECK_LEASE(&io, "", true, LEASE1, 0);
3811 smb2_util_close(tree_3_0, h2);
3812
3813 /* Write some data into it. */
3814 w.in.file.handle = h1;
3815 w.in.offset = 0;
3816 w.in.data = data_blob_talloc(mem_ctx, NULL, 1024);
3817 memset(w.in.data.data, '2', w.in.data.length);
3818 status = smb2_write(tree_3_0, &w);
3819 CHECK_STATUS(status, NT_STATUS_OK);
3820
3821 /* Close everything.. */
3822 smb2_util_close(tree_2_1, h);
3823 smb2_util_close(tree_3_0, h1);
3824
3825 /* And ensure we can get a lease ! */
3826 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3827 status = smb2_create(tree_2_1, mem_ctx, &io);
3828 CHECK_STATUS(status, NT_STATUS_OK);
3829 CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
3830 CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
3831 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3832 h = io.out.file.handle;
3833 /* And the file is the right size. */
3834 CHECK_VAL(io.out.size, 4096); \
3835 /* Close it. */
3836 smb2_util_close(tree_2_1, h);
3837
3838 /* And ensure we can get a lease ! */
3839 smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
3840 status = smb2_create(tree_3_0, mem_ctx, &io);
3841 CHECK_STATUS(status, NT_STATUS_OK);
3842 CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
3843 CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
3844 CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
3845 h = io.out.file.handle;
3846 /* And the file is the right size. */
3847 CHECK_VAL(io.out.size, 1024); \
3848 /* Close it. */
3849 smb2_util_close(tree_3_0, h);
3850
3851 done:
3852
3853 if (tree_2_1 != NULL) {
3854 smb2_util_close(tree_2_1, h);
3855 smb2_util_unlink(tree_2_1, fname);
3856 }
3857 if (tree_3_0 != NULL) {
3858 smb2_util_close(tree_3_0, h1);
3859 smb2_util_close(tree_3_0, h2);
3860
3861 smb2_util_unlink(tree_3_0, fname);
3862 }
3863
3864 /* Set sharename back. */
3865 lpcfg_set_cmdline(tctx->lp_ctx, "torture:share", orig_share);
3866
3867 talloc_free(mem_ctx);
3868
3869 return ret;
3870 }
3871
3872 /*
3873 * Test identifies a bug where the Samba server will not trigger a lease break
3874 * for a handle caching lease held by a client when the underlying file is
3875 * deleted.
3876 * Test:
3877 * Connect session2.
3878 * open file in session1
3879 * session1 should have RWH lease.
3880 * open file in session2
3881 * lease break sent to session1 to downgrade lease to RH
3882 * close file in session 2
3883 * unlink file in session 2
3884 * lease break sent to session1 to downgrade lease to R
3885 * Cleanup
3886 */
test_lease_unlink(struct torture_context * tctx,struct smb2_tree * tree1)3887 static bool test_lease_unlink(struct torture_context *tctx,
3888 struct smb2_tree *tree1)
3889 {
3890 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3891 NTSTATUS status;
3892 bool ret = true;
3893 struct smbcli_options transport2_options;
3894 struct smb2_tree *tree2 = NULL;
3895 struct smb2_transport *transport1 = tree1->session->transport;
3896 struct smb2_transport *transport2;
3897 struct smb2_handle h1 = {{ 0 }};
3898 struct smb2_handle h2 = {{ 0 }};
3899 const char *fname = "lease_unlink.dat";
3900 uint32_t caps;
3901 struct smb2_create io1;
3902 struct smb2_create io2;
3903 struct smb2_lease ls1;
3904 struct smb2_lease ls2;
3905
3906 caps = smb2cli_conn_server_capabilities(
3907 tree1->session->transport->conn);
3908 if (!(caps & SMB2_CAP_LEASING)) {
3909 torture_skip(tctx, "leases are not supported");
3910 }
3911
3912 /* Connect 2nd connection */
3913 transport2_options = transport1->options;
3914 transport2_options.client_guid = GUID_random();
3915 if (!torture_smb2_connection_ext(tctx, 0, &transport2_options, &tree2)) {
3916 torture_warning(tctx, "couldn't reconnect, bailing\n");
3917 return false;
3918 }
3919 transport2 = tree2->session->transport;
3920
3921 /* Set lease handlers */
3922 transport1->lease.handler = torture_lease_handler;
3923 transport1->lease.private_data = tree1;
3924 transport2->lease.handler = torture_lease_handler;
3925 transport2->lease.private_data = tree2;
3926
3927
3928 smb2_lease_create(&io1, &ls1, false, fname, LEASE1,
3929 smb2_util_lease_state("RHW"));
3930 smb2_lease_create(&io2, &ls2, false, fname, LEASE2,
3931 smb2_util_lease_state("RHW"));
3932
3933 smb2_util_unlink(tree1, fname);
3934
3935 torture_comment(tctx, "Client opens fname with session 1\n");
3936 torture_reset_lease_break_info(tctx, &lease_break_info);
3937 status = smb2_create(tree1, mem_ctx, &io1);
3938 CHECK_STATUS(status, NT_STATUS_OK);
3939 h1 = io1.out.file.handle;
3940 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3941 CHECK_LEASE(&io1, "RHW", true, LEASE1, 0);
3942 CHECK_VAL(lease_break_info.count, 0);
3943
3944 torture_comment(tctx, "Client opens fname with session 2\n");
3945 torture_reset_lease_break_info(tctx, &lease_break_info);
3946 status = smb2_create(tree2, mem_ctx, &io2);
3947 CHECK_STATUS(status, NT_STATUS_OK);
3948 h2 = io2.out.file.handle;
3949 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3950 CHECK_LEASE(&io2, "RH", true, LEASE2, 0);
3951 CHECK_VAL(lease_break_info.count, 1);
3952 CHECK_BREAK_INFO("RHW", "RH", LEASE1);
3953
3954 torture_comment(tctx,
3955 "Client closes and then unlinks fname with session 2\n");
3956 torture_reset_lease_break_info(tctx, &lease_break_info);
3957 smb2_util_close(tree2, h2);
3958 smb2_util_unlink(tree2, fname);
3959 CHECK_VAL(lease_break_info.count, 1);
3960 CHECK_BREAK_INFO("RH", "R", LEASE1);
3961
3962 done:
3963 smb2_util_close(tree1, h1);
3964 smb2_util_close(tree2, h2);
3965 smb2_util_unlink(tree1, fname);
3966
3967 return ret;
3968 }
3969
torture_smb2_lease_init(TALLOC_CTX * ctx)3970 struct torture_suite *torture_smb2_lease_init(TALLOC_CTX *ctx)
3971 {
3972 struct torture_suite *suite =
3973 torture_suite_create(ctx, "lease");
3974
3975 torture_suite_add_1smb2_test(suite, "request", test_lease_request);
3976 torture_suite_add_1smb2_test(suite, "break_twice",
3977 test_lease_break_twice);
3978 torture_suite_add_1smb2_test(suite, "nobreakself",
3979 test_lease_nobreakself);
3980 torture_suite_add_1smb2_test(suite, "statopen", test_lease_statopen);
3981 torture_suite_add_1smb2_test(suite, "statopen2", test_lease_statopen2);
3982 torture_suite_add_1smb2_test(suite, "statopen3", test_lease_statopen3);
3983 torture_suite_add_1smb2_test(suite, "upgrade", test_lease_upgrade);
3984 torture_suite_add_1smb2_test(suite, "upgrade2", test_lease_upgrade2);
3985 torture_suite_add_1smb2_test(suite, "upgrade3", test_lease_upgrade3);
3986 torture_suite_add_1smb2_test(suite, "break", test_lease_break);
3987 torture_suite_add_1smb2_test(suite, "oplock", test_lease_oplock);
3988 torture_suite_add_1smb2_test(suite, "multibreak", test_lease_multibreak);
3989 torture_suite_add_1smb2_test(suite, "breaking1", test_lease_breaking1);
3990 torture_suite_add_1smb2_test(suite, "breaking2", test_lease_breaking2);
3991 torture_suite_add_1smb2_test(suite, "breaking3", test_lease_breaking3);
3992 torture_suite_add_1smb2_test(suite, "v2_breaking3", test_lease_v2_breaking3);
3993 torture_suite_add_1smb2_test(suite, "breaking4", test_lease_breaking4);
3994 torture_suite_add_1smb2_test(suite, "breaking5", test_lease_breaking5);
3995 torture_suite_add_1smb2_test(suite, "breaking6", test_lease_breaking6);
3996 torture_suite_add_2smb2_test(suite, "lock1", test_lease_lock1);
3997 torture_suite_add_1smb2_test(suite, "complex1", test_lease_complex1);
3998 torture_suite_add_1smb2_test(suite, "v2_request_parent",
3999 test_lease_v2_request_parent);
4000 torture_suite_add_1smb2_test(suite, "v2_request", test_lease_v2_request);
4001 torture_suite_add_1smb2_test(suite, "v2_epoch1", test_lease_v2_epoch1);
4002 torture_suite_add_1smb2_test(suite, "v2_epoch2", test_lease_v2_epoch2);
4003 torture_suite_add_1smb2_test(suite, "v2_epoch3", test_lease_v2_epoch3);
4004 torture_suite_add_1smb2_test(suite, "v2_complex1", test_lease_v2_complex1);
4005 torture_suite_add_1smb2_test(suite, "v2_complex2", test_lease_v2_complex2);
4006 torture_suite_add_1smb2_test(suite, "v2_rename", test_lease_v2_rename);
4007 torture_suite_add_1smb2_test(suite, "dynamic_share", test_lease_dynamic_share);
4008 torture_suite_add_1smb2_test(suite, "timeout", test_lease_timeout);
4009 torture_suite_add_1smb2_test(suite, "unlink", test_lease_unlink);
4010
4011 suite->description = talloc_strdup(suite, "SMB2-LEASE tests");
4012
4013 return suite;
4014 }
4015