another SMB2-LOCK fix now that we know that the UNLOCK flag is only
[kai/samba.git] / source / torture / smb2 / lock.c
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)
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,
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)
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)
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)
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)
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)
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