fixed SMB2 locking
[ira/wip.git] / source4 / 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[1];
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         = 0xFFFFFFFF;
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         status = smb2_lock(tree, &lck);
104         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
105
106         status = smb2_lock(tree, &lck);
107         CHECK_STATUS(status, NT_STATUS_OK);
108         CHECK_VALUE(lck.out.reserved, 0);
109
110         status = smb2_lock(tree, &lck);
111         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
112
113         status = smb2_lock(tree, &lck);
114         CHECK_STATUS(status, NT_STATUS_OK);
115         CHECK_VALUE(lck.out.reserved, 0);
116
117         lck.in.lock_count       = 0x0001;
118         lck.in.reserved         = 0x12345678;
119         lck.in.file.handle      = h;
120         el[0].offset            = UINT32_MAX;
121         el[0].length            = UINT32_MAX;
122         el[0].reserved          = 0x87654321;
123         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
124         status = smb2_lock(tree, &lck);
125         CHECK_STATUS(status, NT_STATUS_OK);
126         CHECK_VALUE(lck.out.reserved, 0);
127
128         status = smb2_lock(tree, &lck);
129         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
130
131         status = smb2_lock(tree, &lck);
132         CHECK_STATUS(status, NT_STATUS_OK);
133         CHECK_VALUE(lck.out.reserved, 0);
134
135         status = smb2_lock(tree, &lck);
136         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
137
138         status = smb2_lock(tree, &lck);
139         CHECK_STATUS(status, NT_STATUS_OK);
140         CHECK_VALUE(lck.out.reserved, 0);
141
142         el[0].flags             = 0x00000000;
143         status = smb2_lock(tree, &lck);
144         CHECK_STATUS(status, NT_STATUS_OK);
145         CHECK_VALUE(lck.out.reserved, 0);
146
147         status = smb2_lock(tree, &lck);
148         CHECK_STATUS(status, NT_STATUS_OK);
149         CHECK_VALUE(lck.out.reserved, 0);
150
151         el[0].flags             = 0x00000001;
152         status = smb2_lock(tree, &lck);
153         CHECK_STATUS(status, NT_STATUS_OK);
154         CHECK_VALUE(lck.out.reserved, 0);
155
156         status = smb2_lock(tree, &lck);
157         CHECK_STATUS(status, NT_STATUS_OK);
158         CHECK_VALUE(lck.out.reserved, 0);
159
160         lck.in.lock_count       = 0x0001;
161         lck.in.reserved         = 0x87654321;
162         lck.in.file.handle      = h;
163         el[0].offset            = 0x00000000FFFFFFFF;
164         el[0].length            = 0x00000000FFFFFFFF;
165         el[0].reserved          = 0x12345678;
166         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
167         status = smb2_lock(tree, &lck);
168         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
169
170         lck.in.lock_count       = 0x0001;
171         lck.in.reserved         = 0x12345678;
172         lck.in.file.handle      = h;
173         el[0].offset            = 0x00000000FFFFFFFF;
174         el[0].length            = 0x00000000FFFFFFFF;
175         el[0].reserved          = 0x00000000;
176         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
177         status = smb2_lock(tree, &lck);
178         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
179
180         status = smb2_lock(tree, &lck);
181         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
182         status = smb2_lock(tree, &lck);
183         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
184         status = smb2_lock(tree, &lck);
185         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
186
187 done:
188         return ret;
189 }
190
191 struct test_lock_read_write_state {
192         const char *fname;
193         uint32_t lock_flags;
194         NTSTATUS write_h1_status;
195         NTSTATUS read_h1_status;
196         NTSTATUS write_h2_status;
197         NTSTATUS read_h2_status;
198 };
199
200 static bool test_lock_read_write(struct torture_context *torture,
201                                  struct smb2_tree *tree,
202                                  struct test_lock_read_write_state *s)
203 {
204         bool ret = true;
205         NTSTATUS status;
206         struct smb2_handle h1, h2;
207         uint8_t buf[200];
208         struct smb2_lock lck;
209         struct smb2_create cr;
210         struct smb2_write wr;
211         struct smb2_read rd;
212         struct smb2_lock_element el[1];
213
214         lck.in.locks            = el;
215
216         ZERO_STRUCT(buf);
217
218         status = torture_smb2_testfile(tree, s->fname, &h1);
219         CHECK_STATUS(status, NT_STATUS_OK);
220
221         status = smb2_util_write(tree, h1, buf, 0, ARRAY_SIZE(buf));
222         CHECK_STATUS(status, NT_STATUS_OK);
223
224         lck.in.lock_count       = 0x0001;
225         lck.in.reserved         = 0x00000000;
226         lck.in.file.handle      = h1;
227         el[0].offset            = 0;
228         el[0].length            = ARRAY_SIZE(buf)/2;
229         el[0].reserved          = 0x00000000;
230         el[0].flags             = s->lock_flags;
231         status = smb2_lock(tree, &lck);
232         CHECK_STATUS(status, NT_STATUS_OK);
233         CHECK_VALUE(lck.out.reserved, 0);
234
235         lck.in.lock_count       = 0x0001;
236         lck.in.reserved         = 0x00000000;
237         lck.in.file.handle      = h1;
238         el[0].offset            = ARRAY_SIZE(buf)/2;
239         el[0].length            = ARRAY_SIZE(buf)/2;
240         el[0].reserved          = 0x00000000;
241         el[0].flags             = s->lock_flags;
242         status = smb2_lock(tree, &lck);
243         CHECK_STATUS(status, NT_STATUS_OK);
244         CHECK_VALUE(lck.out.reserved, 0);
245
246         ZERO_STRUCT(cr);
247         cr.in.oplock_level = 0;
248         cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
249         cr.in.file_attributes   = FILE_ATTRIBUTE_NORMAL;
250         cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
251         cr.in.share_access = 
252                 NTCREATEX_SHARE_ACCESS_DELETE|
253                 NTCREATEX_SHARE_ACCESS_READ|
254                 NTCREATEX_SHARE_ACCESS_WRITE;
255         cr.in.create_options = 0;
256         cr.in.fname = s->fname;
257
258         status = smb2_create(tree, tree, &cr);
259         CHECK_STATUS(status, NT_STATUS_OK);
260
261         h2 = cr.out.file.handle;
262
263         ZERO_STRUCT(wr);
264         wr.in.file.handle = h1;
265         wr.in.offset      = ARRAY_SIZE(buf)/2;
266         wr.in.data        = data_blob_const(buf, ARRAY_SIZE(buf)/2);
267
268         status = smb2_write(tree, &wr);
269         CHECK_STATUS(status, s->write_h1_status);
270
271         ZERO_STRUCT(rd);
272         rd.in.file.handle = h1;
273         rd.in.offset      = ARRAY_SIZE(buf)/2;
274         rd.in.length      = ARRAY_SIZE(buf)/2;
275
276         status = smb2_read(tree, tree, &rd);
277         CHECK_STATUS(status, s->read_h1_status);
278
279         ZERO_STRUCT(wr);
280         wr.in.file.handle = h2;
281         wr.in.offset      = ARRAY_SIZE(buf)/2;
282         wr.in.data        = data_blob_const(buf, ARRAY_SIZE(buf)/2);
283
284         status = smb2_write(tree, &wr);
285         CHECK_STATUS(status, s->write_h2_status);
286
287         ZERO_STRUCT(rd);
288         rd.in.file.handle = h2;
289         rd.in.offset      = ARRAY_SIZE(buf)/2;
290         rd.in.length      = ARRAY_SIZE(buf)/2;
291
292         status = smb2_read(tree, tree, &rd);
293         CHECK_STATUS(status, s->read_h2_status);
294
295         lck.in.lock_count       = 0x0001;
296         lck.in.reserved         = 0x00000000;
297         lck.in.file.handle      = h1;
298         el[0].offset            = ARRAY_SIZE(buf)/2;
299         el[0].length            = ARRAY_SIZE(buf)/2;
300         el[0].reserved          = 0x00000000;
301         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
302         status = smb2_lock(tree, &lck);
303         CHECK_STATUS(status, NT_STATUS_OK);
304         CHECK_VALUE(lck.out.reserved, 0);
305
306         ZERO_STRUCT(wr);
307         wr.in.file.handle = h2;
308         wr.in.offset      = ARRAY_SIZE(buf)/2;
309         wr.in.data        = data_blob_const(buf, ARRAY_SIZE(buf)/2);
310
311         status = smb2_write(tree, &wr);
312         CHECK_STATUS(status, NT_STATUS_OK);
313
314         ZERO_STRUCT(rd);
315         rd.in.file.handle = h2;
316         rd.in.offset      = ARRAY_SIZE(buf)/2;
317         rd.in.length      = ARRAY_SIZE(buf)/2;
318
319         status = smb2_read(tree, tree, &rd);
320         CHECK_STATUS(status, NT_STATUS_OK);
321
322 done:
323         return ret;
324 }
325
326 static bool test_lock_rw_none(struct torture_context *torture, struct smb2_tree *tree)
327 {
328         struct test_lock_read_write_state s = {
329                 .fname                  = "lock_rw_none.dat",
330                 .lock_flags             = SMB2_LOCK_FLAG_NONE,
331                 .write_h1_status        = NT_STATUS_FILE_LOCK_CONFLICT,
332                 .read_h1_status         = NT_STATUS_OK,
333                 .write_h2_status        = NT_STATUS_FILE_LOCK_CONFLICT,
334                 .read_h2_status         = NT_STATUS_OK,
335         };
336
337         return test_lock_read_write(torture, tree, &s);
338 }
339
340 static bool test_lock_rw_shared(struct torture_context *torture, struct smb2_tree *tree)
341 {
342         struct test_lock_read_write_state s = {
343                 .fname                  = "lock_rw_shared.dat",
344                 .lock_flags             = SMB2_LOCK_FLAG_SHARED,
345                 .write_h1_status        = NT_STATUS_FILE_LOCK_CONFLICT,
346                 .read_h1_status         = NT_STATUS_OK,
347                 .write_h2_status        = NT_STATUS_FILE_LOCK_CONFLICT,
348                 .read_h2_status         = NT_STATUS_OK,
349         };
350
351         return test_lock_read_write(torture, tree, &s);
352 }
353
354 static bool test_lock_rw_exclusiv(struct torture_context *torture, struct smb2_tree *tree)
355 {
356         struct test_lock_read_write_state s = {
357                 .fname                  = "lock_rw_exclusiv.dat",
358                 .lock_flags             = SMB2_LOCK_FLAG_EXCLUSIVE,
359                 .write_h1_status        = NT_STATUS_OK,
360                 .read_h1_status         = NT_STATUS_OK,
361                 .write_h2_status        = NT_STATUS_FILE_LOCK_CONFLICT,
362                 .read_h2_status         = NT_STATUS_FILE_LOCK_CONFLICT,
363         };
364
365         return test_lock_read_write(torture, tree, &s);
366 }
367
368 /* basic testing of SMB2 locking
369 */
370 struct torture_suite *torture_smb2_lock_init(void)
371 {
372         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "LOCK");
373
374         torture_suite_add_1smb2_test(suite, "VALID-REQUEST", test_valid_request);
375         torture_suite_add_1smb2_test(suite, "RW-NONE", test_lock_rw_none);
376         torture_suite_add_1smb2_test(suite, "RW-SHARED", test_lock_rw_shared);
377         torture_suite_add_1smb2_test(suite, "RW-EXCLUSIV", test_lock_rw_exclusiv);
378
379         suite->description = talloc_strdup(suite, "SMB2-LOCK tests");
380
381         return suite;
382 }
383