/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- test_valid_request
- test_lock_read_write
- test_lock_rw_none
- test_lock_rw_shared
- test_lock_rw_exclusiv
- test_lock_auto_unlock
- torture_smb2_lock_init
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
26 #include "torture/torture.h"
27 #include "torture/smb2/proto.h"
28
29 #include "librpc/gen_ndr/ndr_security.h"
30
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)); \
35 ret = false; \
36 goto done; \
37 }} while (0)
38
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); \
43 ret = false; \
44 goto done; \
45 }} while (0)
46
47 static bool test_valid_request(struct torture_context *torture, struct smb2_tree *tree)
/* [<][>][^][v][top][bottom][index][help] */
48 {
49 bool ret = true;
50 NTSTATUS status;
51 struct smb2_handle h;
52 uint8_t buf[200];
53 struct smb2_lock lck;
54 struct smb2_lock_element el[2];
55
56 ZERO_STRUCT(buf);
57
58 status = torture_smb2_testfile(tree, "lock1.txt", &h);
59 CHECK_STATUS(status, NT_STATUS_OK);
60
61 status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
62 CHECK_STATUS(status, NT_STATUS_OK);
63
64 lck.in.locks = el;
65
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);
75
76 lck.in.lock_count = 0x0001;
77 lck.in.reserved = 0x00000000;
78 lck.in.file.handle = h;
79 el[0].offset = 0;
80 el[0].length = 0;
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);
86
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;
91
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);
102
103 lck.in.reserved = 0x123ab2;
104 status = smb2_lock(tree, &lck);
105 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
106
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);
111 } else {
112 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
113 }
114 CHECK_VALUE(lck.out.reserved, 0);
115
116 lck.in.reserved = 0x123ab4;
117 status = smb2_lock(tree, &lck);
118 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
119
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);
124 } else {
125 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
126 }
127 CHECK_VALUE(lck.out.reserved, 0);
128
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);
139
140 status = smb2_lock(tree, &lck);
141 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
142
143 status = smb2_lock(tree, &lck);
144 if (torture_setting_bool(torture, "windows", false)) {
145 CHECK_STATUS(status, NT_STATUS_OK);
146 } else {
147 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
148 }
149 CHECK_VALUE(lck.out.reserved, 0);
150
151 status = smb2_lock(tree, &lck);
152 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
153
154 status = smb2_lock(tree, &lck);
155 if (torture_setting_bool(torture, "windows", false)) {
156 CHECK_STATUS(status, NT_STATUS_OK);
157 } else {
158 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
159 }
160 CHECK_VALUE(lck.out.reserved, 0);
161
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);
166
167 status = smb2_lock(tree, &lck);
168 CHECK_STATUS(status, NT_STATUS_OK);
169 CHECK_VALUE(lck.out.reserved, 0);
170
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);
175
176 status = smb2_lock(tree, &lck);
177 CHECK_STATUS(status, NT_STATUS_OK);
178 CHECK_VALUE(lck.out.reserved, 0);
179
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);
189
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);
199
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);
208
209 lck.in.lock_count = 0x0001;
210 lck.in.reserved = 0;
211 lck.in.file.handle = h;
212 el[0].offset = 1;
213 el[0].length = 1;
214 el[0].reserved = 0x00000000;
215 el[0].flags = ~SMB2_LOCK_FLAG_ALL_MASK;
216
217 status = smb2_lock(tree, &lck);
218 CHECK_STATUS(status, NT_STATUS_OK);
219
220 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
221 status = smb2_lock(tree, &lck);
222 CHECK_STATUS(status, NT_STATUS_OK);
223
224 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
225 status = smb2_lock(tree, &lck);
226 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
227
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);
231
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);
235
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);
239
240 lck.in.lock_count = 2;
241 lck.in.reserved = 0;
242 lck.in.file.handle = h;
243 el[0].offset = 9999;
244 el[0].length = 1;
245 el[0].reserved = 0x00000000;
246 el[1].offset = 9999;
247 el[1].length = 1;
248 el[1].reserved = 0x00000000;
249
250 lck.in.lock_count = 2;
251 el[0].flags = 0;
252 el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
253 status = smb2_lock(tree, &lck);
254 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
255
256 lck.in.lock_count = 2;
257 el[0].flags = 0;
258 el[1].flags = 0;
259 status = smb2_lock(tree, &lck);
260 CHECK_STATUS(status, NT_STATUS_OK);
261
262 lck.in.lock_count = 2;
263 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
264 el[1].flags = 0;
265 status = smb2_lock(tree, &lck);
266 CHECK_STATUS(status, NT_STATUS_OK);
267
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);
272
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);
277
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);
282
283 lck.in.lock_count = 1;
284 el[0].flags = 0;
285 status = smb2_lock(tree, &lck);
286 CHECK_STATUS(status, NT_STATUS_OK);
287
288 status = smb2_lock(tree, &lck);
289 CHECK_STATUS(status, NT_STATUS_OK);
290
291 lck.in.lock_count = 2;
292 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
293 el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
294 status = smb2_lock(tree, &lck);
295 CHECK_STATUS(status, NT_STATUS_OK);
296
297 lck.in.lock_count = 1;
298 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
299 status = smb2_lock(tree, &lck);
300 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
301
302
303 done:
304 return ret;
305 }
306
307 struct test_lock_read_write_state {
308 const char *fname;
309 uint32_t lock_flags;
310 NTSTATUS write_h1_status;
311 NTSTATUS read_h1_status;
312 NTSTATUS write_h2_status;
313 NTSTATUS read_h2_status;
314 };
315
316 static bool test_lock_read_write(struct torture_context *torture,
/* [<][>][^][v][top][bottom][index][help] */
317 struct smb2_tree *tree,
318 struct test_lock_read_write_state *s)
319 {
320 bool ret = true;
321 NTSTATUS status;
322 struct smb2_handle h1, h2;
323 uint8_t buf[200];
324 struct smb2_lock lck;
325 struct smb2_create cr;
326 struct smb2_write wr;
327 struct smb2_read rd;
328 struct smb2_lock_element el[1];
329
330 lck.in.locks = el;
331
332 ZERO_STRUCT(buf);
333
334 status = torture_smb2_testfile(tree, s->fname, &h1);
335 CHECK_STATUS(status, NT_STATUS_OK);
336
337 status = smb2_util_write(tree, h1, buf, 0, ARRAY_SIZE(buf));
338 CHECK_STATUS(status, NT_STATUS_OK);
339
340 lck.in.lock_count = 0x0001;
341 lck.in.reserved = 0x00000000;
342 lck.in.file.handle = h1;
343 el[0].offset = 0;
344 el[0].length = ARRAY_SIZE(buf)/2;
345 el[0].reserved = 0x00000000;
346 el[0].flags = s->lock_flags;
347 status = smb2_lock(tree, &lck);
348 CHECK_STATUS(status, NT_STATUS_OK);
349 CHECK_VALUE(lck.out.reserved, 0);
350
351 lck.in.lock_count = 0x0001;
352 lck.in.reserved = 0x00000000;
353 lck.in.file.handle = h1;
354 el[0].offset = ARRAY_SIZE(buf)/2;
355 el[0].length = ARRAY_SIZE(buf)/2;
356 el[0].reserved = 0x00000000;
357 el[0].flags = s->lock_flags;
358 status = smb2_lock(tree, &lck);
359 CHECK_STATUS(status, NT_STATUS_OK);
360 CHECK_VALUE(lck.out.reserved, 0);
361
362 ZERO_STRUCT(cr);
363 cr.in.oplock_level = 0;
364 cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
365 cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
366 cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
367 cr.in.share_access =
368 NTCREATEX_SHARE_ACCESS_DELETE|
369 NTCREATEX_SHARE_ACCESS_READ|
370 NTCREATEX_SHARE_ACCESS_WRITE;
371 cr.in.create_options = 0;
372 cr.in.fname = s->fname;
373
374 status = smb2_create(tree, tree, &cr);
375 CHECK_STATUS(status, NT_STATUS_OK);
376
377 h2 = cr.out.file.handle;
378
379 ZERO_STRUCT(wr);
380 wr.in.file.handle = h1;
381 wr.in.offset = ARRAY_SIZE(buf)/2;
382 wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
383
384 status = smb2_write(tree, &wr);
385 CHECK_STATUS(status, s->write_h1_status);
386
387 ZERO_STRUCT(rd);
388 rd.in.file.handle = h1;
389 rd.in.offset = ARRAY_SIZE(buf)/2;
390 rd.in.length = ARRAY_SIZE(buf)/2;
391
392 status = smb2_read(tree, tree, &rd);
393 CHECK_STATUS(status, s->read_h1_status);
394
395 ZERO_STRUCT(wr);
396 wr.in.file.handle = h2;
397 wr.in.offset = ARRAY_SIZE(buf)/2;
398 wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
399
400 status = smb2_write(tree, &wr);
401 CHECK_STATUS(status, s->write_h2_status);
402
403 ZERO_STRUCT(rd);
404 rd.in.file.handle = h2;
405 rd.in.offset = ARRAY_SIZE(buf)/2;
406 rd.in.length = ARRAY_SIZE(buf)/2;
407
408 status = smb2_read(tree, tree, &rd);
409 CHECK_STATUS(status, s->read_h2_status);
410
411 lck.in.lock_count = 0x0001;
412 lck.in.reserved = 0x00000000;
413 lck.in.file.handle = h1;
414 el[0].offset = ARRAY_SIZE(buf)/2;
415 el[0].length = ARRAY_SIZE(buf)/2;
416 el[0].reserved = 0x00000000;
417 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
418 status = smb2_lock(tree, &lck);
419 CHECK_STATUS(status, NT_STATUS_OK);
420 CHECK_VALUE(lck.out.reserved, 0);
421
422 ZERO_STRUCT(wr);
423 wr.in.file.handle = h2;
424 wr.in.offset = ARRAY_SIZE(buf)/2;
425 wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
426
427 status = smb2_write(tree, &wr);
428 CHECK_STATUS(status, NT_STATUS_OK);
429
430 ZERO_STRUCT(rd);
431 rd.in.file.handle = h2;
432 rd.in.offset = ARRAY_SIZE(buf)/2;
433 rd.in.length = ARRAY_SIZE(buf)/2;
434
435 status = smb2_read(tree, tree, &rd);
436 CHECK_STATUS(status, NT_STATUS_OK);
437
438 done:
439 return ret;
440 }
441
442 static bool test_lock_rw_none(struct torture_context *torture, struct smb2_tree *tree)
/* [<][>][^][v][top][bottom][index][help] */
443 {
444 struct test_lock_read_write_state s = {
445 .fname = "lock_rw_none.dat",
446 .lock_flags = SMB2_LOCK_FLAG_NONE,
447 .write_h1_status = NT_STATUS_FILE_LOCK_CONFLICT,
448 .read_h1_status = NT_STATUS_OK,
449 .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
450 .read_h2_status = NT_STATUS_OK,
451 };
452
453 return test_lock_read_write(torture, tree, &s);
454 }
455
456 static bool test_lock_rw_shared(struct torture_context *torture, struct smb2_tree *tree)
/* [<][>][^][v][top][bottom][index][help] */
457 {
458 struct test_lock_read_write_state s = {
459 .fname = "lock_rw_shared.dat",
460 .lock_flags = SMB2_LOCK_FLAG_SHARED,
461 .write_h1_status = NT_STATUS_FILE_LOCK_CONFLICT,
462 .read_h1_status = NT_STATUS_OK,
463 .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
464 .read_h2_status = NT_STATUS_OK,
465 };
466
467 return test_lock_read_write(torture, tree, &s);
468 }
469
470 static bool test_lock_rw_exclusiv(struct torture_context *torture, struct smb2_tree *tree)
/* [<][>][^][v][top][bottom][index][help] */
471 {
472 struct test_lock_read_write_state s = {
473 .fname = "lock_rw_exclusiv.dat",
474 .lock_flags = SMB2_LOCK_FLAG_EXCLUSIVE,
475 .write_h1_status = NT_STATUS_OK,
476 .read_h1_status = NT_STATUS_OK,
477 .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
478 .read_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
479 };
480
481 return test_lock_read_write(torture, tree, &s);
482 }
483
484
485 static bool test_lock_auto_unlock(struct torture_context *torture, struct smb2_tree *tree)
/* [<][>][^][v][top][bottom][index][help] */
486 {
487 bool ret = true;
488 NTSTATUS status;
489 struct smb2_handle h;
490 uint8_t buf[200];
491 struct smb2_lock lck;
492 struct smb2_lock_element el[2];
493
494 ZERO_STRUCT(buf);
495
496 status = torture_smb2_testfile(tree, "autounlock.txt", &h);
497 CHECK_STATUS(status, NT_STATUS_OK);
498
499 status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
500 CHECK_STATUS(status, NT_STATUS_OK);
501
502 ZERO_STRUCT(lck);
503 lck.in.locks = el;
504 lck.in.lock_count = 0x0001;
505 lck.in.file.handle = h;
506 el[0].offset = 0;
507 el[0].length = 1;
508 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
509 status = smb2_lock(tree, &lck);
510 CHECK_STATUS(status, NT_STATUS_OK);
511
512 status = smb2_lock(tree, &lck);
513 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
514
515 status = smb2_lock(tree, &lck);
516 if (torture_setting_bool(torture, "windows", false)) {
517 CHECK_STATUS(status, NT_STATUS_OK);
518 } else {
519 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
520 }
521
522
523
524 done:
525 return ret;
526 }
527
528
529 /* basic testing of SMB2 locking
530 */
531 struct torture_suite *torture_smb2_lock_init(void)
/* [<][>][^][v][top][bottom][index][help] */
532 {
533 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "LOCK");
534
535 torture_suite_add_1smb2_test(suite, "VALID-REQUEST", test_valid_request);
536 torture_suite_add_1smb2_test(suite, "RW-NONE", test_lock_rw_none);
537 torture_suite_add_1smb2_test(suite, "RW-SHARED", test_lock_rw_shared);
538 torture_suite_add_1smb2_test(suite, "RW-EXCLUSIV", test_lock_rw_exclusiv);
539 torture_suite_add_1smb2_test(suite, "AUTO-UNLOCK", test_lock_auto_unlock);
540
541 suite->description = talloc_strdup(suite, "SMB2-LOCK tests");
542
543 return suite;
544 }
545