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_IS_WINDOWS(_tctx) (torture_setting_bool(_tctx, "win7", false) || torture_setting_bool(torture, "windows", false))
31 #define TARGET_IS_WIN7(_tctx) (torture_setting_bool(_tctx, "win7", false))
33 #define CHECK_STATUS(status, correct) do { \
34 if (!NT_STATUS_EQUAL(status, correct)) { \
35 printf("(%s) Incorrect status %s - should be %s\n", \
36 __location__, nt_errstr(status), nt_errstr(correct)); \
41 #define CHECK_VALUE(v, correct) do { \
42 if ((v) != (correct)) { \
43 printf("(%s) Incorrect value %s=%d - should be %d\n", \
44 __location__, #v, v, correct); \
49 static bool test_valid_request(struct torture_context
*torture
, struct smb2_tree
*tree
)
56 struct smb2_lock_element el
[2];
60 status
= torture_smb2_testfile(tree
, "lock1.txt", &h
);
61 CHECK_STATUS(status
, NT_STATUS_OK
);
63 status
= smb2_util_write(tree
, h
, buf
, 0, ARRAY_SIZE(buf
));
64 CHECK_STATUS(status
, NT_STATUS_OK
);
68 lck
.in
.lock_count
= 0x0000;
69 lck
.in
.reserved
= 0x00000000;
70 lck
.in
.file
.handle
= h
;
71 el
[0].offset
= 0x0000000000000000;
72 el
[0].length
= 0x0000000000000000;
73 el
[0].reserved
= 0x0000000000000000;
74 el
[0].flags
= 0x00000000;
75 status
= smb2_lock(tree
, &lck
);
76 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
78 lck
.in
.lock_count
= 0x0001;
79 lck
.in
.reserved
= 0x00000000;
80 lck
.in
.file
.handle
= h
;
83 el
[0].reserved
= 0x00000000;
84 el
[0].flags
= SMB2_LOCK_FLAG_NONE
;
85 status
= smb2_lock(tree
, &lck
);
86 CHECK_STATUS(status
, NT_STATUS_OK
);
87 CHECK_VALUE(lck
.out
.reserved
, 0);
89 lck
.in
.file
.handle
.data
[0] +=1;
90 status
= smb2_lock(tree
, &lck
);
91 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
92 lck
.in
.file
.handle
.data
[0] -=1;
94 lck
.in
.lock_count
= 0x0001;
95 lck
.in
.reserved
= 0x123ab1;
96 lck
.in
.file
.handle
= h
;
97 el
[0].offset
= UINT64_MAX
;
98 el
[0].length
= UINT64_MAX
;
99 el
[0].reserved
= 0x00000000;
100 el
[0].flags
= SMB2_LOCK_FLAG_EXCLUSIVE
|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
;
101 status
= smb2_lock(tree
, &lck
);
102 if (TARGET_IS_WIN7(torture
)) {
103 CHECK_STATUS(status
, NT_STATUS_INVALID_LOCK_RANGE
);
105 CHECK_STATUS(status
, NT_STATUS_OK
);
107 CHECK_VALUE(lck
.out
.reserved
, 0);
109 lck
.in
.reserved
= 0x123ab2;
110 status
= smb2_lock(tree
, &lck
);
111 if (TARGET_IS_WIN7(torture
)) {
112 CHECK_STATUS(status
, NT_STATUS_INVALID_LOCK_RANGE
);
113 } else if (TARGET_IS_WINDOWS(torture
)) {
114 CHECK_STATUS(status
, NT_STATUS_OK
);
116 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
118 CHECK_VALUE(lck
.out
.reserved
, 0);
120 lck
.in
.reserved
= 0x123ab3;
121 status
= smb2_lock(tree
, &lck
);
122 if (TARGET_IS_WIN7(torture
)) {
123 CHECK_STATUS(status
, NT_STATUS_INVALID_LOCK_RANGE
);
124 } else if (TARGET_IS_WINDOWS(torture
)) {
125 CHECK_STATUS(status
, NT_STATUS_OK
);
127 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
129 CHECK_VALUE(lck
.out
.reserved
, 0);
131 lck
.in
.reserved
= 0x123ab4;
132 status
= smb2_lock(tree
, &lck
);
133 if (TARGET_IS_WIN7(torture
)) {
134 CHECK_STATUS(status
, NT_STATUS_INVALID_LOCK_RANGE
);
135 } else if (TARGET_IS_WINDOWS(torture
)) {
136 CHECK_STATUS(status
, NT_STATUS_OK
);
138 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
140 CHECK_VALUE(lck
.out
.reserved
, 0);
142 lck
.in
.reserved
= 0x123ab5;
143 status
= smb2_lock(tree
, &lck
);
144 if (TARGET_IS_WIN7(torture
)) {
145 CHECK_STATUS(status
, NT_STATUS_INVALID_LOCK_RANGE
);
146 } else if (TARGET_IS_WINDOWS(torture
)) {
147 CHECK_STATUS(status
, NT_STATUS_OK
);
149 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
151 CHECK_VALUE(lck
.out
.reserved
, 0);
153 lck
.in
.lock_count
= 0x0001;
154 lck
.in
.reserved
= 0x12345678;
155 lck
.in
.file
.handle
= h
;
156 el
[0].offset
= UINT32_MAX
;
157 el
[0].length
= UINT32_MAX
;
158 el
[0].reserved
= 0x87654321;
159 el
[0].flags
= SMB2_LOCK_FLAG_EXCLUSIVE
|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
;
160 status
= smb2_lock(tree
, &lck
);
161 CHECK_STATUS(status
, NT_STATUS_OK
);
162 CHECK_VALUE(lck
.out
.reserved
, 0);
164 status
= smb2_lock(tree
, &lck
);
165 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
167 status
= smb2_lock(tree
, &lck
);
168 if (TARGET_IS_WINDOWS(torture
)) {
169 CHECK_STATUS(status
, NT_STATUS_OK
);
171 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
173 CHECK_VALUE(lck
.out
.reserved
, 0);
175 status
= smb2_lock(tree
, &lck
);
176 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
178 status
= smb2_lock(tree
, &lck
);
179 if (TARGET_IS_WINDOWS(torture
)) {
180 CHECK_STATUS(status
, NT_STATUS_OK
);
182 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
184 CHECK_VALUE(lck
.out
.reserved
, 0);
186 el
[0].flags
= 0x00000000;
187 status
= smb2_lock(tree
, &lck
);
188 CHECK_STATUS(status
, NT_STATUS_OK
);
189 CHECK_VALUE(lck
.out
.reserved
, 0);
191 status
= smb2_lock(tree
, &lck
);
192 CHECK_STATUS(status
, NT_STATUS_OK
);
193 CHECK_VALUE(lck
.out
.reserved
, 0);
195 el
[0].flags
= 0x00000001;
196 status
= smb2_lock(tree
, &lck
);
197 CHECK_STATUS(status
, NT_STATUS_OK
);
198 CHECK_VALUE(lck
.out
.reserved
, 0);
200 status
= smb2_lock(tree
, &lck
);
201 CHECK_STATUS(status
, NT_STATUS_OK
);
202 CHECK_VALUE(lck
.out
.reserved
, 0);
204 lck
.in
.lock_count
= 0x0001;
205 lck
.in
.reserved
= 0x87654321;
206 lck
.in
.file
.handle
= h
;
207 el
[0].offset
= 0x00000000FFFFFFFF;
208 el
[0].length
= 0x00000000FFFFFFFF;
209 el
[0].reserved
= 0x1234567;
210 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
211 status
= smb2_lock(tree
, &lck
);
212 CHECK_STATUS(status
, NT_STATUS_OK
);
214 lck
.in
.lock_count
= 0x0001;
215 lck
.in
.reserved
= 0x1234567;
216 lck
.in
.file
.handle
= h
;
217 el
[0].offset
= 0x00000000FFFFFFFF;
218 el
[0].length
= 0x00000000FFFFFFFF;
219 el
[0].reserved
= 0x00000000;
220 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
221 status
= smb2_lock(tree
, &lck
);
222 CHECK_STATUS(status
, NT_STATUS_OK
);
224 status
= smb2_lock(tree
, &lck
);
225 CHECK_STATUS(status
, NT_STATUS_OK
);
226 status
= smb2_lock(tree
, &lck
);
227 CHECK_STATUS(status
, NT_STATUS_OK
);
228 status
= smb2_lock(tree
, &lck
);
229 CHECK_STATUS(status
, NT_STATUS_OK
);
230 status
= smb2_lock(tree
, &lck
);
231 CHECK_STATUS(status
, NT_STATUS_RANGE_NOT_LOCKED
);
233 lck
.in
.lock_count
= 0x0001;
235 lck
.in
.file
.handle
= h
;
238 el
[0].reserved
= 0x00000000;
239 el
[0].flags
= ~SMB2_LOCK_FLAG_ALL_MASK
;
241 status
= smb2_lock(tree
, &lck
);
242 CHECK_STATUS(status
, NT_STATUS_OK
);
244 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
245 status
= smb2_lock(tree
, &lck
);
246 CHECK_STATUS(status
, NT_STATUS_OK
);
248 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
249 status
= smb2_lock(tree
, &lck
);
250 CHECK_STATUS(status
, NT_STATUS_RANGE_NOT_LOCKED
);
252 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
| SMB2_LOCK_FLAG_EXCLUSIVE
;
253 status
= smb2_lock(tree
, &lck
);
254 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
256 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
| SMB2_LOCK_FLAG_SHARED
;
257 status
= smb2_lock(tree
, &lck
);
258 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
260 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
| SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
;
261 status
= smb2_lock(tree
, &lck
);
262 CHECK_STATUS(status
, NT_STATUS_RANGE_NOT_LOCKED
);
264 lck
.in
.lock_count
= 2;
266 lck
.in
.file
.handle
= h
;
269 el
[0].reserved
= 0x00000000;
272 el
[1].reserved
= 0x00000000;
274 lck
.in
.lock_count
= 2;
276 el
[1].flags
= SMB2_LOCK_FLAG_UNLOCK
;
277 status
= smb2_lock(tree
, &lck
);
278 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
280 lck
.in
.lock_count
= 2;
283 status
= smb2_lock(tree
, &lck
);
284 CHECK_STATUS(status
, NT_STATUS_OK
);
286 lck
.in
.lock_count
= 2;
287 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
289 status
= smb2_lock(tree
, &lck
);
290 CHECK_STATUS(status
, NT_STATUS_OK
);
292 lck
.in
.lock_count
= 1;
293 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
294 status
= smb2_lock(tree
, &lck
);
295 CHECK_STATUS(status
, NT_STATUS_RANGE_NOT_LOCKED
);
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
);
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
);
307 lck
.in
.lock_count
= 1;
309 status
= smb2_lock(tree
, &lck
);
310 CHECK_STATUS(status
, NT_STATUS_OK
);
312 status
= smb2_lock(tree
, &lck
);
313 CHECK_STATUS(status
, NT_STATUS_OK
);
315 lck
.in
.lock_count
= 2;
316 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
317 el
[1].flags
= SMB2_LOCK_FLAG_UNLOCK
;
318 status
= smb2_lock(tree
, &lck
);
319 CHECK_STATUS(status
, NT_STATUS_OK
);
321 lck
.in
.lock_count
= 1;
322 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
323 status
= smb2_lock(tree
, &lck
);
324 CHECK_STATUS(status
, NT_STATUS_RANGE_NOT_LOCKED
);
331 struct test_lock_read_write_state
{
334 NTSTATUS write_h1_status
;
335 NTSTATUS read_h1_status
;
336 NTSTATUS write_h2_status
;
337 NTSTATUS read_h2_status
;
340 static bool test_lock_read_write(struct torture_context
*torture
,
341 struct smb2_tree
*tree
,
342 struct test_lock_read_write_state
*s
)
346 struct smb2_handle h1
, h2
;
348 struct smb2_lock lck
;
349 struct smb2_create cr
;
350 struct smb2_write wr
;
352 struct smb2_lock_element el
[1];
358 status
= torture_smb2_testfile(tree
, s
->fname
, &h1
);
359 CHECK_STATUS(status
, NT_STATUS_OK
);
361 status
= smb2_util_write(tree
, h1
, buf
, 0, ARRAY_SIZE(buf
));
362 CHECK_STATUS(status
, NT_STATUS_OK
);
364 lck
.in
.lock_count
= 0x0001;
365 lck
.in
.reserved
= 0x00000000;
366 lck
.in
.file
.handle
= h1
;
368 el
[0].length
= ARRAY_SIZE(buf
)/2;
369 el
[0].reserved
= 0x00000000;
370 el
[0].flags
= s
->lock_flags
;
371 status
= smb2_lock(tree
, &lck
);
372 CHECK_STATUS(status
, NT_STATUS_OK
);
373 CHECK_VALUE(lck
.out
.reserved
, 0);
375 lck
.in
.lock_count
= 0x0001;
376 lck
.in
.reserved
= 0x00000000;
377 lck
.in
.file
.handle
= h1
;
378 el
[0].offset
= ARRAY_SIZE(buf
)/2;
379 el
[0].length
= ARRAY_SIZE(buf
)/2;
380 el
[0].reserved
= 0x00000000;
381 el
[0].flags
= s
->lock_flags
;
382 status
= smb2_lock(tree
, &lck
);
383 CHECK_STATUS(status
, NT_STATUS_OK
);
384 CHECK_VALUE(lck
.out
.reserved
, 0);
387 cr
.in
.oplock_level
= 0;
388 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
389 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
390 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
392 NTCREATEX_SHARE_ACCESS_DELETE
|
393 NTCREATEX_SHARE_ACCESS_READ
|
394 NTCREATEX_SHARE_ACCESS_WRITE
;
395 cr
.in
.create_options
= 0;
396 cr
.in
.fname
= s
->fname
;
398 status
= smb2_create(tree
, tree
, &cr
);
399 CHECK_STATUS(status
, NT_STATUS_OK
);
401 h2
= cr
.out
.file
.handle
;
404 wr
.in
.file
.handle
= h1
;
405 wr
.in
.offset
= ARRAY_SIZE(buf
)/2;
406 wr
.in
.data
= data_blob_const(buf
, ARRAY_SIZE(buf
)/2);
408 status
= smb2_write(tree
, &wr
);
409 CHECK_STATUS(status
, s
->write_h1_status
);
412 rd
.in
.file
.handle
= h1
;
413 rd
.in
.offset
= ARRAY_SIZE(buf
)/2;
414 rd
.in
.length
= ARRAY_SIZE(buf
)/2;
416 status
= smb2_read(tree
, tree
, &rd
);
417 CHECK_STATUS(status
, s
->read_h1_status
);
420 wr
.in
.file
.handle
= h2
;
421 wr
.in
.offset
= ARRAY_SIZE(buf
)/2;
422 wr
.in
.data
= data_blob_const(buf
, ARRAY_SIZE(buf
)/2);
424 status
= smb2_write(tree
, &wr
);
425 CHECK_STATUS(status
, s
->write_h2_status
);
428 rd
.in
.file
.handle
= h2
;
429 rd
.in
.offset
= ARRAY_SIZE(buf
)/2;
430 rd
.in
.length
= ARRAY_SIZE(buf
)/2;
432 status
= smb2_read(tree
, tree
, &rd
);
433 CHECK_STATUS(status
, s
->read_h2_status
);
435 lck
.in
.lock_count
= 0x0001;
436 lck
.in
.reserved
= 0x00000000;
437 lck
.in
.file
.handle
= h1
;
438 el
[0].offset
= ARRAY_SIZE(buf
)/2;
439 el
[0].length
= ARRAY_SIZE(buf
)/2;
440 el
[0].reserved
= 0x00000000;
441 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
442 status
= smb2_lock(tree
, &lck
);
443 CHECK_STATUS(status
, NT_STATUS_OK
);
444 CHECK_VALUE(lck
.out
.reserved
, 0);
447 wr
.in
.file
.handle
= h2
;
448 wr
.in
.offset
= ARRAY_SIZE(buf
)/2;
449 wr
.in
.data
= data_blob_const(buf
, ARRAY_SIZE(buf
)/2);
451 status
= smb2_write(tree
, &wr
);
452 CHECK_STATUS(status
, NT_STATUS_OK
);
455 rd
.in
.file
.handle
= h2
;
456 rd
.in
.offset
= ARRAY_SIZE(buf
)/2;
457 rd
.in
.length
= ARRAY_SIZE(buf
)/2;
459 status
= smb2_read(tree
, tree
, &rd
);
460 CHECK_STATUS(status
, NT_STATUS_OK
);
466 static bool test_lock_rw_none(struct torture_context
*torture
, struct smb2_tree
*tree
)
468 struct test_lock_read_write_state s
= {
469 .fname
= "lock_rw_none.dat",
470 .lock_flags
= SMB2_LOCK_FLAG_NONE
,
471 .write_h1_status
= NT_STATUS_FILE_LOCK_CONFLICT
,
472 .read_h1_status
= NT_STATUS_OK
,
473 .write_h2_status
= NT_STATUS_FILE_LOCK_CONFLICT
,
474 .read_h2_status
= NT_STATUS_OK
,
477 return test_lock_read_write(torture
, tree
, &s
);
480 static bool test_lock_rw_shared(struct torture_context
*torture
, struct smb2_tree
*tree
)
482 struct test_lock_read_write_state s
= {
483 .fname
= "lock_rw_shared.dat",
484 .lock_flags
= SMB2_LOCK_FLAG_SHARED
,
485 .write_h1_status
= NT_STATUS_FILE_LOCK_CONFLICT
,
486 .read_h1_status
= NT_STATUS_OK
,
487 .write_h2_status
= NT_STATUS_FILE_LOCK_CONFLICT
,
488 .read_h2_status
= NT_STATUS_OK
,
491 return test_lock_read_write(torture
, tree
, &s
);
494 static bool test_lock_rw_exclusiv(struct torture_context
*torture
, struct smb2_tree
*tree
)
496 struct test_lock_read_write_state s
= {
497 .fname
= "lock_rw_exclusiv.dat",
498 .lock_flags
= SMB2_LOCK_FLAG_EXCLUSIVE
,
499 .write_h1_status
= NT_STATUS_OK
,
500 .read_h1_status
= NT_STATUS_OK
,
501 .write_h2_status
= NT_STATUS_FILE_LOCK_CONFLICT
,
502 .read_h2_status
= NT_STATUS_FILE_LOCK_CONFLICT
,
505 return test_lock_read_write(torture
, tree
, &s
);
508 static bool test_lock_auto_unlock(struct torture_context
*torture
, struct smb2_tree
*tree
)
512 struct smb2_handle h
;
514 struct smb2_lock lck
;
515 struct smb2_lock_element el
[2];
519 status
= torture_smb2_testfile(tree
, "autounlock.txt", &h
);
520 CHECK_STATUS(status
, NT_STATUS_OK
);
522 status
= smb2_util_write(tree
, h
, buf
, 0, ARRAY_SIZE(buf
));
523 CHECK_STATUS(status
, NT_STATUS_OK
);
527 lck
.in
.lock_count
= 0x0001;
528 lck
.in
.file
.handle
= h
;
531 el
[0].flags
= SMB2_LOCK_FLAG_EXCLUSIVE
| SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
;
532 status
= smb2_lock(tree
, &lck
);
533 CHECK_STATUS(status
, NT_STATUS_OK
);
535 status
= smb2_lock(tree
, &lck
);
536 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
538 status
= smb2_lock(tree
, &lck
);
539 if (TARGET_IS_WINDOWS(torture
)) {
540 CHECK_STATUS(status
, NT_STATUS_OK
);
542 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
545 status
= smb2_lock(tree
, &lck
);
546 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
553 /* basic testing of SMB2 locking
555 struct torture_suite
*torture_smb2_lock_init(void)
557 struct torture_suite
*suite
= torture_suite_create(talloc_autofree_context(), "LOCK");
559 torture_suite_add_1smb2_test(suite
, "VALID-REQUEST", test_valid_request
);
560 torture_suite_add_1smb2_test(suite
, "RW-NONE", test_lock_rw_none
);
561 torture_suite_add_1smb2_test(suite
, "RW-SHARED", test_lock_rw_shared
);
562 torture_suite_add_1smb2_test(suite
, "RW-EXCLUSIV", test_lock_rw_exclusiv
);
563 torture_suite_add_1smb2_test(suite
, "AUTO-UNLOCK", test_lock_auto_unlock
);
565 suite
->description
= talloc_strdup(suite
, "SMB2-LOCK tests");