2 Unix SMB/CIFS implementation.
6 Copyright (C) Stefan Metzmacher 2006
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
26 #include "torture/torture.h"
27 #include "torture/smb2/proto.h"
30 #define TARGET_SUPPORTS_INVALID_LOCK_RANGE(_tctx) \
31 (torture_setting_bool(_tctx, "invalid_lock_range_support", true))
32 #define TARGET_IS_W2K8(_tctx) (torture_setting_bool(_tctx, "w2k8", false))
34 #define CHECK_STATUS(status, correct) do { \
35 const char *_cmt = "(" __location__ ")"; \
36 torture_assert_ntstatus_equal_goto(torture,status,correct,ret,done,_cmt); \
39 #define CHECK_VALUE(v, correct) do { \
40 const char *_cmt = "(" __location__ ")"; \
41 torture_assert_int_equal_goto(torture,v,correct,ret,done,_cmt); \
44 static bool test_valid_request(struct torture_context *torture, struct smb2_tree *tree)
51 struct smb2_lock_element el[2];
55 status = torture_smb2_testfile(tree, "lock1.txt", &h);
56 CHECK_STATUS(status, NT_STATUS_OK);
58 status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
59 CHECK_STATUS(status, NT_STATUS_OK);
63 torture_comment(torture, "Test request with 0 locks.\n");
65 lck.in.lock_count = 0x0000;
66 lck.in.reserved = 0x00000000;
67 lck.in.file.handle = h;
68 el[0].offset = 0x0000000000000000;
69 el[0].length = 0x0000000000000000;
70 el[0].reserved = 0x0000000000000000;
71 el[0].flags = 0x00000000;
72 status = smb2_lock(tree, &lck);
73 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
75 lck.in.lock_count = 0x0000;
76 lck.in.reserved = 0x00000000;
77 lck.in.file.handle = h;
80 el[0].reserved = 0x00000000;
81 el[0].flags = SMB2_LOCK_FLAG_SHARED;
82 status = smb2_lock(tree, &lck);
83 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
85 lck.in.lock_count = 0x0001;
86 lck.in.reserved = 0x00000000;
87 lck.in.file.handle = h;
90 el[0].reserved = 0x00000000;
91 el[0].flags = SMB2_LOCK_FLAG_NONE;
92 status = smb2_lock(tree, &lck);
93 if (TARGET_IS_W2K8(torture)) {
94 CHECK_STATUS(status, NT_STATUS_OK);
95 torture_warning(torture, "Target has bug validating lock flags "
98 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
101 torture_comment(torture, "Test >63-bit lock requests.\n");
103 lck.in.file.handle.data[0] +=1;
104 status = smb2_lock(tree, &lck);
105 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
106 lck.in.file.handle.data[0] -=1;
108 lck.in.lock_count = 0x0001;
109 lck.in.reserved = 0x123ab1;
110 lck.in.file.handle = h;
111 el[0].offset = UINT64_MAX;
112 el[0].length = UINT64_MAX;
113 el[0].reserved = 0x00000000;
114 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
115 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
116 status = smb2_lock(tree, &lck);
117 if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(torture)) {
118 CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
120 CHECK_STATUS(status, NT_STATUS_OK);
121 CHECK_VALUE(lck.out.reserved, 0);
124 lck.in.reserved = 0x123ab2;
125 status = smb2_lock(tree, &lck);
126 if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(torture)) {
127 CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
129 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
132 torture_comment(torture, "Test basic lock stacking.\n");
134 lck.in.lock_count = 0x0001;
135 lck.in.reserved = 0x12345678;
136 lck.in.file.handle = h;
137 el[0].offset = UINT32_MAX;
138 el[0].length = UINT32_MAX;
139 el[0].reserved = 0x87654321;
140 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
141 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
142 status = smb2_lock(tree, &lck);
143 CHECK_STATUS(status, NT_STATUS_OK);
144 CHECK_VALUE(lck.out.reserved, 0);
146 el[0].flags = SMB2_LOCK_FLAG_SHARED;
147 status = smb2_lock(tree, &lck);
148 CHECK_STATUS(status, NT_STATUS_OK);
149 CHECK_VALUE(lck.out.reserved, 0);
151 status = smb2_lock(tree, &lck);
152 CHECK_STATUS(status, NT_STATUS_OK);
153 CHECK_VALUE(lck.out.reserved, 0);
155 lck.in.lock_count = 0x0001;
156 lck.in.reserved = 0x87654321;
157 lck.in.file.handle = h;
158 el[0].offset = 0x00000000FFFFFFFF;
159 el[0].length = 0x00000000FFFFFFFF;
160 el[0].reserved = 0x1234567;
161 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
162 status = smb2_lock(tree, &lck);
163 CHECK_STATUS(status, NT_STATUS_OK);
165 lck.in.lock_count = 0x0001;
166 lck.in.reserved = 0x1234567;
167 lck.in.file.handle = h;
168 el[0].offset = 0x00000000FFFFFFFF;
169 el[0].length = 0x00000000FFFFFFFF;
170 el[0].reserved = 0x00000000;
171 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
172 status = smb2_lock(tree, &lck);
173 CHECK_STATUS(status, NT_STATUS_OK);
175 status = smb2_lock(tree, &lck);
176 CHECK_STATUS(status, NT_STATUS_OK);
177 status = smb2_lock(tree, &lck);
178 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
180 torture_comment(torture, "Test flags field permutations.\n");
182 lck.in.lock_count = 0x0001;
184 lck.in.file.handle = h;
187 el[0].reserved = 0x00000000;
188 el[0].flags = ~SMB2_LOCK_FLAG_ALL_MASK;
190 status = smb2_lock(tree, &lck);
191 if (TARGET_IS_W2K8(torture)) {
192 CHECK_STATUS(status, NT_STATUS_OK);
193 torture_warning(torture, "Target has bug validating lock flags "
196 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
199 if (TARGET_IS_W2K8(torture)) {
200 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
201 status = smb2_lock(tree, &lck);
202 CHECK_STATUS(status, NT_STATUS_OK);
205 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
206 status = smb2_lock(tree, &lck);
207 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
209 el[0].flags = SMB2_LOCK_FLAG_UNLOCK |
210 SMB2_LOCK_FLAG_EXCLUSIVE;
211 status = smb2_lock(tree, &lck);
212 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
214 el[0].flags = SMB2_LOCK_FLAG_UNLOCK |
215 SMB2_LOCK_FLAG_SHARED;
216 status = smb2_lock(tree, &lck);
217 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
219 el[0].flags = SMB2_LOCK_FLAG_UNLOCK |
220 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
221 status = smb2_lock(tree, &lck);
222 if (TARGET_IS_W2K8(torture)) {
223 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
224 torture_warning(torture, "Target has bug validating lock flags "
227 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
230 torture_comment(torture, "Test return error when 2 locks are "
233 lck.in.lock_count = 2;
235 lck.in.file.handle = h;
238 el[0].reserved = 0x00000000;
241 el[1].reserved = 0x00000000;
243 lck.in.lock_count = 2;
245 el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
246 status = smb2_lock(tree, &lck);
247 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
249 lck.in.lock_count = 2;
252 status = smb2_lock(tree, &lck);
253 if (TARGET_IS_W2K8(torture)) {
254 CHECK_STATUS(status, NT_STATUS_OK);
255 torture_warning(torture, "Target has bug validating lock flags "
258 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
261 lck.in.lock_count = 2;
262 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
264 status = smb2_lock(tree, &lck);
265 if (TARGET_IS_W2K8(torture)) {
266 CHECK_STATUS(status, NT_STATUS_OK);
267 torture_warning(torture, "Target has bug validating lock flags "
270 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
273 lck.in.lock_count = 1;
274 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
275 status = smb2_lock(tree, &lck);
276 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
278 lck.in.lock_count = 1;
279 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
280 status = smb2_lock(tree, &lck);
281 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
283 lck.in.lock_count = 1;
284 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
285 status = smb2_lock(tree, &lck);
286 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
288 lck.in.lock_count = 1;
289 el[0].flags = SMB2_LOCK_FLAG_SHARED;
290 status = smb2_lock(tree, &lck);
291 CHECK_STATUS(status, NT_STATUS_OK);
293 status = smb2_lock(tree, &lck);
294 CHECK_STATUS(status, NT_STATUS_OK);
296 lck.in.lock_count = 2;
297 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
298 el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
299 status = smb2_lock(tree, &lck);
300 CHECK_STATUS(status, NT_STATUS_OK);
302 lck.in.lock_count = 1;
303 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
304 status = smb2_lock(tree, &lck);
305 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
311 struct test_lock_read_write_state {
314 NTSTATUS write_h1_status;
315 NTSTATUS read_h1_status;
316 NTSTATUS write_h2_status;
317 NTSTATUS read_h2_status;
320 static bool test_lock_read_write(struct torture_context *torture,
321 struct smb2_tree *tree,
322 struct test_lock_read_write_state *s)
326 struct smb2_handle h1, h2;
328 struct smb2_lock lck;
329 struct smb2_create cr;
330 struct smb2_write wr;
332 struct smb2_lock_element el[1];
338 status = torture_smb2_testfile(tree, s->fname, &h1);
339 CHECK_STATUS(status, NT_STATUS_OK);
341 status = smb2_util_write(tree, h1, buf, 0, ARRAY_SIZE(buf));
342 CHECK_STATUS(status, NT_STATUS_OK);
344 lck.in.lock_count = 0x0001;
345 lck.in.reserved = 0x00000000;
346 lck.in.file.handle = h1;
348 el[0].length = ARRAY_SIZE(buf)/2;
349 el[0].reserved = 0x00000000;
350 el[0].flags = s->lock_flags;
351 status = smb2_lock(tree, &lck);
352 CHECK_STATUS(status, NT_STATUS_OK);
353 CHECK_VALUE(lck.out.reserved, 0);
355 lck.in.lock_count = 0x0001;
356 lck.in.reserved = 0x00000000;
357 lck.in.file.handle = h1;
358 el[0].offset = ARRAY_SIZE(buf)/2;
359 el[0].length = ARRAY_SIZE(buf)/2;
360 el[0].reserved = 0x00000000;
361 el[0].flags = s->lock_flags;
362 status = smb2_lock(tree, &lck);
363 CHECK_STATUS(status, NT_STATUS_OK);
364 CHECK_VALUE(lck.out.reserved, 0);
367 cr.in.oplock_level = 0;
368 cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
369 cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
370 cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
372 NTCREATEX_SHARE_ACCESS_DELETE|
373 NTCREATEX_SHARE_ACCESS_READ|
374 NTCREATEX_SHARE_ACCESS_WRITE;
375 cr.in.create_options = 0;
376 cr.in.fname = s->fname;
378 status = smb2_create(tree, tree, &cr);
379 CHECK_STATUS(status, NT_STATUS_OK);
381 h2 = cr.out.file.handle;
384 wr.in.file.handle = h1;
385 wr.in.offset = ARRAY_SIZE(buf)/2;
386 wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
388 status = smb2_write(tree, &wr);
389 CHECK_STATUS(status, s->write_h1_status);
392 rd.in.file.handle = h1;
393 rd.in.offset = ARRAY_SIZE(buf)/2;
394 rd.in.length = ARRAY_SIZE(buf)/2;
396 status = smb2_read(tree, tree, &rd);
397 CHECK_STATUS(status, s->read_h1_status);
400 wr.in.file.handle = h2;
401 wr.in.offset = ARRAY_SIZE(buf)/2;
402 wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
404 status = smb2_write(tree, &wr);
405 CHECK_STATUS(status, s->write_h2_status);
408 rd.in.file.handle = h2;
409 rd.in.offset = ARRAY_SIZE(buf)/2;
410 rd.in.length = ARRAY_SIZE(buf)/2;
412 status = smb2_read(tree, tree, &rd);
413 CHECK_STATUS(status, s->read_h2_status);
415 lck.in.lock_count = 0x0001;
416 lck.in.reserved = 0x00000000;
417 lck.in.file.handle = h1;
418 el[0].offset = ARRAY_SIZE(buf)/2;
419 el[0].length = ARRAY_SIZE(buf)/2;
420 el[0].reserved = 0x00000000;
421 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
422 status = smb2_lock(tree, &lck);
423 CHECK_STATUS(status, NT_STATUS_OK);
424 CHECK_VALUE(lck.out.reserved, 0);
427 wr.in.file.handle = h2;
428 wr.in.offset = ARRAY_SIZE(buf)/2;
429 wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
431 status = smb2_write(tree, &wr);
432 CHECK_STATUS(status, NT_STATUS_OK);
435 rd.in.file.handle = h2;
436 rd.in.offset = ARRAY_SIZE(buf)/2;
437 rd.in.length = ARRAY_SIZE(buf)/2;
439 status = smb2_read(tree, tree, &rd);
440 CHECK_STATUS(status, NT_STATUS_OK);
446 static bool test_lock_rw_none(struct torture_context *torture,
447 struct smb2_tree *tree)
449 struct test_lock_read_write_state s = {
450 .fname = "lock_rw_none.dat",
451 .lock_flags = SMB2_LOCK_FLAG_NONE,
452 .write_h1_status = NT_STATUS_FILE_LOCK_CONFLICT,
453 .read_h1_status = NT_STATUS_OK,
454 .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
455 .read_h2_status = NT_STATUS_OK,
458 if (!TARGET_IS_W2K8(torture)) {
459 torture_skip(torture, "RW-NONE tests the behavior of a "
460 "NONE-type lock, which is the same as a SHARED "
461 "lock but is granted due to a bug in W2K8. If "
462 "target is not W2K8 we skip this test.\n");
465 return test_lock_read_write(torture, tree, &s);
468 static bool test_lock_rw_shared(struct torture_context *torture,
469 struct smb2_tree *tree)
471 struct test_lock_read_write_state s = {
472 .fname = "lock_rw_shared.dat",
473 .lock_flags = SMB2_LOCK_FLAG_SHARED,
474 .write_h1_status = NT_STATUS_FILE_LOCK_CONFLICT,
475 .read_h1_status = NT_STATUS_OK,
476 .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
477 .read_h2_status = NT_STATUS_OK,
480 return test_lock_read_write(torture, tree, &s);
483 static bool test_lock_rw_exclusive(struct torture_context *torture,
484 struct smb2_tree *tree)
486 struct test_lock_read_write_state s = {
487 .fname = "lock_rw_exclusive.dat",
488 .lock_flags = SMB2_LOCK_FLAG_EXCLUSIVE,
489 .write_h1_status = NT_STATUS_OK,
490 .read_h1_status = NT_STATUS_OK,
491 .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
492 .read_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
495 return test_lock_read_write(torture, tree, &s);
498 static bool test_lock_auto_unlock(struct torture_context *torture,
499 struct smb2_tree *tree)
503 struct smb2_handle h;
505 struct smb2_lock lck;
506 struct smb2_lock_element el[2];
510 status = torture_smb2_testfile(tree, "autounlock.txt", &h);
511 CHECK_STATUS(status, NT_STATUS_OK);
513 status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
514 CHECK_STATUS(status, NT_STATUS_OK);
518 lck.in.lock_count = 0x0001;
519 lck.in.file.handle = h;
522 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
523 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
524 status = smb2_lock(tree, &lck);
525 CHECK_STATUS(status, NT_STATUS_OK);
527 status = smb2_lock(tree, &lck);
528 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
530 status = smb2_lock(tree, &lck);
531 if (TARGET_IS_W2K8(torture)) {
532 CHECK_STATUS(status, NT_STATUS_OK);
533 torture_warning(torture, "Target has \"pretty please\" bug. "
534 "Every other contending lock request "
537 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
540 status = smb2_lock(tree, &lck);
541 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
548 /* basic testing of SMB2 locking
550 struct torture_suite *torture_smb2_lock_init(void)
552 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "LOCK");
554 torture_suite_add_1smb2_test(suite, "VALID-REQUEST", test_valid_request);
555 torture_suite_add_1smb2_test(suite, "RW-NONE", test_lock_rw_none);
556 torture_suite_add_1smb2_test(suite, "RW-SHARED", test_lock_rw_shared);
557 torture_suite_add_1smb2_test(suite, "RW-EXCLUSIVE", test_lock_rw_exclusive);
558 torture_suite_add_1smb2_test(suite, "AUTO-UNLOCK", test_lock_auto_unlock);
560 suite->description = talloc_strdup(suite, "SMB2-LOCK tests");