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"
29 #include "librpc/gen_ndr/ndr_security.h"
31 #define CHECK_STATUS(status, correct) do { \
32 if (!NT_STATUS_EQUAL(status, correct)) { \
33 printf("(%s) Incorrect status %s - should be %s\n", \
34 __location__, nt_errstr(status), nt_errstr(correct)); \
39 #define CHECK_VALUE(v, correct) do { \
40 if ((v) != (correct)) { \
41 printf("(%s) Incorrect value %s=%d - should be %d\n", \
42 __location__, #v, v, correct); \
47 static bool test_valid_request(struct torture_context *torture, struct smb2_tree *tree)
54 struct smb2_lock_element el[2];
58 status = torture_smb2_testfile(tree, "lock1.txt", &h);
59 CHECK_STATUS(status, NT_STATUS_OK);
61 status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
62 CHECK_STATUS(status, NT_STATUS_OK);
66 lck.in.lock_count = 0x0000;
67 lck.in.reserved = 0x00000000;
68 lck.in.file.handle = h;
69 el[0].offset = 0x0000000000000000;
70 el[0].length = 0x0000000000000000;
71 el[0].reserved = 0x0000000000000000;
72 el[0].flags = 0x00000000;
73 status = smb2_lock(tree, &lck);
74 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
76 lck.in.lock_count = 0x0001;
77 lck.in.reserved = 0x00000000;
78 lck.in.file.handle = h;
81 el[0].reserved = 0x00000000;
82 el[0].flags = SMB2_LOCK_FLAG_NONE;
83 status = smb2_lock(tree, &lck);
84 CHECK_STATUS(status, NT_STATUS_OK);
85 CHECK_VALUE(lck.out.reserved, 0);
87 lck.in.file.handle.data[0] +=1;
88 status = smb2_lock(tree, &lck);
89 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
90 lck.in.file.handle.data[0] -=1;
92 lck.in.lock_count = 0x0001;
93 lck.in.reserved = 0x123ab1;
94 lck.in.file.handle = h;
95 el[0].offset = UINT64_MAX;
96 el[0].length = UINT64_MAX;
97 el[0].reserved = 0x00000000;
98 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
99 status = smb2_lock(tree, &lck);
100 CHECK_STATUS(status, NT_STATUS_OK);
101 CHECK_VALUE(lck.out.reserved, 0);
103 lck.in.reserved = 0x123ab2;
104 status = smb2_lock(tree, &lck);
105 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
107 lck.in.reserved = 0x123ab3;
108 status = smb2_lock(tree, &lck);
109 CHECK_STATUS(status, NT_STATUS_OK);
110 CHECK_VALUE(lck.out.reserved, 0);
112 lck.in.reserved = 0x123ab4;
113 status = smb2_lock(tree, &lck);
114 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
116 lck.in.reserved = 0x123ab5;
117 status = smb2_lock(tree, &lck);
118 CHECK_STATUS(status, NT_STATUS_OK);
119 CHECK_VALUE(lck.out.reserved, 0);
121 lck.in.lock_count = 0x0001;
122 lck.in.reserved = 0x12345678;
123 lck.in.file.handle = h;
124 el[0].offset = UINT32_MAX;
125 el[0].length = UINT32_MAX;
126 el[0].reserved = 0x87654321;
127 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
128 status = smb2_lock(tree, &lck);
129 CHECK_STATUS(status, NT_STATUS_OK);
130 CHECK_VALUE(lck.out.reserved, 0);
132 status = smb2_lock(tree, &lck);
133 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
135 status = smb2_lock(tree, &lck);
136 CHECK_STATUS(status, NT_STATUS_OK);
137 CHECK_VALUE(lck.out.reserved, 0);
139 status = smb2_lock(tree, &lck);
140 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
142 status = smb2_lock(tree, &lck);
143 CHECK_STATUS(status, NT_STATUS_OK);
144 CHECK_VALUE(lck.out.reserved, 0);
146 el[0].flags = 0x00000000;
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 el[0].flags = 0x00000001;
156 status = smb2_lock(tree, &lck);
157 CHECK_STATUS(status, NT_STATUS_OK);
158 CHECK_VALUE(lck.out.reserved, 0);
160 status = smb2_lock(tree, &lck);
161 CHECK_STATUS(status, NT_STATUS_OK);
162 CHECK_VALUE(lck.out.reserved, 0);
164 lck.in.lock_count = 0x0001;
165 lck.in.reserved = 0x87654321;
166 lck.in.file.handle = h;
167 el[0].offset = 0x00000000FFFFFFFF;
168 el[0].length = 0x00000000FFFFFFFF;
169 el[0].reserved = 0x1234567;
170 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
171 status = smb2_lock(tree, &lck);
172 CHECK_STATUS(status, NT_STATUS_OK);
174 lck.in.lock_count = 0x0001;
175 lck.in.reserved = 0x1234567;
176 lck.in.file.handle = h;
177 el[0].offset = 0x00000000FFFFFFFF;
178 el[0].length = 0x00000000FFFFFFFF;
179 el[0].reserved = 0x00000000;
180 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
181 status = smb2_lock(tree, &lck);
182 CHECK_STATUS(status, NT_STATUS_OK);
184 status = smb2_lock(tree, &lck);
185 CHECK_STATUS(status, NT_STATUS_OK);
186 status = smb2_lock(tree, &lck);
187 CHECK_STATUS(status, NT_STATUS_OK);
188 status = smb2_lock(tree, &lck);
189 CHECK_STATUS(status, NT_STATUS_OK);
190 status = smb2_lock(tree, &lck);
191 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
193 lck.in.lock_count = 0x0001;
195 lck.in.file.handle = h;
198 el[0].reserved = 0x00000000;
199 el[0].flags = ~SMB2_LOCK_FLAG_ALL_MASK;
201 status = smb2_lock(tree, &lck);
202 CHECK_STATUS(status, NT_STATUS_OK);
204 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
205 status = smb2_lock(tree, &lck);
206 CHECK_STATUS(status, NT_STATUS_OK);
208 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
209 status = smb2_lock(tree, &lck);
210 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
212 el[0].flags = SMB2_LOCK_FLAG_UNLOCK | SMB2_LOCK_FLAG_EXCLUSIVE;
213 status = smb2_lock(tree, &lck);
214 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
216 el[0].flags = SMB2_LOCK_FLAG_UNLOCK | SMB2_LOCK_FLAG_SHARED;
217 status = smb2_lock(tree, &lck);
218 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
220 el[0].flags = SMB2_LOCK_FLAG_UNLOCK | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
221 status = smb2_lock(tree, &lck);
222 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
224 lck.in.lock_count = 2;
226 lck.in.file.handle = h;
229 el[0].reserved = 0x00000000;
232 el[1].reserved = 0x00000000;
234 lck.in.lock_count = 2;
236 el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
237 status = smb2_lock(tree, &lck);
238 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
240 lck.in.lock_count = 2;
243 status = smb2_lock(tree, &lck);
244 CHECK_STATUS(status, NT_STATUS_OK);
246 lck.in.lock_count = 2;
247 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
249 status = smb2_lock(tree, &lck);
250 CHECK_STATUS(status, NT_STATUS_OK);
252 lck.in.lock_count = 1;
253 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
254 status = smb2_lock(tree, &lck);
255 if (torture_setting_bool(torture, "windows", false)) {
256 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
258 CHECK_STATUS(status, NT_STATUS_OK);
261 lck.in.lock_count = 1;
262 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
263 status = smb2_lock(tree, &lck);
264 if (torture_setting_bool(torture, "windows", false)) {
265 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
267 CHECK_STATUS(status, NT_STATUS_OK);
270 lck.in.lock_count = 1;
271 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
272 status = smb2_lock(tree, &lck);
273 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
275 lck.in.lock_count = 1;
277 status = smb2_lock(tree, &lck);
278 CHECK_STATUS(status, NT_STATUS_OK);
280 status = smb2_lock(tree, &lck);
281 CHECK_STATUS(status, NT_STATUS_OK);
283 lck.in.lock_count = 2;
284 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
285 el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
286 status = smb2_lock(tree, &lck);
287 CHECK_STATUS(status, NT_STATUS_OK);
289 lck.in.lock_count = 1;
290 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
291 status = smb2_lock(tree, &lck);
292 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
299 struct test_lock_read_write_state {
302 NTSTATUS write_h1_status;
303 NTSTATUS read_h1_status;
304 NTSTATUS write_h2_status;
305 NTSTATUS read_h2_status;
308 static bool test_lock_read_write(struct torture_context *torture,
309 struct smb2_tree *tree,
310 struct test_lock_read_write_state *s)
314 struct smb2_handle h1, h2;
316 struct smb2_lock lck;
317 struct smb2_create cr;
318 struct smb2_write wr;
320 struct smb2_lock_element el[1];
326 status = torture_smb2_testfile(tree, s->fname, &h1);
327 CHECK_STATUS(status, NT_STATUS_OK);
329 status = smb2_util_write(tree, h1, buf, 0, ARRAY_SIZE(buf));
330 CHECK_STATUS(status, NT_STATUS_OK);
332 lck.in.lock_count = 0x0001;
333 lck.in.reserved = 0x00000000;
334 lck.in.file.handle = h1;
336 el[0].length = ARRAY_SIZE(buf)/2;
337 el[0].reserved = 0x00000000;
338 el[0].flags = s->lock_flags;
339 status = smb2_lock(tree, &lck);
340 CHECK_STATUS(status, NT_STATUS_OK);
341 CHECK_VALUE(lck.out.reserved, 0);
343 lck.in.lock_count = 0x0001;
344 lck.in.reserved = 0x00000000;
345 lck.in.file.handle = h1;
346 el[0].offset = ARRAY_SIZE(buf)/2;
347 el[0].length = ARRAY_SIZE(buf)/2;
348 el[0].reserved = 0x00000000;
349 el[0].flags = s->lock_flags;
350 status = smb2_lock(tree, &lck);
351 CHECK_STATUS(status, NT_STATUS_OK);
352 CHECK_VALUE(lck.out.reserved, 0);
355 cr.in.oplock_level = 0;
356 cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
357 cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
358 cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
360 NTCREATEX_SHARE_ACCESS_DELETE|
361 NTCREATEX_SHARE_ACCESS_READ|
362 NTCREATEX_SHARE_ACCESS_WRITE;
363 cr.in.create_options = 0;
364 cr.in.fname = s->fname;
366 status = smb2_create(tree, tree, &cr);
367 CHECK_STATUS(status, NT_STATUS_OK);
369 h2 = cr.out.file.handle;
372 wr.in.file.handle = h1;
373 wr.in.offset = ARRAY_SIZE(buf)/2;
374 wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
376 status = smb2_write(tree, &wr);
377 CHECK_STATUS(status, s->write_h1_status);
380 rd.in.file.handle = h1;
381 rd.in.offset = ARRAY_SIZE(buf)/2;
382 rd.in.length = ARRAY_SIZE(buf)/2;
384 status = smb2_read(tree, tree, &rd);
385 CHECK_STATUS(status, s->read_h1_status);
388 wr.in.file.handle = h2;
389 wr.in.offset = ARRAY_SIZE(buf)/2;
390 wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
392 status = smb2_write(tree, &wr);
393 CHECK_STATUS(status, s->write_h2_status);
396 rd.in.file.handle = h2;
397 rd.in.offset = ARRAY_SIZE(buf)/2;
398 rd.in.length = ARRAY_SIZE(buf)/2;
400 status = smb2_read(tree, tree, &rd);
401 CHECK_STATUS(status, s->read_h2_status);
403 lck.in.lock_count = 0x0001;
404 lck.in.reserved = 0x00000000;
405 lck.in.file.handle = h1;
406 el[0].offset = ARRAY_SIZE(buf)/2;
407 el[0].length = ARRAY_SIZE(buf)/2;
408 el[0].reserved = 0x00000000;
409 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
410 status = smb2_lock(tree, &lck);
411 CHECK_STATUS(status, NT_STATUS_OK);
412 CHECK_VALUE(lck.out.reserved, 0);
415 wr.in.file.handle = h2;
416 wr.in.offset = ARRAY_SIZE(buf)/2;
417 wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
419 status = smb2_write(tree, &wr);
420 CHECK_STATUS(status, NT_STATUS_OK);
423 rd.in.file.handle = h2;
424 rd.in.offset = ARRAY_SIZE(buf)/2;
425 rd.in.length = ARRAY_SIZE(buf)/2;
427 status = smb2_read(tree, tree, &rd);
428 CHECK_STATUS(status, NT_STATUS_OK);
434 static bool test_lock_rw_none(struct torture_context *torture, struct smb2_tree *tree)
436 struct test_lock_read_write_state s = {
437 .fname = "lock_rw_none.dat",
438 .lock_flags = SMB2_LOCK_FLAG_NONE,
439 .write_h1_status = NT_STATUS_FILE_LOCK_CONFLICT,
440 .read_h1_status = NT_STATUS_OK,
441 .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
442 .read_h2_status = NT_STATUS_OK,
445 return test_lock_read_write(torture, tree, &s);
448 static bool test_lock_rw_shared(struct torture_context *torture, struct smb2_tree *tree)
450 struct test_lock_read_write_state s = {
451 .fname = "lock_rw_shared.dat",
452 .lock_flags = SMB2_LOCK_FLAG_SHARED,
453 .write_h1_status = NT_STATUS_FILE_LOCK_CONFLICT,
454 .read_h1_status = NT_STATUS_OK,
455 .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
456 .read_h2_status = NT_STATUS_OK,
459 return test_lock_read_write(torture, tree, &s);
462 static bool test_lock_rw_exclusiv(struct torture_context *torture, struct smb2_tree *tree)
464 struct test_lock_read_write_state s = {
465 .fname = "lock_rw_exclusiv.dat",
466 .lock_flags = SMB2_LOCK_FLAG_EXCLUSIVE,
467 .write_h1_status = NT_STATUS_OK,
468 .read_h1_status = NT_STATUS_OK,
469 .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
470 .read_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
473 return test_lock_read_write(torture, tree, &s);
476 /* basic testing of SMB2 locking
478 struct torture_suite *torture_smb2_lock_init(void)
480 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "LOCK");
482 torture_suite_add_1smb2_test(suite, "VALID-REQUEST", test_valid_request);
483 torture_suite_add_1smb2_test(suite, "RW-NONE", test_lock_rw_none);
484 torture_suite_add_1smb2_test(suite, "RW-SHARED", test_lock_rw_shared);
485 torture_suite_add_1smb2_test(suite, "RW-EXCLUSIV", test_lock_rw_exclusiv);
487 suite->description = talloc_strdup(suite, "SMB2-LOCK tests");