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 if (torture_setting_bool(torture, "windows", false)) {
110 CHECK_STATUS(status, NT_STATUS_OK);
112 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
114 CHECK_VALUE(lck.out.reserved, 0);
116 lck.in.reserved = 0x123ab4;
117 status = smb2_lock(tree, &lck);
118 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
120 lck.in.reserved = 0x123ab5;
121 status = smb2_lock(tree, &lck);
122 if (torture_setting_bool(torture, "windows", false)) {
123 CHECK_STATUS(status, NT_STATUS_OK);
125 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
127 CHECK_VALUE(lck.out.reserved, 0);
129 lck.in.lock_count = 0x0001;
130 lck.in.reserved = 0x12345678;
131 lck.in.file.handle = h;
132 el[0].offset = UINT32_MAX;
133 el[0].length = UINT32_MAX;
134 el[0].reserved = 0x87654321;
135 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
136 status = smb2_lock(tree, &lck);
137 CHECK_STATUS(status, NT_STATUS_OK);
138 CHECK_VALUE(lck.out.reserved, 0);
140 status = smb2_lock(tree, &lck);
141 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
143 status = smb2_lock(tree, &lck);
144 if (torture_setting_bool(torture, "windows", false)) {
145 CHECK_STATUS(status, NT_STATUS_OK);
147 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
149 CHECK_VALUE(lck.out.reserved, 0);
151 status = smb2_lock(tree, &lck);
152 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
154 status = smb2_lock(tree, &lck);
155 if (torture_setting_bool(torture, "windows", false)) {
156 CHECK_STATUS(status, NT_STATUS_OK);
158 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
160 CHECK_VALUE(lck.out.reserved, 0);
162 el[0].flags = 0x00000000;
163 status = smb2_lock(tree, &lck);
164 CHECK_STATUS(status, NT_STATUS_OK);
165 CHECK_VALUE(lck.out.reserved, 0);
167 status = smb2_lock(tree, &lck);
168 CHECK_STATUS(status, NT_STATUS_OK);
169 CHECK_VALUE(lck.out.reserved, 0);
171 el[0].flags = 0x00000001;
172 status = smb2_lock(tree, &lck);
173 CHECK_STATUS(status, NT_STATUS_OK);
174 CHECK_VALUE(lck.out.reserved, 0);
176 status = smb2_lock(tree, &lck);
177 CHECK_STATUS(status, NT_STATUS_OK);
178 CHECK_VALUE(lck.out.reserved, 0);
180 lck.in.lock_count = 0x0001;
181 lck.in.reserved = 0x87654321;
182 lck.in.file.handle = h;
183 el[0].offset = 0x00000000FFFFFFFF;
184 el[0].length = 0x00000000FFFFFFFF;
185 el[0].reserved = 0x1234567;
186 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
187 status = smb2_lock(tree, &lck);
188 CHECK_STATUS(status, NT_STATUS_OK);
190 lck.in.lock_count = 0x0001;
191 lck.in.reserved = 0x1234567;
192 lck.in.file.handle = h;
193 el[0].offset = 0x00000000FFFFFFFF;
194 el[0].length = 0x00000000FFFFFFFF;
195 el[0].reserved = 0x00000000;
196 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
197 status = smb2_lock(tree, &lck);
198 CHECK_STATUS(status, NT_STATUS_OK);
200 status = smb2_lock(tree, &lck);
201 CHECK_STATUS(status, NT_STATUS_OK);
202 status = smb2_lock(tree, &lck);
203 CHECK_STATUS(status, NT_STATUS_OK);
204 status = smb2_lock(tree, &lck);
205 CHECK_STATUS(status, NT_STATUS_OK);
206 status = smb2_lock(tree, &lck);
207 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
209 lck.in.lock_count = 0x0001;
211 lck.in.file.handle = h;
214 el[0].reserved = 0x00000000;
215 el[0].flags = ~SMB2_LOCK_FLAG_ALL_MASK;
217 status = smb2_lock(tree, &lck);
218 CHECK_STATUS(status, NT_STATUS_OK);
220 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
221 status = smb2_lock(tree, &lck);
222 CHECK_STATUS(status, NT_STATUS_OK);
224 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
225 status = smb2_lock(tree, &lck);
226 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
228 el[0].flags = SMB2_LOCK_FLAG_UNLOCK | SMB2_LOCK_FLAG_EXCLUSIVE;
229 status = smb2_lock(tree, &lck);
230 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
232 el[0].flags = SMB2_LOCK_FLAG_UNLOCK | SMB2_LOCK_FLAG_SHARED;
233 status = smb2_lock(tree, &lck);
234 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
236 el[0].flags = SMB2_LOCK_FLAG_UNLOCK | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
237 status = smb2_lock(tree, &lck);
238 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
240 lck.in.lock_count = 2;
242 lck.in.file.handle = h;
245 el[0].reserved = 0x00000000;
248 el[1].reserved = 0x00000000;
250 lck.in.lock_count = 2;
252 el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
253 status = smb2_lock(tree, &lck);
254 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
256 lck.in.lock_count = 2;
259 status = smb2_lock(tree, &lck);
260 CHECK_STATUS(status, NT_STATUS_OK);
262 lck.in.lock_count = 2;
263 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
265 status = smb2_lock(tree, &lck);
266 CHECK_STATUS(status, NT_STATUS_OK);
268 lck.in.lock_count = 1;
269 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
270 status = smb2_lock(tree, &lck);
271 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 if (torture_setting_bool(torture, "windows", false)) {
277 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
279 CHECK_STATUS(status, NT_STATUS_OK);
282 lck.in.lock_count = 1;
283 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
284 status = smb2_lock(tree, &lck);
285 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
287 lck.in.lock_count = 1;
289 status = smb2_lock(tree, &lck);
290 CHECK_STATUS(status, NT_STATUS_OK);
292 status = smb2_lock(tree, &lck);
293 CHECK_STATUS(status, NT_STATUS_OK);
295 lck.in.lock_count = 2;
296 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
297 el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
298 status = smb2_lock(tree, &lck);
299 CHECK_STATUS(status, NT_STATUS_OK);
301 lck.in.lock_count = 1;
302 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
303 status = smb2_lock(tree, &lck);
304 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, struct smb2_tree *tree)
448 struct test_lock_read_write_state s = {
449 .fname = "lock_rw_none.dat",
450 .lock_flags = SMB2_LOCK_FLAG_NONE,
451 .write_h1_status = NT_STATUS_FILE_LOCK_CONFLICT,
452 .read_h1_status = NT_STATUS_OK,
453 .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
454 .read_h2_status = NT_STATUS_OK,
457 return test_lock_read_write(torture, tree, &s);
460 static bool test_lock_rw_shared(struct torture_context *torture, struct smb2_tree *tree)
462 struct test_lock_read_write_state s = {
463 .fname = "lock_rw_shared.dat",
464 .lock_flags = SMB2_LOCK_FLAG_SHARED,
465 .write_h1_status = NT_STATUS_FILE_LOCK_CONFLICT,
466 .read_h1_status = NT_STATUS_OK,
467 .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
468 .read_h2_status = NT_STATUS_OK,
471 return test_lock_read_write(torture, tree, &s);
474 static bool test_lock_rw_exclusiv(struct torture_context *torture, struct smb2_tree *tree)
476 struct test_lock_read_write_state s = {
477 .fname = "lock_rw_exclusiv.dat",
478 .lock_flags = SMB2_LOCK_FLAG_EXCLUSIVE,
479 .write_h1_status = NT_STATUS_OK,
480 .read_h1_status = NT_STATUS_OK,
481 .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
482 .read_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
485 return test_lock_read_write(torture, tree, &s);
489 static bool test_lock_auto_unlock(struct torture_context *torture, struct smb2_tree *tree)
493 struct smb2_handle h;
495 struct smb2_lock lck;
496 struct smb2_lock_element el[2];
500 status = torture_smb2_testfile(tree, "autounlock.txt", &h);
501 CHECK_STATUS(status, NT_STATUS_OK);
503 status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
504 CHECK_STATUS(status, NT_STATUS_OK);
508 lck.in.lock_count = 0x0001;
509 lck.in.file.handle = h;
512 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
513 status = smb2_lock(tree, &lck);
514 CHECK_STATUS(status, NT_STATUS_OK);
516 status = smb2_lock(tree, &lck);
517 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
519 status = smb2_lock(tree, &lck);
520 if (torture_setting_bool(torture, "windows", false)) {
521 CHECK_STATUS(status, NT_STATUS_OK);
523 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
533 /* basic testing of SMB2 locking
535 struct torture_suite *torture_smb2_lock_init(void)
537 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "LOCK");
539 torture_suite_add_1smb2_test(suite, "VALID-REQUEST", test_valid_request);
540 torture_suite_add_1smb2_test(suite, "RW-NONE", test_lock_rw_none);
541 torture_suite_add_1smb2_test(suite, "RW-SHARED", test_lock_rw_shared);
542 torture_suite_add_1smb2_test(suite, "RW-EXCLUSIV", test_lock_rw_exclusiv);
543 torture_suite_add_1smb2_test(suite, "AUTO-UNLOCK", test_lock_auto_unlock);
545 suite->description = talloc_strdup(suite, "SMB2-LOCK tests");