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 1 : static bool test_valid_request(struct torture_context *torture,
72 : struct smb2_tree *tree)
73 : {
74 1 : bool ret = true;
75 : NTSTATUS status;
76 : struct smb2_handle h;
77 : uint8_t buf[200];
78 : struct smb2_lock lck;
79 : struct smb2_lock_element el[2];
80 :
81 1 : ZERO_STRUCT(buf);
82 :
83 1 : status = torture_smb2_testfile(tree, "lock1.txt", &h);
84 1 : CHECK_STATUS(status, NT_STATUS_OK);
85 :
86 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
87 1 : CHECK_STATUS(status, NT_STATUS_OK);
88 :
89 1 : lck.in.locks = el;
90 :
91 1 : torture_comment(torture, "Test request with 0 locks.\n");
92 :
93 1 : lck.in.lock_count = 0x0000;
94 1 : lck.in.lock_sequence = 0x00000000;
95 1 : lck.in.file.handle = h;
96 1 : el[0].offset = 0x0000000000000000;
97 1 : el[0].length = 0x0000000000000000;
98 1 : el[0].reserved = 0x0000000000000000;
99 1 : el[0].flags = 0x00000000;
100 1 : status = smb2_lock(tree, &lck);
101 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
102 :
103 1 : lck.in.lock_count = 0x0000;
104 1 : lck.in.lock_sequence = 0x00000000;
105 1 : lck.in.file.handle = h;
106 1 : el[0].offset = 0;
107 1 : el[0].length = 0;
108 1 : el[0].reserved = 0x00000000;
109 1 : el[0].flags = SMB2_LOCK_FLAG_SHARED;
110 1 : status = smb2_lock(tree, &lck);
111 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
112 :
113 1 : lck.in.lock_count = 0x0001;
114 1 : lck.in.lock_sequence = 0x00000000;
115 1 : lck.in.file.handle = h;
116 1 : el[0].offset = 0;
117 1 : el[0].length = 0;
118 1 : el[0].reserved = 0x00000000;
119 1 : el[0].flags = SMB2_LOCK_FLAG_NONE;
120 1 : status = smb2_lock(tree, &lck);
121 1 : 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 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
127 : }
128 :
129 1 : torture_comment(torture, "Test >63-bit lock requests.\n");
130 :
131 1 : lck.in.file.handle.data[0] +=1;
132 1 : status = smb2_lock(tree, &lck);
133 1 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
134 1 : lck.in.file.handle.data[0] -=1;
135 :
136 1 : lck.in.lock_count = 0x0001;
137 1 : lck.in.lock_sequence = 0x123ab1;
138 1 : lck.in.file.handle = h;
139 1 : el[0].offset = UINT64_MAX;
140 1 : el[0].length = UINT64_MAX;
141 1 : el[0].reserved = 0x00000000;
142 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
143 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
144 1 : status = smb2_lock(tree, &lck);
145 1 : if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(torture)) {
146 1 : 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 1 : lck.in.lock_sequence = 0x123ab2;
153 1 : status = smb2_lock(tree, &lck);
154 1 : if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(torture)) {
155 1 : CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
156 : } else {
157 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
158 : }
159 :
160 1 : torture_comment(torture, "Test basic lock stacking.\n");
161 :
162 1 : lck.in.lock_count = 0x0001;
163 1 : lck.in.lock_sequence = 0x12345678;
164 1 : lck.in.file.handle = h;
165 1 : el[0].offset = UINT32_MAX;
166 1 : el[0].length = UINT32_MAX;
167 1 : el[0].reserved = 0x87654321;
168 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
169 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
170 1 : status = smb2_lock(tree, &lck);
171 1 : CHECK_STATUS(status, NT_STATUS_OK);
172 1 : CHECK_VALUE(lck.out.reserved, 0);
173 :
174 1 : el[0].flags = SMB2_LOCK_FLAG_SHARED;
175 1 : status = smb2_lock(tree, &lck);
176 1 : CHECK_STATUS(status, NT_STATUS_OK);
177 1 : CHECK_VALUE(lck.out.reserved, 0);
178 :
179 1 : status = smb2_lock(tree, &lck);
180 1 : CHECK_STATUS(status, NT_STATUS_OK);
181 1 : CHECK_VALUE(lck.out.reserved, 0);
182 :
183 1 : lck.in.lock_count = 0x0001;
184 1 : lck.in.lock_sequence = 0x87654321;
185 1 : lck.in.file.handle = h;
186 1 : el[0].offset = 0x00000000FFFFFFFF;
187 1 : el[0].length = 0x00000000FFFFFFFF;
188 1 : el[0].reserved = 0x1234567;
189 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
190 1 : status = smb2_lock(tree, &lck);
191 1 : CHECK_STATUS(status, NT_STATUS_OK);
192 :
193 1 : lck.in.lock_count = 0x0001;
194 1 : lck.in.lock_sequence = 0x1234567;
195 1 : lck.in.file.handle = h;
196 1 : el[0].offset = 0x00000000FFFFFFFF;
197 1 : el[0].length = 0x00000000FFFFFFFF;
198 1 : el[0].reserved = 0x00000000;
199 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
200 1 : status = smb2_lock(tree, &lck);
201 1 : CHECK_STATUS(status, NT_STATUS_OK);
202 :
203 1 : status = smb2_lock(tree, &lck);
204 1 : CHECK_STATUS(status, NT_STATUS_OK);
205 1 : status = smb2_lock(tree, &lck);
206 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
207 :
208 1 : torture_comment(torture, "Test flags field permutations.\n");
209 :
210 1 : lck.in.lock_count = 0x0001;
211 1 : lck.in.lock_sequence = 0;
212 1 : lck.in.file.handle = h;
213 1 : el[0].offset = 1;
214 1 : el[0].length = 1;
215 1 : el[0].reserved = 0x00000000;
216 1 : el[0].flags = ~SMB2_LOCK_FLAG_ALL_MASK;
217 :
218 1 : status = smb2_lock(tree, &lck);
219 1 : 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 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
225 : }
226 :
227 1 : 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 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
234 1 : status = smb2_lock(tree, &lck);
235 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
236 :
237 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK |
238 : SMB2_LOCK_FLAG_EXCLUSIVE;
239 1 : status = smb2_lock(tree, &lck);
240 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
241 :
242 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK |
243 : SMB2_LOCK_FLAG_SHARED;
244 1 : status = smb2_lock(tree, &lck);
245 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
246 :
247 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK |
248 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
249 1 : status = smb2_lock(tree, &lck);
250 1 : 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 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
256 : }
257 :
258 1 : torture_comment(torture, "Test return error when 2 locks are "
259 : "requested\n");
260 :
261 1 : lck.in.lock_count = 2;
262 1 : lck.in.lock_sequence = 0;
263 1 : lck.in.file.handle = h;
264 1 : el[0].offset = 9999;
265 1 : el[0].length = 1;
266 1 : el[0].reserved = 0x00000000;
267 1 : el[1].offset = 9999;
268 1 : el[1].length = 1;
269 1 : el[1].reserved = 0x00000000;
270 :
271 1 : lck.in.lock_count = 2;
272 1 : el[0].flags = 0;
273 1 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
274 1 : status = smb2_lock(tree, &lck);
275 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
276 :
277 1 : lck.in.lock_count = 2;
278 1 : el[0].flags = SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
279 1 : el[1].flags = SMB2_LOCK_FLAG_SHARED;
280 1 : status = smb2_lock(tree, &lck);
281 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
282 :
283 0 : lck.in.lock_count = 2;
284 0 : el[0].flags = 0;
285 0 : el[1].flags = 0;
286 0 : status = smb2_lock(tree, &lck);
287 0 : 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 0 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
293 : }
294 :
295 0 : lck.in.lock_count = 2;
296 0 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
297 0 : el[1].flags = 0;
298 0 : status = smb2_lock(tree, &lck);
299 0 : 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 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
305 : }
306 :
307 0 : lck.in.lock_count = 1;
308 0 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
309 0 : status = smb2_lock(tree, &lck);
310 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
311 :
312 0 : lck.in.lock_count = 1;
313 0 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
314 0 : status = smb2_lock(tree, &lck);
315 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
316 :
317 0 : lck.in.lock_count = 1;
318 0 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
319 0 : status = smb2_lock(tree, &lck);
320 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
321 :
322 0 : lck.in.lock_count = 1;
323 0 : el[0].flags = SMB2_LOCK_FLAG_SHARED;
324 0 : status = smb2_lock(tree, &lck);
325 0 : CHECK_STATUS(status, NT_STATUS_OK);
326 :
327 0 : status = smb2_lock(tree, &lck);
328 0 : CHECK_STATUS(status, NT_STATUS_OK);
329 :
330 0 : lck.in.lock_count = 2;
331 0 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
332 0 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
333 0 : status = smb2_lock(tree, &lck);
334 0 : CHECK_STATUS(status, NT_STATUS_OK);
335 :
336 0 : lck.in.lock_count = 1;
337 0 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
338 0 : status = smb2_lock(tree, &lck);
339 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
340 :
341 1 : done:
342 1 : 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 2 : 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 2 : bool ret = true;
359 : NTSTATUS status;
360 : struct smb2_handle h1, h2;
361 : uint8_t buf[200];
362 : struct smb2_lock lck;
363 : struct smb2_create cr;
364 : struct smb2_write wr;
365 : struct smb2_read rd;
366 : struct smb2_lock_element el[1];
367 :
368 2 : lck.in.locks = el;
369 :
370 2 : ZERO_STRUCT(buf);
371 :
372 2 : status = torture_smb2_testfile(tree, s->fname, &h1);
373 2 : CHECK_STATUS(status, NT_STATUS_OK);
374 :
375 2 : status = smb2_util_write(tree, h1, buf, 0, ARRAY_SIZE(buf));
376 2 : CHECK_STATUS(status, NT_STATUS_OK);
377 :
378 2 : lck.in.lock_count = 0x0001;
379 2 : lck.in.lock_sequence = 0x00000000;
380 2 : lck.in.file.handle = h1;
381 2 : el[0].offset = 0;
382 2 : el[0].length = ARRAY_SIZE(buf)/2;
383 2 : el[0].reserved = 0x00000000;
384 2 : el[0].flags = s->lock_flags;
385 2 : status = smb2_lock(tree, &lck);
386 2 : CHECK_STATUS(status, NT_STATUS_OK);
387 2 : CHECK_VALUE(lck.out.reserved, 0);
388 :
389 2 : lck.in.lock_count = 0x0001;
390 2 : lck.in.lock_sequence = 0x00000000;
391 2 : lck.in.file.handle = h1;
392 2 : el[0].offset = ARRAY_SIZE(buf)/2;
393 2 : el[0].length = ARRAY_SIZE(buf)/2;
394 2 : el[0].reserved = 0x00000000;
395 2 : el[0].flags = s->lock_flags;
396 2 : status = smb2_lock(tree, &lck);
397 2 : CHECK_STATUS(status, NT_STATUS_OK);
398 2 : CHECK_VALUE(lck.out.reserved, 0);
399 :
400 2 : ZERO_STRUCT(cr);
401 2 : cr.in.oplock_level = 0;
402 2 : cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
403 2 : cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
404 2 : cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
405 2 : cr.in.share_access =
406 : NTCREATEX_SHARE_ACCESS_DELETE|
407 : NTCREATEX_SHARE_ACCESS_READ|
408 : NTCREATEX_SHARE_ACCESS_WRITE;
409 2 : cr.in.create_options = 0;
410 2 : cr.in.fname = s->fname;
411 :
412 2 : status = smb2_create(tree, tree, &cr);
413 2 : CHECK_STATUS(status, NT_STATUS_OK);
414 :
415 2 : h2 = cr.out.file.handle;
416 :
417 2 : ZERO_STRUCT(wr);
418 2 : wr.in.file.handle = h1;
419 2 : wr.in.offset = ARRAY_SIZE(buf)/2;
420 2 : wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
421 :
422 2 : status = smb2_write(tree, &wr);
423 2 : CHECK_STATUS(status, s->write_h1_status);
424 :
425 2 : ZERO_STRUCT(rd);
426 2 : rd.in.file.handle = h1;
427 2 : rd.in.offset = ARRAY_SIZE(buf)/2;
428 2 : rd.in.length = ARRAY_SIZE(buf)/2;
429 :
430 2 : status = smb2_read(tree, tree, &rd);
431 2 : CHECK_STATUS(status, s->read_h1_status);
432 :
433 2 : ZERO_STRUCT(wr);
434 2 : wr.in.file.handle = h2;
435 2 : wr.in.offset = ARRAY_SIZE(buf)/2;
436 2 : wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
437 :
438 2 : status = smb2_write(tree, &wr);
439 2 : CHECK_STATUS(status, s->write_h2_status);
440 :
441 2 : ZERO_STRUCT(rd);
442 2 : rd.in.file.handle = h2;
443 2 : rd.in.offset = ARRAY_SIZE(buf)/2;
444 2 : rd.in.length = ARRAY_SIZE(buf)/2;
445 :
446 2 : status = smb2_read(tree, tree, &rd);
447 2 : CHECK_STATUS(status, s->read_h2_status);
448 :
449 2 : lck.in.lock_count = 0x0001;
450 2 : lck.in.lock_sequence = 0x00000000;
451 2 : lck.in.file.handle = h1;
452 2 : el[0].offset = ARRAY_SIZE(buf)/2;
453 2 : el[0].length = ARRAY_SIZE(buf)/2;
454 2 : el[0].reserved = 0x00000000;
455 2 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
456 2 : status = smb2_lock(tree, &lck);
457 2 : CHECK_STATUS(status, NT_STATUS_OK);
458 2 : CHECK_VALUE(lck.out.reserved, 0);
459 :
460 2 : ZERO_STRUCT(wr);
461 2 : wr.in.file.handle = h2;
462 2 : wr.in.offset = ARRAY_SIZE(buf)/2;
463 2 : wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
464 :
465 2 : status = smb2_write(tree, &wr);
466 2 : CHECK_STATUS(status, NT_STATUS_OK);
467 :
468 2 : ZERO_STRUCT(rd);
469 2 : rd.in.file.handle = h2;
470 2 : rd.in.offset = ARRAY_SIZE(buf)/2;
471 2 : rd.in.length = ARRAY_SIZE(buf)/2;
472 :
473 2 : status = smb2_read(tree, tree, &rd);
474 2 : CHECK_STATUS(status, NT_STATUS_OK);
475 :
476 2 : done:
477 2 : return ret;
478 : }
479 :
480 1 : static bool test_lock_rw_none(struct torture_context *torture,
481 : struct smb2_tree *tree)
482 : {
483 1 : 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 1 : if (!TARGET_IS_W2K8(torture)) {
493 1 : 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 1 : static bool test_lock_rw_shared(struct torture_context *torture,
503 : struct smb2_tree *tree)
504 : {
505 1 : 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 1 : return test_lock_read_write(torture, tree, &s);
515 : }
516 :
517 1 : static bool test_lock_rw_exclusive(struct torture_context *torture,
518 : struct smb2_tree *tree)
519 : {
520 1 : 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 1 : return test_lock_read_write(torture, tree, &s);
530 : }
531 :
532 1 : static bool test_lock_auto_unlock(struct torture_context *torture,
533 : struct smb2_tree *tree)
534 : {
535 1 : bool ret = true;
536 : NTSTATUS status;
537 : struct smb2_handle h;
538 : uint8_t buf[200];
539 : struct smb2_lock lck;
540 : struct smb2_lock_element el[1];
541 :
542 1 : ZERO_STRUCT(buf);
543 :
544 1 : status = torture_smb2_testfile(tree, "autounlock.txt", &h);
545 1 : CHECK_STATUS(status, NT_STATUS_OK);
546 :
547 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
548 1 : CHECK_STATUS(status, NT_STATUS_OK);
549 :
550 1 : ZERO_STRUCT(lck);
551 1 : ZERO_STRUCT(el[0]);
552 1 : lck.in.locks = el;
553 1 : lck.in.lock_count = 0x0001;
554 1 : lck.in.file.handle = h;
555 1 : el[0].offset = 0;
556 1 : el[0].length = 1;
557 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
558 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
559 1 : status = smb2_lock(tree, &lck);
560 1 : CHECK_STATUS(status, NT_STATUS_OK);
561 :
562 1 : status = smb2_lock(tree, &lck);
563 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
564 :
565 1 : status = smb2_lock(tree, &lck);
566 1 : 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 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
573 : }
574 :
575 1 : status = smb2_lock(tree, &lck);
576 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
577 :
578 1 : done:
579 1 : return ret;
580 : }
581 :
582 : /*
583 : test different lock ranges and see if different handles conflict
584 : */
585 1 : static bool test_lock(struct torture_context *torture,
586 : struct smb2_tree *tree)
587 : {
588 : NTSTATUS status;
589 1 : bool ret = true;
590 1 : struct smb2_handle h = {{0}};
591 1 : struct smb2_handle h2 = {{0}};
592 : uint8_t buf[200];
593 : struct smb2_lock lck;
594 : struct smb2_lock_element el[2];
595 :
596 1 : const char *fname = BASEDIR "\\async.txt";
597 :
598 1 : status = torture_smb2_testdir(tree, BASEDIR, &h);
599 1 : CHECK_STATUS(status, NT_STATUS_OK);
600 1 : smb2_util_close(tree, h);
601 :
602 1 : status = torture_smb2_testfile(tree, fname, &h);
603 1 : CHECK_STATUS(status, NT_STATUS_OK);
604 :
605 1 : ZERO_STRUCT(buf);
606 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
607 1 : CHECK_STATUS(status, NT_STATUS_OK);
608 :
609 1 : status = torture_smb2_testfile(tree, fname, &h2);
610 1 : CHECK_STATUS(status, NT_STATUS_OK);
611 :
612 1 : lck.in.locks = el;
613 :
614 1 : lck.in.lock_count = 0x0001;
615 1 : lck.in.lock_sequence = 0x00000000;
616 1 : lck.in.file.handle = h;
617 1 : el[0].reserved = 0x00000000;
618 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
619 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
620 :
621 1 : torture_comment(torture, "Trying 0/0 lock\n");
622 1 : el[0].offset = 0x0000000000000000;
623 1 : el[0].length = 0x0000000000000000;
624 1 : status = smb2_lock(tree, &lck);
625 1 : CHECK_STATUS(status, NT_STATUS_OK);
626 1 : lck.in.file.handle = h2;
627 1 : status = smb2_lock(tree, &lck);
628 1 : CHECK_STATUS(status, NT_STATUS_OK);
629 1 : lck.in.file.handle = h;
630 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
631 1 : status = smb2_lock(tree, &lck);
632 1 : CHECK_STATUS(status, NT_STATUS_OK);
633 :
634 1 : torture_comment(torture, "Trying 0/1 lock\n");
635 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
636 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
637 1 : el[0].offset = 0x0000000000000000;
638 1 : el[0].length = 0x0000000000000001;
639 1 : status = smb2_lock(tree, &lck);
640 1 : CHECK_STATUS(status, NT_STATUS_OK);
641 1 : lck.in.file.handle = h2;
642 1 : status = smb2_lock(tree, &lck);
643 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
644 1 : lck.in.file.handle = h;
645 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
646 1 : status = smb2_lock(tree, &lck);
647 1 : CHECK_STATUS(status, NT_STATUS_OK);
648 1 : status = smb2_lock(tree, &lck);
649 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
650 :
651 1 : torture_comment(torture, "Trying 0xEEFFFFF lock\n");
652 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
653 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
654 1 : el[0].offset = 0xEEFFFFFF;
655 1 : el[0].length = 4000;
656 1 : status = smb2_lock(tree, &lck);
657 1 : CHECK_STATUS(status, NT_STATUS_OK);
658 1 : lck.in.file.handle = h2;
659 1 : status = smb2_lock(tree, &lck);
660 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
661 1 : lck.in.file.handle = h;
662 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
663 1 : status = smb2_lock(tree, &lck);
664 1 : CHECK_STATUS(status, NT_STATUS_OK);
665 1 : status = smb2_lock(tree, &lck);
666 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
667 :
668 1 : torture_comment(torture, "Trying 0xEF00000 lock\n");
669 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
670 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
671 1 : el[0].offset = 0xEF000000;
672 1 : el[0].length = 4000;
673 1 : status = smb2_lock(tree, &lck);
674 1 : CHECK_STATUS(status, NT_STATUS_OK);
675 1 : lck.in.file.handle = h2;
676 1 : status = smb2_lock(tree, &lck);
677 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
678 1 : lck.in.file.handle = h;
679 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
680 1 : status = smb2_lock(tree, &lck);
681 1 : CHECK_STATUS(status, NT_STATUS_OK);
682 1 : status = smb2_lock(tree, &lck);
683 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
684 :
685 1 : torture_comment(torture, "Trying (2^63 - 1)/1\n");
686 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
687 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
688 1 : el[0].offset = 1;
689 1 : el[0].offset <<= 63;
690 1 : el[0].offset--;
691 1 : el[0].length = 1;
692 1 : status = smb2_lock(tree, &lck);
693 1 : CHECK_STATUS(status, NT_STATUS_OK);
694 1 : lck.in.file.handle = h2;
695 1 : status = smb2_lock(tree, &lck);
696 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
697 1 : lck.in.file.handle = h;
698 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
699 1 : status = smb2_lock(tree, &lck);
700 1 : CHECK_STATUS(status, NT_STATUS_OK);
701 1 : status = smb2_lock(tree, &lck);
702 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
703 :
704 1 : torture_comment(torture, "Trying 2^63/1\n");
705 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
706 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
707 1 : el[0].offset = 1;
708 1 : el[0].offset <<= 63;
709 1 : el[0].length = 1;
710 1 : status = smb2_lock(tree, &lck);
711 1 : CHECK_STATUS(status, NT_STATUS_OK);
712 1 : lck.in.file.handle = h2;
713 1 : status = smb2_lock(tree, &lck);
714 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
715 1 : lck.in.file.handle = h;
716 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
717 1 : status = smb2_lock(tree, &lck);
718 1 : CHECK_STATUS(status, NT_STATUS_OK);
719 1 : status = smb2_lock(tree, &lck);
720 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
721 :
722 1 : torture_comment(torture, "Trying max/0 lock\n");
723 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
724 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
725 1 : el[0].offset = ~0;
726 1 : el[0].length = 0;
727 1 : status = smb2_lock(tree, &lck);
728 1 : CHECK_STATUS(status, NT_STATUS_OK);
729 1 : lck.in.file.handle = h2;
730 1 : status = smb2_lock(tree, &lck);
731 1 : CHECK_STATUS(status, NT_STATUS_OK);
732 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
733 1 : status = smb2_lock(tree, &lck);
734 1 : CHECK_STATUS(status, NT_STATUS_OK);
735 1 : lck.in.file.handle = h;
736 1 : status = smb2_lock(tree, &lck);
737 1 : CHECK_STATUS(status, NT_STATUS_OK);
738 1 : status = smb2_lock(tree, &lck);
739 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
740 :
741 1 : torture_comment(torture, "Trying max/1 lock\n");
742 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
743 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
744 1 : el[0].offset = ~0;
745 1 : el[0].length = 1;
746 1 : status = smb2_lock(tree, &lck);
747 1 : CHECK_STATUS(status, NT_STATUS_OK);
748 1 : lck.in.file.handle = h2;
749 1 : status = smb2_lock(tree, &lck);
750 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
751 1 : lck.in.file.handle = h;
752 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
753 1 : status = smb2_lock(tree, &lck);
754 1 : CHECK_STATUS(status, NT_STATUS_OK);
755 1 : status = smb2_lock(tree, &lck);
756 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
757 :
758 1 : torture_comment(torture, "Trying max/2 lock\n");
759 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
760 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
761 1 : el[0].offset = ~0;
762 1 : el[0].length = 2;
763 1 : status = smb2_lock(tree, &lck);
764 1 : if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(torture)) {
765 1 : 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 1 : torture_comment(torture, "Trying wrong handle unlock\n");
774 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
775 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
776 1 : el[0].offset = 10001;
777 1 : el[0].length = 40002;
778 1 : status = smb2_lock(tree, &lck);
779 1 : CHECK_STATUS(status, NT_STATUS_OK);
780 1 : lck.in.file.handle = h2;
781 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
782 1 : status = smb2_lock(tree, &lck);
783 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
784 1 : lck.in.file.handle = h;
785 1 : status = smb2_lock(tree, &lck);
786 1 : CHECK_STATUS(status, NT_STATUS_OK);
787 :
788 1 : done:
789 1 : smb2_util_close(tree, h2);
790 1 : smb2_util_close(tree, h);
791 1 : smb2_deltree(tree, BASEDIR);
792 1 : return ret;
793 : }
794 :
795 : /*
796 : test SMB2 LOCK async operation
797 : */
798 1 : static bool test_async(struct torture_context *torture,
799 : struct smb2_tree *tree)
800 : {
801 : NTSTATUS status;
802 1 : bool ret = true;
803 1 : struct smb2_handle h = {{0}};
804 1 : struct smb2_handle h2 = {{0}};
805 : uint8_t buf[200];
806 : struct smb2_lock lck;
807 : struct smb2_lock_element el[2];
808 1 : struct smb2_request *req = NULL;
809 :
810 1 : const char *fname = BASEDIR "\\async.txt";
811 :
812 1 : status = torture_smb2_testdir(tree, BASEDIR, &h);
813 1 : CHECK_STATUS(status, NT_STATUS_OK);
814 1 : smb2_util_close(tree, h);
815 :
816 1 : status = torture_smb2_testfile(tree, fname, &h);
817 1 : CHECK_STATUS(status, NT_STATUS_OK);
818 :
819 1 : ZERO_STRUCT(buf);
820 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
821 1 : CHECK_STATUS(status, NT_STATUS_OK);
822 :
823 1 : status = torture_smb2_testfile(tree, fname, &h2);
824 1 : CHECK_STATUS(status, NT_STATUS_OK);
825 :
826 1 : lck.in.locks = el;
827 :
828 1 : lck.in.lock_count = 0x0001;
829 1 : lck.in.lock_sequence = 0x00000000;
830 1 : lck.in.file.handle = h;
831 1 : el[0].offset = 100;
832 1 : el[0].length = 50;
833 1 : el[0].reserved = 0x00000000;
834 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
835 :
836 1 : torture_comment(torture, " Acquire first lock\n");
837 1 : status = smb2_lock(tree, &lck);
838 1 : CHECK_STATUS(status, NT_STATUS_OK);
839 :
840 1 : torture_comment(torture, " Second lock should pend on first\n");
841 1 : lck.in.file.handle = h2;
842 1 : req = smb2_lock_send(tree, &lck);
843 4 : WAIT_FOR_ASYNC_RESPONSE(req);
844 :
845 1 : torture_comment(torture, " Unlock first lock\n");
846 1 : lck.in.file.handle = h;
847 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
848 1 : status = smb2_lock(tree, &lck);
849 1 : CHECK_STATUS(status, NT_STATUS_OK);
850 :
851 1 : torture_comment(torture, " Second lock should now succeed\n");
852 1 : lck.in.file.handle = h2;
853 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
854 1 : status = smb2_lock_recv(req, &lck);
855 1 : CHECK_STATUS(status, NT_STATUS_OK);
856 :
857 1 : done:
858 1 : smb2_util_close(tree, h2);
859 1 : smb2_util_close(tree, h);
860 1 : smb2_deltree(tree, BASEDIR);
861 1 : return ret;
862 : }
863 :
864 : /*
865 : test SMB2 LOCK Cancel operation
866 : */
867 1 : static bool test_cancel(struct torture_context *torture,
868 : struct smb2_tree *tree)
869 : {
870 : NTSTATUS status;
871 1 : bool ret = true;
872 1 : struct smb2_handle h = {{0}};
873 1 : struct smb2_handle h2 = {{0}};
874 : uint8_t buf[200];
875 : struct smb2_lock lck;
876 : struct smb2_lock_element el[2];
877 1 : struct smb2_request *req = NULL;
878 :
879 1 : const char *fname = BASEDIR "\\cancel.txt";
880 :
881 1 : status = torture_smb2_testdir(tree, BASEDIR, &h);
882 1 : CHECK_STATUS(status, NT_STATUS_OK);
883 1 : smb2_util_close(tree, h);
884 :
885 1 : status = torture_smb2_testfile(tree, fname, &h);
886 1 : CHECK_STATUS(status, NT_STATUS_OK);
887 :
888 1 : ZERO_STRUCT(buf);
889 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
890 1 : CHECK_STATUS(status, NT_STATUS_OK);
891 :
892 1 : status = torture_smb2_testfile(tree, fname, &h2);
893 1 : CHECK_STATUS(status, NT_STATUS_OK);
894 :
895 1 : lck.in.locks = el;
896 :
897 1 : lck.in.lock_count = 0x0001;
898 1 : lck.in.lock_sequence = 0x00000000;
899 1 : lck.in.file.handle = h;
900 1 : el[0].offset = 100;
901 1 : el[0].length = 10;
902 1 : el[0].reserved = 0x00000000;
903 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
904 :
905 1 : torture_comment(torture, "Testing basic cancel\n");
906 :
907 1 : torture_comment(torture, " Acquire first lock\n");
908 1 : status = smb2_lock(tree, &lck);
909 1 : CHECK_STATUS(status, NT_STATUS_OK);
910 :
911 1 : torture_comment(torture, " Second lock should pend on first\n");
912 1 : lck.in.file.handle = h2;
913 1 : req = smb2_lock_send(tree, &lck);
914 4 : WAIT_FOR_ASYNC_RESPONSE(req);
915 :
916 1 : torture_comment(torture, " Cancel the second lock\n");
917 1 : smb2_cancel(req);
918 1 : lck.in.file.handle = h2;
919 1 : status = smb2_lock_recv(req, &lck);
920 1 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
921 :
922 1 : torture_comment(torture, " Unlock first lock\n");
923 1 : lck.in.file.handle = h;
924 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
925 1 : status = smb2_lock(tree, &lck);
926 1 : CHECK_STATUS(status, NT_STATUS_OK);
927 :
928 :
929 1 : torture_comment(torture, "Testing cancel by unlock\n");
930 :
931 1 : torture_comment(torture, " Acquire first lock\n");
932 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
933 1 : status = smb2_lock(tree, &lck);
934 1 : CHECK_STATUS(status, NT_STATUS_OK);
935 :
936 1 : torture_comment(torture, " Second lock should pend on first\n");
937 1 : lck.in.file.handle = h2;
938 1 : req = smb2_lock_send(tree, &lck);
939 4 : WAIT_FOR_ASYNC_RESPONSE(req);
940 :
941 1 : torture_comment(torture, " Attempt to unlock pending second lock\n");
942 1 : lck.in.file.handle = h2;
943 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
944 1 : status = smb2_lock(tree, &lck);
945 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
946 :
947 1 : torture_comment(torture, " Now cancel the second lock\n");
948 1 : smb2_cancel(req);
949 1 : lck.in.file.handle = h2;
950 1 : status = smb2_lock_recv(req, &lck);
951 1 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
952 :
953 1 : torture_comment(torture, " Unlock first lock\n");
954 1 : lck.in.file.handle = h;
955 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
956 1 : status = smb2_lock(tree, &lck);
957 1 : CHECK_STATUS(status, NT_STATUS_OK);
958 :
959 :
960 1 : torture_comment(torture, "Testing cancel by close\n");
961 :
962 1 : torture_comment(torture, " Acquire first lock\n");
963 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
964 1 : status = smb2_lock(tree, &lck);
965 1 : CHECK_STATUS(status, NT_STATUS_OK);
966 :
967 1 : torture_comment(torture, " Second lock should pend on first\n");
968 1 : lck.in.file.handle = h2;
969 1 : req = smb2_lock_send(tree, &lck);
970 4 : WAIT_FOR_ASYNC_RESPONSE(req);
971 :
972 1 : torture_comment(torture, " Close the second lock handle\n");
973 1 : smb2_util_close(tree, h2);
974 1 : CHECK_STATUS(status, NT_STATUS_OK);
975 :
976 1 : torture_comment(torture, " Check pending lock reply\n");
977 1 : status = smb2_lock_recv(req, &lck);
978 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
979 :
980 1 : torture_comment(torture, " Unlock first lock\n");
981 1 : lck.in.file.handle = h;
982 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
983 1 : status = smb2_lock(tree, &lck);
984 1 : CHECK_STATUS(status, NT_STATUS_OK);
985 :
986 1 : done:
987 1 : smb2_util_close(tree, h2);
988 1 : smb2_util_close(tree, h);
989 1 : smb2_deltree(tree, BASEDIR);
990 1 : return ret;
991 : }
992 :
993 : /*
994 : test SMB2 LOCK Cancel by tree disconnect
995 : */
996 1 : static bool test_cancel_tdis(struct torture_context *torture,
997 : struct smb2_tree *tree)
998 : {
999 : NTSTATUS status;
1000 1 : bool ret = true;
1001 1 : struct smb2_handle h = {{0}};
1002 1 : struct smb2_handle h2 = {{0}};
1003 : uint8_t buf[200];
1004 : struct smb2_lock lck;
1005 : struct smb2_lock_element el[2];
1006 1 : struct smb2_request *req = NULL;
1007 :
1008 1 : const char *fname = BASEDIR "\\cancel_tdis.txt";
1009 :
1010 1 : status = torture_smb2_testdir(tree, BASEDIR, &h);
1011 1 : CHECK_STATUS(status, NT_STATUS_OK);
1012 1 : smb2_util_close(tree, h);
1013 :
1014 1 : status = torture_smb2_testfile(tree, fname, &h);
1015 1 : CHECK_STATUS(status, NT_STATUS_OK);
1016 :
1017 1 : ZERO_STRUCT(buf);
1018 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
1019 1 : CHECK_STATUS(status, NT_STATUS_OK);
1020 :
1021 1 : status = torture_smb2_testfile(tree, fname, &h2);
1022 1 : CHECK_STATUS(status, NT_STATUS_OK);
1023 :
1024 1 : lck.in.locks = el;
1025 :
1026 1 : lck.in.lock_count = 0x0001;
1027 1 : lck.in.lock_sequence = 0x00000000;
1028 1 : lck.in.file.handle = h;
1029 1 : el[0].offset = 100;
1030 1 : el[0].length = 10;
1031 1 : el[0].reserved = 0x00000000;
1032 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
1033 :
1034 1 : torture_comment(torture, "Testing cancel by tree disconnect\n");
1035 :
1036 1 : status = torture_smb2_testfile(tree, fname, &h);
1037 1 : CHECK_STATUS(status, NT_STATUS_OK);
1038 :
1039 1 : status = torture_smb2_testfile(tree, fname, &h2);
1040 1 : CHECK_STATUS(status, NT_STATUS_OK);
1041 :
1042 1 : torture_comment(torture, " Acquire first lock\n");
1043 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
1044 1 : status = smb2_lock(tree, &lck);
1045 1 : CHECK_STATUS(status, NT_STATUS_OK);
1046 :
1047 1 : torture_comment(torture, " Second lock should pend on first\n");
1048 1 : lck.in.file.handle = h2;
1049 1 : req = smb2_lock_send(tree, &lck);
1050 4 : WAIT_FOR_ASYNC_RESPONSE(req);
1051 :
1052 1 : torture_comment(torture, " Disconnect the tree\n");
1053 1 : smb2_tdis(tree);
1054 1 : CHECK_STATUS(status, NT_STATUS_OK);
1055 :
1056 1 : torture_comment(torture, " Check pending lock reply\n");
1057 1 : status = smb2_lock_recv(req, &lck);
1058 1 : 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 1 : torture_comment(torture, " Attempt to unlock first lock\n");
1068 1 : lck.in.file.handle = h;
1069 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1070 1 : 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 1 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) {
1078 0 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1079 : }
1080 :
1081 2 : done:
1082 1 : smb2_util_close(tree, h2);
1083 1 : smb2_util_close(tree, h);
1084 1 : smb2_deltree(tree, BASEDIR);
1085 1 : return ret;
1086 : }
1087 :
1088 : /*
1089 : test SMB2 LOCK Cancel by user logoff
1090 : */
1091 1 : static bool test_cancel_logoff(struct torture_context *torture,
1092 : struct smb2_tree *tree)
1093 : {
1094 : NTSTATUS status;
1095 1 : bool ret = true;
1096 1 : struct smb2_handle h = {{0}};
1097 1 : struct smb2_handle h2 = {{0}};
1098 : uint8_t buf[200];
1099 : struct smb2_lock lck;
1100 : struct smb2_lock_element el[2];
1101 1 : struct smb2_request *req = NULL;
1102 :
1103 1 : const char *fname = BASEDIR "\\cancel_logoff.txt";
1104 :
1105 1 : status = torture_smb2_testdir(tree, BASEDIR, &h);
1106 1 : CHECK_STATUS(status, NT_STATUS_OK);
1107 1 : smb2_util_close(tree, h);
1108 :
1109 1 : status = torture_smb2_testfile(tree, fname, &h);
1110 1 : CHECK_STATUS(status, NT_STATUS_OK);
1111 :
1112 1 : ZERO_STRUCT(buf);
1113 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
1114 1 : CHECK_STATUS(status, NT_STATUS_OK);
1115 :
1116 1 : status = torture_smb2_testfile(tree, fname, &h2);
1117 1 : CHECK_STATUS(status, NT_STATUS_OK);
1118 :
1119 1 : lck.in.locks = el;
1120 :
1121 1 : lck.in.lock_count = 0x0001;
1122 1 : lck.in.lock_sequence = 0x00000000;
1123 1 : lck.in.file.handle = h;
1124 1 : el[0].offset = 100;
1125 1 : el[0].length = 10;
1126 1 : el[0].reserved = 0x00000000;
1127 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
1128 :
1129 1 : torture_comment(torture, "Testing cancel by ulogoff\n");
1130 :
1131 1 : torture_comment(torture, " Acquire first lock\n");
1132 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
1133 1 : status = smb2_lock(tree, &lck);
1134 1 : CHECK_STATUS(status, NT_STATUS_OK);
1135 :
1136 1 : torture_comment(torture, " Second lock should pend on first\n");
1137 1 : lck.in.file.handle = h2;
1138 1 : req = smb2_lock_send(tree, &lck);
1139 4 : WAIT_FOR_ASYNC_RESPONSE(req);
1140 :
1141 1 : torture_comment(torture, " Logoff user\n");
1142 1 : smb2_logoff(tree->session);
1143 :
1144 1 : torture_comment(torture, " Check pending lock reply\n");
1145 1 : status = smb2_lock_recv(req, &lck);
1146 1 : 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 1 : torture_comment(torture, " Attempt to unlock first lock\n");
1156 1 : lck.in.file.handle = h;
1157 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1158 1 : 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 1 : if (!NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
1166 0 : CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
1167 : }
1168 :
1169 2 : done:
1170 1 : smb2_util_close(tree, h2);
1171 1 : smb2_util_close(tree, h);
1172 1 : smb2_deltree(tree, BASEDIR);
1173 1 : 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 1 : static bool test_errorcode(struct torture_context *torture,
1189 : struct smb2_tree *tree)
1190 : {
1191 : NTSTATUS status;
1192 1 : bool ret = true;
1193 1 : struct smb2_handle h = {{0}};
1194 1 : struct smb2_handle h2 = {{0}};
1195 : uint8_t buf[200];
1196 : struct smb2_lock lck;
1197 : struct smb2_lock_element el[2];
1198 :
1199 1 : const char *fname = BASEDIR "\\errorcode.txt";
1200 :
1201 1 : status = torture_smb2_testdir(tree, BASEDIR, &h);
1202 1 : CHECK_STATUS(status, NT_STATUS_OK);
1203 1 : smb2_util_close(tree, h);
1204 :
1205 1 : status = torture_smb2_testfile(tree, fname, &h);
1206 1 : CHECK_STATUS(status, NT_STATUS_OK);
1207 :
1208 1 : ZERO_STRUCT(buf);
1209 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
1210 1 : CHECK_STATUS(status, NT_STATUS_OK);
1211 :
1212 1 : status = torture_smb2_testfile(tree, fname, &h2);
1213 1 : CHECK_STATUS(status, NT_STATUS_OK);
1214 :
1215 1 : lck.in.locks = el;
1216 :
1217 1 : lck.in.lock_count = 0x0001;
1218 1 : lck.in.lock_sequence = 0x00000000;
1219 1 : lck.in.file.handle = h;
1220 1 : el[0].offset = 100;
1221 1 : el[0].length = 10;
1222 1 : el[0].reserved = 0x00000000;
1223 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1224 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1225 :
1226 1 : torture_comment(torture, "Testing LOCK_NOT_GRANTED vs. "
1227 : "FILE_LOCK_CONFLICT\n");
1228 :
1229 1 : 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 1 : status = smb2_lock(tree, &lck);
1237 1 : CHECK_STATUS(status, NT_STATUS_OK);
1238 :
1239 : /* Demonstrate that the first conflicting lock on each handle gives
1240 : * LOCK_NOT_GRANTED. */
1241 1 : lck.in.file.handle = h;
1242 1 : status = smb2_lock(tree, &lck);
1243 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1244 :
1245 1 : lck.in.file.handle = h2;
1246 1 : status = smb2_lock(tree, &lck);
1247 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1248 :
1249 : /* Demonstrate that each following conflict also gives
1250 : * LOCK_NOT_GRANTED */
1251 1 : lck.in.file.handle = h;
1252 1 : status = smb2_lock(tree, &lck);
1253 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1254 :
1255 1 : lck.in.file.handle = h2;
1256 1 : status = smb2_lock(tree, &lck);
1257 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1258 :
1259 1 : lck.in.file.handle = h;
1260 1 : status = smb2_lock(tree, &lck);
1261 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1262 :
1263 1 : lck.in.file.handle = h2;
1264 1 : status = smb2_lock(tree, &lck);
1265 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1266 :
1267 : /* Demonstrate that the smbpid doesn't matter */
1268 1 : lck.in.file.handle = h;
1269 1 : status = smb2_lock(tree, &lck);
1270 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1271 :
1272 1 : lck.in.file.handle = h2;
1273 1 : status = smb2_lock(tree, &lck);
1274 1 : 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 1 : el[0].offset = 102;
1280 1 : el[0].length = 0;
1281 1 : lck.in.file.handle = h;
1282 1 : status = smb2_lock(tree, &lck);
1283 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1284 :
1285 1 : lck.in.file.handle = h2;
1286 1 : status = smb2_lock(tree, &lck);
1287 1 : 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 1 : el[0].offset = 102;
1293 1 : el[0].length = 5;
1294 1 : lck.in.file.handle = h;
1295 1 : status = smb2_lock(tree, &lck);
1296 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1297 :
1298 1 : lck.in.file.handle = h2;
1299 1 : status = smb2_lock(tree, &lck);
1300 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1301 :
1302 1 : done:
1303 1 : smb2_util_close(tree, h2);
1304 1 : smb2_util_close(tree, h);
1305 1 : smb2_deltree(tree, BASEDIR);
1306 1 : 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 1 : static bool test_zerobytelength(struct torture_context *torture,
1353 : struct smb2_tree *tree)
1354 : {
1355 : NTSTATUS status;
1356 1 : bool ret = true;
1357 1 : struct smb2_handle h = {{0}};
1358 1 : struct smb2_handle h2 = {{0}};
1359 : uint8_t buf[200];
1360 : struct smb2_lock lck;
1361 : int i;
1362 :
1363 1 : const char *fname = BASEDIR "\\zero.txt";
1364 :
1365 1 : torture_comment(torture, "Testing zero length byte range locks:\n");
1366 :
1367 1 : status = torture_smb2_testdir(tree, BASEDIR, &h);
1368 1 : CHECK_STATUS(status, NT_STATUS_OK);
1369 1 : smb2_util_close(tree, h);
1370 :
1371 1 : status = torture_smb2_testfile(tree, fname, &h);
1372 1 : CHECK_STATUS(status, NT_STATUS_OK);
1373 :
1374 1 : ZERO_STRUCT(buf);
1375 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
1376 1 : CHECK_STATUS(status, NT_STATUS_OK);
1377 :
1378 1 : status = torture_smb2_testfile(tree, fname, &h2);
1379 1 : CHECK_STATUS(status, NT_STATUS_OK);
1380 :
1381 : /* Setup initial parameters */
1382 1 : lck.in.lock_count = 0x0001;
1383 1 : lck.in.lock_sequence = 0x00000000;
1384 1 : 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 16 : for (i = 0; i < ARRAY_SIZE(zero_byte_tests); i++) {
1390 30 : torture_comment(torture,
1391 : " ... {%llu, %llu} + {%llu, %llu} = %s\n",
1392 15 : (unsigned long long) zero_byte_tests[i].lock1.offset,
1393 15 : (unsigned long long) zero_byte_tests[i].lock1.length,
1394 15 : (unsigned long long) zero_byte_tests[i].lock2.offset,
1395 15 : (unsigned long long) zero_byte_tests[i].lock2.length,
1396 : nt_errstr(zero_byte_tests[i].status));
1397 :
1398 : /* Lock both locks. */
1399 15 : lck.in.locks = &zero_byte_tests[i].lock1;
1400 15 : lck.in.locks[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1401 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1402 15 : status = smb2_lock(tree, &lck);
1403 15 : CHECK_STATUS(status, NT_STATUS_OK);
1404 :
1405 15 : lck.in.locks = &zero_byte_tests[i].lock2;
1406 15 : lck.in.locks[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1407 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1408 15 : status = smb2_lock(tree, &lck);
1409 15 : CHECK_STATUS_CONT(status, zero_byte_tests[i].status);
1410 :
1411 : /* Unlock both locks in reverse order. */
1412 15 : lck.in.locks[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1413 15 : if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1414 11 : status = smb2_lock(tree, &lck);
1415 11 : CHECK_STATUS(status, NT_STATUS_OK);
1416 : }
1417 :
1418 15 : lck.in.locks = &zero_byte_tests[i].lock1;
1419 15 : lck.in.locks[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1420 15 : status = smb2_lock(tree, &lck);
1421 15 : CHECK_STATUS(status, NT_STATUS_OK);
1422 : }
1423 :
1424 : /* Try every combination of locks in zero_byte_tests, using two
1425 : * different handles. */
1426 16 : for (i = 0; i < ARRAY_SIZE(zero_byte_tests); i++) {
1427 30 : torture_comment(torture,
1428 : " ... {%llu, %llu} + {%llu, %llu} = %s\n",
1429 15 : (unsigned long long) zero_byte_tests[i].lock1.offset,
1430 15 : (unsigned long long) zero_byte_tests[i].lock1.length,
1431 15 : (unsigned long long) zero_byte_tests[i].lock2.offset,
1432 15 : (unsigned long long) zero_byte_tests[i].lock2.length,
1433 : nt_errstr(zero_byte_tests[i].status));
1434 :
1435 : /* Lock both locks. */
1436 15 : lck.in.file.handle = h;
1437 15 : lck.in.locks = &zero_byte_tests[i].lock1;
1438 15 : lck.in.locks[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1439 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1440 15 : status = smb2_lock(tree, &lck);
1441 15 : CHECK_STATUS(status, NT_STATUS_OK);
1442 :
1443 15 : lck.in.file.handle = h2;
1444 15 : lck.in.locks = &zero_byte_tests[i].lock2;
1445 15 : lck.in.locks[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1446 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1447 15 : status = smb2_lock(tree, &lck);
1448 15 : CHECK_STATUS_CONT(status, zero_byte_tests[i].status);
1449 :
1450 : /* Unlock both locks in reverse order. */
1451 15 : lck.in.file.handle = h2;
1452 15 : lck.in.locks[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1453 15 : if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1454 11 : status = smb2_lock(tree, &lck);
1455 11 : CHECK_STATUS(status, NT_STATUS_OK);
1456 : }
1457 :
1458 15 : lck.in.file.handle = h;
1459 15 : lck.in.locks = &zero_byte_tests[i].lock1;
1460 15 : lck.in.locks[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1461 15 : status = smb2_lock(tree, &lck);
1462 15 : CHECK_STATUS(status, NT_STATUS_OK);
1463 : }
1464 :
1465 1 : done:
1466 1 : smb2_util_close(tree, h2);
1467 1 : smb2_util_close(tree, h);
1468 1 : smb2_deltree(tree, BASEDIR);
1469 1 : return ret;
1470 : }
1471 :
1472 1 : static bool test_zerobyteread(struct torture_context *torture,
1473 : struct smb2_tree *tree)
1474 : {
1475 : NTSTATUS status;
1476 1 : bool ret = true;
1477 1 : struct smb2_handle h = {{0}};
1478 1 : struct smb2_handle h2 = {{0}};
1479 : uint8_t buf[200];
1480 : struct smb2_lock lck;
1481 : struct smb2_lock_element el[1];
1482 : struct smb2_read rd;
1483 :
1484 1 : const char *fname = BASEDIR "\\zerobyteread.txt";
1485 :
1486 1 : status = torture_smb2_testdir(tree, BASEDIR, &h);
1487 1 : CHECK_STATUS(status, NT_STATUS_OK);
1488 1 : smb2_util_close(tree, h);
1489 :
1490 1 : status = torture_smb2_testfile(tree, fname, &h);
1491 1 : CHECK_STATUS(status, NT_STATUS_OK);
1492 :
1493 1 : ZERO_STRUCT(buf);
1494 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
1495 1 : CHECK_STATUS(status, NT_STATUS_OK);
1496 :
1497 1 : status = torture_smb2_testfile(tree, fname, &h2);
1498 1 : CHECK_STATUS(status, NT_STATUS_OK);
1499 :
1500 : /* Setup initial parameters */
1501 1 : lck.in.locks = el;
1502 1 : lck.in.lock_count = 0x0001;
1503 1 : lck.in.lock_sequence = 0x00000000;
1504 1 : lck.in.file.handle = h;
1505 :
1506 1 : ZERO_STRUCT(rd);
1507 1 : rd.in.file.handle = h2;
1508 :
1509 1 : torture_comment(torture, "Testing zero byte read on lock range:\n");
1510 :
1511 : /* Take an exclusive lock */
1512 1 : torture_comment(torture, " taking exclusive lock.\n");
1513 1 : el[0].offset = 0;
1514 1 : el[0].length = 10;
1515 1 : el[0].reserved = 0x00000000;
1516 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1517 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1518 1 : status = smb2_lock(tree, &lck);
1519 1 : CHECK_STATUS(status, NT_STATUS_OK);
1520 1 : CHECK_VALUE(lck.out.reserved, 0);
1521 :
1522 : /* Try a zero byte read */
1523 1 : torture_comment(torture, " reading 0 bytes.\n");
1524 1 : rd.in.offset = 5;
1525 1 : rd.in.length = 0;
1526 1 : status = smb2_read(tree, tree, &rd);
1527 1 : torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done,
1528 : "zero byte read did not return 0 bytes");
1529 1 : CHECK_STATUS(status, NT_STATUS_OK);
1530 :
1531 : /* Unlock lock */
1532 0 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1533 0 : status = smb2_lock(tree, &lck);
1534 0 : CHECK_STATUS(status, NT_STATUS_OK);
1535 0 : CHECK_VALUE(lck.out.reserved, 0);
1536 :
1537 0 : torture_comment(torture, "Testing zero byte read on zero byte lock "
1538 : "range:\n");
1539 :
1540 : /* Take an exclusive lock */
1541 0 : torture_comment(torture, " taking exclusive 0-byte lock.\n");
1542 0 : el[0].offset = 5;
1543 0 : el[0].length = 0;
1544 0 : el[0].reserved = 0x00000000;
1545 0 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1546 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1547 0 : status = smb2_lock(tree, &lck);
1548 0 : CHECK_STATUS(status, NT_STATUS_OK);
1549 0 : CHECK_VALUE(lck.out.reserved, 0);
1550 :
1551 : /* Try a zero byte read before the lock */
1552 0 : torture_comment(torture, " reading 0 bytes before the lock.\n");
1553 0 : rd.in.offset = 4;
1554 0 : rd.in.length = 0;
1555 0 : status = smb2_read(tree, tree, &rd);
1556 0 : torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done,
1557 : "zero byte read did not return 0 bytes");
1558 0 : CHECK_STATUS(status, NT_STATUS_OK);
1559 :
1560 : /* Try a zero byte read on the lock */
1561 0 : torture_comment(torture, " reading 0 bytes on the lock.\n");
1562 0 : rd.in.offset = 5;
1563 0 : rd.in.length = 0;
1564 0 : status = smb2_read(tree, tree, &rd);
1565 0 : torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done,
1566 : "zero byte read did not return 0 bytes");
1567 0 : CHECK_STATUS(status, NT_STATUS_OK);
1568 :
1569 : /* Try a zero byte read after the lock */
1570 0 : torture_comment(torture, " reading 0 bytes after the lock.\n");
1571 0 : rd.in.offset = 6;
1572 0 : rd.in.length = 0;
1573 0 : status = smb2_read(tree, tree, &rd);
1574 0 : torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done,
1575 : "zero byte read did not return 0 bytes");
1576 0 : CHECK_STATUS(status, NT_STATUS_OK);
1577 :
1578 : /* Unlock lock */
1579 0 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1580 0 : status = smb2_lock(tree, &lck);
1581 0 : CHECK_STATUS(status, NT_STATUS_OK);
1582 0 : CHECK_VALUE(lck.out.reserved, 0);
1583 :
1584 1 : done:
1585 1 : smb2_util_close(tree, h2);
1586 1 : smb2_util_close(tree, h);
1587 1 : smb2_deltree(tree, BASEDIR);
1588 1 : return ret;
1589 : }
1590 :
1591 1 : static bool test_unlock(struct torture_context *torture,
1592 : struct smb2_tree *tree)
1593 : {
1594 : NTSTATUS status;
1595 1 : bool ret = true;
1596 1 : struct smb2_handle h = {{0}};
1597 1 : struct smb2_handle h2 = {{0}};
1598 : uint8_t buf[200];
1599 : struct smb2_lock lck;
1600 : struct smb2_lock_element el1[1];
1601 : struct smb2_lock_element el2[1];
1602 :
1603 1 : const char *fname = BASEDIR "\\unlock.txt";
1604 :
1605 1 : status = torture_smb2_testdir(tree, BASEDIR, &h);
1606 1 : CHECK_STATUS(status, NT_STATUS_OK);
1607 1 : smb2_util_close(tree, h);
1608 :
1609 1 : status = torture_smb2_testfile(tree, fname, &h);
1610 1 : CHECK_STATUS(status, NT_STATUS_OK);
1611 :
1612 1 : ZERO_STRUCT(buf);
1613 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
1614 1 : CHECK_STATUS(status, NT_STATUS_OK);
1615 :
1616 1 : status = torture_smb2_testfile(tree, fname, &h2);
1617 1 : CHECK_STATUS(status, NT_STATUS_OK);
1618 :
1619 : /* Setup initial parameters */
1620 1 : lck.in.locks = el1;
1621 1 : lck.in.lock_count = 0x0001;
1622 1 : lck.in.lock_sequence = 0x00000000;
1623 1 : el1[0].offset = 0;
1624 1 : el1[0].length = 10;
1625 1 : el1[0].reserved = 0x00000000;
1626 :
1627 : /* Take exclusive lock, then unlock it with a shared-unlock call. */
1628 :
1629 1 : torture_comment(torture, "Testing unlock exclusive with shared\n");
1630 :
1631 1 : torture_comment(torture, " taking exclusive lock.\n");
1632 1 : lck.in.file.handle = h;
1633 1 : el1[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
1634 1 : status = smb2_lock(tree, &lck);
1635 1 : CHECK_STATUS(status, NT_STATUS_OK);
1636 :
1637 1 : torture_comment(torture, " try to unlock the exclusive with a shared "
1638 : "unlock call.\n");
1639 1 : el1[0].flags = SMB2_LOCK_FLAG_SHARED |
1640 : SMB2_LOCK_FLAG_UNLOCK;
1641 1 : status = smb2_lock(tree, &lck);
1642 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1643 :
1644 1 : torture_comment(torture, " try shared lock on h2, to test the "
1645 : "unlock.\n");
1646 1 : lck.in.file.handle = h2;
1647 1 : el1[0].flags = SMB2_LOCK_FLAG_SHARED |
1648 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1649 1 : status = smb2_lock(tree, &lck);
1650 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1651 :
1652 1 : torture_comment(torture, " unlock the exclusive lock\n");
1653 1 : lck.in.file.handle = h;
1654 1 : el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1655 1 : status = smb2_lock(tree, &lck);
1656 1 : CHECK_STATUS(status, NT_STATUS_OK);
1657 :
1658 : /* Unlock a shared lock with an exclusive-unlock call. */
1659 :
1660 1 : torture_comment(torture, "Testing unlock shared with exclusive\n");
1661 :
1662 1 : torture_comment(torture, " taking shared lock.\n");
1663 1 : lck.in.file.handle = h;
1664 1 : el1[0].flags = SMB2_LOCK_FLAG_SHARED;
1665 1 : status = smb2_lock(tree, &lck);
1666 1 : CHECK_STATUS(status, NT_STATUS_OK);
1667 :
1668 1 : torture_comment(torture, " try to unlock the shared with an exclusive "
1669 : "unlock call.\n");
1670 1 : el1[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1671 : SMB2_LOCK_FLAG_UNLOCK;
1672 1 : status = smb2_lock(tree, &lck);
1673 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1674 :
1675 1 : torture_comment(torture, " try exclusive lock on h2, to test the "
1676 : "unlock.\n");
1677 1 : lck.in.file.handle = h2;
1678 1 : el1[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1679 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1680 1 : status = smb2_lock(tree, &lck);
1681 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1682 :
1683 1 : torture_comment(torture, " unlock the exclusive lock\n");
1684 1 : lck.in.file.handle = h;
1685 1 : el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1686 1 : status = smb2_lock(tree, &lck);
1687 1 : 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 1 : torture_comment(torture, "Test unlocking stacked 0-byte locks\n");
1694 :
1695 1 : lck.in.locks = el1;
1696 1 : lck.in.file.handle = h;
1697 1 : el1[0].offset = 10;
1698 1 : el1[0].length = 0;
1699 1 : el1[0].reserved = 0x00000000;
1700 1 : el2[0].offset = 5;
1701 1 : el2[0].length = 10;
1702 1 : el2[0].reserved = 0x00000000;
1703 :
1704 : /* lock 0-byte exclusive */
1705 1 : el1[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1706 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1707 1 : status = smb2_lock(tree, &lck);
1708 1 : CHECK_STATUS(status, NT_STATUS_OK);
1709 :
1710 : /* lock 0-byte shared */
1711 1 : el1[0].flags = SMB2_LOCK_FLAG_SHARED |
1712 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1713 1 : status = smb2_lock(tree, &lck);
1714 1 : CHECK_STATUS(status, NT_STATUS_OK);
1715 :
1716 : /* test contention */
1717 1 : lck.in.locks = el2;
1718 1 : lck.in.file.handle = h2;
1719 1 : el2[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1720 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1721 1 : status = smb2_lock(tree, &lck);
1722 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1723 :
1724 1 : lck.in.locks = el2;
1725 1 : lck.in.file.handle = h2;
1726 1 : el2[0].flags = SMB2_LOCK_FLAG_SHARED |
1727 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1728 1 : status = smb2_lock(tree, &lck);
1729 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1730 :
1731 : /* unlock */
1732 1 : lck.in.locks = el1;
1733 1 : lck.in.file.handle = h;
1734 1 : el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1735 1 : status = smb2_lock(tree, &lck);
1736 1 : CHECK_STATUS(status, NT_STATUS_OK);
1737 :
1738 : /* test - can we take a shared lock? */
1739 1 : lck.in.locks = el2;
1740 1 : lck.in.file.handle = h2;
1741 1 : el2[0].flags = SMB2_LOCK_FLAG_SHARED |
1742 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1743 1 : status = smb2_lock(tree, &lck);
1744 1 : CHECK_STATUS(status, NT_STATUS_OK);
1745 :
1746 1 : el2[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1747 1 : status = smb2_lock(tree, &lck);
1748 1 : CHECK_STATUS(status, NT_STATUS_OK);
1749 :
1750 : /* cleanup */
1751 1 : lck.in.locks = el1;
1752 1 : lck.in.file.handle = h;
1753 1 : el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1754 1 : status = smb2_lock(tree, &lck);
1755 1 : 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 1 : torture_comment(torture, "Test unlocking stacked exclusive/shared "
1761 : "locks\n");
1762 :
1763 1 : lck.in.locks = el1;
1764 1 : lck.in.file.handle = h;
1765 1 : el1[0].offset = 10;
1766 1 : el1[0].length = 10;
1767 1 : el1[0].reserved = 0x00000000;
1768 1 : el2[0].offset = 5;
1769 1 : el2[0].length = 10;
1770 1 : el2[0].reserved = 0x00000000;
1771 :
1772 : /* lock exclusive */
1773 1 : el1[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1774 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1775 1 : status = smb2_lock(tree, &lck);
1776 1 : CHECK_STATUS(status, NT_STATUS_OK);
1777 :
1778 : /* lock shared */
1779 1 : el1[0].flags = SMB2_LOCK_FLAG_SHARED |
1780 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1781 1 : status = smb2_lock(tree, &lck);
1782 1 : CHECK_STATUS(status, NT_STATUS_OK);
1783 :
1784 : /* test contention */
1785 1 : lck.in.locks = el2;
1786 1 : lck.in.file.handle = h2;
1787 1 : el2[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1788 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1789 1 : status = smb2_lock(tree, &lck);
1790 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1791 :
1792 1 : lck.in.locks = el2;
1793 1 : lck.in.file.handle = h2;
1794 1 : el2[0].flags = SMB2_LOCK_FLAG_SHARED |
1795 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1796 1 : status = smb2_lock(tree, &lck);
1797 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1798 :
1799 : /* unlock */
1800 1 : lck.in.locks = el1;
1801 1 : lck.in.file.handle = h;
1802 1 : el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1803 1 : status = smb2_lock(tree, &lck);
1804 1 : CHECK_STATUS(status, NT_STATUS_OK);
1805 :
1806 : /* test - can we take a shared lock? */
1807 1 : lck.in.locks = el2;
1808 1 : lck.in.file.handle = h2;
1809 1 : el2[0].flags = SMB2_LOCK_FLAG_SHARED |
1810 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1811 1 : status = smb2_lock(tree, &lck);
1812 1 : CHECK_STATUS(status, NT_STATUS_OK);
1813 :
1814 1 : el2[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1815 1 : status = smb2_lock(tree, &lck);
1816 1 : CHECK_STATUS(status, NT_STATUS_OK);
1817 :
1818 : /* cleanup */
1819 1 : lck.in.locks = el1;
1820 1 : lck.in.file.handle = h;
1821 1 : el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1822 1 : status = smb2_lock(tree, &lck);
1823 1 : CHECK_STATUS(status, NT_STATUS_OK);
1824 :
1825 1 : done:
1826 1 : smb2_util_close(tree, h2);
1827 1 : smb2_util_close(tree, h);
1828 1 : smb2_deltree(tree, BASEDIR);
1829 1 : return ret;
1830 : }
1831 :
1832 1 : static bool test_multiple_unlock(struct torture_context *torture,
1833 : struct smb2_tree *tree)
1834 : {
1835 : NTSTATUS status;
1836 1 : bool ret = true;
1837 : struct smb2_handle h;
1838 : uint8_t buf[200];
1839 : struct smb2_lock lck;
1840 : struct smb2_lock_element el[2];
1841 :
1842 1 : const char *fname = BASEDIR "\\unlock_multiple.txt";
1843 :
1844 1 : status = torture_smb2_testdir(tree, BASEDIR, &h);
1845 1 : CHECK_STATUS(status, NT_STATUS_OK);
1846 1 : smb2_util_close(tree, h);
1847 :
1848 1 : status = torture_smb2_testfile(tree, fname, &h);
1849 1 : CHECK_STATUS(status, NT_STATUS_OK);
1850 :
1851 1 : ZERO_STRUCT(buf);
1852 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
1853 1 : CHECK_STATUS(status, NT_STATUS_OK);
1854 :
1855 1 : torture_comment(torture, "Testing multiple unlocks:\n");
1856 :
1857 : /* Setup initial parameters */
1858 1 : lck.in.lock_count = 0x0002;
1859 1 : lck.in.lock_sequence = 0x00000000;
1860 1 : lck.in.file.handle = h;
1861 1 : el[0].offset = 0;
1862 1 : el[0].length = 10;
1863 1 : el[0].reserved = 0x00000000;
1864 1 : el[1].offset = 10;
1865 1 : el[1].length = 10;
1866 1 : el[1].reserved = 0x00000000;
1867 :
1868 : /* Test1: Acquire second lock, but not first. */
1869 1 : torture_comment(torture, " unlock 2 locks, first one not locked. "
1870 : "Expect no locks unlocked. \n");
1871 :
1872 1 : lck.in.lock_count = 0x0001;
1873 1 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1874 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1875 1 : lck.in.locks = &el[1];
1876 1 : status = smb2_lock(tree, &lck);
1877 1 : CHECK_STATUS(status, NT_STATUS_OK);
1878 :
1879 : /* Try to unlock both locks */
1880 1 : lck.in.lock_count = 0x0002;
1881 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1882 1 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
1883 1 : lck.in.locks = el;
1884 1 : status = smb2_lock(tree, &lck);
1885 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1886 :
1887 : /* Second lock should not be unlocked. */
1888 1 : lck.in.lock_count = 0x0001;
1889 1 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1890 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1891 1 : lck.in.locks = &el[1];
1892 1 : status = smb2_lock(tree, &lck);
1893 1 : 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 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1900 : }
1901 :
1902 : /* cleanup */
1903 1 : lck.in.lock_count = 0x0001;
1904 1 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
1905 1 : lck.in.locks = &el[1];
1906 1 : status = smb2_lock(tree, &lck);
1907 1 : CHECK_STATUS(status, NT_STATUS_OK);
1908 :
1909 : /* Test2: Acquire first lock, but not second. */
1910 1 : torture_comment(torture, " unlock 2 locks, second one not locked. "
1911 : "Expect first lock unlocked.\n");
1912 :
1913 1 : lck.in.lock_count = 0x0001;
1914 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1915 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1916 1 : lck.in.locks = &el[0];
1917 1 : status = smb2_lock(tree, &lck);
1918 1 : CHECK_STATUS(status, NT_STATUS_OK);
1919 :
1920 : /* Try to unlock both locks */
1921 1 : lck.in.lock_count = 0x0002;
1922 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1923 1 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
1924 1 : lck.in.locks = el;
1925 1 : status = smb2_lock(tree, &lck);
1926 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1927 :
1928 : /* First lock should be unlocked. */
1929 1 : lck.in.lock_count = 0x0001;
1930 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1931 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1932 1 : lck.in.locks = &el[0];
1933 1 : status = smb2_lock(tree, &lck);
1934 1 : CHECK_STATUS(status, NT_STATUS_OK);
1935 :
1936 : /* cleanup */
1937 1 : lck.in.lock_count = 0x0001;
1938 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1939 1 : lck.in.locks = &el[0];
1940 1 : status = smb2_lock(tree, &lck);
1941 1 : CHECK_STATUS(status, NT_STATUS_OK);
1942 :
1943 : /* Test3: Request 2 locks, second will contend. What happens to the
1944 : * first? */
1945 1 : torture_comment(torture, " request 2 locks, second one will contend. "
1946 : "Expect both to fail.\n");
1947 :
1948 : /* Lock the second range */
1949 1 : lck.in.lock_count = 0x0001;
1950 1 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1951 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1952 1 : lck.in.locks = &el[1];
1953 1 : status = smb2_lock(tree, &lck);
1954 1 : CHECK_STATUS(status, NT_STATUS_OK);
1955 :
1956 : /* Request both locks */
1957 1 : lck.in.lock_count = 0x0002;
1958 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
1959 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1960 1 : lck.in.locks = el;
1961 1 : status = smb2_lock(tree, &lck);
1962 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1963 :
1964 : /* First lock should be unlocked. */
1965 1 : lck.in.lock_count = 0x0001;
1966 1 : lck.in.locks = &el[0];
1967 1 : status = smb2_lock(tree, &lck);
1968 1 : CHECK_STATUS(status, NT_STATUS_OK);
1969 :
1970 : /* cleanup */
1971 1 : 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 1 : lck.in.lock_count = 0x0002;
1982 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
1983 1 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
1984 1 : lck.in.locks = el;
1985 1 : status = smb2_lock(tree, &lck);
1986 1 : 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 1 : torture_comment(torture, " request unlock and lock, second one will "
1995 : "error. Expect the unlock to succeed.\n");
1996 :
1997 : /* Lock both ranges */
1998 1 : lck.in.lock_count = 0x0002;
1999 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2000 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2001 1 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2002 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2003 1 : lck.in.locks = el;
2004 1 : status = smb2_lock(tree, &lck);
2005 1 : 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 1 : lck.in.lock_count = 0x0002;
2010 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2011 1 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2012 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2013 1 : lck.in.locks = el;
2014 1 : status = smb2_lock(tree, &lck);
2015 1 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
2016 :
2017 : /* The first lock should've been unlocked */
2018 1 : lck.in.lock_count = 0x0001;
2019 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2020 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2021 1 : lck.in.locks = &el[0];
2022 1 : status = smb2_lock(tree, &lck);
2023 1 : CHECK_STATUS(status, NT_STATUS_OK);
2024 :
2025 : /* cleanup */
2026 0 : lck.in.lock_count = 0x0002;
2027 0 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2028 0 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
2029 0 : lck.in.locks = el;
2030 0 : status = smb2_lock(tree, &lck);
2031 0 : 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 0 : torture_comment(torture, " request unlock and lock. Unlock will "
2038 : "succeed, but lock will fail.\n");
2039 :
2040 : /* Lock first range */
2041 0 : lck.in.lock_count = 0x0001;
2042 0 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2043 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2044 0 : lck.in.locks = &el[0];
2045 0 : status = smb2_lock(tree, &lck);
2046 0 : CHECK_STATUS(status, NT_STATUS_OK);
2047 :
2048 : /* Attempt to unlock the first range and lock the second */
2049 0 : lck.in.lock_count = 0x0002;
2050 0 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2051 0 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2052 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2053 0 : lck.in.locks = el;
2054 0 : status = smb2_lock(tree, &lck);
2055 0 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
2056 :
2057 : /* Neither lock should still be locked */
2058 0 : lck.in.lock_count = 0x0002;
2059 0 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2060 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2061 0 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2062 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2063 0 : lck.in.locks = el;
2064 0 : status = smb2_lock(tree, &lck);
2065 0 : CHECK_STATUS(status, NT_STATUS_OK);
2066 :
2067 : /* cleanup */
2068 0 : lck.in.lock_count = 0x0002;
2069 0 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2070 0 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
2071 0 : lck.in.locks = el;
2072 0 : status = smb2_lock(tree, &lck);
2073 0 : 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 0 : torture_comment(torture, " request lock and unlock. Both will "
2080 : "fail.\n");
2081 :
2082 : /* Lock second range */
2083 0 : lck.in.lock_count = 0x0001;
2084 0 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2085 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2086 0 : lck.in.locks = &el[1];
2087 0 : status = smb2_lock(tree, &lck);
2088 0 : CHECK_STATUS(status, NT_STATUS_OK);
2089 :
2090 : /* Attempt to lock the first range and unlock the second */
2091 0 : lck.in.lock_count = 0x0002;
2092 0 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2093 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2094 0 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
2095 0 : lck.in.locks = el;
2096 0 : status = smb2_lock(tree, &lck);
2097 0 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
2098 :
2099 : /* First range should be unlocked, second locked. */
2100 0 : lck.in.lock_count = 0x0001;
2101 0 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2102 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2103 0 : lck.in.locks = &el[0];
2104 0 : status = smb2_lock(tree, &lck);
2105 0 : CHECK_STATUS(status, NT_STATUS_OK);
2106 :
2107 0 : lck.in.lock_count = 0x0001;
2108 0 : el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2109 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2110 0 : lck.in.locks = &el[1];
2111 0 : status = smb2_lock(tree, &lck);
2112 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2113 :
2114 : /* cleanup */
2115 0 : 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 0 : lck.in.lock_count = 0x0002;
2126 0 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2127 0 : el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
2128 0 : lck.in.locks = el;
2129 0 : status = smb2_lock(tree, &lck);
2130 0 : CHECK_STATUS(status, NT_STATUS_OK);
2131 : }
2132 :
2133 1 : done:
2134 1 : smb2_util_close(tree, h);
2135 1 : smb2_deltree(tree, BASEDIR);
2136 1 : return ret;
2137 : }
2138 :
2139 : /**
2140 : * Test lock stacking
2141 : * - some tests ported from BASE-LOCK-LOCK5
2142 : */
2143 1 : static bool test_stacking(struct torture_context *torture,
2144 : struct smb2_tree *tree)
2145 : {
2146 : NTSTATUS status;
2147 1 : bool ret = true;
2148 1 : struct smb2_handle h = {{0}};
2149 1 : struct smb2_handle h2 = {{0}};
2150 : uint8_t buf[200];
2151 : struct smb2_lock lck;
2152 : struct smb2_lock_element el[1];
2153 :
2154 1 : const char *fname = BASEDIR "\\stacking.txt";
2155 :
2156 1 : status = torture_smb2_testdir(tree, BASEDIR, &h);
2157 1 : CHECK_STATUS(status, NT_STATUS_OK);
2158 1 : smb2_util_close(tree, h);
2159 :
2160 1 : status = torture_smb2_testfile(tree, fname, &h);
2161 1 : CHECK_STATUS(status, NT_STATUS_OK);
2162 :
2163 1 : ZERO_STRUCT(buf);
2164 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
2165 1 : CHECK_STATUS(status, NT_STATUS_OK);
2166 :
2167 1 : status = torture_smb2_testfile(tree, fname, &h2);
2168 1 : CHECK_STATUS(status, NT_STATUS_OK);
2169 :
2170 1 : torture_comment(torture, "Testing lock stacking:\n");
2171 :
2172 : /* Setup initial parameters */
2173 1 : lck.in.locks = el;
2174 1 : lck.in.lock_count = 0x0001;
2175 1 : lck.in.lock_sequence = 0x00000000;
2176 1 : lck.in.file.handle = h;
2177 1 : el[0].offset = 0;
2178 1 : el[0].length = 10;
2179 1 : el[0].reserved = 0x00000000;
2180 :
2181 : /* Try to take a shared lock, then a shared lock on same handle */
2182 1 : torture_comment(torture, " stacking a shared on top of a shared"
2183 : "lock succeeds.\n");
2184 :
2185 1 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2186 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2187 1 : status = smb2_lock(tree, &lck);
2188 1 : CHECK_STATUS(status, NT_STATUS_OK);
2189 :
2190 1 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2191 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2192 1 : status = smb2_lock(tree, &lck);
2193 1 : CHECK_STATUS(status, NT_STATUS_OK);
2194 :
2195 : /* cleanup */
2196 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2197 1 : status = smb2_lock(tree, &lck);
2198 1 : CHECK_STATUS(status, NT_STATUS_OK);
2199 :
2200 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2201 1 : status = smb2_lock(tree, &lck);
2202 1 : CHECK_STATUS(status, NT_STATUS_OK);
2203 :
2204 :
2205 : /* Try to take an exclusive lock, then a shared lock on same handle */
2206 1 : torture_comment(torture, " stacking a shared on top of an exclusive "
2207 : "lock succeeds.\n");
2208 :
2209 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2210 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2211 1 : status = smb2_lock(tree, &lck);
2212 1 : CHECK_STATUS(status, NT_STATUS_OK);
2213 :
2214 1 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2215 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2216 1 : status = smb2_lock(tree, &lck);
2217 1 : CHECK_STATUS(status, NT_STATUS_OK);
2218 :
2219 1 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2220 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2221 1 : status = smb2_lock(tree, &lck);
2222 1 : CHECK_STATUS(status, NT_STATUS_OK);
2223 :
2224 : /* stacking a shared from a different handle should fail */
2225 1 : lck.in.file.handle = h2;
2226 1 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2227 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2228 1 : status = smb2_lock(tree, &lck);
2229 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2230 :
2231 : /* cleanup */
2232 1 : lck.in.file.handle = h;
2233 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2234 1 : status = smb2_lock(tree, &lck);
2235 1 : CHECK_STATUS(status, NT_STATUS_OK);
2236 :
2237 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2238 1 : status = smb2_lock(tree, &lck);
2239 1 : CHECK_STATUS(status, NT_STATUS_OK);
2240 :
2241 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2242 1 : status = smb2_lock(tree, &lck);
2243 1 : CHECK_STATUS(status, NT_STATUS_OK);
2244 :
2245 : /* ensure the 4th unlock fails */
2246 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2247 1 : status = smb2_lock(tree, &lck);
2248 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
2249 :
2250 : /* ensure a second handle can now take an exclusive lock */
2251 1 : lck.in.file.handle = h2;
2252 1 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2253 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2254 1 : status = smb2_lock(tree, &lck);
2255 1 : CHECK_STATUS(status, NT_STATUS_OK);
2256 :
2257 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2258 1 : status = smb2_lock(tree, &lck);
2259 1 : CHECK_STATUS(status, NT_STATUS_OK);
2260 :
2261 : /* Try to take an exclusive lock, then a shared lock on a
2262 : * different handle */
2263 1 : torture_comment(torture, " stacking a shared on top of an exclusive "
2264 : "lock with different handles fails.\n");
2265 :
2266 1 : lck.in.file.handle = h;
2267 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2268 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2269 1 : status = smb2_lock(tree, &lck);
2270 1 : CHECK_STATUS(status, NT_STATUS_OK);
2271 :
2272 1 : lck.in.file.handle = h2;
2273 1 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2274 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2275 1 : status = smb2_lock(tree, &lck);
2276 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2277 :
2278 : /* cleanup */
2279 1 : lck.in.file.handle = h;
2280 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2281 1 : status = smb2_lock(tree, &lck);
2282 1 : CHECK_STATUS(status, NT_STATUS_OK);
2283 :
2284 : /* Try to take a shared lock, then stack an exclusive with same
2285 : * handle. */
2286 1 : torture_comment(torture, " stacking an exclusive on top of a shared "
2287 : "lock fails.\n");
2288 :
2289 1 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2290 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2291 1 : status = smb2_lock(tree, &lck);
2292 1 : CHECK_STATUS(status, NT_STATUS_OK);
2293 :
2294 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2295 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2296 1 : status = smb2_lock(tree, &lck);
2297 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2298 :
2299 : /* cleanup */
2300 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2301 1 : status = smb2_lock(tree, &lck);
2302 1 : 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 1 : CHECK_STATUS(status, NT_STATUS_OK);
2309 : }
2310 :
2311 : /* Prove that two exclusive locks do not stack on the same handle. */
2312 1 : torture_comment(torture, " two exclusive locks do not stack.\n");
2313 :
2314 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2315 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2316 1 : status = smb2_lock(tree, &lck);
2317 1 : CHECK_STATUS(status, NT_STATUS_OK);
2318 :
2319 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2320 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2321 1 : status = smb2_lock(tree, &lck);
2322 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2323 :
2324 : /* cleanup */
2325 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2326 1 : status = smb2_lock(tree, &lck);
2327 1 : 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 1 : CHECK_STATUS(status, NT_STATUS_OK);
2334 : }
2335 :
2336 1 : done:
2337 1 : smb2_util_close(tree, h2);
2338 1 : smb2_util_close(tree, h);
2339 1 : smb2_deltree(tree, BASEDIR);
2340 1 : return ret;
2341 : }
2342 :
2343 : /**
2344 : * Test lock contention
2345 : * - shared lock should contend with exclusive lock on different handle
2346 : */
2347 1 : static bool test_contend(struct torture_context *torture,
2348 : struct smb2_tree *tree)
2349 : {
2350 : NTSTATUS status;
2351 1 : bool ret = true;
2352 1 : struct smb2_handle h = {{0}};
2353 1 : struct smb2_handle h2 = {{0}};
2354 : uint8_t buf[200];
2355 : struct smb2_lock lck;
2356 : struct smb2_lock_element el[1];
2357 :
2358 1 : const char *fname = BASEDIR "\\contend.txt";
2359 :
2360 1 : status = torture_smb2_testdir(tree, BASEDIR, &h);
2361 1 : CHECK_STATUS(status, NT_STATUS_OK);
2362 1 : smb2_util_close(tree, h);
2363 :
2364 1 : status = torture_smb2_testfile(tree, fname, &h);
2365 1 : CHECK_STATUS(status, NT_STATUS_OK);
2366 :
2367 1 : ZERO_STRUCT(buf);
2368 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
2369 1 : CHECK_STATUS(status, NT_STATUS_OK);
2370 :
2371 1 : status = torture_smb2_testfile(tree, fname, &h2);
2372 1 : CHECK_STATUS(status, NT_STATUS_OK);
2373 :
2374 1 : torture_comment(torture, "Testing lock contention:\n");
2375 :
2376 : /* Setup initial parameters */
2377 1 : lck.in.locks = el;
2378 1 : lck.in.lock_count = 0x0001;
2379 1 : lck.in.lock_sequence = 0x00000000;
2380 1 : lck.in.file.handle = h;
2381 1 : el[0].offset = 0;
2382 1 : el[0].length = 10;
2383 1 : el[0].reserved = 0x00000000;
2384 :
2385 : /* Take an exclusive lock, then a shared lock on different handle */
2386 1 : torture_comment(torture, " shared should contend on exclusive on "
2387 : "different handle.\n");
2388 :
2389 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2390 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2391 1 : status = smb2_lock(tree, &lck);
2392 1 : CHECK_STATUS(status, NT_STATUS_OK);
2393 :
2394 1 : lck.in.file.handle = h2;
2395 1 : el[0].flags = SMB2_LOCK_FLAG_SHARED |
2396 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2397 1 : status = smb2_lock(tree, &lck);
2398 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2399 :
2400 : /* cleanup */
2401 1 : lck.in.file.handle = h;
2402 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2403 1 : status = smb2_lock(tree, &lck);
2404 1 : CHECK_STATUS(status, NT_STATUS_OK);
2405 :
2406 1 : done:
2407 1 : smb2_util_close(tree, h2);
2408 1 : smb2_util_close(tree, h);
2409 1 : smb2_deltree(tree, BASEDIR);
2410 1 : return ret;
2411 : }
2412 :
2413 : /**
2414 : * Test locker context
2415 : * - test that pid does not affect the locker context
2416 : */
2417 1 : static bool test_context(struct torture_context *torture,
2418 : struct smb2_tree *tree)
2419 : {
2420 : NTSTATUS status;
2421 1 : bool ret = true;
2422 1 : struct smb2_handle h = {{0}};
2423 1 : struct smb2_handle h2 = {{0}};
2424 : uint8_t buf[200];
2425 : struct smb2_lock lck;
2426 : struct smb2_lock_element el[1];
2427 :
2428 1 : const char *fname = BASEDIR "\\context.txt";
2429 :
2430 1 : status = torture_smb2_testdir(tree, BASEDIR, &h);
2431 1 : CHECK_STATUS(status, NT_STATUS_OK);
2432 1 : smb2_util_close(tree, h);
2433 :
2434 1 : status = torture_smb2_testfile(tree, fname, &h);
2435 1 : CHECK_STATUS(status, NT_STATUS_OK);
2436 :
2437 1 : ZERO_STRUCT(buf);
2438 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
2439 1 : CHECK_STATUS(status, NT_STATUS_OK);
2440 :
2441 1 : status = torture_smb2_testfile(tree, fname, &h2);
2442 1 : CHECK_STATUS(status, NT_STATUS_OK);
2443 :
2444 1 : torture_comment(torture, "Testing locker context:\n");
2445 :
2446 : /* Setup initial parameters */
2447 1 : lck.in.locks = el;
2448 1 : lck.in.lock_count = 0x0001;
2449 1 : lck.in.lock_sequence = 0x00000000;
2450 1 : lck.in.file.handle = h;
2451 1 : el[0].offset = 0;
2452 1 : el[0].length = 10;
2453 1 : 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 1 : torture_comment(torture, " pid shouldn't affect locker context\n");
2459 :
2460 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2461 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2462 1 : status = smb2_lock(tree, &lck);
2463 1 : CHECK_STATUS(status, NT_STATUS_OK);
2464 :
2465 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2466 1 : status = smb2_lock(tree, &lck);
2467 1 : CHECK_STATUS(status, NT_STATUS_OK);
2468 :
2469 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2470 1 : status = smb2_lock(tree, &lck);
2471 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
2472 :
2473 1 : done:
2474 1 : smb2_util_close(tree, h2);
2475 1 : smb2_util_close(tree, h);
2476 1 : smb2_deltree(tree, BASEDIR);
2477 1 : 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 1 : static bool test_range(struct torture_context *torture,
2485 : struct smb2_tree *tree)
2486 : {
2487 : NTSTATUS status;
2488 1 : bool ret = true;
2489 1 : struct smb2_handle h = {{0}};
2490 1 : struct smb2_handle h2 = {{0}};
2491 : uint8_t buf[200];
2492 : struct smb2_lock lck;
2493 : struct smb2_lock_element el[1];
2494 : uint64_t offset, i;
2495 : extern int torture_numops;
2496 :
2497 1 : const char *fname = BASEDIR "\\range.txt";
2498 :
2499 : #define NEXT_OFFSET offset += (~(uint64_t)0) / torture_numops
2500 :
2501 1 : status = torture_smb2_testdir(tree, BASEDIR, &h);
2502 1 : CHECK_STATUS(status, NT_STATUS_OK);
2503 1 : smb2_util_close(tree, h);
2504 :
2505 1 : status = torture_smb2_testfile(tree, fname, &h);
2506 1 : CHECK_STATUS(status, NT_STATUS_OK);
2507 :
2508 1 : ZERO_STRUCT(buf);
2509 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
2510 1 : CHECK_STATUS(status, NT_STATUS_OK);
2511 :
2512 1 : status = torture_smb2_testfile(tree, fname, &h2);
2513 1 : CHECK_STATUS(status, NT_STATUS_OK);
2514 :
2515 1 : torture_comment(torture, "Testing locks spread across the 64-bit "
2516 : "offset range\n");
2517 :
2518 1 : 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 1 : lck.in.locks = el;
2527 1 : lck.in.lock_count = 0x0001;
2528 1 : lck.in.lock_sequence = 0x00000000;
2529 1 : lck.in.file.handle = h;
2530 1 : el[0].offset = 0;
2531 1 : el[0].length = 1;
2532 1 : el[0].reserved = 0x00000000;
2533 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2534 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2535 :
2536 1 : torture_comment(torture, " establishing %d locks\n", torture_numops);
2537 :
2538 11 : for (offset=i=0; i<torture_numops; i++) {
2539 10 : NEXT_OFFSET;
2540 :
2541 10 : lck.in.file.handle = h;
2542 10 : el[0].offset = offset - 1;
2543 10 : status = smb2_lock(tree, &lck);
2544 10 : 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 10 : lck.in.file.handle = h2;
2550 10 : el[0].offset = offset - 2;
2551 10 : status = smb2_lock(tree, &lck);
2552 10 : 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 1 : torture_comment(torture, " testing %d locks\n", torture_numops);
2559 :
2560 11 : for (offset=i=0; i<torture_numops; i++) {
2561 10 : NEXT_OFFSET;
2562 :
2563 10 : lck.in.file.handle = h;
2564 10 : el[0].offset = offset - 1;
2565 10 : status = smb2_lock(tree, &lck);
2566 10 : 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 10 : lck.in.file.handle = h;
2573 10 : el[0].offset = offset - 2;
2574 10 : status = smb2_lock(tree, &lck);
2575 10 : 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 10 : lck.in.file.handle = h2;
2582 10 : el[0].offset = offset - 1;
2583 10 : status = smb2_lock(tree, &lck);
2584 10 : 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 10 : lck.in.file.handle = h2;
2591 10 : el[0].offset = offset - 2;
2592 10 : status = smb2_lock(tree, &lck);
2593 10 : 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 1 : torture_comment(torture, " removing %d locks\n", torture_numops);
2601 :
2602 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2603 :
2604 11 : for (offset=i=0; i<torture_numops; i++) {
2605 10 : NEXT_OFFSET;
2606 :
2607 10 : lck.in.file.handle = h;
2608 10 : el[0].offset = offset - 1;
2609 10 : status = smb2_lock(tree, &lck);
2610 10 : 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 10 : lck.in.file.handle = h2;
2616 10 : el[0].offset = offset - 2;
2617 10 : status = smb2_lock(tree, &lck);
2618 10 : 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 1 : done:
2625 1 : smb2_util_close(tree, h2);
2626 1 : smb2_util_close(tree, h);
2627 1 : smb2_deltree(tree, BASEDIR);
2628 1 : return ret;
2629 : }
2630 :
2631 17 : static NTSTATUS test_smb2_lock(struct smb2_tree *tree, struct smb2_handle h,
2632 : uint64_t offset, uint64_t length, bool exclusive)
2633 : {
2634 : struct smb2_lock lck;
2635 : struct smb2_lock_element el[1];
2636 : NTSTATUS status;
2637 :
2638 17 : lck.in.locks = el;
2639 17 : lck.in.lock_count = 0x0001;
2640 17 : lck.in.lock_sequence = 0x00000000;
2641 17 : lck.in.file.handle = h;
2642 17 : el[0].offset = offset;
2643 17 : el[0].length = length;
2644 17 : el[0].reserved = 0x00000000;
2645 17 : el[0].flags = (exclusive ?
2646 : SMB2_LOCK_FLAG_EXCLUSIVE :
2647 17 : SMB2_LOCK_FLAG_SHARED) |
2648 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2649 :
2650 17 : status = smb2_lock(tree, &lck);
2651 :
2652 17 : return status;
2653 : }
2654 :
2655 1 : static NTSTATUS test_smb2_unlock(struct smb2_tree *tree, struct smb2_handle h,
2656 : uint64_t offset, uint64_t length)
2657 : {
2658 : struct smb2_lock lck;
2659 : struct smb2_lock_element el[1];
2660 : NTSTATUS status;
2661 :
2662 1 : lck.in.locks = el;
2663 1 : lck.in.lock_count = 0x0001;
2664 1 : lck.in.lock_sequence = 0x00000000;
2665 1 : lck.in.file.handle = h;
2666 1 : el[0].offset = offset;
2667 1 : el[0].length = length;
2668 1 : el[0].reserved = 0x00000000;
2669 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2670 :
2671 1 : status = smb2_lock(tree, &lck);
2672 :
2673 1 : 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 1 : static bool test_overlap(struct torture_context *torture,
2686 : struct smb2_tree *tree,
2687 : struct smb2_tree *tree2)
2688 : {
2689 : NTSTATUS status;
2690 1 : bool ret = true;
2691 1 : struct smb2_handle h = {{0}};
2692 1 : struct smb2_handle h2 = {{0}};
2693 1 : struct smb2_handle h3 = {{0}};
2694 : uint8_t buf[200];
2695 1 : bool correct = true;
2696 :
2697 1 : const char *fname = BASEDIR "\\overlap.txt";
2698 :
2699 1 : status = torture_smb2_testdir(tree, BASEDIR, &h);
2700 1 : CHECK_STATUS(status, NT_STATUS_OK);
2701 1 : smb2_util_close(tree, h);
2702 :
2703 1 : status = torture_smb2_testfile(tree, fname, &h);
2704 1 : CHECK_STATUS(status, NT_STATUS_OK);
2705 :
2706 1 : ZERO_STRUCT(buf);
2707 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
2708 1 : CHECK_STATUS(status, NT_STATUS_OK);
2709 :
2710 1 : status = torture_smb2_testfile(tree, fname, &h2);
2711 1 : CHECK_STATUS(status, NT_STATUS_OK);
2712 :
2713 1 : status = torture_smb2_testfile(tree2, fname, &h3);
2714 1 : CHECK_STATUS(status, NT_STATUS_OK);
2715 :
2716 1 : torture_comment(torture, "Testing overlapping locks:\n");
2717 :
2718 2 : ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 0, 4, true)) &&
2719 1 : NT_STATUS_IS_OK(test_smb2_lock(tree, h, 2, 4, true));
2720 1 : EXPECTED(ret, false);
2721 1 : torture_comment(torture, "the same session/handle %s set overlapping "
2722 : "exclusive locks\n", ret?"can":"cannot");
2723 :
2724 2 : ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 10, 4, false)) &&
2725 1 : NT_STATUS_IS_OK(test_smb2_lock(tree, h, 12, 4, false));
2726 1 : EXPECTED(ret, true);
2727 1 : torture_comment(torture, "the same session/handle %s set overlapping "
2728 : "shared locks\n", ret?"can":"cannot");
2729 :
2730 2 : ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 20, 4, true)) &&
2731 1 : NT_STATUS_IS_OK(test_smb2_lock(tree2, h3, 22, 4, true));
2732 1 : EXPECTED(ret, false);
2733 1 : torture_comment(torture, "a different session %s set overlapping "
2734 : "exclusive locks\n", ret?"can":"cannot");
2735 :
2736 2 : ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 30, 4, false)) &&
2737 1 : NT_STATUS_IS_OK(test_smb2_lock(tree2, h3, 32, 4, false));
2738 1 : EXPECTED(ret, true);
2739 1 : torture_comment(torture, "a different session %s set overlapping "
2740 : "shared locks\n", ret?"can":"cannot");
2741 :
2742 2 : ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 40, 4, true)) &&
2743 1 : NT_STATUS_IS_OK(test_smb2_lock(tree, h2, 42, 4, true));
2744 1 : EXPECTED(ret, false);
2745 1 : torture_comment(torture, "a different handle %s set overlapping "
2746 : "exclusive locks\n", ret?"can":"cannot");
2747 :
2748 2 : ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 50, 4, false)) &&
2749 1 : NT_STATUS_IS_OK(test_smb2_lock(tree, h2, 52, 4, false));
2750 1 : EXPECTED(ret, true);
2751 1 : torture_comment(torture, "a different handle %s set overlapping "
2752 : "shared locks\n", ret?"can":"cannot");
2753 :
2754 3 : ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 110, 4, false)) &&
2755 2 : NT_STATUS_IS_OK(test_smb2_lock(tree, h, 112, 4, false)) &&
2756 1 : NT_STATUS_IS_OK(test_smb2_unlock(tree, h, 110, 6));
2757 1 : EXPECTED(ret, false);
2758 1 : torture_comment(torture, "the same handle %s coalesce read locks\n",
2759 : ret?"can":"cannot");
2760 :
2761 1 : smb2_util_close(tree, h2);
2762 1 : smb2_util_close(tree, h);
2763 1 : status = torture_smb2_testfile(tree, fname, &h);
2764 1 : CHECK_STATUS(status, NT_STATUS_OK);
2765 1 : status = torture_smb2_testfile(tree, fname, &h2);
2766 1 : CHECK_STATUS(status, NT_STATUS_OK);
2767 3 : ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 0, 8, false)) &&
2768 2 : NT_STATUS_IS_OK(test_smb2_lock(tree, h2, 0, 1, false)) &&
2769 2 : NT_STATUS_IS_OK(smb2_util_close(tree, h)) &&
2770 3 : NT_STATUS_IS_OK(torture_smb2_testfile(tree, fname, &h)) &&
2771 1 : NT_STATUS_IS_OK(test_smb2_lock(tree, h, 7, 1, true));
2772 1 : EXPECTED(ret, true);
2773 1 : torture_comment(torture, "the server %s have the NT byte range lock "
2774 1 : "bug\n", !ret?"does":"doesn't");
2775 :
2776 1 : done:
2777 1 : smb2_util_close(tree2, h3);
2778 1 : smb2_util_close(tree, h2);
2779 1 : smb2_util_close(tree, h);
2780 1 : smb2_deltree(tree, BASEDIR);
2781 1 : return correct;
2782 : }
2783 :
2784 : /**
2785 : * Test truncation of locked file
2786 : * - some tests ported from BASE-LOCK-LOCK7
2787 : */
2788 1 : static bool test_truncate(struct torture_context *torture,
2789 : struct smb2_tree *tree)
2790 : {
2791 : NTSTATUS status;
2792 1 : bool ret = true;
2793 1 : struct smb2_handle h = {{0}};
2794 1 : struct smb2_handle h2 = {{0}};
2795 : uint8_t buf[200];
2796 : struct smb2_lock lck;
2797 : struct smb2_lock_element el[1];
2798 : struct smb2_create io;
2799 :
2800 1 : const char *fname = BASEDIR "\\truncate.txt";
2801 :
2802 1 : status = torture_smb2_testdir(tree, BASEDIR, &h);
2803 1 : CHECK_STATUS(status, NT_STATUS_OK);
2804 1 : smb2_util_close(tree, h);
2805 :
2806 1 : status = torture_smb2_testfile(tree, fname, &h);
2807 1 : CHECK_STATUS(status, NT_STATUS_OK);
2808 :
2809 1 : ZERO_STRUCT(buf);
2810 1 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
2811 1 : CHECK_STATUS(status, NT_STATUS_OK);
2812 :
2813 1 : torture_comment(torture, "Testing truncation of locked file:\n");
2814 :
2815 : /* Setup initial parameters */
2816 1 : lck.in.locks = el;
2817 1 : lck.in.lock_count = 0x0001;
2818 1 : lck.in.lock_sequence = 0x00000000;
2819 1 : lck.in.file.handle = h;
2820 1 : el[0].offset = 0;
2821 1 : el[0].length = 10;
2822 1 : el[0].reserved = 0x00000000;
2823 :
2824 1 : ZERO_STRUCT(io);
2825 1 : io.in.oplock_level = 0;
2826 1 : io.in.desired_access = SEC_RIGHTS_FILE_ALL;
2827 1 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2828 1 : io.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2829 1 : io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
2830 : NTCREATEX_SHARE_ACCESS_READ |
2831 : NTCREATEX_SHARE_ACCESS_WRITE;
2832 1 : io.in.create_options = 0;
2833 1 : io.in.fname = fname;
2834 :
2835 : /* Take an exclusive lock */
2836 1 : el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
2837 : SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2838 1 : status = smb2_lock(tree, &lck);
2839 1 : CHECK_STATUS(status, NT_STATUS_OK);
2840 :
2841 : /* On second handle open the file with OVERWRITE disposition */
2842 1 : torture_comment(torture, " overwrite disposition is allowed on a "
2843 : "locked file.\n");
2844 :
2845 1 : io.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
2846 1 : status = smb2_create(tree, tree, &io);
2847 1 : CHECK_STATUS(status, NT_STATUS_OK);
2848 1 : h2 = io.out.file.handle;
2849 1 : smb2_util_close(tree, h2);
2850 :
2851 : /* On second handle open the file with SUPERSEDE disposition */
2852 1 : torture_comment(torture, " supersede disposition is allowed on a "
2853 : "locked file.\n");
2854 :
2855 1 : io.in.create_disposition = NTCREATEX_DISP_SUPERSEDE;
2856 1 : status = smb2_create(tree, tree, &io);
2857 1 : CHECK_STATUS(status, NT_STATUS_OK);
2858 1 : h2 = io.out.file.handle;
2859 1 : smb2_util_close(tree, h2);
2860 :
2861 : /* cleanup */
2862 1 : lck.in.file.handle = h;
2863 1 : el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
2864 1 : status = smb2_lock(tree, &lck);
2865 1 : CHECK_STATUS(status, NT_STATUS_OK);
2866 :
2867 1 : done:
2868 1 : smb2_util_close(tree, h2);
2869 1 : smb2_util_close(tree, h);
2870 1 : smb2_deltree(tree, BASEDIR);
2871 1 : 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 1 : static bool test_replay_broken_windows(struct torture_context *torture,
2907 : struct smb2_tree *tree)
2908 : {
2909 : NTSTATUS status;
2910 1 : bool ret = true;
2911 : struct smb2_handle h;
2912 : struct smb2_ioctl ioctl;
2913 : struct smb2_lock lck;
2914 : struct smb2_lock_element el;
2915 : uint8_t res_req[8];
2916 1 : const char *fname = BASEDIR "\\replay_broken_windows.txt";
2917 1 : struct smb2_transport *transport = tree->session->transport;
2918 :
2919 1 : 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 0 : status = torture_smb2_testdir(tree, BASEDIR, &h);
2925 0 : CHECK_STATUS(status, NT_STATUS_OK);
2926 0 : smb2_util_close(tree, h);
2927 :
2928 0 : torture_comment(torture, "Testing Open File:\n");
2929 0 : status = torture_smb2_testfile(tree, fname, &h);
2930 0 : CHECK_STATUS(status, NT_STATUS_OK);
2931 :
2932 : /*
2933 : * Setup initial parameters
2934 : */
2935 0 : el = (struct smb2_lock_element) {
2936 : .length = 100,
2937 : .offset = 100,
2938 : };
2939 0 : lck = (struct smb2_lock) {
2940 : .in.locks = &el,
2941 : .in.lock_count = 0x0001,
2942 : .in.file.handle = h
2943 : };
2944 :
2945 0 : torture_comment(torture, "Testing Lock Replay detection [ignored]:\n");
2946 0 : lck.in.lock_sequence = 0x010 + 0x1;
2947 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2948 0 : status = smb2_lock(tree, &lck);
2949 0 : CHECK_STATUS(status, NT_STATUS_OK);
2950 0 : status = smb2_lock(tree, &lck);
2951 0 : if (NT_STATUS_IS_OK(status)) {
2952 0 : lck.in.lock_sequence = 0x020 + 0x2;
2953 0 : status = smb2_lock(tree, &lck);
2954 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2955 0 : lck.in.lock_sequence = 0x010 + 0x1;
2956 0 : status = smb2_lock(tree, &lck);
2957 0 : CHECK_STATUS(status, NT_STATUS_OK);
2958 0 : if (smbXcli_conn_protocol(transport->conn) > PROTOCOL_SMB2_10) {
2959 0 : 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 0 : done:
3133 0 : smb2_util_close(tree, h);
3134 0 : smb2_deltree(tree, BASEDIR);
3135 0 : 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 0 : 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 : NTSTATUS status;
3176 0 : bool ret = true;
3177 : struct smb2_create io;
3178 : struct smb2_handle h;
3179 : struct smb2_lock lck;
3180 : struct smb2_lock_element el;
3181 : char fname[256];
3182 0 : struct smb2_transport *transport = tree->session->transport;
3183 :
3184 0 : 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 0 : snprintf(fname, sizeof(fname), "%s\\%s.dat", BASEDIR, testname);
3190 :
3191 0 : status = torture_smb2_testdir(tree, BASEDIR, &h);
3192 0 : CHECK_STATUS(status, NT_STATUS_OK);
3193 0 : smb2_util_close(tree, h);
3194 :
3195 0 : torture_comment(torture, "%s: Testing Open File:\n", testname);
3196 :
3197 0 : smb2_oplock_create_share(&io, fname,
3198 : smb2_util_share_access(""),
3199 0 : smb2_util_oplock_level("b"));
3200 0 : io.in.durable_open = use_durable;
3201 :
3202 0 : status = smb2_create(tree, torture, &io);
3203 0 : CHECK_STATUS(status, NT_STATUS_OK);
3204 0 : h = io.out.file.handle;
3205 0 : CHECK_VALUE(io.out.oplock_level, smb2_util_oplock_level("b"));
3206 0 : CHECK_VALUE(io.out.durable_open, use_durable);
3207 0 : CHECK_VALUE(io.out.durable_open_v2, false);
3208 0 : CHECK_VALUE(io.out.persistent_open, false);
3209 :
3210 : /*
3211 : * Setup initial parameters
3212 : */
3213 0 : el = (struct smb2_lock_element) {
3214 : .length = 100,
3215 : .offset = 100,
3216 : };
3217 0 : lck = (struct smb2_lock) {
3218 : .in.locks = &el,
3219 : .in.lock_count = 0x0001,
3220 : .in.file.handle = h
3221 : };
3222 :
3223 0 : 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 0 : torture_comment(torture, "Testing Lock (ignored) Replay detection "
3231 : "(Bucket No: 0 (invalid)) [ignored]:\n");
3232 0 : lck.in.lock_sequence = 0x000 + 0x1;
3233 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3234 0 : status = smb2_lock(tree, &lck);
3235 0 : CHECK_STATUS(status, NT_STATUS_OK);
3236 0 : status = smb2_lock(tree, &lck);
3237 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3238 :
3239 0 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3240 0 : status = smb2_lock(tree, &lck);
3241 0 : CHECK_STATUS(status, NT_STATUS_OK);
3242 0 : status = smb2_lock(tree, &lck);
3243 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
3244 :
3245 0 : 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 0 : lck.in.lock_sequence = 0x010 + 0x1;
3253 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3254 0 : status = smb2_lock(tree, &lck);
3255 0 : 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 0 : status = smb2_lock(tree, &lck);
3262 0 : CHECK_STATUS(status, NT_STATUS_OK);
3263 0 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3264 0 : status = smb2_lock(tree, &lck);
3265 0 : CHECK_STATUS(status, NT_STATUS_OK);
3266 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3267 0 : status = smb2_lock(tree, &lck);
3268 0 : CHECK_STATUS(status, NT_STATUS_OK);
3269 0 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3270 0 : status = smb2_lock(tree, &lck);
3271 0 : CHECK_STATUS(status, NT_STATUS_OK);
3272 0 : status = smb2_lock(tree, &lck);
3273 0 : 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 0 : lck.in.lock_sequence = 0x010 + 0x2;
3281 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3282 0 : status = smb2_lock(tree, &lck);
3283 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3284 0 : status = smb2_lock(tree, &lck);
3285 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3286 :
3287 0 : 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 0 : lck.in.lock_sequence = 0x020 + 0x1;
3294 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3295 0 : status = smb2_lock(tree, &lck);
3296 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3297 0 : status = smb2_lock(tree, &lck);
3298 0 : 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 0 : torture_comment(torture, "Testing Lock Replay detection "
3305 : "(Bucket No: 65 (invalid)) [ignored]:\n");
3306 :
3307 0 : lck.in.lock_sequence = 0x410 + 0x1;
3308 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3309 0 : status = smb2_lock(tree, &lck);
3310 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3311 0 : status = smb2_lock(tree, &lck);
3312 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3313 :
3314 0 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3315 0 : status = smb2_lock(tree, &lck);
3316 0 : CHECK_STATUS(status, NT_STATUS_OK);
3317 0 : status = smb2_lock(tree, &lck);
3318 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
3319 :
3320 : /* status: unlocked */
3321 :
3322 : /*
3323 : * Lock again for the unlock replay test
3324 : */
3325 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3326 0 : status = smb2_lock(tree, &lck);
3327 0 : CHECK_STATUS(status, NT_STATUS_OK);
3328 :
3329 0 : 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 0 : lck.in.lock_sequence = 0x400 + 0x1;
3336 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3337 0 : status = smb2_lock(tree, &lck);
3338 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3339 0 : status = smb2_lock(tree, &lck);
3340 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3341 :
3342 : /*
3343 : * Test Unlock replay detection
3344 : */
3345 0 : lck.in.lock_sequence = 0x400 + 0x2;
3346 0 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3347 0 : status = smb2_lock(tree, &lck);
3348 0 : CHECK_STATUS(status, NT_STATUS_OK); /* new seq num ==> unlocked */
3349 0 : status = smb2_lock(tree, &lck);
3350 0 : CHECK_STATUS(status, NT_STATUS_OK); /* replay detected ==> ignored */
3351 :
3352 0 : el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3353 0 : status = smb2_lock(tree, &lck); /* same seq num ==> ignored */
3354 0 : CHECK_STATUS(status, NT_STATUS_OK);
3355 :
3356 : /* verify it's unlocked: */
3357 0 : lck.in.lock_sequence = 0x400 + 0x3;
3358 0 : el.flags = SMB2_LOCK_FLAG_UNLOCK;
3359 0 : status = smb2_lock(tree, &lck);
3360 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
3361 :
3362 : /* status: not locked */
3363 :
3364 0 : done:
3365 0 : smb2_util_close(tree, h);
3366 0 : smb2_deltree(tree, BASEDIR);
3367 0 : return ret;
3368 : }
3369 :
3370 1 : static bool test_replay_smb3_specification_durable(struct torture_context *torture,
3371 : struct smb2_tree *tree)
3372 : {
3373 1 : const char *testname = "replay_smb3_specification_durable";
3374 1 : struct smb2_transport *transport = tree->session->transport;
3375 :
3376 1 : 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 0 : return _test_replay_smb3_specification(torture, tree, testname, true);
3382 : }
3383 :
3384 1 : static bool test_replay_smb3_specification_multi(struct torture_context *torture,
3385 : struct smb2_tree *tree)
3386 : {
3387 1 : const char *testname = "replay_smb3_specification_multi";
3388 1 : struct smb2_transport *transport = tree->session->transport;
3389 : uint32_t server_capabilities;
3390 :
3391 1 : 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 0 : server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
3397 0 : 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 0 : 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 1 : static bool test_deadlock(struct torture_context *torture,
3415 : struct smb2_tree *tree)
3416 : {
3417 : NTSTATUS status;
3418 1 : bool ret = true;
3419 : struct smb2_handle _h;
3420 1 : struct smb2_handle *h = NULL;
3421 : uint8_t buf[200];
3422 1 : const char *fname = BASEDIR "\\deadlock.txt";
3423 :
3424 1 : if (!lpcfg_clustering(torture->lp_ctx)) {
3425 1 : 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 964 : struct torture_suite *torture_smb2_lock_init(TALLOC_CTX *ctx)
3471 : {
3472 738 : struct torture_suite *suite =
3473 226 : torture_suite_create(ctx, "lock");
3474 964 : torture_suite_add_1smb2_test(suite, "valid-request",
3475 : test_valid_request);
3476 964 : torture_suite_add_1smb2_test(suite, "rw-none", test_lock_rw_none);
3477 964 : torture_suite_add_1smb2_test(suite, "rw-shared", test_lock_rw_shared);
3478 964 : torture_suite_add_1smb2_test(suite, "rw-exclusive",
3479 : test_lock_rw_exclusive);
3480 964 : torture_suite_add_1smb2_test(suite, "auto-unlock",
3481 : test_lock_auto_unlock);
3482 964 : torture_suite_add_1smb2_test(suite, "lock", test_lock);
3483 964 : torture_suite_add_1smb2_test(suite, "async", test_async);
3484 964 : torture_suite_add_1smb2_test(suite, "cancel", test_cancel);
3485 964 : torture_suite_add_1smb2_test(suite, "cancel-tdis", test_cancel_tdis);
3486 964 : torture_suite_add_1smb2_test(suite, "cancel-logoff",
3487 : test_cancel_logoff);
3488 964 : torture_suite_add_1smb2_test(suite, "errorcode", test_errorcode);
3489 964 : torture_suite_add_1smb2_test(suite, "zerobytelength",
3490 : test_zerobytelength);
3491 964 : torture_suite_add_1smb2_test(suite, "zerobyteread",
3492 : test_zerobyteread);
3493 964 : torture_suite_add_1smb2_test(suite, "unlock", test_unlock);
3494 964 : torture_suite_add_1smb2_test(suite, "multiple-unlock",
3495 : test_multiple_unlock);
3496 964 : torture_suite_add_1smb2_test(suite, "stacking", test_stacking);
3497 964 : torture_suite_add_1smb2_test(suite, "contend", test_contend);
3498 964 : torture_suite_add_1smb2_test(suite, "context", test_context);
3499 964 : torture_suite_add_1smb2_test(suite, "range", test_range);
3500 964 : torture_suite_add_2smb2_test(suite, "overlap", test_overlap);
3501 964 : torture_suite_add_1smb2_test(suite, "truncate", test_truncate);
3502 964 : torture_suite_add_1smb2_test(suite, "replay_broken_windows",
3503 : test_replay_broken_windows);
3504 964 : torture_suite_add_1smb2_test(suite, "replay_smb3_specification_durable",
3505 : test_replay_smb3_specification_durable);
3506 964 : torture_suite_add_1smb2_test(suite, "replay_smb3_specification_multi",
3507 : test_replay_smb3_specification_multi);
3508 964 : torture_suite_add_1smb2_test(suite, "ctdb-delrec-deadlock", test_deadlock);
3509 :
3510 964 : suite->description = talloc_strdup(suite, "SMB2-LOCK tests");
3511 :
3512 964 : return suite;
3513 : }
|