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 TARGET_IS_WINDOWS(_tctx) (torture_setting_bool(_tctx, "win7", false) || torture_setting_bool(torture, "windows", false))
32 #define TARGET_IS_WIN7(_tctx) (torture_setting_bool(_tctx, "win7", false))
34 #define CHECK_STATUS(status, correct) do { \
35 if (!NT_STATUS_EQUAL(status, correct)) { \
36 printf("(%s) Incorrect status %s - should be %s\n", \
37 __location__, nt_errstr(status), nt_errstr(correct)); \
42 #define CHECK_VALUE(v, correct) do { \
43 if ((v) != (correct)) { \
44 printf("(%s) Incorrect value %s=%d - should be %d\n", \
45 __location__, #v, v, correct); \
50 static bool test_valid_request(struct torture_context
*torture
, struct smb2_tree
*tree
)
57 struct smb2_lock_element el
[2];
61 status
= torture_smb2_testfile(tree
, "lock1.txt", &h
);
62 CHECK_STATUS(status
, NT_STATUS_OK
);
64 status
= smb2_util_write(tree
, h
, buf
, 0, ARRAY_SIZE(buf
));
65 CHECK_STATUS(status
, NT_STATUS_OK
);
69 lck
.in
.lock_count
= 0x0000;
70 lck
.in
.reserved
= 0x00000000;
71 lck
.in
.file
.handle
= h
;
72 el
[0].offset
= 0x0000000000000000;
73 el
[0].length
= 0x0000000000000000;
74 el
[0].reserved
= 0x0000000000000000;
75 el
[0].flags
= 0x00000000;
76 status
= smb2_lock(tree
, &lck
);
77 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
79 lck
.in
.lock_count
= 0x0001;
80 lck
.in
.reserved
= 0x00000000;
81 lck
.in
.file
.handle
= h
;
84 el
[0].reserved
= 0x00000000;
85 el
[0].flags
= SMB2_LOCK_FLAG_NONE
;
86 status
= smb2_lock(tree
, &lck
);
87 CHECK_STATUS(status
, NT_STATUS_OK
);
88 CHECK_VALUE(lck
.out
.reserved
, 0);
90 lck
.in
.file
.handle
.data
[0] +=1;
91 status
= smb2_lock(tree
, &lck
);
92 CHECK_STATUS(status
, NT_STATUS_FILE_CLOSED
);
93 lck
.in
.file
.handle
.data
[0] -=1;
95 lck
.in
.lock_count
= 0x0001;
96 lck
.in
.reserved
= 0x123ab1;
97 lck
.in
.file
.handle
= h
;
98 el
[0].offset
= UINT64_MAX
;
99 el
[0].length
= UINT64_MAX
;
100 el
[0].reserved
= 0x00000000;
101 el
[0].flags
= SMB2_LOCK_FLAG_EXCLUSIVE
|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
;
102 status
= smb2_lock(tree
, &lck
);
103 if (TARGET_IS_WIN7(torture
)) {
104 CHECK_STATUS(status
, NT_STATUS_INVALID_LOCK_RANGE
);
106 CHECK_STATUS(status
, NT_STATUS_OK
);
108 CHECK_VALUE(lck
.out
.reserved
, 0);
110 lck
.in
.reserved
= 0x123ab2;
111 status
= smb2_lock(tree
, &lck
);
112 if (TARGET_IS_WIN7(torture
)) {
113 CHECK_STATUS(status
, NT_STATUS_INVALID_LOCK_RANGE
);
114 } else if (TARGET_IS_WINDOWS(torture
)) {
115 CHECK_STATUS(status
, NT_STATUS_OK
);
117 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
119 CHECK_VALUE(lck
.out
.reserved
, 0);
121 lck
.in
.reserved
= 0x123ab3;
122 status
= smb2_lock(tree
, &lck
);
123 if (TARGET_IS_WIN7(torture
)) {
124 CHECK_STATUS(status
, NT_STATUS_INVALID_LOCK_RANGE
);
125 } else if (TARGET_IS_WINDOWS(torture
)) {
126 CHECK_STATUS(status
, NT_STATUS_OK
);
128 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
130 CHECK_VALUE(lck
.out
.reserved
, 0);
132 lck
.in
.reserved
= 0x123ab4;
133 status
= smb2_lock(tree
, &lck
);
134 if (TARGET_IS_WIN7(torture
)) {
135 CHECK_STATUS(status
, NT_STATUS_INVALID_LOCK_RANGE
);
136 } else if (TARGET_IS_WINDOWS(torture
)) {
137 CHECK_STATUS(status
, NT_STATUS_OK
);
139 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
141 CHECK_VALUE(lck
.out
.reserved
, 0);
143 lck
.in
.reserved
= 0x123ab5;
144 status
= smb2_lock(tree
, &lck
);
145 if (TARGET_IS_WIN7(torture
)) {
146 CHECK_STATUS(status
, NT_STATUS_INVALID_LOCK_RANGE
);
147 } else if (TARGET_IS_WINDOWS(torture
)) {
148 CHECK_STATUS(status
, NT_STATUS_OK
);
150 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
152 CHECK_VALUE(lck
.out
.reserved
, 0);
154 lck
.in
.lock_count
= 0x0001;
155 lck
.in
.reserved
= 0x12345678;
156 lck
.in
.file
.handle
= h
;
157 el
[0].offset
= UINT32_MAX
;
158 el
[0].length
= UINT32_MAX
;
159 el
[0].reserved
= 0x87654321;
160 el
[0].flags
= SMB2_LOCK_FLAG_EXCLUSIVE
|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
;
161 status
= smb2_lock(tree
, &lck
);
162 CHECK_STATUS(status
, NT_STATUS_OK
);
163 CHECK_VALUE(lck
.out
.reserved
, 0);
165 status
= smb2_lock(tree
, &lck
);
166 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
168 status
= smb2_lock(tree
, &lck
);
169 if (TARGET_IS_WINDOWS(torture
)) {
170 CHECK_STATUS(status
, NT_STATUS_OK
);
172 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
174 CHECK_VALUE(lck
.out
.reserved
, 0);
176 status
= smb2_lock(tree
, &lck
);
177 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
179 status
= smb2_lock(tree
, &lck
);
180 if (TARGET_IS_WINDOWS(torture
)) {
181 CHECK_STATUS(status
, NT_STATUS_OK
);
183 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
185 CHECK_VALUE(lck
.out
.reserved
, 0);
187 el
[0].flags
= 0x00000000;
188 status
= smb2_lock(tree
, &lck
);
189 CHECK_STATUS(status
, NT_STATUS_OK
);
190 CHECK_VALUE(lck
.out
.reserved
, 0);
192 status
= smb2_lock(tree
, &lck
);
193 CHECK_STATUS(status
, NT_STATUS_OK
);
194 CHECK_VALUE(lck
.out
.reserved
, 0);
196 el
[0].flags
= 0x00000001;
197 status
= smb2_lock(tree
, &lck
);
198 CHECK_STATUS(status
, NT_STATUS_OK
);
199 CHECK_VALUE(lck
.out
.reserved
, 0);
201 status
= smb2_lock(tree
, &lck
);
202 CHECK_STATUS(status
, NT_STATUS_OK
);
203 CHECK_VALUE(lck
.out
.reserved
, 0);
205 lck
.in
.lock_count
= 0x0001;
206 lck
.in
.reserved
= 0x87654321;
207 lck
.in
.file
.handle
= h
;
208 el
[0].offset
= 0x00000000FFFFFFFF;
209 el
[0].length
= 0x00000000FFFFFFFF;
210 el
[0].reserved
= 0x1234567;
211 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
212 status
= smb2_lock(tree
, &lck
);
213 CHECK_STATUS(status
, NT_STATUS_OK
);
215 lck
.in
.lock_count
= 0x0001;
216 lck
.in
.reserved
= 0x1234567;
217 lck
.in
.file
.handle
= h
;
218 el
[0].offset
= 0x00000000FFFFFFFF;
219 el
[0].length
= 0x00000000FFFFFFFF;
220 el
[0].reserved
= 0x00000000;
221 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
222 status
= smb2_lock(tree
, &lck
);
223 CHECK_STATUS(status
, NT_STATUS_OK
);
225 status
= smb2_lock(tree
, &lck
);
226 CHECK_STATUS(status
, NT_STATUS_OK
);
227 status
= smb2_lock(tree
, &lck
);
228 CHECK_STATUS(status
, NT_STATUS_OK
);
229 status
= smb2_lock(tree
, &lck
);
230 CHECK_STATUS(status
, NT_STATUS_OK
);
231 status
= smb2_lock(tree
, &lck
);
232 CHECK_STATUS(status
, NT_STATUS_RANGE_NOT_LOCKED
);
234 lck
.in
.lock_count
= 0x0001;
236 lck
.in
.file
.handle
= h
;
239 el
[0].reserved
= 0x00000000;
240 el
[0].flags
= ~SMB2_LOCK_FLAG_ALL_MASK
;
242 status
= smb2_lock(tree
, &lck
);
243 CHECK_STATUS(status
, NT_STATUS_OK
);
245 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
246 status
= smb2_lock(tree
, &lck
);
247 CHECK_STATUS(status
, NT_STATUS_OK
);
249 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
250 status
= smb2_lock(tree
, &lck
);
251 CHECK_STATUS(status
, NT_STATUS_RANGE_NOT_LOCKED
);
253 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
| SMB2_LOCK_FLAG_EXCLUSIVE
;
254 status
= smb2_lock(tree
, &lck
);
255 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
257 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
| SMB2_LOCK_FLAG_SHARED
;
258 status
= smb2_lock(tree
, &lck
);
259 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
261 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
| SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
;
262 status
= smb2_lock(tree
, &lck
);
263 CHECK_STATUS(status
, NT_STATUS_RANGE_NOT_LOCKED
);
265 lck
.in
.lock_count
= 2;
267 lck
.in
.file
.handle
= h
;
270 el
[0].reserved
= 0x00000000;
273 el
[1].reserved
= 0x00000000;
275 lck
.in
.lock_count
= 2;
277 el
[1].flags
= SMB2_LOCK_FLAG_UNLOCK
;
278 status
= smb2_lock(tree
, &lck
);
279 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
281 lck
.in
.lock_count
= 2;
284 status
= smb2_lock(tree
, &lck
);
285 CHECK_STATUS(status
, NT_STATUS_OK
);
287 lck
.in
.lock_count
= 2;
288 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
290 status
= smb2_lock(tree
, &lck
);
291 CHECK_STATUS(status
, NT_STATUS_OK
);
293 lck
.in
.lock_count
= 1;
294 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
295 status
= smb2_lock(tree
, &lck
);
296 CHECK_STATUS(status
, NT_STATUS_RANGE_NOT_LOCKED
);
298 lck
.in
.lock_count
= 1;
299 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
300 status
= smb2_lock(tree
, &lck
);
301 CHECK_STATUS(status
, NT_STATUS_RANGE_NOT_LOCKED
);
303 lck
.in
.lock_count
= 1;
304 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
305 status
= smb2_lock(tree
, &lck
);
306 CHECK_STATUS(status
, NT_STATUS_RANGE_NOT_LOCKED
);
308 lck
.in
.lock_count
= 1;
310 status
= smb2_lock(tree
, &lck
);
311 CHECK_STATUS(status
, NT_STATUS_OK
);
313 status
= smb2_lock(tree
, &lck
);
314 CHECK_STATUS(status
, NT_STATUS_OK
);
316 lck
.in
.lock_count
= 2;
317 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
318 el
[1].flags
= SMB2_LOCK_FLAG_UNLOCK
;
319 status
= smb2_lock(tree
, &lck
);
320 CHECK_STATUS(status
, NT_STATUS_OK
);
322 lck
.in
.lock_count
= 1;
323 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
324 status
= smb2_lock(tree
, &lck
);
325 CHECK_STATUS(status
, NT_STATUS_RANGE_NOT_LOCKED
);
332 struct test_lock_read_write_state
{
335 NTSTATUS write_h1_status
;
336 NTSTATUS read_h1_status
;
337 NTSTATUS write_h2_status
;
338 NTSTATUS read_h2_status
;
341 static bool test_lock_read_write(struct torture_context
*torture
,
342 struct smb2_tree
*tree
,
343 struct test_lock_read_write_state
*s
)
347 struct smb2_handle h1
, h2
;
349 struct smb2_lock lck
;
350 struct smb2_create cr
;
351 struct smb2_write wr
;
353 struct smb2_lock_element el
[1];
359 status
= torture_smb2_testfile(tree
, s
->fname
, &h1
);
360 CHECK_STATUS(status
, NT_STATUS_OK
);
362 status
= smb2_util_write(tree
, h1
, buf
, 0, ARRAY_SIZE(buf
));
363 CHECK_STATUS(status
, NT_STATUS_OK
);
365 lck
.in
.lock_count
= 0x0001;
366 lck
.in
.reserved
= 0x00000000;
367 lck
.in
.file
.handle
= h1
;
369 el
[0].length
= ARRAY_SIZE(buf
)/2;
370 el
[0].reserved
= 0x00000000;
371 el
[0].flags
= s
->lock_flags
;
372 status
= smb2_lock(tree
, &lck
);
373 CHECK_STATUS(status
, NT_STATUS_OK
);
374 CHECK_VALUE(lck
.out
.reserved
, 0);
376 lck
.in
.lock_count
= 0x0001;
377 lck
.in
.reserved
= 0x00000000;
378 lck
.in
.file
.handle
= h1
;
379 el
[0].offset
= ARRAY_SIZE(buf
)/2;
380 el
[0].length
= ARRAY_SIZE(buf
)/2;
381 el
[0].reserved
= 0x00000000;
382 el
[0].flags
= s
->lock_flags
;
383 status
= smb2_lock(tree
, &lck
);
384 CHECK_STATUS(status
, NT_STATUS_OK
);
385 CHECK_VALUE(lck
.out
.reserved
, 0);
388 cr
.in
.oplock_level
= 0;
389 cr
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
390 cr
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
391 cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
393 NTCREATEX_SHARE_ACCESS_DELETE
|
394 NTCREATEX_SHARE_ACCESS_READ
|
395 NTCREATEX_SHARE_ACCESS_WRITE
;
396 cr
.in
.create_options
= 0;
397 cr
.in
.fname
= s
->fname
;
399 status
= smb2_create(tree
, tree
, &cr
);
400 CHECK_STATUS(status
, NT_STATUS_OK
);
402 h2
= cr
.out
.file
.handle
;
405 wr
.in
.file
.handle
= h1
;
406 wr
.in
.offset
= ARRAY_SIZE(buf
)/2;
407 wr
.in
.data
= data_blob_const(buf
, ARRAY_SIZE(buf
)/2);
409 status
= smb2_write(tree
, &wr
);
410 CHECK_STATUS(status
, s
->write_h1_status
);
413 rd
.in
.file
.handle
= h1
;
414 rd
.in
.offset
= ARRAY_SIZE(buf
)/2;
415 rd
.in
.length
= ARRAY_SIZE(buf
)/2;
417 status
= smb2_read(tree
, tree
, &rd
);
418 CHECK_STATUS(status
, s
->read_h1_status
);
421 wr
.in
.file
.handle
= h2
;
422 wr
.in
.offset
= ARRAY_SIZE(buf
)/2;
423 wr
.in
.data
= data_blob_const(buf
, ARRAY_SIZE(buf
)/2);
425 status
= smb2_write(tree
, &wr
);
426 CHECK_STATUS(status
, s
->write_h2_status
);
429 rd
.in
.file
.handle
= h2
;
430 rd
.in
.offset
= ARRAY_SIZE(buf
)/2;
431 rd
.in
.length
= ARRAY_SIZE(buf
)/2;
433 status
= smb2_read(tree
, tree
, &rd
);
434 CHECK_STATUS(status
, s
->read_h2_status
);
436 lck
.in
.lock_count
= 0x0001;
437 lck
.in
.reserved
= 0x00000000;
438 lck
.in
.file
.handle
= h1
;
439 el
[0].offset
= ARRAY_SIZE(buf
)/2;
440 el
[0].length
= ARRAY_SIZE(buf
)/2;
441 el
[0].reserved
= 0x00000000;
442 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
443 status
= smb2_lock(tree
, &lck
);
444 CHECK_STATUS(status
, NT_STATUS_OK
);
445 CHECK_VALUE(lck
.out
.reserved
, 0);
448 wr
.in
.file
.handle
= h2
;
449 wr
.in
.offset
= ARRAY_SIZE(buf
)/2;
450 wr
.in
.data
= data_blob_const(buf
, ARRAY_SIZE(buf
)/2);
452 status
= smb2_write(tree
, &wr
);
453 CHECK_STATUS(status
, NT_STATUS_OK
);
456 rd
.in
.file
.handle
= h2
;
457 rd
.in
.offset
= ARRAY_SIZE(buf
)/2;
458 rd
.in
.length
= ARRAY_SIZE(buf
)/2;
460 status
= smb2_read(tree
, tree
, &rd
);
461 CHECK_STATUS(status
, NT_STATUS_OK
);
467 static bool test_lock_rw_none(struct torture_context
*torture
, struct smb2_tree
*tree
)
469 struct test_lock_read_write_state s
= {
470 .fname
= "lock_rw_none.dat",
471 .lock_flags
= SMB2_LOCK_FLAG_NONE
,
472 .write_h1_status
= NT_STATUS_FILE_LOCK_CONFLICT
,
473 .read_h1_status
= NT_STATUS_OK
,
474 .write_h2_status
= NT_STATUS_FILE_LOCK_CONFLICT
,
475 .read_h2_status
= NT_STATUS_OK
,
478 return test_lock_read_write(torture
, tree
, &s
);
481 static bool test_lock_rw_shared(struct torture_context
*torture
, struct smb2_tree
*tree
)
483 struct test_lock_read_write_state s
= {
484 .fname
= "lock_rw_shared.dat",
485 .lock_flags
= SMB2_LOCK_FLAG_SHARED
,
486 .write_h1_status
= NT_STATUS_FILE_LOCK_CONFLICT
,
487 .read_h1_status
= NT_STATUS_OK
,
488 .write_h2_status
= NT_STATUS_FILE_LOCK_CONFLICT
,
489 .read_h2_status
= NT_STATUS_OK
,
492 return test_lock_read_write(torture
, tree
, &s
);
495 static bool test_lock_rw_exclusiv(struct torture_context
*torture
, struct smb2_tree
*tree
)
497 struct test_lock_read_write_state s
= {
498 .fname
= "lock_rw_exclusiv.dat",
499 .lock_flags
= SMB2_LOCK_FLAG_EXCLUSIVE
,
500 .write_h1_status
= NT_STATUS_OK
,
501 .read_h1_status
= NT_STATUS_OK
,
502 .write_h2_status
= NT_STATUS_FILE_LOCK_CONFLICT
,
503 .read_h2_status
= NT_STATUS_FILE_LOCK_CONFLICT
,
506 return test_lock_read_write(torture
, tree
, &s
);
509 static bool test_lock_auto_unlock(struct torture_context
*torture
, struct smb2_tree
*tree
)
513 struct smb2_handle h
;
515 struct smb2_lock lck
;
516 struct smb2_lock_element el
[2];
520 status
= torture_smb2_testfile(tree
, "autounlock.txt", &h
);
521 CHECK_STATUS(status
, NT_STATUS_OK
);
523 status
= smb2_util_write(tree
, h
, buf
, 0, ARRAY_SIZE(buf
));
524 CHECK_STATUS(status
, NT_STATUS_OK
);
528 lck
.in
.lock_count
= 0x0001;
529 lck
.in
.file
.handle
= h
;
532 el
[0].flags
= SMB2_LOCK_FLAG_EXCLUSIVE
| SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
;
533 status
= smb2_lock(tree
, &lck
);
534 CHECK_STATUS(status
, NT_STATUS_OK
);
536 status
= smb2_lock(tree
, &lck
);
537 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
539 status
= smb2_lock(tree
, &lck
);
540 if (TARGET_IS_WINDOWS(torture
)) {
541 CHECK_STATUS(status
, NT_STATUS_OK
);
543 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
546 status
= smb2_lock(tree
, &lck
);
547 CHECK_STATUS(status
, NT_STATUS_LOCK_NOT_GRANTED
);
554 /* basic testing of SMB2 locking
556 struct torture_suite
*torture_smb2_lock_init(void)
558 struct torture_suite
*suite
= torture_suite_create(talloc_autofree_context(), "LOCK");
560 torture_suite_add_1smb2_test(suite
, "VALID-REQUEST", test_valid_request
);
561 torture_suite_add_1smb2_test(suite
, "RW-NONE", test_lock_rw_none
);
562 torture_suite_add_1smb2_test(suite
, "RW-SHARED", test_lock_rw_shared
);
563 torture_suite_add_1smb2_test(suite
, "RW-EXCLUSIV", test_lock_rw_exclusiv
);
564 torture_suite_add_1smb2_test(suite
, "AUTO-UNLOCK", test_lock_auto_unlock
);
566 suite
->description
= talloc_strdup(suite
, "SMB2-LOCK tests");