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