Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : SMB2 lock test suite
5 :
6 : Copyright (C) Stefan Metzmacher 2006
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 "libcli/smb2/smb2.h"
24 : #include "libcli/smb2/smb2_calls.h"
25 : #include "../libcli/smb/smbXcli_base.h"
26 :
27 : #include "torture/torture.h"
28 : #include "torture/smb2/proto.h"
29 : #include "torture/util.h"
30 :
31 : #include "lib/events/events.h"
32 : #include "param/param.h"
33 :
34 : #define CHECK_STATUS(status, correct) do { \
35 : const char *_cmt = "(" __location__ ")"; \
36 : torture_assert_ntstatus_equal_goto(torture,status,correct, \
37 : ret,done,_cmt); \
38 : } while (0)
39 :
40 : #define CHECK_STATUS_CMT(status, correct, cmt) do { \
41 : torture_assert_ntstatus_equal_goto(torture,status,correct, \
42 : ret,done,cmt); \
43 : } while (0)
44 :
45 : #define CHECK_STATUS_CONT(status, correct) do { \
46 : if (!NT_STATUS_EQUAL(status, correct)) { \
47 : torture_result(torture, TORTURE_FAIL, \
48 : "(%s) Incorrect status %s - should be %s\n", \
49 : __location__, nt_errstr(status), nt_errstr(correct)); \
50 : ret = false; \
51 : }} while (0)
52 :
53 : #define CHECK_VALUE(v, correct) do { \
54 : const char *_cmt = "(" __location__ ")"; \
55 : torture_assert_int_equal_goto(torture,v,correct,ret,done,_cmt); \
56 : } while (0)
57 :
58 : #define BASEDIR "testlock"
59 :
60 : #define TARGET_SUPPORTS_INVALID_LOCK_RANGE(_tctx) \
61 : (torture_setting_bool(_tctx, "invalid_lock_range_support", true))
62 : #define TARGET_IS_W2K8(_tctx) (torture_setting_bool(_tctx, "w2k8", false))
63 :
64 : #define WAIT_FOR_ASYNC_RESPONSE(req) \
65 : while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \
66 : if (tevent_loop_once(torture->ev) != 0) { \
67 : break; \
68 : } \
69 : }
70 :
71 5 : static bool test_valid_request(struct torture_context *torture,
72 : struct smb2_tree *tree)
73 : {
74 5 : bool ret = true;
75 0 : NTSTATUS status;
76 0 : struct smb2_handle h;
77 0 : uint8_t buf[200];
78 0 : struct smb2_lock lck;
79 0 : struct smb2_lock_element el[2];
80 :
81 5 : ZERO_STRUCT(buf);
82 :
83 5 : status = torture_smb2_testfile(tree, "lock1.txt", &h);
84 5 : CHECK_STATUS(status, NT_STATUS_OK);
85 :
86 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
87 5 : CHECK_STATUS(status, NT_STATUS_OK);
88 :
89 5 : lck.in.locks = el;
90 :
91 5 : torture_comment(torture, "Test request with 0 locks.\n");
92 :
93 5 : lck.in.lock_count = 0x0000;
94 5 : lck.in.lock_sequence = 0x00000000;
95 5 : lck.in.file.handle = h;
96 5 : el[0].offset = 0x0000000000000000;
97 5 : el[0].length = 0x0000000000000000;
98 5 : el[0].reserved = 0x0000000000000000;
99 5 : el[0].flags = 0x00000000;
100 5 : status = smb2_lock(tree, &lck);
101 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
102 :
103 5 : lck.in.lock_count = 0x0000;
104 5 : lck.in.lock_sequence = 0x00000000;
105 5 : lck.in.file.handle = h;
106 5 : el[0].offset = 0;
107 5 : el[0].length = 0;
108 5 : el[0].reserved = 0x00000000;
109 5 : el[0].flags = SMB2_LOCK_FLAG_SHARED;
110 5 : status = smb2_lock(tree, &lck);
111 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
112 :
113 5 : lck.in.lock_count = 0x0001;
114 5 : lck.in.lock_sequence = 0x00000000;
115 5 : lck.in.file.handle = h;
116 5 : el[0].offset = 0;
117 5 : el[0].length = 0;
118 5 : el[0].reserved = 0x00000000;
119 5 : el[0].flags = SMB2_LOCK_FLAG_NONE;
120 5 : status = smb2_lock(tree, &lck);
121 5 : if (TARGET_IS_W2K8(torture)) {
122 0 : CHECK_STATUS(status, NT_STATUS_OK);
123 0 : torture_warning(torture, "Target has bug validating lock flags "
124 : "parameter.\n");
125 : } else {
126 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
127 : }
128 :
129 5 : torture_comment(torture, "Test >63-bit lock requests.\n");
130 :
131 5 : lck.in.file.handle.data[0] +=1;
132 5 : status = smb2_lock(tree, &lck);
133 5 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
134 5 : lck.in.file.handle.data[0] -=1;
135 :
136 5 : lck.in.lock_count = 0x0001;
137 5 : lck.in.lock_sequence = 0x123ab1;
138 5 : lck.in.file.handle = h;
139 5 : el[0].offset = UINT64_MAX;
140 5 : el[0].length = UINT64_MAX;
141 5 : el[0].reserved = 0x00000000;
142 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
143 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
144 5 : status = smb2_lock(tree, &lck);
145 5 : if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(torture)) {
146 5 : CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
147 : } else {
148 0 : CHECK_STATUS(status, NT_STATUS_OK);
149 0 : CHECK_VALUE(lck.out.reserved, 0);
150 : }
151 :
152 5 : lck.in.lock_sequence = 0x123ab2;
153 5 : status = smb2_lock(tree, &lck);
154 5 : if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(torture)) {
155 5 : CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
156 : } else {
157 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
158 : }
159 :
160 5 : torture_comment(torture, "Test basic lock stacking.\n");
161 :
162 5 : lck.in.lock_count = 0x0001;
163 5 : lck.in.lock_sequence = 0x12345678;
164 5 : lck.in.file.handle = h;
165 5 : el[0].offset = UINT32_MAX;
166 5 : el[0].length = UINT32_MAX;
167 5 : el[0].reserved = 0x87654321;
168 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
169 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
170 5 : status = smb2_lock(tree, &lck);
171 5 : CHECK_STATUS(status, NT_STATUS_OK);
172 5 : CHECK_VALUE(lck.out.reserved, 0);
173 :
174 5 : el[0].flags = SMB2_LOCK_FLAG_SHARED;
175 5 : status = smb2_lock(tree, &lck);
176 5 : CHECK_STATUS(status, NT_STATUS_OK);
177 5 : CHECK_VALUE(lck.out.reserved, 0);
178 :
179 5 : status = smb2_lock(tree, &lck);
180 5 : CHECK_STATUS(status, NT_STATUS_OK);
181 5 : CHECK_VALUE(lck.out.reserved, 0);
182 :
183 5 : lck.in.lock_count = 0x0001;
184 5 : lck.in.lock_sequence = 0x87654321;
185 5 : lck.in.file.handle = h;
186 5 : el[0].offset = 0x00000000FFFFFFFF;
187 5 : el[0].length = 0x00000000FFFFFFFF;
188 5 : el[0].reserved = 0x1234567;
189 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
190 5 : status = smb2_lock(tree, &lck);
191 5 : CHECK_STATUS(status, NT_STATUS_OK);
192 :
193 5 : lck.in.lock_count = 0x0001;
194 5 : lck.in.lock_sequence = 0x1234567;
195 5 : lck.in.file.handle = h;
196 5 : el[0].offset = 0x00000000FFFFFFFF;
197 5 : el[0].length = 0x00000000FFFFFFFF;
198 5 : el[0].reserved = 0x00000000;
199 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
200 5 : status = smb2_lock(tree, &lck);
201 5 : CHECK_STATUS(status, NT_STATUS_OK);
202 :
203 5 : status = smb2_lock(tree, &lck);
204 5 : CHECK_STATUS(status, NT_STATUS_OK);
205 5 : status = smb2_lock(tree, &lck);
206 5 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
207 :
208 5 : torture_comment(torture, "Test flags field permutations.\n");
209 :
210 5 : lck.in.lock_count = 0x0001;
211 5 : lck.in.lock_sequence = 0;
212 5 : lck.in.file.handle = h;
213 5 : el[0].offset = 1;
214 5 : el[0].length = 1;
215 5 : el[0].reserved = 0x00000000;
216 5 : el[0].flags = ~SMB2_LOCK_FLAG_ALL_MASK;
217 :
218 5 : status = smb2_lock(tree, &lck);
219 5 : if (TARGET_IS_W2K8(torture)) {
220 0 : CHECK_STATUS(status, NT_STATUS_OK);
221 0 : torture_warning(torture, "Target has bug validating lock flags "
222 : "parameter.\n");
223 : } else {
224 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
225 : }
226 :
227 5 : if (TARGET_IS_W2K8(torture)) {
228 0 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
229 0 : status = smb2_lock(tree, &lck);
230 0 : CHECK_STATUS(status, NT_STATUS_OK);
231 : }
232 :
233 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
234 5 : status = smb2_lock(tree, &lck);
235 5 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
236 :
237 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK |
238 : SMB2_LOCK_FLAG_EXCLUSIVE;
239 5 : status = smb2_lock(tree, &lck);
240 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
241 :
242 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK |
243 : SMB2_LOCK_FLAG_SHARED;
244 5 : status = smb2_lock(tree, &lck);
245 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
246 :
247 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK |
248 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
249 5 : status = smb2_lock(tree, &lck);
250 5 : if (TARGET_IS_W2K8(torture)) {
251 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
252 0 : torture_warning(torture, "Target has bug validating lock flags "
253 : "parameter.\n");
254 : } else {
255 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
256 : }
257 :
258 5 : torture_comment(torture, "Test return error when 2 locks are "
259 : "requested\n");
260 :
261 5 : lck.in.lock_count = 2;
262 5 : lck.in.lock_sequence = 0;
263 5 : lck.in.file.handle = h;
264 5 : el[0].offset = 9999;
265 5 : el[0].length = 1;
266 5 : el[0].reserved = 0x00000000;
267 5 : el[1].offset = 9999;
268 5 : el[1].length = 1;
269 5 : el[1].reserved = 0x00000000;
270 :
271 5 : lck.in.lock_count = 2;
272 5 : el[0].flags = 0;
273 5 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
274 5 : status = smb2_lock(tree, &lck);
275 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
276 :
277 5 : lck.in.lock_count = 2;
278 5 : el[0].flags = SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
279 5 : el[1].flags = SMB2_LOCK_FLAG_SHARED;
280 5 : status = smb2_lock(tree, &lck);
281 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
282 :
283 4 : lck.in.lock_count = 2;
284 4 : el[0].flags = 0;
285 4 : el[1].flags = 0;
286 4 : status = smb2_lock(tree, &lck);
287 4 : if (TARGET_IS_W2K8(torture)) {
288 0 : CHECK_STATUS(status, NT_STATUS_OK);
289 0 : torture_warning(torture, "Target has bug validating lock flags "
290 : "parameter.\n");
291 : } else {
292 4 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
293 : }
294 :
295 4 : lck.in.lock_count = 2;
296 4 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
297 4 : el[1].flags = 0;
298 4 : status = smb2_lock(tree, &lck);
299 4 : if (TARGET_IS_W2K8(torture)) {
300 0 : CHECK_STATUS(status, NT_STATUS_OK);
301 0 : torture_warning(torture, "Target has bug validating lock flags "
302 : "parameter.\n");
303 : } else {
304 4 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
305 : }
306 :
307 4 : lck.in.lock_count = 1;
308 4 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
309 4 : status = smb2_lock(tree, &lck);
310 4 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
311 :
312 4 : lck.in.lock_count = 1;
313 4 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
314 4 : status = smb2_lock(tree, &lck);
315 4 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
316 :
317 4 : lck.in.lock_count = 1;
318 4 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
319 4 : status = smb2_lock(tree, &lck);
320 4 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
321 :
322 4 : lck.in.lock_count = 1;
323 4 : el[0].flags = SMB2_LOCK_FLAG_SHARED;
324 4 : status = smb2_lock(tree, &lck);
325 4 : CHECK_STATUS(status, NT_STATUS_OK);
326 :
327 4 : status = smb2_lock(tree, &lck);
328 4 : CHECK_STATUS(status, NT_STATUS_OK);
329 :
330 4 : lck.in.lock_count = 2;
331 4 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
332 4 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
333 4 : status = smb2_lock(tree, &lck);
334 4 : CHECK_STATUS(status, NT_STATUS_OK);
335 :
336 4 : lck.in.lock_count = 1;
337 4 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
338 4 : status = smb2_lock(tree, &lck);
339 4 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
340 :
341 5 : done:
342 5 : return ret;
343 : }
344 :
345 : struct test_lock_read_write_state {
346 : const char *fname;
347 : uint32_t lock_flags;
348 : NTSTATUS write_h1_status;
349 : NTSTATUS read_h1_status;
350 : NTSTATUS write_h2_status;
351 : NTSTATUS read_h2_status;
352 : };
353 :
354 10 : static bool test_lock_read_write(struct torture_context *torture,
355 : struct smb2_tree *tree,
356 : struct test_lock_read_write_state *s)
357 : {
358 10 : bool ret = true;
359 0 : NTSTATUS status;
360 0 : struct smb2_handle h1, h2;
361 0 : uint8_t buf[200];
362 0 : struct smb2_lock lck;
363 0 : struct smb2_create cr;
364 0 : struct smb2_write wr;
365 0 : struct smb2_read rd;
366 0 : struct smb2_lock_element el[1];
367 :
368 10 : lck.in.locks = el;
369 :
370 10 : ZERO_STRUCT(buf);
371 :
372 10 : status = torture_smb2_testfile(tree, s->fname, &h1);
373 10 : CHECK_STATUS(status, NT_STATUS_OK);
374 :
375 10 : status = smb2_util_write(tree, h1, buf, 0, ARRAY_SIZE(buf));
376 10 : CHECK_STATUS(status, NT_STATUS_OK);
377 :
378 10 : lck.in.lock_count = 0x0001;
379 10 : lck.in.lock_sequence = 0x00000000;
380 10 : lck.in.file.handle = h1;
381 10 : el[0].offset = 0;
382 10 : el[0].length = ARRAY_SIZE(buf)/2;
383 10 : el[0].reserved = 0x00000000;
384 10 : el[0].flags = s->lock_flags;
385 10 : status = smb2_lock(tree, &lck);
386 10 : CHECK_STATUS(status, NT_STATUS_OK);
387 10 : CHECK_VALUE(lck.out.reserved, 0);
388 :
389 10 : lck.in.lock_count = 0x0001;
390 10 : lck.in.lock_sequence = 0x00000000;
391 10 : lck.in.file.handle = h1;
392 10 : el[0].offset = ARRAY_SIZE(buf)/2;
393 10 : el[0].length = ARRAY_SIZE(buf)/2;
394 10 : el[0].reserved = 0x00000000;
395 10 : el[0].flags = s->lock_flags;
396 10 : status = smb2_lock(tree, &lck);
397 10 : CHECK_STATUS(status, NT_STATUS_OK);
398 10 : CHECK_VALUE(lck.out.reserved, 0);
399 :
400 10 : ZERO_STRUCT(cr);
401 10 : cr.in.oplock_level = 0;
402 10 : cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
403 10 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
404 10 : cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
405 10 : cr.in.share_access =
406 : NTCREATEX_SHARE_ACCESS_DELETE|
407 : NTCREATEX_SHARE_ACCESS_READ|
408 : NTCREATEX_SHARE_ACCESS_WRITE;
409 10 : cr.in.create_options = 0;
410 10 : cr.in.fname = s->fname;
411 :
412 10 : status = smb2_create(tree, tree, &cr);
413 10 : CHECK_STATUS(status, NT_STATUS_OK);
414 :
415 10 : h2 = cr.out.file.handle;
416 :
417 10 : ZERO_STRUCT(wr);
418 10 : wr.in.file.handle = h1;
419 10 : wr.in.offset = ARRAY_SIZE(buf)/2;
420 10 : wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
421 :
422 10 : status = smb2_write(tree, &wr);
423 10 : CHECK_STATUS(status, s->write_h1_status);
424 :
425 10 : ZERO_STRUCT(rd);
426 10 : rd.in.file.handle = h1;
427 10 : rd.in.offset = ARRAY_SIZE(buf)/2;
428 10 : rd.in.length = ARRAY_SIZE(buf)/2;
429 :
430 10 : status = smb2_read(tree, tree, &rd);
431 10 : CHECK_STATUS(status, s->read_h1_status);
432 :
433 10 : ZERO_STRUCT(wr);
434 10 : wr.in.file.handle = h2;
435 10 : wr.in.offset = ARRAY_SIZE(buf)/2;
436 10 : wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
437 :
438 10 : status = smb2_write(tree, &wr);
439 10 : CHECK_STATUS(status, s->write_h2_status);
440 :
441 10 : ZERO_STRUCT(rd);
442 10 : rd.in.file.handle = h2;
443 10 : rd.in.offset = ARRAY_SIZE(buf)/2;
444 10 : rd.in.length = ARRAY_SIZE(buf)/2;
445 :
446 10 : status = smb2_read(tree, tree, &rd);
447 10 : CHECK_STATUS(status, s->read_h2_status);
448 :
449 10 : lck.in.lock_count = 0x0001;
450 10 : lck.in.lock_sequence = 0x00000000;
451 10 : lck.in.file.handle = h1;
452 10 : el[0].offset = ARRAY_SIZE(buf)/2;
453 10 : el[0].length = ARRAY_SIZE(buf)/2;
454 10 : el[0].reserved = 0x00000000;
455 10 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
456 10 : status = smb2_lock(tree, &lck);
457 10 : CHECK_STATUS(status, NT_STATUS_OK);
458 10 : CHECK_VALUE(lck.out.reserved, 0);
459 :
460 10 : ZERO_STRUCT(wr);
461 10 : wr.in.file.handle = h2;
462 10 : wr.in.offset = ARRAY_SIZE(buf)/2;
463 10 : wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
464 :
465 10 : status = smb2_write(tree, &wr);
466 10 : CHECK_STATUS(status, NT_STATUS_OK);
467 :
468 10 : ZERO_STRUCT(rd);
469 10 : rd.in.file.handle = h2;
470 10 : rd.in.offset = ARRAY_SIZE(buf)/2;
471 10 : rd.in.length = ARRAY_SIZE(buf)/2;
472 :
473 10 : status = smb2_read(tree, tree, &rd);
474 10 : CHECK_STATUS(status, NT_STATUS_OK);
475 :
476 10 : done:
477 10 : return ret;
478 : }
479 :
480 5 : static bool test_lock_rw_none(struct torture_context *torture,
481 : struct smb2_tree *tree)
482 : {
483 5 : struct test_lock_read_write_state s = {
484 : .fname = "lock_rw_none.dat",
485 : .lock_flags = SMB2_LOCK_FLAG_NONE,
486 : .write_h1_status = NT_STATUS_FILE_LOCK_CONFLICT,
487 : .read_h1_status = NT_STATUS_OK,
488 : .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
489 : .read_h2_status = NT_STATUS_OK,
490 : };
491 :
492 5 : if (!TARGET_IS_W2K8(torture)) {
493 5 : torture_skip(torture, "RW-NONE tests the behavior of a "
494 : "NONE-type lock, which is the same as a SHARED "
495 : "lock but is granted due to a bug in W2K8. If "
496 : "target is not W2K8 we skip this test.\n");
497 : }
498 :
499 0 : return test_lock_read_write(torture, tree, &s);
500 : }
501 :
502 5 : static bool test_lock_rw_shared(struct torture_context *torture,
503 : struct smb2_tree *tree)
504 : {
505 5 : struct test_lock_read_write_state s = {
506 : .fname = "lock_rw_shared.dat",
507 : .lock_flags = SMB2_LOCK_FLAG_SHARED,
508 : .write_h1_status = NT_STATUS_FILE_LOCK_CONFLICT,
509 : .read_h1_status = NT_STATUS_OK,
510 : .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
511 : .read_h2_status = NT_STATUS_OK,
512 : };
513 :
514 5 : return test_lock_read_write(torture, tree, &s);
515 : }
516 :
517 5 : static bool test_lock_rw_exclusive(struct torture_context *torture,
518 : struct smb2_tree *tree)
519 : {
520 5 : struct test_lock_read_write_state s = {
521 : .fname = "lock_rw_exclusive.dat",
522 : .lock_flags = SMB2_LOCK_FLAG_EXCLUSIVE,
523 : .write_h1_status = NT_STATUS_OK,
524 : .read_h1_status = NT_STATUS_OK,
525 : .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
526 : .read_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
527 : };
528 :
529 5 : return test_lock_read_write(torture, tree, &s);
530 : }
531 :
532 5 : static bool test_lock_auto_unlock(struct torture_context *torture,
533 : struct smb2_tree *tree)
534 : {
535 5 : bool ret = true;
536 0 : NTSTATUS status;
537 0 : struct smb2_handle h;
538 0 : uint8_t buf[200];
539 0 : struct smb2_lock lck;
540 0 : struct smb2_lock_element el[1];
541 :
542 5 : ZERO_STRUCT(buf);
543 :
544 5 : status = torture_smb2_testfile(tree, "autounlock.txt", &h);
545 5 : CHECK_STATUS(status, NT_STATUS_OK);
546 :
547 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
548 5 : CHECK_STATUS(status, NT_STATUS_OK);
549 :
550 5 : ZERO_STRUCT(lck);
551 5 : ZERO_STRUCT(el[0]);
552 5 : lck.in.locks = el;
553 5 : lck.in.lock_count = 0x0001;
554 5 : lck.in.file.handle = h;
555 5 : el[0].offset = 0;
556 5 : el[0].length = 1;
557 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
558 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
559 5 : status = smb2_lock(tree, &lck);
560 5 : CHECK_STATUS(status, NT_STATUS_OK);
561 :
562 5 : status = smb2_lock(tree, &lck);
563 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
564 :
565 5 : status = smb2_lock(tree, &lck);
566 5 : if (TARGET_IS_W2K8(torture)) {
567 0 : CHECK_STATUS(status, NT_STATUS_OK);
568 0 : torture_warning(torture, "Target has \"pretty please\" bug. "
569 : "A contending lock request on the same handle "
570 : "unlocks the lock.\n");
571 : } else {
572 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
573 : }
574 :
575 5 : status = smb2_lock(tree, &lck);
576 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
577 :
578 5 : done:
579 5 : return ret;
580 : }
581 :
582 : /*
583 : test different lock ranges and see if different handles conflict
584 : */
585 5 : static bool test_lock(struct torture_context *torture,
586 : struct smb2_tree *tree)
587 : {
588 0 : NTSTATUS status;
589 5 : bool ret = true;
590 5 : struct smb2_handle h = {{0}};
591 5 : struct smb2_handle h2 = {{0}};
592 0 : uint8_t buf[200];
593 0 : struct smb2_lock lck;
594 0 : struct smb2_lock_element el[2];
595 :
596 5 : const char *fname = BASEDIR "\\async.txt";
597 :
598 5 : status = torture_smb2_testdir(tree, BASEDIR, &h);
599 5 : CHECK_STATUS(status, NT_STATUS_OK);
600 5 : smb2_util_close(tree, h);
601 :
602 5 : status = torture_smb2_testfile(tree, fname, &h);
603 5 : CHECK_STATUS(status, NT_STATUS_OK);
604 :
605 5 : ZERO_STRUCT(buf);
606 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
607 5 : CHECK_STATUS(status, NT_STATUS_OK);
608 :
609 5 : status = torture_smb2_testfile(tree, fname, &h2);
610 5 : CHECK_STATUS(status, NT_STATUS_OK);
611 :
612 5 : lck.in.locks = el;
613 :
614 5 : lck.in.lock_count = 0x0001;
615 5 : lck.in.lock_sequence = 0x00000000;
616 5 : lck.in.file.handle = h;
617 5 : el[0].reserved = 0x00000000;
618 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
619 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
620 :
621 5 : torture_comment(torture, "Trying 0/0 lock\n");
622 5 : el[0].offset = 0x0000000000000000;
623 5 : el[0].length = 0x0000000000000000;
624 5 : status = smb2_lock(tree, &lck);
625 5 : CHECK_STATUS(status, NT_STATUS_OK);
626 5 : lck.in.file.handle = h2;
627 5 : status = smb2_lock(tree, &lck);
628 5 : CHECK_STATUS(status, NT_STATUS_OK);
629 5 : lck.in.file.handle = h;
630 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
631 5 : status = smb2_lock(tree, &lck);
632 5 : CHECK_STATUS(status, NT_STATUS_OK);
633 :
634 5 : torture_comment(torture, "Trying 0/1 lock\n");
635 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
636 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
637 5 : el[0].offset = 0x0000000000000000;
638 5 : el[0].length = 0x0000000000000001;
639 5 : status = smb2_lock(tree, &lck);
640 5 : CHECK_STATUS(status, NT_STATUS_OK);
641 5 : lck.in.file.handle = h2;
642 5 : status = smb2_lock(tree, &lck);
643 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
644 5 : lck.in.file.handle = h;
645 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
646 5 : status = smb2_lock(tree, &lck);
647 5 : CHECK_STATUS(status, NT_STATUS_OK);
648 5 : status = smb2_lock(tree, &lck);
649 5 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
650 :
651 5 : torture_comment(torture, "Trying 0xEEFFFFF lock\n");
652 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
653 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
654 5 : el[0].offset = 0xEEFFFFFF;
655 5 : el[0].length = 4000;
656 5 : status = smb2_lock(tree, &lck);
657 5 : CHECK_STATUS(status, NT_STATUS_OK);
658 5 : lck.in.file.handle = h2;
659 5 : status = smb2_lock(tree, &lck);
660 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
661 5 : lck.in.file.handle = h;
662 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
663 5 : status = smb2_lock(tree, &lck);
664 5 : CHECK_STATUS(status, NT_STATUS_OK);
665 5 : status = smb2_lock(tree, &lck);
666 5 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
667 :
668 5 : torture_comment(torture, "Trying 0xEF00000 lock\n");
669 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
670 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
671 5 : el[0].offset = 0xEF000000;
672 5 : el[0].length = 4000;
673 5 : status = smb2_lock(tree, &lck);
674 5 : CHECK_STATUS(status, NT_STATUS_OK);
675 5 : lck.in.file.handle = h2;
676 5 : status = smb2_lock(tree, &lck);
677 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
678 5 : lck.in.file.handle = h;
679 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
680 5 : status = smb2_lock(tree, &lck);
681 5 : CHECK_STATUS(status, NT_STATUS_OK);
682 5 : status = smb2_lock(tree, &lck);
683 5 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
684 :
685 5 : torture_comment(torture, "Trying (2^63 - 1)/1\n");
686 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
687 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
688 5 : el[0].offset = 1;
689 5 : el[0].offset <<= 63;
690 5 : el[0].offset--;
691 5 : el[0].length = 1;
692 5 : status = smb2_lock(tree, &lck);
693 5 : CHECK_STATUS(status, NT_STATUS_OK);
694 5 : lck.in.file.handle = h2;
695 5 : status = smb2_lock(tree, &lck);
696 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
697 5 : lck.in.file.handle = h;
698 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
699 5 : status = smb2_lock(tree, &lck);
700 5 : CHECK_STATUS(status, NT_STATUS_OK);
701 5 : status = smb2_lock(tree, &lck);
702 5 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
703 :
704 5 : torture_comment(torture, "Trying 2^63/1\n");
705 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
706 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
707 5 : el[0].offset = 1;
708 5 : el[0].offset <<= 63;
709 5 : el[0].length = 1;
710 5 : status = smb2_lock(tree, &lck);
711 5 : CHECK_STATUS(status, NT_STATUS_OK);
712 5 : lck.in.file.handle = h2;
713 5 : status = smb2_lock(tree, &lck);
714 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
715 5 : lck.in.file.handle = h;
716 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
717 5 : status = smb2_lock(tree, &lck);
718 5 : CHECK_STATUS(status, NT_STATUS_OK);
719 5 : status = smb2_lock(tree, &lck);
720 5 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
721 :
722 5 : torture_comment(torture, "Trying max/0 lock\n");
723 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
724 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
725 5 : el[0].offset = ~0;
726 5 : el[0].length = 0;
727 5 : status = smb2_lock(tree, &lck);
728 5 : CHECK_STATUS(status, NT_STATUS_OK);
729 5 : lck.in.file.handle = h2;
730 5 : status = smb2_lock(tree, &lck);
731 5 : CHECK_STATUS(status, NT_STATUS_OK);
732 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
733 5 : status = smb2_lock(tree, &lck);
734 5 : CHECK_STATUS(status, NT_STATUS_OK);
735 5 : lck.in.file.handle = h;
736 5 : status = smb2_lock(tree, &lck);
737 5 : CHECK_STATUS(status, NT_STATUS_OK);
738 5 : status = smb2_lock(tree, &lck);
739 5 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
740 :
741 5 : torture_comment(torture, "Trying max/1 lock\n");
742 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
743 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
744 5 : el[0].offset = ~0;
745 5 : el[0].length = 1;
746 5 : status = smb2_lock(tree, &lck);
747 5 : CHECK_STATUS(status, NT_STATUS_OK);
748 5 : lck.in.file.handle = h2;
749 5 : status = smb2_lock(tree, &lck);
750 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
751 5 : lck.in.file.handle = h;
752 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
753 5 : status = smb2_lock(tree, &lck);
754 5 : CHECK_STATUS(status, NT_STATUS_OK);
755 5 : status = smb2_lock(tree, &lck);
756 5 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
757 :
758 5 : torture_comment(torture, "Trying max/2 lock\n");
759 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
760 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
761 5 : el[0].offset = ~0;
762 5 : el[0].length = 2;
763 5 : status = smb2_lock(tree, &lck);
764 5 : if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(torture)) {
765 5 : CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
766 : } else {
767 0 : CHECK_STATUS(status, NT_STATUS_OK);
768 0 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
769 0 : status = smb2_lock(tree, &lck);
770 0 : CHECK_STATUS(status, NT_STATUS_OK);
771 : }
772 :
773 5 : torture_comment(torture, "Trying wrong handle unlock\n");
774 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
775 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
776 5 : el[0].offset = 10001;
777 5 : el[0].length = 40002;
778 5 : status = smb2_lock(tree, &lck);
779 5 : CHECK_STATUS(status, NT_STATUS_OK);
780 5 : lck.in.file.handle = h2;
781 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
782 5 : status = smb2_lock(tree, &lck);
783 5 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
784 5 : lck.in.file.handle = h;
785 5 : status = smb2_lock(tree, &lck);
786 5 : CHECK_STATUS(status, NT_STATUS_OK);
787 :
788 5 : done:
789 5 : smb2_util_close(tree, h2);
790 5 : smb2_util_close(tree, h);
791 5 : smb2_deltree(tree, BASEDIR);
792 5 : return ret;
793 : }
794 :
795 : /*
796 : test SMB2 LOCK async operation
797 : */
798 5 : static bool test_async(struct torture_context *torture,
799 : struct smb2_tree *tree)
800 : {
801 0 : NTSTATUS status;
802 5 : bool ret = true;
803 5 : struct smb2_handle h = {{0}};
804 5 : struct smb2_handle h2 = {{0}};
805 0 : uint8_t buf[200];
806 0 : struct smb2_lock lck;
807 0 : struct smb2_lock_element el[2];
808 5 : struct smb2_request *req = NULL;
809 :
810 5 : const char *fname = BASEDIR "\\async.txt";
811 :
812 5 : status = torture_smb2_testdir(tree, BASEDIR, &h);
813 5 : CHECK_STATUS(status, NT_STATUS_OK);
814 5 : smb2_util_close(tree, h);
815 :
816 5 : status = torture_smb2_testfile(tree, fname, &h);
817 5 : CHECK_STATUS(status, NT_STATUS_OK);
818 :
819 5 : ZERO_STRUCT(buf);
820 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
821 5 : CHECK_STATUS(status, NT_STATUS_OK);
822 :
823 5 : status = torture_smb2_testfile(tree, fname, &h2);
824 5 : CHECK_STATUS(status, NT_STATUS_OK);
825 :
826 5 : lck.in.locks = el;
827 :
828 5 : lck.in.lock_count = 0x0001;
829 5 : lck.in.lock_sequence = 0x00000000;
830 5 : lck.in.file.handle = h;
831 5 : el[0].offset = 100;
832 5 : el[0].length = 50;
833 5 : el[0].reserved = 0x00000000;
834 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
835 :
836 5 : torture_comment(torture, " Acquire first lock\n");
837 5 : status = smb2_lock(tree, &lck);
838 5 : CHECK_STATUS(status, NT_STATUS_OK);
839 :
840 5 : torture_comment(torture, " Second lock should pend on first\n");
841 5 : lck.in.file.handle = h2;
842 5 : req = smb2_lock_send(tree, &lck);
843 25 : WAIT_FOR_ASYNC_RESPONSE(req);
844 :
845 5 : torture_comment(torture, " Unlock first lock\n");
846 5 : lck.in.file.handle = h;
847 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
848 5 : status = smb2_lock(tree, &lck);
849 5 : CHECK_STATUS(status, NT_STATUS_OK);
850 :
851 5 : torture_comment(torture, " Second lock should now succeed\n");
852 5 : lck.in.file.handle = h2;
853 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
854 5 : status = smb2_lock_recv(req, &lck);
855 5 : CHECK_STATUS(status, NT_STATUS_OK);
856 :
857 5 : done:
858 5 : smb2_util_close(tree, h2);
859 5 : smb2_util_close(tree, h);
860 5 : smb2_deltree(tree, BASEDIR);
861 5 : return ret;
862 : }
863 :
864 : /*
865 : test SMB2 LOCK Cancel operation
866 : */
867 5 : static bool test_cancel(struct torture_context *torture,
868 : struct smb2_tree *tree)
869 : {
870 0 : NTSTATUS status;
871 5 : bool ret = true;
872 5 : struct smb2_handle h = {{0}};
873 5 : struct smb2_handle h2 = {{0}};
874 0 : uint8_t buf[200];
875 0 : struct smb2_lock lck;
876 0 : struct smb2_lock_element el[2];
877 5 : struct smb2_request *req = NULL;
878 :
879 5 : const char *fname = BASEDIR "\\cancel.txt";
880 :
881 5 : status = torture_smb2_testdir(tree, BASEDIR, &h);
882 5 : CHECK_STATUS(status, NT_STATUS_OK);
883 5 : smb2_util_close(tree, h);
884 :
885 5 : status = torture_smb2_testfile(tree, fname, &h);
886 5 : CHECK_STATUS(status, NT_STATUS_OK);
887 :
888 5 : ZERO_STRUCT(buf);
889 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
890 5 : CHECK_STATUS(status, NT_STATUS_OK);
891 :
892 5 : status = torture_smb2_testfile(tree, fname, &h2);
893 5 : CHECK_STATUS(status, NT_STATUS_OK);
894 :
895 5 : lck.in.locks = el;
896 :
897 5 : lck.in.lock_count = 0x0001;
898 5 : lck.in.lock_sequence = 0x00000000;
899 5 : lck.in.file.handle = h;
900 5 : el[0].offset = 100;
901 5 : el[0].length = 10;
902 5 : el[0].reserved = 0x00000000;
903 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
904 :
905 5 : torture_comment(torture, "Testing basic cancel\n");
906 :
907 5 : torture_comment(torture, " Acquire first lock\n");
908 5 : status = smb2_lock(tree, &lck);
909 5 : CHECK_STATUS(status, NT_STATUS_OK);
910 :
911 5 : torture_comment(torture, " Second lock should pend on first\n");
912 5 : lck.in.file.handle = h2;
913 5 : req = smb2_lock_send(tree, &lck);
914 25 : WAIT_FOR_ASYNC_RESPONSE(req);
915 :
916 5 : torture_comment(torture, " Cancel the second lock\n");
917 5 : smb2_cancel(req);
918 5 : lck.in.file.handle = h2;
919 5 : status = smb2_lock_recv(req, &lck);
920 5 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
921 :
922 5 : torture_comment(torture, " Unlock first lock\n");
923 5 : lck.in.file.handle = h;
924 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
925 5 : status = smb2_lock(tree, &lck);
926 5 : CHECK_STATUS(status, NT_STATUS_OK);
927 :
928 :
929 5 : torture_comment(torture, "Testing cancel by unlock\n");
930 :
931 5 : torture_comment(torture, " Acquire first lock\n");
932 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
933 5 : status = smb2_lock(tree, &lck);
934 5 : CHECK_STATUS(status, NT_STATUS_OK);
935 :
936 5 : torture_comment(torture, " Second lock should pend on first\n");
937 5 : lck.in.file.handle = h2;
938 5 : req = smb2_lock_send(tree, &lck);
939 25 : WAIT_FOR_ASYNC_RESPONSE(req);
940 :
941 5 : torture_comment(torture, " Attempt to unlock pending second lock\n");
942 5 : lck.in.file.handle = h2;
943 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
944 5 : status = smb2_lock(tree, &lck);
945 5 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
946 :
947 5 : torture_comment(torture, " Now cancel the second lock\n");
948 5 : smb2_cancel(req);
949 5 : lck.in.file.handle = h2;
950 5 : status = smb2_lock_recv(req, &lck);
951 5 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
952 :
953 5 : torture_comment(torture, " Unlock first lock\n");
954 5 : lck.in.file.handle = h;
955 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
956 5 : status = smb2_lock(tree, &lck);
957 5 : CHECK_STATUS(status, NT_STATUS_OK);
958 :
959 :
960 5 : torture_comment(torture, "Testing cancel by close\n");
961 :
962 5 : torture_comment(torture, " Acquire first lock\n");
963 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
964 5 : status = smb2_lock(tree, &lck);
965 5 : CHECK_STATUS(status, NT_STATUS_OK);
966 :
967 5 : torture_comment(torture, " Second lock should pend on first\n");
968 5 : lck.in.file.handle = h2;
969 5 : req = smb2_lock_send(tree, &lck);
970 25 : WAIT_FOR_ASYNC_RESPONSE(req);
971 :
972 5 : torture_comment(torture, " Close the second lock handle\n");
973 5 : smb2_util_close(tree, h2);
974 5 : CHECK_STATUS(status, NT_STATUS_OK);
975 :
976 5 : torture_comment(torture, " Check pending lock reply\n");
977 5 : status = smb2_lock_recv(req, &lck);
978 5 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
979 :
980 5 : torture_comment(torture, " Unlock first lock\n");
981 5 : lck.in.file.handle = h;
982 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
983 5 : status = smb2_lock(tree, &lck);
984 5 : CHECK_STATUS(status, NT_STATUS_OK);
985 :
986 5 : done:
987 5 : smb2_util_close(tree, h2);
988 5 : smb2_util_close(tree, h);
989 5 : smb2_deltree(tree, BASEDIR);
990 5 : return ret;
991 : }
992 :
993 : /*
994 : test SMB2 LOCK Cancel by tree disconnect
995 : */
996 5 : static bool test_cancel_tdis(struct torture_context *torture,
997 : struct smb2_tree *tree)
998 : {
999 0 : NTSTATUS status;
1000 5 : bool ret = true;
1001 5 : struct smb2_handle h = {{0}};
1002 5 : struct smb2_handle h2 = {{0}};
1003 0 : uint8_t buf[200];
1004 0 : struct smb2_lock lck;
1005 0 : struct smb2_lock_element el[2];
1006 5 : struct smb2_request *req = NULL;
1007 :
1008 5 : const char *fname = BASEDIR "\\cancel_tdis.txt";
1009 :
1010 5 : status = torture_smb2_testdir(tree, BASEDIR, &h);
1011 5 : CHECK_STATUS(status, NT_STATUS_OK);
1012 5 : smb2_util_close(tree, h);
1013 :
1014 5 : status = torture_smb2_testfile(tree, fname, &h);
1015 5 : CHECK_STATUS(status, NT_STATUS_OK);
1016 :
1017 5 : ZERO_STRUCT(buf);
1018 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
1019 5 : CHECK_STATUS(status, NT_STATUS_OK);
1020 :
1021 5 : status = torture_smb2_testfile(tree, fname, &h2);
1022 5 : CHECK_STATUS(status, NT_STATUS_OK);
1023 :
1024 5 : lck.in.locks = el;
1025 :
1026 5 : lck.in.lock_count = 0x0001;
1027 5 : lck.in.lock_sequence = 0x00000000;
1028 5 : lck.in.file.handle = h;
1029 5 : el[0].offset = 100;
1030 5 : el[0].length = 10;
1031 5 : el[0].reserved = 0x00000000;
1032 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
1033 :
1034 5 : torture_comment(torture, "Testing cancel by tree disconnect\n");
1035 :
1036 5 : status = torture_smb2_testfile(tree, fname, &h);
1037 5 : CHECK_STATUS(status, NT_STATUS_OK);
1038 :
1039 5 : status = torture_smb2_testfile(tree, fname, &h2);
1040 5 : CHECK_STATUS(status, NT_STATUS_OK);
1041 :
1042 5 : torture_comment(torture, " Acquire first lock\n");
1043 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
1044 5 : status = smb2_lock(tree, &lck);
1045 5 : CHECK_STATUS(status, NT_STATUS_OK);
1046 :
1047 5 : torture_comment(torture, " Second lock should pend on first\n");
1048 5 : lck.in.file.handle = h2;
1049 5 : req = smb2_lock_send(tree, &lck);
1050 25 : WAIT_FOR_ASYNC_RESPONSE(req);
1051 :
1052 5 : torture_comment(torture, " Disconnect the tree\n");
1053 5 : smb2_tdis(tree);
1054 5 : CHECK_STATUS(status, NT_STATUS_OK);
1055 :
1056 5 : torture_comment(torture, " Check pending lock reply\n");
1057 5 : status = smb2_lock_recv(req, &lck);
1058 5 : if (!NT_STATUS_EQUAL(status, NT_STATUS_RANGE_NOT_LOCKED)) {
1059 : /*
1060 : * The status depends on the server internals
1061 : * the order in which the files are closed
1062 : * by smb2_tdis().
1063 : */
1064 0 : CHECK_STATUS(status, NT_STATUS_OK);
1065 : }
1066 :
1067 5 : torture_comment(torture, " Attempt to unlock first lock\n");
1068 5 : lck.in.file.handle = h;
1069 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1070 5 : status = smb2_lock(tree, &lck);
1071 : /*
1072 : * Most Windows versions have a strange order to
1073 : * verify the session id, tree id and file id.
1074 : * (They should be checked in that order, but windows
1075 : * seems to check the file id before the others).
1076 : */
1077 5 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) {
1078 0 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1079 : }
1080 :
1081 5 : done:
1082 5 : smb2_util_close(tree, h2);
1083 5 : smb2_util_close(tree, h);
1084 5 : smb2_deltree(tree, BASEDIR);
1085 5 : return ret;
1086 : }
1087 :
1088 : /*
1089 : test SMB2 LOCK Cancel by user logoff
1090 : */
1091 5 : static bool test_cancel_logoff(struct torture_context *torture,
1092 : struct smb2_tree *tree)
1093 : {
1094 0 : NTSTATUS status;
1095 5 : bool ret = true;
1096 5 : struct smb2_handle h = {{0}};
1097 5 : struct smb2_handle h2 = {{0}};
1098 0 : uint8_t buf[200];
1099 0 : struct smb2_lock lck;
1100 0 : struct smb2_lock_element el[2];
1101 5 : struct smb2_request *req = NULL;
1102 :
1103 5 : const char *fname = BASEDIR "\\cancel_logoff.txt";
1104 :
1105 5 : status = torture_smb2_testdir(tree, BASEDIR, &h);
1106 5 : CHECK_STATUS(status, NT_STATUS_OK);
1107 5 : smb2_util_close(tree, h);
1108 :
1109 5 : status = torture_smb2_testfile(tree, fname, &h);
1110 5 : CHECK_STATUS(status, NT_STATUS_OK);
1111 :
1112 5 : ZERO_STRUCT(buf);
1113 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
1114 5 : CHECK_STATUS(status, NT_STATUS_OK);
1115 :
1116 5 : status = torture_smb2_testfile(tree, fname, &h2);
1117 5 : CHECK_STATUS(status, NT_STATUS_OK);
1118 :
1119 5 : lck.in.locks = el;
1120 :
1121 5 : lck.in.lock_count = 0x0001;
1122 5 : lck.in.lock_sequence = 0x00000000;
1123 5 : lck.in.file.handle = h;
1124 5 : el[0].offset = 100;
1125 5 : el[0].length = 10;
1126 5 : el[0].reserved = 0x00000000;
1127 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
1128 :
1129 5 : torture_comment(torture, "Testing cancel by ulogoff\n");
1130 :
1131 5 : torture_comment(torture, " Acquire first lock\n");
1132 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
1133 5 : status = smb2_lock(tree, &lck);
1134 5 : CHECK_STATUS(status, NT_STATUS_OK);
1135 :
1136 5 : torture_comment(torture, " Second lock should pend on first\n");
1137 5 : lck.in.file.handle = h2;
1138 5 : req = smb2_lock_send(tree, &lck);
1139 25 : WAIT_FOR_ASYNC_RESPONSE(req);
1140 :
1141 5 : torture_comment(torture, " Logoff user\n");
1142 5 : smb2_logoff(tree->session);
1143 :
1144 5 : torture_comment(torture, " Check pending lock reply\n");
1145 5 : status = smb2_lock_recv(req, &lck);
1146 5 : if (!NT_STATUS_EQUAL(status, NT_STATUS_RANGE_NOT_LOCKED)) {
1147 : /*
1148 : * The status depends on the server internals
1149 : * the order in which the files are closed
1150 : * by smb2_logoff().
1151 : */
1152 0 : CHECK_STATUS(status, NT_STATUS_OK);
1153 : }
1154 :
1155 5 : torture_comment(torture, " Attempt to unlock first lock\n");
1156 5 : lck.in.file.handle = h;
1157 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1158 5 : status = smb2_lock(tree, &lck);
1159 : /*
1160 : * Most Windows versions have a strange order to
1161 : * verify the session id, tree id and file id.
1162 : * (They should be checked in that order, but windows
1163 : * seems to check the file id before the others).
1164 : */
1165 5 : if (!NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
1166 0 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1167 : }
1168 :
1169 5 : done:
1170 5 : smb2_util_close(tree, h2);
1171 5 : smb2_util_close(tree, h);
1172 5 : smb2_deltree(tree, BASEDIR);
1173 5 : return ret;
1174 : }
1175 :
1176 : /*
1177 : * Test NT_STATUS_LOCK_NOT_GRANTED vs. NT_STATUS_FILE_LOCK_CONFLICT
1178 : *
1179 : * The SMBv1 protocol returns a different error code on lock acquisition
1180 : * failure depending on a number of parameters, including what error code
1181 : * was returned to the previous failure.
1182 : *
1183 : * SMBv2 has cleaned up these semantics and should always return
1184 : * NT_STATUS_LOCK_NOT_GRANTED to failed lock requests, and
1185 : * NT_STATUS_FILE_LOCK_CONFLICT to failed read/write requests due to a lock
1186 : * being held on that range.
1187 : */
1188 5 : static bool test_errorcode(struct torture_context *torture,
1189 : struct smb2_tree *tree)
1190 : {
1191 0 : NTSTATUS status;
1192 5 : bool ret = true;
1193 5 : struct smb2_handle h = {{0}};
1194 5 : struct smb2_handle h2 = {{0}};
1195 0 : uint8_t buf[200];
1196 0 : struct smb2_lock lck;
1197 0 : struct smb2_lock_element el[2];
1198 :
1199 5 : const char *fname = BASEDIR "\\errorcode.txt";
1200 :
1201 5 : status = torture_smb2_testdir(tree, BASEDIR, &h);
1202 5 : CHECK_STATUS(status, NT_STATUS_OK);
1203 5 : smb2_util_close(tree, h);
1204 :
1205 5 : status = torture_smb2_testfile(tree, fname, &h);
1206 5 : CHECK_STATUS(status, NT_STATUS_OK);
1207 :
1208 5 : ZERO_STRUCT(buf);
1209 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
1210 5 : CHECK_STATUS(status, NT_STATUS_OK);
1211 :
1212 5 : status = torture_smb2_testfile(tree, fname, &h2);
1213 5 : CHECK_STATUS(status, NT_STATUS_OK);
1214 :
1215 5 : lck.in.locks = el;
1216 :
1217 5 : lck.in.lock_count = 0x0001;
1218 5 : lck.in.lock_sequence = 0x00000000;
1219 5 : lck.in.file.handle = h;
1220 5 : el[0].offset = 100;
1221 5 : el[0].length = 10;
1222 5 : el[0].reserved = 0x00000000;
1223 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1224 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1225 :
1226 5 : torture_comment(torture, "Testing LOCK_NOT_GRANTED vs. "
1227 : "FILE_LOCK_CONFLICT\n");
1228 :
1229 5 : if (TARGET_IS_W2K8(torture)) {
1230 0 : torture_result(torture, TORTURE_SKIP,
1231 : "Target has \"pretty please\" bug. A contending lock "
1232 : "request on the same handle unlocks the lock.");
1233 0 : goto done;
1234 : }
1235 :
1236 5 : status = smb2_lock(tree, &lck);
1237 5 : CHECK_STATUS(status, NT_STATUS_OK);
1238 :
1239 : /* Demonstrate that the first conflicting lock on each handle gives
1240 : * LOCK_NOT_GRANTED. */
1241 5 : lck.in.file.handle = h;
1242 5 : status = smb2_lock(tree, &lck);
1243 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1244 :
1245 5 : lck.in.file.handle = h2;
1246 5 : status = smb2_lock(tree, &lck);
1247 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1248 :
1249 : /* Demonstrate that each following conflict also gives
1250 : * LOCK_NOT_GRANTED */
1251 5 : lck.in.file.handle = h;
1252 5 : status = smb2_lock(tree, &lck);
1253 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1254 :
1255 5 : lck.in.file.handle = h2;
1256 5 : status = smb2_lock(tree, &lck);
1257 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1258 :
1259 5 : lck.in.file.handle = h;
1260 5 : status = smb2_lock(tree, &lck);
1261 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1262 :
1263 5 : lck.in.file.handle = h2;
1264 5 : status = smb2_lock(tree, &lck);
1265 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1266 :
1267 : /* Demonstrate that the smbpid doesn't matter */
1268 5 : lck.in.file.handle = h;
1269 5 : status = smb2_lock(tree, &lck);
1270 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1271 :
1272 5 : lck.in.file.handle = h2;
1273 5 : status = smb2_lock(tree, &lck);
1274 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1275 :
1276 : /* Demonstrate that a 0-byte lock inside the locked range still
1277 : * gives the same error. */
1278 :
1279 5 : el[0].offset = 102;
1280 5 : el[0].length = 0;
1281 5 : lck.in.file.handle = h;
1282 5 : status = smb2_lock(tree, &lck);
1283 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1284 :
1285 5 : lck.in.file.handle = h2;
1286 5 : status = smb2_lock(tree, &lck);
1287 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1288 :
1289 : /* Demonstrate that a lock inside the locked range still gives the
1290 : * same error. */
1291 :
1292 5 : el[0].offset = 102;
1293 5 : el[0].length = 5;
1294 5 : lck.in.file.handle = h;
1295 5 : status = smb2_lock(tree, &lck);
1296 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1297 :
1298 5 : lck.in.file.handle = h2;
1299 5 : status = smb2_lock(tree, &lck);
1300 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1301 :
1302 5 : done:
1303 5 : smb2_util_close(tree, h2);
1304 5 : smb2_util_close(tree, h);
1305 5 : smb2_deltree(tree, BASEDIR);
1306 5 : return ret;
1307 : }
1308 :
1309 : /**
1310 : * Tests zero byte locks.
1311 : */
1312 :
1313 : struct double_lock_test {
1314 : struct smb2_lock_element lock1;
1315 : struct smb2_lock_element lock2;
1316 : NTSTATUS status;
1317 : };
1318 :
1319 : static struct double_lock_test zero_byte_tests[] = {
1320 : /* {offset, count, reserved, flags},
1321 : * {offset, count, reserved, flags},
1322 : * status */
1323 :
1324 : /** First, takes a zero byte lock at offset 10. Then:
1325 : * - Taking 0 byte lock at 10 should succeed.
1326 : * - Taking 1 byte locks at 9,10,11 should succeed.
1327 : * - Taking 2 byte lock at 9 should fail.
1328 : * - Taking 2 byte lock at 10 should succeed.
1329 : * - Taking 3 byte lock at 9 should fail.
1330 : */
1331 : {{10, 0, 0, 0}, {10, 0, 0, 0}, NT_STATUS_OK},
1332 : {{10, 0, 0, 0}, {9, 1, 0, 0}, NT_STATUS_OK},
1333 : {{10, 0, 0, 0}, {10, 1, 0, 0}, NT_STATUS_OK},
1334 : {{10, 0, 0, 0}, {11, 1, 0, 0}, NT_STATUS_OK},
1335 : {{10, 0, 0, 0}, {9, 2, 0, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1336 : {{10, 0, 0, 0}, {10, 2, 0, 0}, NT_STATUS_OK},
1337 : {{10, 0, 0, 0}, {9, 3, 0, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1338 :
1339 : /** Same, but opposite order. */
1340 : {{10, 0, 0, 0}, {10, 0, 0, 0}, NT_STATUS_OK},
1341 : {{9, 1, 0, 0}, {10, 0, 0, 0}, NT_STATUS_OK},
1342 : {{10, 1, 0, 0}, {10, 0, 0, 0}, NT_STATUS_OK},
1343 : {{11, 1, 0, 0}, {10, 0, 0, 0}, NT_STATUS_OK},
1344 : {{9, 2, 0, 0}, {10, 0, 0, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1345 : {{10, 2, 0, 0}, {10, 0, 0, 0}, NT_STATUS_OK},
1346 : {{9, 3, 0, 0}, {10, 0, 0, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1347 :
1348 : /** Zero zero case. */
1349 : {{0, 0, 0, 0}, {0, 0, 0, 0}, NT_STATUS_OK},
1350 : };
1351 :
1352 5 : static bool test_zerobytelength(struct torture_context *torture,
1353 : struct smb2_tree *tree)
1354 : {
1355 0 : NTSTATUS status;
1356 5 : bool ret = true;
1357 5 : struct smb2_handle h = {{0}};
1358 5 : struct smb2_handle h2 = {{0}};
1359 0 : uint8_t buf[200];
1360 0 : struct smb2_lock lck;
1361 0 : int i;
1362 :
1363 5 : const char *fname = BASEDIR "\\zero.txt";
1364 :
1365 5 : torture_comment(torture, "Testing zero length byte range locks:\n");
1366 :
1367 5 : status = torture_smb2_testdir(tree, BASEDIR, &h);
1368 5 : CHECK_STATUS(status, NT_STATUS_OK);
1369 5 : smb2_util_close(tree, h);
1370 :
1371 5 : status = torture_smb2_testfile(tree, fname, &h);
1372 5 : CHECK_STATUS(status, NT_STATUS_OK);
1373 :
1374 5 : ZERO_STRUCT(buf);
1375 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
1376 5 : CHECK_STATUS(status, NT_STATUS_OK);
1377 :
1378 5 : status = torture_smb2_testfile(tree, fname, &h2);
1379 5 : CHECK_STATUS(status, NT_STATUS_OK);
1380 :
1381 : /* Setup initial parameters */
1382 5 : lck.in.lock_count = 0x0001;
1383 5 : lck.in.lock_sequence = 0x00000000;
1384 5 : lck.in.file.handle = h;
1385 :
1386 : /* Try every combination of locks in zero_byte_tests, using the same
1387 : * handle for both locks. The first lock is assumed to succeed. The
1388 : * second lock may contend, depending on the expected status. */
1389 80 : for (i = 0; i < ARRAY_SIZE(zero_byte_tests); i++) {
1390 75 : torture_comment(torture,
1391 : " ... {%llu, %llu} + {%llu, %llu} = %s\n",
1392 75 : (unsigned long long) zero_byte_tests[i].lock1.offset,
1393 75 : (unsigned long long) zero_byte_tests[i].lock1.length,
1394 75 : (unsigned long long) zero_byte_tests[i].lock2.offset,
1395 75 : (unsigned long long) zero_byte_tests[i].lock2.length,
1396 : nt_errstr(zero_byte_tests[i].status));
1397 :
1398 : /* Lock both locks. */
1399 75 : lck.in.locks = &zero_byte_tests[i].lock1;
1400 75 : lck.in.locks[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1401 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1402 75 : status = smb2_lock(tree, &lck);
1403 75 : CHECK_STATUS(status, NT_STATUS_OK);
1404 :
1405 75 : lck.in.locks = &zero_byte_tests[i].lock2;
1406 75 : lck.in.locks[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1407 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1408 75 : status = smb2_lock(tree, &lck);
1409 75 : CHECK_STATUS_CONT(status, zero_byte_tests[i].status);
1410 :
1411 : /* Unlock both locks in reverse order. */
1412 75 : lck.in.locks[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1413 75 : if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1414 55 : status = smb2_lock(tree, &lck);
1415 55 : CHECK_STATUS(status, NT_STATUS_OK);
1416 : }
1417 :
1418 75 : lck.in.locks = &zero_byte_tests[i].lock1;
1419 75 : lck.in.locks[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1420 75 : status = smb2_lock(tree, &lck);
1421 75 : CHECK_STATUS(status, NT_STATUS_OK);
1422 : }
1423 :
1424 : /* Try every combination of locks in zero_byte_tests, using two
1425 : * different handles. */
1426 80 : for (i = 0; i < ARRAY_SIZE(zero_byte_tests); i++) {
1427 75 : torture_comment(torture,
1428 : " ... {%llu, %llu} + {%llu, %llu} = %s\n",
1429 75 : (unsigned long long) zero_byte_tests[i].lock1.offset,
1430 75 : (unsigned long long) zero_byte_tests[i].lock1.length,
1431 75 : (unsigned long long) zero_byte_tests[i].lock2.offset,
1432 75 : (unsigned long long) zero_byte_tests[i].lock2.length,
1433 : nt_errstr(zero_byte_tests[i].status));
1434 :
1435 : /* Lock both locks. */
1436 75 : lck.in.file.handle = h;
1437 75 : lck.in.locks = &zero_byte_tests[i].lock1;
1438 75 : lck.in.locks[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1439 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1440 75 : status = smb2_lock(tree, &lck);
1441 75 : CHECK_STATUS(status, NT_STATUS_OK);
1442 :
1443 75 : lck.in.file.handle = h2;
1444 75 : lck.in.locks = &zero_byte_tests[i].lock2;
1445 75 : lck.in.locks[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1446 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1447 75 : status = smb2_lock(tree, &lck);
1448 75 : CHECK_STATUS_CONT(status, zero_byte_tests[i].status);
1449 :
1450 : /* Unlock both locks in reverse order. */
1451 75 : lck.in.file.handle = h2;
1452 75 : lck.in.locks[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1453 75 : if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1454 55 : status = smb2_lock(tree, &lck);
1455 55 : CHECK_STATUS(status, NT_STATUS_OK);
1456 : }
1457 :
1458 75 : lck.in.file.handle = h;
1459 75 : lck.in.locks = &zero_byte_tests[i].lock1;
1460 75 : lck.in.locks[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1461 75 : status = smb2_lock(tree, &lck);
1462 75 : CHECK_STATUS(status, NT_STATUS_OK);
1463 : }
1464 :
1465 5 : done:
1466 5 : smb2_util_close(tree, h2);
1467 5 : smb2_util_close(tree, h);
1468 5 : smb2_deltree(tree, BASEDIR);
1469 5 : return ret;
1470 : }
1471 :
1472 5 : static bool test_zerobyteread(struct torture_context *torture,
1473 : struct smb2_tree *tree)
1474 : {
1475 0 : NTSTATUS status;
1476 5 : bool ret = true;
1477 5 : struct smb2_handle h = {{0}};
1478 5 : struct smb2_handle h2 = {{0}};
1479 0 : uint8_t buf[200];
1480 0 : struct smb2_lock lck;
1481 0 : struct smb2_lock_element el[1];
1482 0 : struct smb2_read rd;
1483 :
1484 5 : const char *fname = BASEDIR "\\zerobyteread.txt";
1485 :
1486 5 : status = torture_smb2_testdir(tree, BASEDIR, &h);
1487 5 : CHECK_STATUS(status, NT_STATUS_OK);
1488 5 : smb2_util_close(tree, h);
1489 :
1490 5 : status = torture_smb2_testfile(tree, fname, &h);
1491 5 : CHECK_STATUS(status, NT_STATUS_OK);
1492 :
1493 5 : ZERO_STRUCT(buf);
1494 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
1495 5 : CHECK_STATUS(status, NT_STATUS_OK);
1496 :
1497 5 : status = torture_smb2_testfile(tree, fname, &h2);
1498 5 : CHECK_STATUS(status, NT_STATUS_OK);
1499 :
1500 : /* Setup initial parameters */
1501 5 : lck.in.locks = el;
1502 5 : lck.in.lock_count = 0x0001;
1503 5 : lck.in.lock_sequence = 0x00000000;
1504 5 : lck.in.file.handle = h;
1505 :
1506 5 : ZERO_STRUCT(rd);
1507 5 : rd.in.file.handle = h2;
1508 :
1509 5 : torture_comment(torture, "Testing zero byte read on lock range:\n");
1510 :
1511 : /* Take an exclusive lock */
1512 5 : torture_comment(torture, " taking exclusive lock.\n");
1513 5 : el[0].offset = 0;
1514 5 : el[0].length = 10;
1515 5 : el[0].reserved = 0x00000000;
1516 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1517 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1518 5 : status = smb2_lock(tree, &lck);
1519 5 : CHECK_STATUS(status, NT_STATUS_OK);
1520 5 : CHECK_VALUE(lck.out.reserved, 0);
1521 :
1522 : /* Try a zero byte read */
1523 5 : torture_comment(torture, " reading 0 bytes.\n");
1524 5 : rd.in.offset = 5;
1525 5 : rd.in.length = 0;
1526 5 : status = smb2_read(tree, tree, &rd);
1527 5 : torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done,
1528 : "zero byte read did not return 0 bytes");
1529 5 : CHECK_STATUS(status, NT_STATUS_OK);
1530 :
1531 : /* Unlock lock */
1532 4 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1533 4 : status = smb2_lock(tree, &lck);
1534 4 : CHECK_STATUS(status, NT_STATUS_OK);
1535 4 : CHECK_VALUE(lck.out.reserved, 0);
1536 :
1537 4 : torture_comment(torture, "Testing zero byte read on zero byte lock "
1538 : "range:\n");
1539 :
1540 : /* Take an exclusive lock */
1541 4 : torture_comment(torture, " taking exclusive 0-byte lock.\n");
1542 4 : el[0].offset = 5;
1543 4 : el[0].length = 0;
1544 4 : el[0].reserved = 0x00000000;
1545 4 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1546 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1547 4 : status = smb2_lock(tree, &lck);
1548 4 : CHECK_STATUS(status, NT_STATUS_OK);
1549 4 : CHECK_VALUE(lck.out.reserved, 0);
1550 :
1551 : /* Try a zero byte read before the lock */
1552 4 : torture_comment(torture, " reading 0 bytes before the lock.\n");
1553 4 : rd.in.offset = 4;
1554 4 : rd.in.length = 0;
1555 4 : status = smb2_read(tree, tree, &rd);
1556 4 : torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done,
1557 : "zero byte read did not return 0 bytes");
1558 4 : CHECK_STATUS(status, NT_STATUS_OK);
1559 :
1560 : /* Try a zero byte read on the lock */
1561 4 : torture_comment(torture, " reading 0 bytes on the lock.\n");
1562 4 : rd.in.offset = 5;
1563 4 : rd.in.length = 0;
1564 4 : status = smb2_read(tree, tree, &rd);
1565 4 : torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done,
1566 : "zero byte read did not return 0 bytes");
1567 4 : CHECK_STATUS(status, NT_STATUS_OK);
1568 :
1569 : /* Try a zero byte read after the lock */
1570 4 : torture_comment(torture, " reading 0 bytes after the lock.\n");
1571 4 : rd.in.offset = 6;
1572 4 : rd.in.length = 0;
1573 4 : status = smb2_read(tree, tree, &rd);
1574 4 : torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done,
1575 : "zero byte read did not return 0 bytes");
1576 4 : CHECK_STATUS(status, NT_STATUS_OK);
1577 :
1578 : /* Unlock lock */
1579 4 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1580 4 : status = smb2_lock(tree, &lck);
1581 4 : CHECK_STATUS(status, NT_STATUS_OK);
1582 4 : CHECK_VALUE(lck.out.reserved, 0);
1583 :
1584 4 : done:
1585 5 : smb2_util_close(tree, h2);
1586 5 : smb2_util_close(tree, h);
1587 5 : smb2_deltree(tree, BASEDIR);
1588 5 : return ret;
1589 : }
1590 :
1591 5 : static bool test_unlock(struct torture_context *torture,
1592 : struct smb2_tree *tree)
1593 : {
1594 0 : NTSTATUS status;
1595 5 : bool ret = true;
1596 5 : struct smb2_handle h = {{0}};
1597 5 : struct smb2_handle h2 = {{0}};
1598 0 : uint8_t buf[200];
1599 0 : struct smb2_lock lck;
1600 0 : struct smb2_lock_element el1[1];
1601 0 : struct smb2_lock_element el2[1];
1602 :
1603 5 : const char *fname = BASEDIR "\\unlock.txt";
1604 :
1605 5 : status = torture_smb2_testdir(tree, BASEDIR, &h);
1606 5 : CHECK_STATUS(status, NT_STATUS_OK);
1607 5 : smb2_util_close(tree, h);
1608 :
1609 5 : status = torture_smb2_testfile(tree, fname, &h);
1610 5 : CHECK_STATUS(status, NT_STATUS_OK);
1611 :
1612 5 : ZERO_STRUCT(buf);
1613 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
1614 5 : CHECK_STATUS(status, NT_STATUS_OK);
1615 :
1616 5 : status = torture_smb2_testfile(tree, fname, &h2);
1617 5 : CHECK_STATUS(status, NT_STATUS_OK);
1618 :
1619 : /* Setup initial parameters */
1620 5 : lck.in.locks = el1;
1621 5 : lck.in.lock_count = 0x0001;
1622 5 : lck.in.lock_sequence = 0x00000000;
1623 5 : el1[0].offset = 0;
1624 5 : el1[0].length = 10;
1625 5 : el1[0].reserved = 0x00000000;
1626 :
1627 : /* Take exclusive lock, then unlock it with a shared-unlock call. */
1628 :
1629 5 : torture_comment(torture, "Testing unlock exclusive with shared\n");
1630 :
1631 5 : torture_comment(torture, " taking exclusive lock.\n");
1632 5 : lck.in.file.handle = h;
1633 5 : el1[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
1634 5 : status = smb2_lock(tree, &lck);
1635 5 : CHECK_STATUS(status, NT_STATUS_OK);
1636 :
1637 5 : torture_comment(torture, " try to unlock the exclusive with a shared "
1638 : "unlock call.\n");
1639 5 : el1[0].flags = SMB2_LOCK_FLAG_SHARED |
1640 : SMB2_LOCK_FLAG_UNLOCK;
1641 5 : status = smb2_lock(tree, &lck);
1642 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1643 :
1644 5 : torture_comment(torture, " try shared lock on h2, to test the "
1645 : "unlock.\n");
1646 5 : lck.in.file.handle = h2;
1647 5 : el1[0].flags = SMB2_LOCK_FLAG_SHARED |
1648 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1649 5 : status = smb2_lock(tree, &lck);
1650 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1651 :
1652 5 : torture_comment(torture, " unlock the exclusive lock\n");
1653 5 : lck.in.file.handle = h;
1654 5 : el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1655 5 : status = smb2_lock(tree, &lck);
1656 5 : CHECK_STATUS(status, NT_STATUS_OK);
1657 :
1658 : /* Unlock a shared lock with an exclusive-unlock call. */
1659 :
1660 5 : torture_comment(torture, "Testing unlock shared with exclusive\n");
1661 :
1662 5 : torture_comment(torture, " taking shared lock.\n");
1663 5 : lck.in.file.handle = h;
1664 5 : el1[0].flags = SMB2_LOCK_FLAG_SHARED;
1665 5 : status = smb2_lock(tree, &lck);
1666 5 : CHECK_STATUS(status, NT_STATUS_OK);
1667 :
1668 5 : torture_comment(torture, " try to unlock the shared with an exclusive "
1669 : "unlock call.\n");
1670 5 : el1[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1671 : SMB2_LOCK_FLAG_UNLOCK;
1672 5 : status = smb2_lock(tree, &lck);
1673 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1674 :
1675 5 : torture_comment(torture, " try exclusive lock on h2, to test the "
1676 : "unlock.\n");
1677 5 : lck.in.file.handle = h2;
1678 5 : el1[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1679 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1680 5 : status = smb2_lock(tree, &lck);
1681 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1682 :
1683 5 : torture_comment(torture, " unlock the exclusive lock\n");
1684 5 : lck.in.file.handle = h;
1685 5 : el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1686 5 : status = smb2_lock(tree, &lck);
1687 5 : CHECK_STATUS(status, NT_STATUS_OK);
1688 :
1689 : /* Test unlocking of stacked 0-byte locks. SMB2 0-byte lock behavior
1690 : * should be the same as >0-byte behavior. Exclusive locks should be
1691 : * unlocked before shared. */
1692 :
1693 5 : torture_comment(torture, "Test unlocking stacked 0-byte locks\n");
1694 :
1695 5 : lck.in.locks = el1;
1696 5 : lck.in.file.handle = h;
1697 5 : el1[0].offset = 10;
1698 5 : el1[0].length = 0;
1699 5 : el1[0].reserved = 0x00000000;
1700 5 : el2[0].offset = 5;
1701 5 : el2[0].length = 10;
1702 5 : el2[0].reserved = 0x00000000;
1703 :
1704 : /* lock 0-byte exclusive */
1705 5 : el1[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1706 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1707 5 : status = smb2_lock(tree, &lck);
1708 5 : CHECK_STATUS(status, NT_STATUS_OK);
1709 :
1710 : /* lock 0-byte shared */
1711 5 : el1[0].flags = SMB2_LOCK_FLAG_SHARED |
1712 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1713 5 : status = smb2_lock(tree, &lck);
1714 5 : CHECK_STATUS(status, NT_STATUS_OK);
1715 :
1716 : /* test contention */
1717 5 : lck.in.locks = el2;
1718 5 : lck.in.file.handle = h2;
1719 5 : el2[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1720 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1721 5 : status = smb2_lock(tree, &lck);
1722 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1723 :
1724 5 : lck.in.locks = el2;
1725 5 : lck.in.file.handle = h2;
1726 5 : el2[0].flags = SMB2_LOCK_FLAG_SHARED |
1727 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1728 5 : status = smb2_lock(tree, &lck);
1729 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1730 :
1731 : /* unlock */
1732 5 : lck.in.locks = el1;
1733 5 : lck.in.file.handle = h;
1734 5 : el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1735 5 : status = smb2_lock(tree, &lck);
1736 5 : CHECK_STATUS(status, NT_STATUS_OK);
1737 :
1738 : /* test - can we take a shared lock? */
1739 5 : lck.in.locks = el2;
1740 5 : lck.in.file.handle = h2;
1741 5 : el2[0].flags = SMB2_LOCK_FLAG_SHARED |
1742 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1743 5 : status = smb2_lock(tree, &lck);
1744 5 : CHECK_STATUS(status, NT_STATUS_OK);
1745 :
1746 5 : el2[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1747 5 : status = smb2_lock(tree, &lck);
1748 5 : CHECK_STATUS(status, NT_STATUS_OK);
1749 :
1750 : /* cleanup */
1751 5 : lck.in.locks = el1;
1752 5 : lck.in.file.handle = h;
1753 5 : el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1754 5 : status = smb2_lock(tree, &lck);
1755 5 : CHECK_STATUS(status, NT_STATUS_OK);
1756 :
1757 : /* Test unlocking of stacked exclusive, shared locks. Exclusive
1758 : * should be unlocked before any shared. */
1759 :
1760 5 : torture_comment(torture, "Test unlocking stacked exclusive/shared "
1761 : "locks\n");
1762 :
1763 5 : lck.in.locks = el1;
1764 5 : lck.in.file.handle = h;
1765 5 : el1[0].offset = 10;
1766 5 : el1[0].length = 10;
1767 5 : el1[0].reserved = 0x00000000;
1768 5 : el2[0].offset = 5;
1769 5 : el2[0].length = 10;
1770 5 : el2[0].reserved = 0x00000000;
1771 :
1772 : /* lock exclusive */
1773 5 : el1[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1774 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1775 5 : status = smb2_lock(tree, &lck);
1776 5 : CHECK_STATUS(status, NT_STATUS_OK);
1777 :
1778 : /* lock shared */
1779 5 : el1[0].flags = SMB2_LOCK_FLAG_SHARED |
1780 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1781 5 : status = smb2_lock(tree, &lck);
1782 5 : CHECK_STATUS(status, NT_STATUS_OK);
1783 :
1784 : /* test contention */
1785 5 : lck.in.locks = el2;
1786 5 : lck.in.file.handle = h2;
1787 5 : el2[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1788 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1789 5 : status = smb2_lock(tree, &lck);
1790 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1791 :
1792 5 : lck.in.locks = el2;
1793 5 : lck.in.file.handle = h2;
1794 5 : el2[0].flags = SMB2_LOCK_FLAG_SHARED |
1795 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1796 5 : status = smb2_lock(tree, &lck);
1797 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1798 :
1799 : /* unlock */
1800 5 : lck.in.locks = el1;
1801 5 : lck.in.file.handle = h;
1802 5 : el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1803 5 : status = smb2_lock(tree, &lck);
1804 5 : CHECK_STATUS(status, NT_STATUS_OK);
1805 :
1806 : /* test - can we take a shared lock? */
1807 5 : lck.in.locks = el2;
1808 5 : lck.in.file.handle = h2;
1809 5 : el2[0].flags = SMB2_LOCK_FLAG_SHARED |
1810 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1811 5 : status = smb2_lock(tree, &lck);
1812 5 : CHECK_STATUS(status, NT_STATUS_OK);
1813 :
1814 5 : el2[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1815 5 : status = smb2_lock(tree, &lck);
1816 5 : CHECK_STATUS(status, NT_STATUS_OK);
1817 :
1818 : /* cleanup */
1819 5 : lck.in.locks = el1;
1820 5 : lck.in.file.handle = h;
1821 5 : el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1822 5 : status = smb2_lock(tree, &lck);
1823 5 : CHECK_STATUS(status, NT_STATUS_OK);
1824 :
1825 5 : done:
1826 5 : smb2_util_close(tree, h2);
1827 5 : smb2_util_close(tree, h);
1828 5 : smb2_deltree(tree, BASEDIR);
1829 5 : return ret;
1830 : }
1831 :
1832 5 : static bool test_multiple_unlock(struct torture_context *torture,
1833 : struct smb2_tree *tree)
1834 : {
1835 0 : NTSTATUS status;
1836 5 : bool ret = true;
1837 0 : struct smb2_handle h;
1838 0 : uint8_t buf[200];
1839 0 : struct smb2_lock lck;
1840 0 : struct smb2_lock_element el[2];
1841 :
1842 5 : const char *fname = BASEDIR "\\unlock_multiple.txt";
1843 :
1844 5 : status = torture_smb2_testdir(tree, BASEDIR, &h);
1845 5 : CHECK_STATUS(status, NT_STATUS_OK);
1846 5 : smb2_util_close(tree, h);
1847 :
1848 5 : status = torture_smb2_testfile(tree, fname, &h);
1849 5 : CHECK_STATUS(status, NT_STATUS_OK);
1850 :
1851 5 : ZERO_STRUCT(buf);
1852 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
1853 5 : CHECK_STATUS(status, NT_STATUS_OK);
1854 :
1855 5 : torture_comment(torture, "Testing multiple unlocks:\n");
1856 :
1857 : /* Setup initial parameters */
1858 5 : lck.in.lock_count = 0x0002;
1859 5 : lck.in.lock_sequence = 0x00000000;
1860 5 : lck.in.file.handle = h;
1861 5 : el[0].offset = 0;
1862 5 : el[0].length = 10;
1863 5 : el[0].reserved = 0x00000000;
1864 5 : el[1].offset = 10;
1865 5 : el[1].length = 10;
1866 5 : el[1].reserved = 0x00000000;
1867 :
1868 : /* Test1: Acquire second lock, but not first. */
1869 5 : torture_comment(torture, " unlock 2 locks, first one not locked. "
1870 : "Expect no locks unlocked. \n");
1871 :
1872 5 : lck.in.lock_count = 0x0001;
1873 5 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1874 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1875 5 : lck.in.locks = &el[1];
1876 5 : status = smb2_lock(tree, &lck);
1877 5 : CHECK_STATUS(status, NT_STATUS_OK);
1878 :
1879 : /* Try to unlock both locks */
1880 5 : lck.in.lock_count = 0x0002;
1881 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1882 5 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
1883 5 : lck.in.locks = el;
1884 5 : status = smb2_lock(tree, &lck);
1885 5 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1886 :
1887 : /* Second lock should not be unlocked. */
1888 5 : lck.in.lock_count = 0x0001;
1889 5 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1890 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1891 5 : lck.in.locks = &el[1];
1892 5 : status = smb2_lock(tree, &lck);
1893 5 : if (TARGET_IS_W2K8(torture)) {
1894 0 : CHECK_STATUS(status, NT_STATUS_OK);
1895 0 : torture_warning(torture, "Target has \"pretty please\" bug. "
1896 : "A contending lock request on the same handle "
1897 : "unlocks the lock.\n");
1898 : } else {
1899 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1900 : }
1901 :
1902 : /* cleanup */
1903 5 : lck.in.lock_count = 0x0001;
1904 5 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
1905 5 : lck.in.locks = &el[1];
1906 5 : status = smb2_lock(tree, &lck);
1907 5 : CHECK_STATUS(status, NT_STATUS_OK);
1908 :
1909 : /* Test2: Acquire first lock, but not second. */
1910 5 : torture_comment(torture, " unlock 2 locks, second one not locked. "
1911 : "Expect first lock unlocked.\n");
1912 :
1913 5 : lck.in.lock_count = 0x0001;
1914 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1915 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1916 5 : lck.in.locks = &el[0];
1917 5 : status = smb2_lock(tree, &lck);
1918 5 : CHECK_STATUS(status, NT_STATUS_OK);
1919 :
1920 : /* Try to unlock both locks */
1921 5 : lck.in.lock_count = 0x0002;
1922 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1923 5 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
1924 5 : lck.in.locks = el;
1925 5 : status = smb2_lock(tree, &lck);
1926 5 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1927 :
1928 : /* First lock should be unlocked. */
1929 5 : lck.in.lock_count = 0x0001;
1930 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1931 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1932 5 : lck.in.locks = &el[0];
1933 5 : status = smb2_lock(tree, &lck);
1934 5 : CHECK_STATUS(status, NT_STATUS_OK);
1935 :
1936 : /* cleanup */
1937 5 : lck.in.lock_count = 0x0001;
1938 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1939 5 : lck.in.locks = &el[0];
1940 5 : status = smb2_lock(tree, &lck);
1941 5 : CHECK_STATUS(status, NT_STATUS_OK);
1942 :
1943 : /* Test3: Request 2 locks, second will contend. What happens to the
1944 : * first? */
1945 5 : torture_comment(torture, " request 2 locks, second one will contend. "
1946 : "Expect both to fail.\n");
1947 :
1948 : /* Lock the second range */
1949 5 : lck.in.lock_count = 0x0001;
1950 5 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1951 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1952 5 : lck.in.locks = &el[1];
1953 5 : status = smb2_lock(tree, &lck);
1954 5 : CHECK_STATUS(status, NT_STATUS_OK);
1955 :
1956 : /* Request both locks */
1957 5 : lck.in.lock_count = 0x0002;
1958 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1959 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1960 5 : lck.in.locks = el;
1961 5 : status = smb2_lock(tree, &lck);
1962 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1963 :
1964 : /* First lock should be unlocked. */
1965 5 : lck.in.lock_count = 0x0001;
1966 5 : lck.in.locks = &el[0];
1967 5 : status = smb2_lock(tree, &lck);
1968 5 : CHECK_STATUS(status, NT_STATUS_OK);
1969 :
1970 : /* cleanup */
1971 5 : if (TARGET_IS_W2K8(torture)) {
1972 0 : lck.in.lock_count = 0x0001;
1973 0 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1974 0 : lck.in.locks = &el[0];
1975 0 : status = smb2_lock(tree, &lck);
1976 0 : CHECK_STATUS(status, NT_STATUS_OK);
1977 0 : torture_warning(torture, "Target has \"pretty please\" bug. "
1978 : "A contending lock request on the same handle "
1979 : "unlocks the lock.\n");
1980 : } else {
1981 5 : lck.in.lock_count = 0x0002;
1982 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1983 5 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
1984 5 : lck.in.locks = el;
1985 5 : status = smb2_lock(tree, &lck);
1986 5 : CHECK_STATUS(status, NT_STATUS_OK);
1987 : }
1988 :
1989 : /* Test4: Request unlock and lock. The lock contends, is the unlock
1990 : * then relocked? SMB2 doesn't like the lock and unlock requests in the
1991 : * same packet. The unlock will succeed, but the lock will return
1992 : * INVALID_PARAMETER. This behavior is described in MS-SMB2
1993 : * 3.3.5.14.1 */
1994 5 : torture_comment(torture, " request unlock and lock, second one will "
1995 : "error. Expect the unlock to succeed.\n");
1996 :
1997 : /* Lock both ranges */
1998 5 : lck.in.lock_count = 0x0002;
1999 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2000 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2001 5 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2002 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2003 5 : lck.in.locks = el;
2004 5 : status = smb2_lock(tree, &lck);
2005 5 : CHECK_STATUS(status, NT_STATUS_OK);
2006 :
2007 : /* Attempt to unlock the first range and lock the second. The lock
2008 : * request will error. */
2009 5 : lck.in.lock_count = 0x0002;
2010 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2011 5 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2012 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2013 5 : lck.in.locks = el;
2014 5 : status = smb2_lock(tree, &lck);
2015 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
2016 :
2017 : /* The first lock should've been unlocked */
2018 5 : lck.in.lock_count = 0x0001;
2019 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2020 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2021 5 : lck.in.locks = &el[0];
2022 5 : status = smb2_lock(tree, &lck);
2023 5 : CHECK_STATUS(status, NT_STATUS_OK);
2024 :
2025 : /* cleanup */
2026 4 : lck.in.lock_count = 0x0002;
2027 4 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2028 4 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
2029 4 : lck.in.locks = el;
2030 4 : status = smb2_lock(tree, &lck);
2031 4 : CHECK_STATUS(status, NT_STATUS_OK);
2032 :
2033 : /* Test10: SMB2 only test. Request unlock and lock in same packet.
2034 : * Neither contend. SMB2 doesn't like lock and unlock requests in the
2035 : * same packet. The unlock will succeed, but the lock will return
2036 : * INVALID_PARAMETER. */
2037 4 : torture_comment(torture, " request unlock and lock. Unlock will "
2038 : "succeed, but lock will fail.\n");
2039 :
2040 : /* Lock first range */
2041 4 : lck.in.lock_count = 0x0001;
2042 4 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2043 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2044 4 : lck.in.locks = &el[0];
2045 4 : status = smb2_lock(tree, &lck);
2046 4 : CHECK_STATUS(status, NT_STATUS_OK);
2047 :
2048 : /* Attempt to unlock the first range and lock the second */
2049 4 : lck.in.lock_count = 0x0002;
2050 4 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2051 4 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2052 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2053 4 : lck.in.locks = el;
2054 4 : status = smb2_lock(tree, &lck);
2055 4 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
2056 :
2057 : /* Neither lock should still be locked */
2058 4 : lck.in.lock_count = 0x0002;
2059 4 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2060 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2061 4 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2062 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2063 4 : lck.in.locks = el;
2064 4 : status = smb2_lock(tree, &lck);
2065 4 : CHECK_STATUS(status, NT_STATUS_OK);
2066 :
2067 : /* cleanup */
2068 4 : lck.in.lock_count = 0x0002;
2069 4 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2070 4 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
2071 4 : lck.in.locks = el;
2072 4 : status = smb2_lock(tree, &lck);
2073 4 : CHECK_STATUS(status, NT_STATUS_OK);
2074 :
2075 : /* Test11: SMB2 only test. Request lock and unlock in same packet.
2076 : * Neither contend. SMB2 doesn't like lock and unlock requests in the
2077 : * same packet. The lock will succeed, the unlock will fail with
2078 : * INVALID_PARAMETER, and the lock will be unlocked before return. */
2079 4 : torture_comment(torture, " request lock and unlock. Both will "
2080 : "fail.\n");
2081 :
2082 : /* Lock second range */
2083 4 : lck.in.lock_count = 0x0001;
2084 4 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2085 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2086 4 : lck.in.locks = &el[1];
2087 4 : status = smb2_lock(tree, &lck);
2088 4 : CHECK_STATUS(status, NT_STATUS_OK);
2089 :
2090 : /* Attempt to lock the first range and unlock the second */
2091 4 : lck.in.lock_count = 0x0002;
2092 4 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2093 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2094 4 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
2095 4 : lck.in.locks = el;
2096 4 : status = smb2_lock(tree, &lck);
2097 4 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
2098 :
2099 : /* First range should be unlocked, second locked. */
2100 4 : lck.in.lock_count = 0x0001;
2101 4 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2102 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2103 4 : lck.in.locks = &el[0];
2104 4 : status = smb2_lock(tree, &lck);
2105 4 : CHECK_STATUS(status, NT_STATUS_OK);
2106 :
2107 4 : lck.in.lock_count = 0x0001;
2108 4 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2109 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2110 4 : lck.in.locks = &el[1];
2111 4 : status = smb2_lock(tree, &lck);
2112 4 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2113 :
2114 : /* cleanup */
2115 4 : if (TARGET_IS_W2K8(torture)) {
2116 0 : lck.in.lock_count = 0x0001;
2117 0 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2118 0 : lck.in.locks = &el[0];
2119 0 : status = smb2_lock(tree, &lck);
2120 0 : CHECK_STATUS(status, NT_STATUS_OK);
2121 0 : torture_warning(torture, "Target has \"pretty please\" bug. "
2122 : "A contending lock request on the same handle "
2123 : "unlocks the lock.\n");
2124 : } else {
2125 4 : lck.in.lock_count = 0x0002;
2126 4 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2127 4 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
2128 4 : lck.in.locks = el;
2129 4 : status = smb2_lock(tree, &lck);
2130 4 : CHECK_STATUS(status, NT_STATUS_OK);
2131 : }
2132 :
2133 5 : done:
2134 5 : smb2_util_close(tree, h);
2135 5 : smb2_deltree(tree, BASEDIR);
2136 5 : return ret;
2137 : }
2138 :
2139 : /**
2140 : * Test lock stacking
2141 : * - some tests ported from BASE-LOCK-LOCK5
2142 : */
2143 5 : static bool test_stacking(struct torture_context *torture,
2144 : struct smb2_tree *tree)
2145 : {
2146 0 : NTSTATUS status;
2147 5 : bool ret = true;
2148 5 : struct smb2_handle h = {{0}};
2149 5 : struct smb2_handle h2 = {{0}};
2150 0 : uint8_t buf[200];
2151 0 : struct smb2_lock lck;
2152 0 : struct smb2_lock_element el[1];
2153 :
2154 5 : const char *fname = BASEDIR "\\stacking.txt";
2155 :
2156 5 : status = torture_smb2_testdir(tree, BASEDIR, &h);
2157 5 : CHECK_STATUS(status, NT_STATUS_OK);
2158 5 : smb2_util_close(tree, h);
2159 :
2160 5 : status = torture_smb2_testfile(tree, fname, &h);
2161 5 : CHECK_STATUS(status, NT_STATUS_OK);
2162 :
2163 5 : ZERO_STRUCT(buf);
2164 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
2165 5 : CHECK_STATUS(status, NT_STATUS_OK);
2166 :
2167 5 : status = torture_smb2_testfile(tree, fname, &h2);
2168 5 : CHECK_STATUS(status, NT_STATUS_OK);
2169 :
2170 5 : torture_comment(torture, "Testing lock stacking:\n");
2171 :
2172 : /* Setup initial parameters */
2173 5 : lck.in.locks = el;
2174 5 : lck.in.lock_count = 0x0001;
2175 5 : lck.in.lock_sequence = 0x00000000;
2176 5 : lck.in.file.handle = h;
2177 5 : el[0].offset = 0;
2178 5 : el[0].length = 10;
2179 5 : el[0].reserved = 0x00000000;
2180 :
2181 : /* Try to take a shared lock, then a shared lock on same handle */
2182 5 : torture_comment(torture, " stacking a shared on top of a shared"
2183 : "lock succeeds.\n");
2184 :
2185 5 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2186 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2187 5 : status = smb2_lock(tree, &lck);
2188 5 : CHECK_STATUS(status, NT_STATUS_OK);
2189 :
2190 5 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2191 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2192 5 : status = smb2_lock(tree, &lck);
2193 5 : CHECK_STATUS(status, NT_STATUS_OK);
2194 :
2195 : /* cleanup */
2196 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2197 5 : status = smb2_lock(tree, &lck);
2198 5 : CHECK_STATUS(status, NT_STATUS_OK);
2199 :
2200 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2201 5 : status = smb2_lock(tree, &lck);
2202 5 : CHECK_STATUS(status, NT_STATUS_OK);
2203 :
2204 :
2205 : /* Try to take an exclusive lock, then a shared lock on same handle */
2206 5 : torture_comment(torture, " stacking a shared on top of an exclusive "
2207 : "lock succeeds.\n");
2208 :
2209 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2210 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2211 5 : status = smb2_lock(tree, &lck);
2212 5 : CHECK_STATUS(status, NT_STATUS_OK);
2213 :
2214 5 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2215 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2216 5 : status = smb2_lock(tree, &lck);
2217 5 : CHECK_STATUS(status, NT_STATUS_OK);
2218 :
2219 5 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2220 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2221 5 : status = smb2_lock(tree, &lck);
2222 5 : CHECK_STATUS(status, NT_STATUS_OK);
2223 :
2224 : /* stacking a shared from a different handle should fail */
2225 5 : lck.in.file.handle = h2;
2226 5 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2227 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2228 5 : status = smb2_lock(tree, &lck);
2229 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2230 :
2231 : /* cleanup */
2232 5 : lck.in.file.handle = h;
2233 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2234 5 : status = smb2_lock(tree, &lck);
2235 5 : CHECK_STATUS(status, NT_STATUS_OK);
2236 :
2237 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2238 5 : status = smb2_lock(tree, &lck);
2239 5 : CHECK_STATUS(status, NT_STATUS_OK);
2240 :
2241 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2242 5 : status = smb2_lock(tree, &lck);
2243 5 : CHECK_STATUS(status, NT_STATUS_OK);
2244 :
2245 : /* ensure the 4th unlock fails */
2246 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2247 5 : status = smb2_lock(tree, &lck);
2248 5 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
2249 :
2250 : /* ensure a second handle can now take an exclusive lock */
2251 5 : lck.in.file.handle = h2;
2252 5 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2253 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2254 5 : status = smb2_lock(tree, &lck);
2255 5 : CHECK_STATUS(status, NT_STATUS_OK);
2256 :
2257 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2258 5 : status = smb2_lock(tree, &lck);
2259 5 : CHECK_STATUS(status, NT_STATUS_OK);
2260 :
2261 : /* Try to take an exclusive lock, then a shared lock on a
2262 : * different handle */
2263 5 : torture_comment(torture, " stacking a shared on top of an exclusive "
2264 : "lock with different handles fails.\n");
2265 :
2266 5 : lck.in.file.handle = h;
2267 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2268 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2269 5 : status = smb2_lock(tree, &lck);
2270 5 : CHECK_STATUS(status, NT_STATUS_OK);
2271 :
2272 5 : lck.in.file.handle = h2;
2273 5 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2274 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2275 5 : status = smb2_lock(tree, &lck);
2276 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2277 :
2278 : /* cleanup */
2279 5 : lck.in.file.handle = h;
2280 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2281 5 : status = smb2_lock(tree, &lck);
2282 5 : CHECK_STATUS(status, NT_STATUS_OK);
2283 :
2284 : /* Try to take a shared lock, then stack an exclusive with same
2285 : * handle. */
2286 5 : torture_comment(torture, " stacking an exclusive on top of a shared "
2287 : "lock fails.\n");
2288 :
2289 5 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2290 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2291 5 : status = smb2_lock(tree, &lck);
2292 5 : CHECK_STATUS(status, NT_STATUS_OK);
2293 :
2294 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2295 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2296 5 : status = smb2_lock(tree, &lck);
2297 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2298 :
2299 : /* cleanup */
2300 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2301 5 : status = smb2_lock(tree, &lck);
2302 5 : if (TARGET_IS_W2K8(torture)) {
2303 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
2304 0 : torture_warning(torture, "Target has \"pretty please\" bug. "
2305 : "A contending lock request on the same handle "
2306 : "unlocks the lock.\n");
2307 : } else {
2308 5 : CHECK_STATUS(status, NT_STATUS_OK);
2309 : }
2310 :
2311 : /* Prove that two exclusive locks do not stack on the same handle. */
2312 5 : torture_comment(torture, " two exclusive locks do not stack.\n");
2313 :
2314 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2315 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2316 5 : status = smb2_lock(tree, &lck);
2317 5 : CHECK_STATUS(status, NT_STATUS_OK);
2318 :
2319 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2320 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2321 5 : status = smb2_lock(tree, &lck);
2322 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2323 :
2324 : /* cleanup */
2325 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2326 5 : status = smb2_lock(tree, &lck);
2327 5 : if (TARGET_IS_W2K8(torture)) {
2328 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
2329 0 : torture_warning(torture, "Target has \"pretty please\" bug. "
2330 : "A contending lock request on the same handle "
2331 : "unlocks the lock.\n");
2332 : } else {
2333 5 : CHECK_STATUS(status, NT_STATUS_OK);
2334 : }
2335 :
2336 5 : done:
2337 5 : smb2_util_close(tree, h2);
2338 5 : smb2_util_close(tree, h);
2339 5 : smb2_deltree(tree, BASEDIR);
2340 5 : return ret;
2341 : }
2342 :
2343 : /**
2344 : * Test lock contention
2345 : * - shared lock should contend with exclusive lock on different handle
2346 : */
2347 5 : static bool test_contend(struct torture_context *torture,
2348 : struct smb2_tree *tree)
2349 : {
2350 0 : NTSTATUS status;
2351 5 : bool ret = true;
2352 5 : struct smb2_handle h = {{0}};
2353 5 : struct smb2_handle h2 = {{0}};
2354 0 : uint8_t buf[200];
2355 0 : struct smb2_lock lck;
2356 0 : struct smb2_lock_element el[1];
2357 :
2358 5 : const char *fname = BASEDIR "\\contend.txt";
2359 :
2360 5 : status = torture_smb2_testdir(tree, BASEDIR, &h);
2361 5 : CHECK_STATUS(status, NT_STATUS_OK);
2362 5 : smb2_util_close(tree, h);
2363 :
2364 5 : status = torture_smb2_testfile(tree, fname, &h);
2365 5 : CHECK_STATUS(status, NT_STATUS_OK);
2366 :
2367 5 : ZERO_STRUCT(buf);
2368 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
2369 5 : CHECK_STATUS(status, NT_STATUS_OK);
2370 :
2371 5 : status = torture_smb2_testfile(tree, fname, &h2);
2372 5 : CHECK_STATUS(status, NT_STATUS_OK);
2373 :
2374 5 : torture_comment(torture, "Testing lock contention:\n");
2375 :
2376 : /* Setup initial parameters */
2377 5 : lck.in.locks = el;
2378 5 : lck.in.lock_count = 0x0001;
2379 5 : lck.in.lock_sequence = 0x00000000;
2380 5 : lck.in.file.handle = h;
2381 5 : el[0].offset = 0;
2382 5 : el[0].length = 10;
2383 5 : el[0].reserved = 0x00000000;
2384 :
2385 : /* Take an exclusive lock, then a shared lock on different handle */
2386 5 : torture_comment(torture, " shared should contend on exclusive on "
2387 : "different handle.\n");
2388 :
2389 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2390 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2391 5 : status = smb2_lock(tree, &lck);
2392 5 : CHECK_STATUS(status, NT_STATUS_OK);
2393 :
2394 5 : lck.in.file.handle = h2;
2395 5 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2396 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2397 5 : status = smb2_lock(tree, &lck);
2398 5 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2399 :
2400 : /* cleanup */
2401 5 : lck.in.file.handle = h;
2402 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2403 5 : status = smb2_lock(tree, &lck);
2404 5 : CHECK_STATUS(status, NT_STATUS_OK);
2405 :
2406 5 : done:
2407 5 : smb2_util_close(tree, h2);
2408 5 : smb2_util_close(tree, h);
2409 5 : smb2_deltree(tree, BASEDIR);
2410 5 : return ret;
2411 : }
2412 :
2413 : /**
2414 : * Test locker context
2415 : * - test that pid does not affect the locker context
2416 : */
2417 5 : static bool test_context(struct torture_context *torture,
2418 : struct smb2_tree *tree)
2419 : {
2420 0 : NTSTATUS status;
2421 5 : bool ret = true;
2422 5 : struct smb2_handle h = {{0}};
2423 5 : struct smb2_handle h2 = {{0}};
2424 0 : uint8_t buf[200];
2425 0 : struct smb2_lock lck;
2426 0 : struct smb2_lock_element el[1];
2427 :
2428 5 : const char *fname = BASEDIR "\\context.txt";
2429 :
2430 5 : status = torture_smb2_testdir(tree, BASEDIR, &h);
2431 5 : CHECK_STATUS(status, NT_STATUS_OK);
2432 5 : smb2_util_close(tree, h);
2433 :
2434 5 : status = torture_smb2_testfile(tree, fname, &h);
2435 5 : CHECK_STATUS(status, NT_STATUS_OK);
2436 :
2437 5 : ZERO_STRUCT(buf);
2438 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
2439 5 : CHECK_STATUS(status, NT_STATUS_OK);
2440 :
2441 5 : status = torture_smb2_testfile(tree, fname, &h2);
2442 5 : CHECK_STATUS(status, NT_STATUS_OK);
2443 :
2444 5 : torture_comment(torture, "Testing locker context:\n");
2445 :
2446 : /* Setup initial parameters */
2447 5 : lck.in.locks = el;
2448 5 : lck.in.lock_count = 0x0001;
2449 5 : lck.in.lock_sequence = 0x00000000;
2450 5 : lck.in.file.handle = h;
2451 5 : el[0].offset = 0;
2452 5 : el[0].length = 10;
2453 5 : el[0].reserved = 0x00000000;
2454 :
2455 : /* Take an exclusive lock, then try to unlock with a different pid,
2456 : * same handle. This shows that the pid doesn't affect the locker
2457 : * context in SMB2. */
2458 5 : torture_comment(torture, " pid shouldn't affect locker context\n");
2459 :
2460 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2461 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2462 5 : status = smb2_lock(tree, &lck);
2463 5 : CHECK_STATUS(status, NT_STATUS_OK);
2464 :
2465 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2466 5 : status = smb2_lock(tree, &lck);
2467 5 : CHECK_STATUS(status, NT_STATUS_OK);
2468 :
2469 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2470 5 : status = smb2_lock(tree, &lck);
2471 5 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
2472 :
2473 5 : done:
2474 5 : smb2_util_close(tree, h2);
2475 5 : smb2_util_close(tree, h);
2476 5 : smb2_deltree(tree, BASEDIR);
2477 5 : return ret;
2478 : }
2479 :
2480 : /**
2481 : * Test as much of the potential lock range as possible
2482 : * - test ported from BASE-LOCK-LOCK3
2483 : */
2484 5 : static bool test_range(struct torture_context *torture,
2485 : struct smb2_tree *tree)
2486 : {
2487 0 : NTSTATUS status;
2488 5 : bool ret = true;
2489 5 : struct smb2_handle h = {{0}};
2490 5 : struct smb2_handle h2 = {{0}};
2491 0 : uint8_t buf[200];
2492 0 : struct smb2_lock lck;
2493 0 : struct smb2_lock_element el[1];
2494 0 : uint64_t offset, i;
2495 0 : extern int torture_numops;
2496 :
2497 5 : const char *fname = BASEDIR "\\range.txt";
2498 :
2499 : #define NEXT_OFFSET offset += (~(uint64_t)0) / torture_numops
2500 :
2501 5 : status = torture_smb2_testdir(tree, BASEDIR, &h);
2502 5 : CHECK_STATUS(status, NT_STATUS_OK);
2503 5 : smb2_util_close(tree, h);
2504 :
2505 5 : status = torture_smb2_testfile(tree, fname, &h);
2506 5 : CHECK_STATUS(status, NT_STATUS_OK);
2507 :
2508 5 : ZERO_STRUCT(buf);
2509 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
2510 5 : CHECK_STATUS(status, NT_STATUS_OK);
2511 :
2512 5 : status = torture_smb2_testfile(tree, fname, &h2);
2513 5 : CHECK_STATUS(status, NT_STATUS_OK);
2514 :
2515 5 : torture_comment(torture, "Testing locks spread across the 64-bit "
2516 : "offset range\n");
2517 :
2518 5 : if (TARGET_IS_W2K8(torture)) {
2519 0 : torture_result(torture, TORTURE_SKIP,
2520 : "Target has \"pretty please\" bug. A contending lock "
2521 : "request on the same handle unlocks the lock.");
2522 0 : goto done;
2523 : }
2524 :
2525 : /* Setup initial parameters */
2526 5 : lck.in.locks = el;
2527 5 : lck.in.lock_count = 0x0001;
2528 5 : lck.in.lock_sequence = 0x00000000;
2529 5 : lck.in.file.handle = h;
2530 5 : el[0].offset = 0;
2531 5 : el[0].length = 1;
2532 5 : el[0].reserved = 0x00000000;
2533 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2534 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2535 :
2536 5 : torture_comment(torture, " establishing %d locks\n", torture_numops);
2537 :
2538 55 : for (offset=i=0; i<torture_numops; i++) {
2539 50 : NEXT_OFFSET;
2540 :
2541 50 : lck.in.file.handle = h;
2542 50 : el[0].offset = offset - 1;
2543 50 : status = smb2_lock(tree, &lck);
2544 50 : CHECK_STATUS_CMT(status, NT_STATUS_OK,
2545 : talloc_asprintf(torture,
2546 : "lock h failed at offset %#llx ",
2547 : (unsigned long long) el[0].offset));
2548 :
2549 50 : lck.in.file.handle = h2;
2550 50 : el[0].offset = offset - 2;
2551 50 : status = smb2_lock(tree, &lck);
2552 50 : CHECK_STATUS_CMT(status, NT_STATUS_OK,
2553 : talloc_asprintf(torture,
2554 : "lock h2 failed at offset %#llx ",
2555 : (unsigned long long) el[0].offset));
2556 : }
2557 :
2558 5 : torture_comment(torture, " testing %d locks\n", torture_numops);
2559 :
2560 55 : for (offset=i=0; i<torture_numops; i++) {
2561 50 : NEXT_OFFSET;
2562 :
2563 50 : lck.in.file.handle = h;
2564 50 : el[0].offset = offset - 1;
2565 50 : status = smb2_lock(tree, &lck);
2566 50 : CHECK_STATUS_CMT(status, NT_STATUS_LOCK_NOT_GRANTED,
2567 : talloc_asprintf(torture,
2568 : "lock h at offset %#llx should not have "
2569 : "succeeded ",
2570 : (unsigned long long) el[0].offset));
2571 :
2572 50 : lck.in.file.handle = h;
2573 50 : el[0].offset = offset - 2;
2574 50 : status = smb2_lock(tree, &lck);
2575 50 : CHECK_STATUS_CMT(status, NT_STATUS_LOCK_NOT_GRANTED,
2576 : talloc_asprintf(torture,
2577 : "lock h2 at offset %#llx should not have "
2578 : "succeeded ",
2579 : (unsigned long long) el[0].offset));
2580 :
2581 50 : lck.in.file.handle = h2;
2582 50 : el[0].offset = offset - 1;
2583 50 : status = smb2_lock(tree, &lck);
2584 50 : CHECK_STATUS_CMT(status, NT_STATUS_LOCK_NOT_GRANTED,
2585 : talloc_asprintf(torture,
2586 : "lock h at offset %#llx should not have "
2587 : "succeeded ",
2588 : (unsigned long long) el[0].offset));
2589 :
2590 50 : lck.in.file.handle = h2;
2591 50 : el[0].offset = offset - 2;
2592 50 : status = smb2_lock(tree, &lck);
2593 50 : CHECK_STATUS_CMT(status, NT_STATUS_LOCK_NOT_GRANTED,
2594 : talloc_asprintf(torture,
2595 : "lock h2 at offset %#llx should not have "
2596 : "succeeded ",
2597 : (unsigned long long) el[0].offset));
2598 : }
2599 :
2600 5 : torture_comment(torture, " removing %d locks\n", torture_numops);
2601 :
2602 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2603 :
2604 55 : for (offset=i=0; i<torture_numops; i++) {
2605 50 : NEXT_OFFSET;
2606 :
2607 50 : lck.in.file.handle = h;
2608 50 : el[0].offset = offset - 1;
2609 50 : status = smb2_lock(tree, &lck);
2610 50 : CHECK_STATUS_CMT(status, NT_STATUS_OK,
2611 : talloc_asprintf(torture,
2612 : "unlock from h failed at offset %#llx ",
2613 : (unsigned long long) el[0].offset));
2614 :
2615 50 : lck.in.file.handle = h2;
2616 50 : el[0].offset = offset - 2;
2617 50 : status = smb2_lock(tree, &lck);
2618 50 : CHECK_STATUS_CMT(status, NT_STATUS_OK,
2619 : talloc_asprintf(torture,
2620 : "unlock from h2 failed at offset %#llx ",
2621 : (unsigned long long) el[0].offset));
2622 : }
2623 :
2624 5 : done:
2625 5 : smb2_util_close(tree, h2);
2626 5 : smb2_util_close(tree, h);
2627 5 : smb2_deltree(tree, BASEDIR);
2628 5 : return ret;
2629 : }
2630 :
2631 85 : static NTSTATUS test_smb2_lock(struct smb2_tree *tree, struct smb2_handle h,
2632 : uint64_t offset, uint64_t length, bool exclusive)
2633 : {
2634 0 : struct smb2_lock lck;
2635 0 : struct smb2_lock_element el[1];
2636 0 : NTSTATUS status;
2637 :
2638 85 : lck.in.locks = el;
2639 85 : lck.in.lock_count = 0x0001;
2640 85 : lck.in.lock_sequence = 0x00000000;
2641 85 : lck.in.file.handle = h;
2642 85 : el[0].offset = offset;
2643 85 : el[0].length = length;
2644 85 : el[0].reserved = 0x00000000;
2645 85 : el[0].flags = (exclusive ?
2646 : SMB2_LOCK_FLAG_EXCLUSIVE :
2647 85 : SMB2_LOCK_FLAG_SHARED) |
2648 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2649 :
2650 85 : status = smb2_lock(tree, &lck);
2651 :
2652 85 : return status;
2653 : }
2654 :
2655 5 : static NTSTATUS test_smb2_unlock(struct smb2_tree *tree, struct smb2_handle h,
2656 : uint64_t offset, uint64_t length)
2657 : {
2658 0 : struct smb2_lock lck;
2659 0 : struct smb2_lock_element el[1];
2660 0 : NTSTATUS status;
2661 :
2662 5 : lck.in.locks = el;
2663 5 : lck.in.lock_count = 0x0001;
2664 5 : lck.in.lock_sequence = 0x00000000;
2665 5 : lck.in.file.handle = h;
2666 5 : el[0].offset = offset;
2667 5 : el[0].length = length;
2668 5 : el[0].reserved = 0x00000000;
2669 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2670 :
2671 5 : status = smb2_lock(tree, &lck);
2672 :
2673 5 : return status;
2674 : }
2675 :
2676 : #define EXPECTED(ret, v) if ((ret) != (v)) { \
2677 : torture_result(torture, TORTURE_FAIL, __location__": subtest failed");\
2678 : torture_comment(torture, "** "); correct = false; \
2679 : }
2680 :
2681 : /**
2682 : * Test overlapping lock ranges from various lockers
2683 : * - some tests ported from BASE-LOCK-LOCK4
2684 : */
2685 5 : static bool test_overlap(struct torture_context *torture,
2686 : struct smb2_tree *tree,
2687 : struct smb2_tree *tree2)
2688 : {
2689 0 : NTSTATUS status;
2690 5 : bool ret = true;
2691 5 : struct smb2_handle h = {{0}};
2692 5 : struct smb2_handle h2 = {{0}};
2693 5 : struct smb2_handle h3 = {{0}};
2694 0 : uint8_t buf[200];
2695 5 : bool correct = true;
2696 :
2697 5 : const char *fname = BASEDIR "\\overlap.txt";
2698 :
2699 5 : status = torture_smb2_testdir(tree, BASEDIR, &h);
2700 5 : CHECK_STATUS(status, NT_STATUS_OK);
2701 5 : smb2_util_close(tree, h);
2702 :
2703 5 : status = torture_smb2_testfile(tree, fname, &h);
2704 5 : CHECK_STATUS(status, NT_STATUS_OK);
2705 :
2706 5 : ZERO_STRUCT(buf);
2707 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
2708 5 : CHECK_STATUS(status, NT_STATUS_OK);
2709 :
2710 5 : status = torture_smb2_testfile(tree, fname, &h2);
2711 5 : CHECK_STATUS(status, NT_STATUS_OK);
2712 :
2713 5 : status = torture_smb2_testfile(tree2, fname, &h3);
2714 5 : CHECK_STATUS(status, NT_STATUS_OK);
2715 :
2716 5 : torture_comment(torture, "Testing overlapping locks:\n");
2717 :
2718 10 : ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 0, 4, true)) &&
2719 5 : NT_STATUS_IS_OK(test_smb2_lock(tree, h, 2, 4, true));
2720 5 : EXPECTED(ret, false);
2721 5 : torture_comment(torture, "the same session/handle %s set overlapping "
2722 : "exclusive locks\n", ret?"can":"cannot");
2723 :
2724 10 : ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 10, 4, false)) &&
2725 5 : NT_STATUS_IS_OK(test_smb2_lock(tree, h, 12, 4, false));
2726 5 : EXPECTED(ret, true);
2727 5 : torture_comment(torture, "the same session/handle %s set overlapping "
2728 : "shared locks\n", ret?"can":"cannot");
2729 :
2730 10 : ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 20, 4, true)) &&
2731 5 : NT_STATUS_IS_OK(test_smb2_lock(tree2, h3, 22, 4, true));
2732 5 : EXPECTED(ret, false);
2733 5 : torture_comment(torture, "a different session %s set overlapping "
2734 : "exclusive locks\n", ret?"can":"cannot");
2735 :
2736 10 : ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 30, 4, false)) &&
2737 5 : NT_STATUS_IS_OK(test_smb2_lock(tree2, h3, 32, 4, false));
2738 5 : EXPECTED(ret, true);
2739 5 : torture_comment(torture, "a different session %s set overlapping "
2740 : "shared locks\n", ret?"can":"cannot");
2741 :
2742 10 : ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 40, 4, true)) &&
2743 5 : NT_STATUS_IS_OK(test_smb2_lock(tree, h2, 42, 4, true));
2744 5 : EXPECTED(ret, false);
2745 5 : torture_comment(torture, "a different handle %s set overlapping "
2746 : "exclusive locks\n", ret?"can":"cannot");
2747 :
2748 10 : ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 50, 4, false)) &&
2749 5 : NT_STATUS_IS_OK(test_smb2_lock(tree, h2, 52, 4, false));
2750 5 : EXPECTED(ret, true);
2751 5 : torture_comment(torture, "a different handle %s set overlapping "
2752 : "shared locks\n", ret?"can":"cannot");
2753 :
2754 5 : ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 110, 4, false)) &&
2755 10 : NT_STATUS_IS_OK(test_smb2_lock(tree, h, 112, 4, false)) &&
2756 5 : NT_STATUS_IS_OK(test_smb2_unlock(tree, h, 110, 6));
2757 5 : EXPECTED(ret, false);
2758 5 : torture_comment(torture, "the same handle %s coalesce read locks\n",
2759 : ret?"can":"cannot");
2760 :
2761 5 : smb2_util_close(tree, h2);
2762 5 : smb2_util_close(tree, h);
2763 5 : status = torture_smb2_testfile(tree, fname, &h);
2764 5 : CHECK_STATUS(status, NT_STATUS_OK);
2765 5 : status = torture_smb2_testfile(tree, fname, &h2);
2766 5 : CHECK_STATUS(status, NT_STATUS_OK);
2767 5 : ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 0, 8, false)) &&
2768 5 : NT_STATUS_IS_OK(test_smb2_lock(tree, h2, 0, 1, false)) &&
2769 5 : NT_STATUS_IS_OK(smb2_util_close(tree, h)) &&
2770 15 : NT_STATUS_IS_OK(torture_smb2_testfile(tree, fname, &h)) &&
2771 5 : NT_STATUS_IS_OK(test_smb2_lock(tree, h, 7, 1, true));
2772 5 : EXPECTED(ret, true);
2773 5 : torture_comment(torture, "the server %s have the NT byte range lock "
2774 5 : "bug\n", !ret?"does":"doesn't");
2775 :
2776 5 : done:
2777 5 : smb2_util_close(tree2, h3);
2778 5 : smb2_util_close(tree, h2);
2779 5 : smb2_util_close(tree, h);
2780 5 : smb2_deltree(tree, BASEDIR);
2781 5 : return correct;
2782 : }
2783 :
2784 : /**
2785 : * Test truncation of locked file
2786 : * - some tests ported from BASE-LOCK-LOCK7
2787 : */
2788 5 : static bool test_truncate(struct torture_context *torture,
2789 : struct smb2_tree *tree)
2790 : {
2791 0 : NTSTATUS status;
2792 5 : bool ret = true;
2793 5 : struct smb2_handle h = {{0}};
2794 5 : struct smb2_handle h2 = {{0}};
2795 0 : uint8_t buf[200];
2796 0 : struct smb2_lock lck;
2797 0 : struct smb2_lock_element el[1];
2798 0 : struct smb2_create io;
2799 :
2800 5 : const char *fname = BASEDIR "\\truncate.txt";
2801 :
2802 5 : status = torture_smb2_testdir(tree, BASEDIR, &h);
2803 5 : CHECK_STATUS(status, NT_STATUS_OK);
2804 5 : smb2_util_close(tree, h);
2805 :
2806 5 : status = torture_smb2_testfile(tree, fname, &h);
2807 5 : CHECK_STATUS(status, NT_STATUS_OK);
2808 :
2809 5 : ZERO_STRUCT(buf);
2810 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
2811 5 : CHECK_STATUS(status, NT_STATUS_OK);
2812 :
2813 5 : torture_comment(torture, "Testing truncation of locked file:\n");
2814 :
2815 : /* Setup initial parameters */
2816 5 : lck.in.locks = el;
2817 5 : lck.in.lock_count = 0x0001;
2818 5 : lck.in.lock_sequence = 0x00000000;
2819 5 : lck.in.file.handle = h;
2820 5 : el[0].offset = 0;
2821 5 : el[0].length = 10;
2822 5 : el[0].reserved = 0x00000000;
2823 :
2824 5 : ZERO_STRUCT(io);
2825 5 : io.in.oplock_level = 0;
2826 5 : io.in.desired_access = SEC_RIGHTS_FILE_ALL;
2827 5 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2828 5 : io.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2829 5 : io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
2830 : NTCREATEX_SHARE_ACCESS_READ |
2831 : NTCREATEX_SHARE_ACCESS_WRITE;
2832 5 : io.in.create_options = 0;
2833 5 : io.in.fname = fname;
2834 :
2835 : /* Take an exclusive lock */
2836 5 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2837 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2838 5 : status = smb2_lock(tree, &lck);
2839 5 : CHECK_STATUS(status, NT_STATUS_OK);
2840 :
2841 : /* On second handle open the file with OVERWRITE disposition */
2842 5 : torture_comment(torture, " overwrite disposition is allowed on a "
2843 : "locked file.\n");
2844 :
2845 5 : io.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2846 5 : status = smb2_create(tree, tree, &io);
2847 5 : CHECK_STATUS(status, NT_STATUS_OK);
2848 5 : h2 = io.out.file.handle;
2849 5 : smb2_util_close(tree, h2);
2850 :
2851 : /* On second handle open the file with SUPERSEDE disposition */
2852 5 : torture_comment(torture, " supersede disposition is allowed on a "
2853 : "locked file.\n");
2854 :
2855 5 : io.in.create_disposition = NTCREATEX_DISP_SUPERSEDE;
2856 5 : status = smb2_create(tree, tree, &io);
2857 5 : CHECK_STATUS(status, NT_STATUS_OK);
2858 5 : h2 = io.out.file.handle;
2859 5 : smb2_util_close(tree, h2);
2860 :
2861 : /* cleanup */
2862 5 : lck.in.file.handle = h;
2863 5 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2864 5 : status = smb2_lock(tree, &lck);
2865 5 : CHECK_STATUS(status, NT_STATUS_OK);
2866 :
2867 5 : done:
2868 5 : smb2_util_close(tree, h2);
2869 5 : smb2_util_close(tree, h);
2870 5 : smb2_deltree(tree, BASEDIR);
2871 5 : return ret;
2872 : }
2873 :
2874 : /**
2875 : * Test lock replay detection
2876 : *
2877 : * This test checks the SMB 2.1.0 behaviour of lock sequence checking,
2878 : * which is only turned on for resilient handles.
2879 : *
2880 : * Make it clear that this test is supposed to pass against the legacy
2881 : * Windows servers which violate the specification:
2882 : *
2883 : * [MS-SMB2] 3.3.5.14 Receiving an SMB2 LOCK Request
2884 : *
2885 : * ...
2886 : *
2887 : * ... if Open.IsResilient or Open.IsDurable or Open.IsPersistent is
2888 : * TRUE or if Connection.Dialect belongs to the SMB 3.x dialect family
2889 : * and Connection.ServerCapabilities includes
2890 : * SMB2_GLOBAL_CAP_MULTI_CHANNEL bit, the server SHOULD<314>
2891 : * perform lock sequence verification ...
2892 : *
2893 : * ...
2894 : *
2895 : * <314> Section 3.3.5.14: Windows 7 and Windows Server 2008 R2 perform
2896 : * lock sequence verification only when Open.IsResilient is TRUE.
2897 : * Windows 8 through Windows 10 v1909 and Windows Server 2012 through
2898 : * Windows Server v1909 perform lock sequence verification only when
2899 : * Open.IsResilient or Open.IsPersistent is TRUE.
2900 : *
2901 : * Note <314> also applies to all versions (at least) up to Windows Server v2004.
2902 : *
2903 : * Hopefully this will be fixed in future Windows versions and they
2904 : * will avoid Note <314>.
2905 : */
2906 5 : static bool test_replay_broken_windows(struct torture_context *torture,
2907 : struct smb2_tree *tree)
2908 : {
2909 0 : NTSTATUS status;
2910 5 : bool ret = true;
2911 0 : struct smb2_handle h;
2912 0 : struct smb2_ioctl ioctl;
2913 0 : struct smb2_lock lck;
2914 0 : struct smb2_lock_element el;
2915 0 : uint8_t res_req[8];
2916 5 : const char *fname = BASEDIR "\\replay_broken_windows.txt";
2917 5 : struct smb2_transport *transport = tree->session->transport;
2918 :
2919 5 : if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB2_10) {
2920 1 : torture_skip(torture, "SMB 2.1.0 Dialect family or above \
2921 : required for Lock Replay tests\n");
2922 : }
2923 :
2924 4 : status = torture_smb2_testdir(tree, BASEDIR, &h);
2925 4 : CHECK_STATUS(status, NT_STATUS_OK);
2926 4 : smb2_util_close(tree, h);
2927 :
2928 4 : torture_comment(torture, "Testing Open File:\n");
2929 4 : status = torture_smb2_testfile(tree, fname, &h);
2930 4 : CHECK_STATUS(status, NT_STATUS_OK);
2931 :
2932 : /*
2933 : * Setup initial parameters
2934 : */
2935 4 : el = (struct smb2_lock_element) {
2936 : .length = 100,
2937 : .offset = 100,
2938 : };
2939 4 : lck = (struct smb2_lock) {
2940 : .in.locks = &el,
2941 : .in.lock_count = 0x0001,
2942 : .in.file.handle = h
2943 : };
2944 :
2945 4 : torture_comment(torture, "Testing Lock Replay detection [ignored]:\n");
2946 4 : lck.in.lock_sequence = 0x010 + 0x1;
2947 4 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2948 4 : status = smb2_lock(tree, &lck);
2949 4 : CHECK_STATUS(status, NT_STATUS_OK);
2950 4 : status = smb2_lock(tree, &lck);
2951 4 : if (NT_STATUS_IS_OK(status)) {
2952 4 : lck.in.lock_sequence = 0x020 + 0x2;
2953 4 : status = smb2_lock(tree, &lck);
2954 4 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2955 4 : lck.in.lock_sequence = 0x010 + 0x1;
2956 4 : status = smb2_lock(tree, &lck);
2957 4 : CHECK_STATUS(status, NT_STATUS_OK);
2958 4 : if (smbXcli_conn_protocol(transport->conn) > PROTOCOL_SMB2_10) {
2959 4 : torture_skip_goto(torture, done,
2960 : "SMB3 Server implements LockSequence "
2961 : "for all handles\n");
2962 : }
2963 : }
2964 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2965 0 : if (smbXcli_conn_protocol(transport->conn) > PROTOCOL_SMB2_10) {
2966 0 : torture_comment(torture,
2967 : "\nSMB3 Server implements LockSequence as SMB 2.1.0"
2968 : " LEGACY BROKEN Windows!!!\n\n");
2969 : }
2970 0 : torture_comment(torture,
2971 : "Testing SMB 2.1.0 LockSequence for ResilientHandles\n");
2972 :
2973 0 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
2974 0 : status = smb2_lock(tree, &lck);
2975 0 : CHECK_STATUS(status, NT_STATUS_OK);
2976 0 : status = smb2_lock(tree, &lck);
2977 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
2978 :
2979 0 : torture_comment(torture, "Testing Set Resiliency:\n");
2980 0 : SIVAL(res_req, 0, 1000); /* timeout */
2981 0 : SIVAL(res_req, 4, 0); /* reserved */
2982 0 : ioctl = (struct smb2_ioctl) {
2983 : .level = RAW_IOCTL_SMB2,
2984 : .in.file.handle = h,
2985 : .in.function = FSCTL_LMR_REQ_RESILIENCY,
2986 : .in.max_output_response = 0,
2987 : .in.flags = SMB2_IOCTL_FLAG_IS_FSCTL,
2988 : .in.out.data = res_req,
2989 : .in.out.length = sizeof(res_req)
2990 : };
2991 0 : status = smb2_ioctl(tree, torture, &ioctl);
2992 0 : CHECK_STATUS(status, NT_STATUS_OK);
2993 :
2994 : /*
2995 : * Test with an invalid bucket number (only 1..64 are valid).
2996 : * With an invalid number, lock replay detection is not performed.
2997 : */
2998 0 : torture_comment(torture, "Testing Lock (ignored) Replay detection "
2999 : "(Bucket No: 0 (invalid)) [ignored]:\n");
3000 0 : lck.in.lock_sequence = 0x000 + 0x1;
3001 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3002 0 : status = smb2_lock(tree, &lck);
3003 0 : CHECK_STATUS(status, NT_STATUS_OK);
3004 0 : status = smb2_lock(tree, &lck);
3005 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3006 :
3007 0 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3008 0 : status = smb2_lock(tree, &lck);
3009 0 : CHECK_STATUS(status, NT_STATUS_OK);
3010 0 : status = smb2_lock(tree, &lck);
3011 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
3012 :
3013 0 : torture_comment(torture, "Testing Lock Replay detection "
3014 : "(Bucket No: 1):\n");
3015 :
3016 : /*
3017 : * Obtain Exclusive Lock of length 100 bytes using Bucket Num 1
3018 : * and Bucket Seq 1.
3019 : */
3020 0 : lck.in.lock_sequence = 0x010 + 0x1;
3021 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3022 0 : status = smb2_lock(tree, &lck);
3023 0 : CHECK_STATUS(status, NT_STATUS_OK);
3024 :
3025 : /*
3026 : * Server detects Replay of Byte Range locks using the Lock Sequence
3027 : * Numbers. And ignores the requests completely.
3028 : */
3029 0 : status = smb2_lock(tree, &lck);
3030 0 : CHECK_STATUS(status, NT_STATUS_OK);
3031 0 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3032 0 : status = smb2_lock(tree, &lck);
3033 0 : CHECK_STATUS(status, NT_STATUS_OK);
3034 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3035 0 : status = smb2_lock(tree, &lck);
3036 0 : CHECK_STATUS(status, NT_STATUS_OK);
3037 0 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3038 0 : status = smb2_lock(tree, &lck);
3039 0 : CHECK_STATUS(status, NT_STATUS_OK);
3040 0 : status = smb2_lock(tree, &lck);
3041 0 : CHECK_STATUS(status, NT_STATUS_OK);
3042 :
3043 : /* status: still locked */
3044 :
3045 : /*
3046 : * Server will not grant same Byte Range using a different Bucket Seq
3047 : */
3048 0 : lck.in.lock_sequence = 0x010 + 0x2;
3049 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3050 0 : status = smb2_lock(tree, &lck);
3051 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3052 0 : status = smb2_lock(tree, &lck);
3053 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3054 :
3055 0 : torture_comment(torture, "Testing Lock Replay detection "
3056 : "(Bucket No: 2):\n");
3057 :
3058 : /*
3059 : * Server will not grant same Byte Range using a different Bucket Num
3060 : */
3061 0 : lck.in.lock_sequence = 0x020 + 0x1;
3062 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3063 0 : status = smb2_lock(tree, &lck);
3064 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3065 0 : status = smb2_lock(tree, &lck);
3066 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3067 :
3068 : /* status: still locked */
3069 :
3070 : /* test with invalid bucket when file is locked */
3071 :
3072 0 : torture_comment(torture, "Testing Lock Replay detection "
3073 : "(Bucket No: 65 (invalid)) [ignored]:\n");
3074 :
3075 0 : lck.in.lock_sequence = 0x410 + 0x1;
3076 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3077 0 : status = smb2_lock(tree, &lck);
3078 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3079 0 : status = smb2_lock(tree, &lck);
3080 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3081 :
3082 0 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3083 0 : status = smb2_lock(tree, &lck);
3084 0 : CHECK_STATUS(status, NT_STATUS_OK);
3085 0 : status = smb2_lock(tree, &lck);
3086 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
3087 :
3088 : /* status: unlocked */
3089 :
3090 : /*
3091 : * Lock again for the unlock replay test
3092 : */
3093 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3094 0 : status = smb2_lock(tree, &lck);
3095 0 : CHECK_STATUS(status, NT_STATUS_OK);
3096 :
3097 0 : torture_comment(torture, "Testing Lock Replay detection "
3098 : "(Bucket No: 64):\n");
3099 :
3100 : /*
3101 : * Server will not grant same Byte Range using a different Bucket Num
3102 : */
3103 0 : lck.in.lock_sequence = 0x400 + 0x1;
3104 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3105 0 : status = smb2_lock(tree, &lck);
3106 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3107 0 : status = smb2_lock(tree, &lck);
3108 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3109 :
3110 : /*
3111 : * Test Unlock replay detection
3112 : */
3113 0 : lck.in.lock_sequence = 0x400 + 0x2;
3114 0 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3115 0 : status = smb2_lock(tree, &lck);
3116 0 : CHECK_STATUS(status, NT_STATUS_OK); /* new seq num ==> unlocked */
3117 0 : status = smb2_lock(tree, &lck);
3118 0 : CHECK_STATUS(status, NT_STATUS_OK); /* replay detected ==> ignored */
3119 :
3120 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3121 0 : status = smb2_lock(tree, &lck); /* same seq num ==> ignored */
3122 0 : CHECK_STATUS(status, NT_STATUS_OK);
3123 :
3124 : /* verify it's unlocked: */
3125 0 : lck.in.lock_sequence = 0x400 + 0x3;
3126 0 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3127 0 : status = smb2_lock(tree, &lck);
3128 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
3129 :
3130 : /* status: not locked */
3131 :
3132 4 : done:
3133 4 : smb2_util_close(tree, h);
3134 4 : smb2_deltree(tree, BASEDIR);
3135 4 : return ret;
3136 : }
3137 :
3138 : /**
3139 : * Test lock replay detection
3140 : *
3141 : * This test check the SMB 3 behaviour of lock sequence checking,
3142 : * which should be implemented for all handles.
3143 : *
3144 : * Make it clear that this test is supposed to pass a
3145 : * server implementing the specification:
3146 : *
3147 : * [MS-SMB2] 3.3.5.14 Receiving an SMB2 LOCK Request
3148 : *
3149 : * ...
3150 : *
3151 : * ... if Open.IsResilient or Open.IsDurable or Open.IsPersistent is
3152 : * TRUE or if Connection.Dialect belongs to the SMB 3.x dialect family
3153 : * and Connection.ServerCapabilities includes
3154 : * SMB2_GLOBAL_CAP_MULTI_CHANNEL bit, the server SHOULD<314>
3155 : * perform lock sequence verification ...
3156 : *
3157 : * ...
3158 : *
3159 : * <314> Section 3.3.5.14: Windows 7 and Windows Server 2008 R2 perform
3160 : * lock sequence verification only when Open.IsResilient is TRUE.
3161 : * Windows 8 through Windows 10 v1909 and Windows Server 2012 through
3162 : * Windows Server v1909 perform lock sequence verification only when
3163 : * Open.IsResilient or Open.IsPersistent is TRUE.
3164 : *
3165 : * Note <314> also applies to all versions (at least) up to Windows Server v2004.
3166 : *
3167 : * Hopefully this will be fixed in future Windows versions and they
3168 : * will avoid Note <314>.
3169 : */
3170 8 : static bool _test_replay_smb3_specification(struct torture_context *torture,
3171 : struct smb2_tree *tree,
3172 : const char *testname,
3173 : bool use_durable)
3174 : {
3175 0 : NTSTATUS status;
3176 8 : bool ret = true;
3177 0 : struct smb2_create io;
3178 0 : struct smb2_handle h;
3179 0 : struct smb2_lock lck;
3180 0 : struct smb2_lock_element el;
3181 0 : char fname[256];
3182 8 : struct smb2_transport *transport = tree->session->transport;
3183 :
3184 8 : if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
3185 0 : torture_skip(torture, "SMB 3.0.0 Dialect family or above \
3186 : required for Lock Replay tests\n");
3187 : }
3188 :
3189 8 : snprintf(fname, sizeof(fname), "%s\\%s.dat", BASEDIR, testname);
3190 :
3191 8 : status = torture_smb2_testdir(tree, BASEDIR, &h);
3192 8 : CHECK_STATUS(status, NT_STATUS_OK);
3193 8 : smb2_util_close(tree, h);
3194 :
3195 8 : torture_comment(torture, "%s: Testing Open File:\n", testname);
3196 :
3197 8 : smb2_oplock_create_share(&io, fname,
3198 : smb2_util_share_access(""),
3199 8 : smb2_util_oplock_level("b"));
3200 8 : io.in.durable_open = use_durable;
3201 :
3202 8 : status = smb2_create(tree, torture, &io);
3203 8 : CHECK_STATUS(status, NT_STATUS_OK);
3204 8 : h = io.out.file.handle;
3205 8 : CHECK_VALUE(io.out.oplock_level, smb2_util_oplock_level("b"));
3206 8 : CHECK_VALUE(io.out.durable_open, use_durable);
3207 8 : CHECK_VALUE(io.out.durable_open_v2, false);
3208 8 : CHECK_VALUE(io.out.persistent_open, false);
3209 :
3210 : /*
3211 : * Setup initial parameters
3212 : */
3213 8 : el = (struct smb2_lock_element) {
3214 : .length = 100,
3215 : .offset = 100,
3216 : };
3217 8 : lck = (struct smb2_lock) {
3218 : .in.locks = &el,
3219 : .in.lock_count = 0x0001,
3220 : .in.file.handle = h
3221 : };
3222 :
3223 8 : torture_comment(torture,
3224 : "Testing SMB 3 LockSequence for all Handles\n");
3225 :
3226 : /*
3227 : * Test with an invalid bucket number (only 1..64 are valid).
3228 : * With an invalid number, lock replay detection is not performed.
3229 : */
3230 8 : torture_comment(torture, "Testing Lock (ignored) Replay detection "
3231 : "(Bucket No: 0 (invalid)) [ignored]:\n");
3232 8 : lck.in.lock_sequence = 0x000 + 0x1;
3233 8 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3234 8 : status = smb2_lock(tree, &lck);
3235 8 : CHECK_STATUS(status, NT_STATUS_OK);
3236 8 : status = smb2_lock(tree, &lck);
3237 8 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3238 :
3239 8 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3240 8 : status = smb2_lock(tree, &lck);
3241 8 : CHECK_STATUS(status, NT_STATUS_OK);
3242 8 : status = smb2_lock(tree, &lck);
3243 8 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
3244 :
3245 8 : torture_comment(torture, "Testing Lock Replay detection "
3246 : "(Bucket No: 1):\n");
3247 :
3248 : /*
3249 : * Obtain Exclusive Lock of length 100 bytes using Bucket Num 1
3250 : * and Bucket Seq 1.
3251 : */
3252 8 : lck.in.lock_sequence = 0x010 + 0x1;
3253 8 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3254 8 : status = smb2_lock(tree, &lck);
3255 8 : CHECK_STATUS(status, NT_STATUS_OK);
3256 :
3257 : /*
3258 : * Server detects Replay of Byte Range locks using the Lock Sequence
3259 : * Numbers. And ignores the requests completely.
3260 : */
3261 8 : status = smb2_lock(tree, &lck);
3262 8 : CHECK_STATUS(status, NT_STATUS_OK);
3263 8 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3264 8 : status = smb2_lock(tree, &lck);
3265 8 : CHECK_STATUS(status, NT_STATUS_OK);
3266 8 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3267 8 : status = smb2_lock(tree, &lck);
3268 8 : CHECK_STATUS(status, NT_STATUS_OK);
3269 8 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3270 8 : status = smb2_lock(tree, &lck);
3271 8 : CHECK_STATUS(status, NT_STATUS_OK);
3272 8 : status = smb2_lock(tree, &lck);
3273 8 : CHECK_STATUS(status, NT_STATUS_OK);
3274 :
3275 : /* status: still locked */
3276 :
3277 : /*
3278 : * Server will not grant same Byte Range using a different Bucket Seq
3279 : */
3280 8 : lck.in.lock_sequence = 0x010 + 0x2;
3281 8 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3282 8 : status = smb2_lock(tree, &lck);
3283 8 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3284 8 : status = smb2_lock(tree, &lck);
3285 8 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3286 :
3287 8 : torture_comment(torture, "Testing Lock Replay detection "
3288 : "(Bucket No: 2):\n");
3289 :
3290 : /*
3291 : * Server will not grant same Byte Range using a different Bucket Num
3292 : */
3293 8 : lck.in.lock_sequence = 0x020 + 0x1;
3294 8 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3295 8 : status = smb2_lock(tree, &lck);
3296 8 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3297 8 : status = smb2_lock(tree, &lck);
3298 8 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3299 :
3300 : /* status: still locked */
3301 :
3302 : /* test with invalid bucket when file is locked */
3303 :
3304 8 : torture_comment(torture, "Testing Lock Replay detection "
3305 : "(Bucket No: 65 (invalid)) [ignored]:\n");
3306 :
3307 8 : lck.in.lock_sequence = 0x410 + 0x1;
3308 8 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3309 8 : status = smb2_lock(tree, &lck);
3310 8 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3311 8 : status = smb2_lock(tree, &lck);
3312 8 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3313 :
3314 8 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3315 8 : status = smb2_lock(tree, &lck);
3316 8 : CHECK_STATUS(status, NT_STATUS_OK);
3317 8 : status = smb2_lock(tree, &lck);
3318 8 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
3319 :
3320 : /* status: unlocked */
3321 :
3322 : /*
3323 : * Lock again for the unlock replay test
3324 : */
3325 8 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3326 8 : status = smb2_lock(tree, &lck);
3327 8 : CHECK_STATUS(status, NT_STATUS_OK);
3328 :
3329 8 : torture_comment(torture, "Testing Lock Replay detection "
3330 : "(Bucket No: 64):\n");
3331 :
3332 : /*
3333 : * Server will not grant same Byte Range using a different Bucket Num
3334 : */
3335 8 : lck.in.lock_sequence = 0x400 + 0x1;
3336 8 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3337 8 : status = smb2_lock(tree, &lck);
3338 8 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3339 8 : status = smb2_lock(tree, &lck);
3340 8 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3341 :
3342 : /*
3343 : * Test Unlock replay detection
3344 : */
3345 8 : lck.in.lock_sequence = 0x400 + 0x2;
3346 8 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3347 8 : status = smb2_lock(tree, &lck);
3348 8 : CHECK_STATUS(status, NT_STATUS_OK); /* new seq num ==> unlocked */
3349 8 : status = smb2_lock(tree, &lck);
3350 8 : CHECK_STATUS(status, NT_STATUS_OK); /* replay detected ==> ignored */
3351 :
3352 8 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3353 8 : status = smb2_lock(tree, &lck); /* same seq num ==> ignored */
3354 8 : CHECK_STATUS(status, NT_STATUS_OK);
3355 :
3356 : /* verify it's unlocked: */
3357 8 : lck.in.lock_sequence = 0x400 + 0x3;
3358 8 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3359 8 : status = smb2_lock(tree, &lck);
3360 8 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
3361 :
3362 : /* status: not locked */
3363 :
3364 8 : done:
3365 8 : smb2_util_close(tree, h);
3366 8 : smb2_deltree(tree, BASEDIR);
3367 8 : return ret;
3368 : }
3369 :
3370 5 : static bool test_replay_smb3_specification_durable(struct torture_context *torture,
3371 : struct smb2_tree *tree)
3372 : {
3373 5 : const char *testname = "replay_smb3_specification_durable";
3374 5 : struct smb2_transport *transport = tree->session->transport;
3375 :
3376 5 : if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB2_10) {
3377 1 : torture_skip(torture, "SMB 2.1.0 Dialect family or above \
3378 : required for Lock Replay tests on durable handles\n");
3379 : }
3380 :
3381 4 : return _test_replay_smb3_specification(torture, tree, testname, true);
3382 : }
3383 :
3384 5 : static bool test_replay_smb3_specification_multi(struct torture_context *torture,
3385 : struct smb2_tree *tree)
3386 : {
3387 5 : const char *testname = "replay_smb3_specification_multi";
3388 5 : struct smb2_transport *transport = tree->session->transport;
3389 0 : uint32_t server_capabilities;
3390 :
3391 5 : if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
3392 1 : torture_skip(torture, "SMB 3.0.0 Dialect family or above \
3393 : required for Lock Replay tests on without durable handles\n");
3394 : }
3395 :
3396 4 : server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
3397 4 : if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
3398 0 : torture_skip(torture, "MULTI_CHANNEL is \
3399 : required for Lock Replay tests on without durable handles\n");
3400 : }
3401 :
3402 4 : return _test_replay_smb3_specification(torture, tree, testname, false);
3403 : }
3404 :
3405 : /**
3406 : * Test lock interaction between smbd and ctdb with tombstone records.
3407 : *
3408 : * Re-locking an unlocked record could lead to a deadlock between
3409 : * smbd and ctdb. Make sure we don't regress.
3410 : *
3411 : * https://bugzilla.samba.org/show_bug.cgi?id=12005
3412 : * https://bugzilla.samba.org/show_bug.cgi?id=10008
3413 : */
3414 5 : static bool test_deadlock(struct torture_context *torture,
3415 : struct smb2_tree *tree)
3416 : {
3417 0 : NTSTATUS status;
3418 5 : bool ret = true;
3419 0 : struct smb2_handle _h;
3420 5 : struct smb2_handle *h = NULL;
3421 0 : uint8_t buf[200];
3422 5 : const char *fname = BASEDIR "\\deadlock.txt";
3423 :
3424 5 : if (!lpcfg_clustering(torture->lp_ctx)) {
3425 5 : torture_skip(torture, "Test must be run on a ctdb cluster\n");
3426 : return true;
3427 : }
3428 :
3429 0 : status = torture_smb2_testdir(tree, BASEDIR, &_h);
3430 0 : torture_assert_ntstatus_ok(torture, status,
3431 : "torture_smb2_testdir failed");
3432 0 : smb2_util_close(tree, _h);
3433 :
3434 0 : status = torture_smb2_testfile(tree, fname, &_h);
3435 0 : torture_assert_ntstatus_ok_goto(torture, status, ret, done,
3436 : "torture_smb2_testfile failed");
3437 0 : h = &_h;
3438 :
3439 0 : ZERO_STRUCT(buf);
3440 0 : status = smb2_util_write(tree, *h, buf, 0, ARRAY_SIZE(buf));
3441 0 : torture_assert_ntstatus_ok_goto(torture, status, ret, done,
3442 : "smb2_util_write failed");
3443 :
3444 0 : status = test_smb2_lock(tree, *h, 0, 1, true);
3445 0 : torture_assert_ntstatus_ok_goto(torture, status, ret, done,
3446 : "test_smb2_lock failed");
3447 :
3448 0 : status = test_smb2_unlock(tree, *h, 0, 1);
3449 0 : torture_assert_ntstatus_ok_goto(torture, status, ret, done,
3450 : "test_smb2_unlock failed");
3451 :
3452 0 : status = test_smb2_lock(tree, *h, 0, 1, true);
3453 0 : torture_assert_ntstatus_ok_goto(torture, status, ret, done,
3454 : "test_smb2_lock failed");
3455 :
3456 0 : status = test_smb2_unlock(tree, *h, 0, 1);
3457 0 : torture_assert_ntstatus_ok_goto(torture, status, ret, done,
3458 : "test_smb2_unlock failed");
3459 :
3460 0 : done:
3461 0 : if (h != NULL) {
3462 0 : smb2_util_close(tree, *h);
3463 : }
3464 0 : smb2_deltree(tree, BASEDIR);
3465 0 : return ret;
3466 : }
3467 :
3468 : /* basic testing of SMB2 locking
3469 : */
3470 2354 : struct torture_suite *torture_smb2_lock_init(TALLOC_CTX *ctx)
3471 : {
3472 125 : struct torture_suite *suite =
3473 2354 : torture_suite_create(ctx, "lock");
3474 2354 : torture_suite_add_1smb2_test(suite, "valid-request",
3475 : test_valid_request);
3476 2354 : torture_suite_add_1smb2_test(suite, "rw-none", test_lock_rw_none);
3477 2354 : torture_suite_add_1smb2_test(suite, "rw-shared", test_lock_rw_shared);
3478 2354 : torture_suite_add_1smb2_test(suite, "rw-exclusive",
3479 : test_lock_rw_exclusive);
3480 2354 : torture_suite_add_1smb2_test(suite, "auto-unlock",
3481 : test_lock_auto_unlock);
3482 2354 : torture_suite_add_1smb2_test(suite, "lock", test_lock);
3483 2354 : torture_suite_add_1smb2_test(suite, "async", test_async);
3484 2354 : torture_suite_add_1smb2_test(suite, "cancel", test_cancel);
3485 2354 : torture_suite_add_1smb2_test(suite, "cancel-tdis", test_cancel_tdis);
3486 2354 : torture_suite_add_1smb2_test(suite, "cancel-logoff",
3487 : test_cancel_logoff);
3488 2354 : torture_suite_add_1smb2_test(suite, "errorcode", test_errorcode);
3489 2354 : torture_suite_add_1smb2_test(suite, "zerobytelength",
3490 : test_zerobytelength);
3491 2354 : torture_suite_add_1smb2_test(suite, "zerobyteread",
3492 : test_zerobyteread);
3493 2354 : torture_suite_add_1smb2_test(suite, "unlock", test_unlock);
3494 2354 : torture_suite_add_1smb2_test(suite, "multiple-unlock",
3495 : test_multiple_unlock);
3496 2354 : torture_suite_add_1smb2_test(suite, "stacking", test_stacking);
3497 2354 : torture_suite_add_1smb2_test(suite, "contend", test_contend);
3498 2354 : torture_suite_add_1smb2_test(suite, "context", test_context);
3499 2354 : torture_suite_add_1smb2_test(suite, "range", test_range);
3500 2354 : torture_suite_add_2smb2_test(suite, "overlap", test_overlap);
3501 2354 : torture_suite_add_1smb2_test(suite, "truncate", test_truncate);
3502 2354 : torture_suite_add_1smb2_test(suite, "replay_broken_windows",
3503 : test_replay_broken_windows);
3504 2354 : torture_suite_add_1smb2_test(suite, "replay_smb3_specification_durable",
3505 : test_replay_smb3_specification_durable);
3506 2354 : torture_suite_add_1smb2_test(suite, "replay_smb3_specification_multi",
3507 : test_replay_smb3_specification_multi);
3508 2354 : torture_suite_add_1smb2_test(suite, "ctdb-delrec-deadlock", test_deadlock);
3509 :
3510 2354 : suite->description = talloc_strdup(suite, "SMB2-LOCK tests");
3511 :
3512 2354 : return suite;
3513 : }
|