r22858: - let SMB2-LOCK-VALID-REQUEST pass against longhorn beta3
[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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26
27 #include "torture/torture.h"
28 #include "torture/smb2/proto.h"
29
30 #include "librpc/gen_ndr/ndr_security.h"
31
32 #define CHECK_STATUS(status, correct) do { \
33         if (!NT_STATUS_EQUAL(status, correct)) { \
34                 printf("(%s) Incorrect status %s - should be %s\n", \
35                        __location__, nt_errstr(status), nt_errstr(correct)); \
36                 ret = False; \
37                 goto done; \
38         }} while (0)
39
40 #define CHECK_VALUE(v, correct) do { \
41         if ((v) != (correct)) { \
42                 printf("(%s) Incorrect value %s=%d - should be %d\n", \
43                        __location__, #v, v, correct); \
44                 ret = False; \
45                 goto done; \
46         }} while (0)
47
48 static BOOL test_valid_request(struct torture_context *torture, struct smb2_tree *tree)
49 {
50         BOOL ret = True;
51         NTSTATUS status;
52         struct smb2_handle h;
53         uint8_t buf[200];
54         struct smb2_lock lck;
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.unknown1         = 0x0000;
65         lck.in.unknown2         = 0x00000000;
66         lck.in.file.handle      = h;
67         lck.in.offset           = 0x0000000000000000;
68         lck.in.count            = 0x0000000000000000;
69         lck.in.unknown5         = 0x0000000000000000;
70         lck.in.flags            = 0x00000000;
71         status = smb2_lock(tree, &lck);
72         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
73
74         lck.in.unknown1         = 0x0001;
75         lck.in.unknown2         = 0x00000000;
76         lck.in.file.handle      = h;
77         lck.in.offset           = 0;
78         lck.in.count            = 0;
79         lck.in.unknown5         = 0x00000000;
80         lck.in.flags            = SMB2_LOCK_FLAG_NONE;
81         status = smb2_lock(tree, &lck);
82         CHECK_STATUS(status, NT_STATUS_OK);
83         CHECK_VALUE(lck.out.unknown1, 0);
84
85         lck.in.file.handle.data[0] +=1;
86         status = smb2_lock(tree, &lck);
87         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
88         lck.in.file.handle.data[0] -=1;
89
90         lck.in.unknown1         = 0x0001;
91         lck.in.unknown2         = 0xFFFFFFFF;
92         lck.in.file.handle      = h;
93         lck.in.offset           = UINT64_MAX;
94         lck.in.count            = UINT64_MAX;
95         lck.in.unknown5         = 0x00000000;
96         lck.in.flags            = SMB2_LOCK_FLAG_EXCLUSIV|SMB2_LOCK_FLAG_NO_PENDING;
97         status = smb2_lock(tree, &lck);
98         CHECK_STATUS(status, NT_STATUS_OK);
99         CHECK_VALUE(lck.out.unknown1, 0);
100
101         status = smb2_lock(tree, &lck);
102         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
103
104         status = smb2_lock(tree, &lck);
105         CHECK_STATUS(status, NT_STATUS_OK);
106         CHECK_VALUE(lck.out.unknown1, 0);
107
108         status = smb2_lock(tree, &lck);
109         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
110
111         status = smb2_lock(tree, &lck);
112         CHECK_STATUS(status, NT_STATUS_OK);
113         CHECK_VALUE(lck.out.unknown1, 0);
114
115         lck.in.unknown1         = 0x0001;
116         lck.in.unknown2         = 0x12345678;
117         lck.in.file.handle      = h;
118         lck.in.offset           = UINT32_MAX;
119         lck.in.count            = UINT32_MAX;
120         lck.in.unknown5         = 0x87654321;
121         lck.in.flags            = SMB2_LOCK_FLAG_EXCLUSIV|SMB2_LOCK_FLAG_NO_PENDING;
122         status = smb2_lock(tree, &lck);
123         CHECK_STATUS(status, NT_STATUS_OK);
124         CHECK_VALUE(lck.out.unknown1, 0);
125
126         status = smb2_lock(tree, &lck);
127         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
128
129         status = smb2_lock(tree, &lck);
130         CHECK_STATUS(status, NT_STATUS_OK);
131         CHECK_VALUE(lck.out.unknown1, 0);
132
133         status = smb2_lock(tree, &lck);
134         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
135
136         status = smb2_lock(tree, &lck);
137         CHECK_STATUS(status, NT_STATUS_OK);
138         CHECK_VALUE(lck.out.unknown1, 0);
139
140         lck.in.flags            = 0x00000000;
141         status = smb2_lock(tree, &lck);
142         CHECK_STATUS(status, NT_STATUS_OK);
143         CHECK_VALUE(lck.out.unknown1, 0);
144
145         status = smb2_lock(tree, &lck);
146         CHECK_STATUS(status, NT_STATUS_OK);
147         CHECK_VALUE(lck.out.unknown1, 0);
148
149         lck.in.flags            = 0x00000001;
150         status = smb2_lock(tree, &lck);
151         CHECK_STATUS(status, NT_STATUS_OK);
152         CHECK_VALUE(lck.out.unknown1, 0);
153
154         status = smb2_lock(tree, &lck);
155         CHECK_STATUS(status, NT_STATUS_OK);
156         CHECK_VALUE(lck.out.unknown1, 0);
157
158         lck.in.unknown1         = 0x0001;
159         lck.in.unknown2         = 0x87654321;
160         lck.in.file.handle      = h;
161         lck.in.offset           = 0x00000000FFFFFFFF;
162         lck.in.count            = 0x00000000FFFFFFFF;
163         lck.in.unknown5         = 0x12345678;
164         lck.in.flags            = SMB2_LOCK_FLAG_UNLOCK;
165         status = smb2_lock(tree, &lck);
166         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
167
168         lck.in.unknown1         = 0x0001;
169         lck.in.unknown2         = 0x12345678;
170         lck.in.file.handle      = h;
171         lck.in.offset           = 0x00000000FFFFFFFF;
172         lck.in.count            = 0x00000000FFFFFFFF;
173         lck.in.unknown5         = 0x00000000;
174         lck.in.flags            = SMB2_LOCK_FLAG_UNLOCK;
175         status = smb2_lock(tree, &lck);
176         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
177
178         status = smb2_lock(tree, &lck);
179         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
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
185 done:
186         return ret;
187 }
188
189 struct test_lock_read_write_state {
190         const char *fname;
191         uint32_t lock_flags;
192         NTSTATUS write_h1_status;
193         NTSTATUS read_h1_status;
194         NTSTATUS write_h2_status;
195         NTSTATUS read_h2_status;
196 };
197
198 static BOOL test_lock_read_write(struct torture_context *torture,
199                                  struct smb2_tree *tree,
200                                  struct test_lock_read_write_state *s)
201 {
202         BOOL ret = True;
203         NTSTATUS status;
204         struct smb2_handle h1, h2;
205         uint8_t buf[200];
206         struct smb2_lock lck;
207         struct smb2_create cr;
208         struct smb2_write wr;
209         struct smb2_read rd;
210
211         ZERO_STRUCT(buf);
212
213         status = torture_smb2_testfile(tree, s->fname, &h1);
214         CHECK_STATUS(status, NT_STATUS_OK);
215
216         status = smb2_util_write(tree, h1, buf, 0, ARRAY_SIZE(buf));
217         CHECK_STATUS(status, NT_STATUS_OK);
218
219         lck.in.unknown1         = 0x0001;
220         lck.in.unknown2         = 0x00000000;
221         lck.in.file.handle      = h1;
222         lck.in.offset           = 0;
223         lck.in.count            = ARRAY_SIZE(buf)/2;
224         lck.in.unknown5         = 0x00000000;
225         lck.in.flags            = s->lock_flags;
226         status = smb2_lock(tree, &lck);
227         CHECK_STATUS(status, NT_STATUS_OK);
228         CHECK_VALUE(lck.out.unknown1, 0);
229
230         lck.in.unknown1         = 0x0001;
231         lck.in.unknown2         = 0x00000000;
232         lck.in.file.handle      = h1;
233         lck.in.offset           = ARRAY_SIZE(buf)/2;
234         lck.in.count            = ARRAY_SIZE(buf)/2;
235         lck.in.unknown5         = 0x00000000;
236         lck.in.flags            = s->lock_flags;
237         status = smb2_lock(tree, &lck);
238         CHECK_STATUS(status, NT_STATUS_OK);
239         CHECK_VALUE(lck.out.unknown1, 0);
240
241         ZERO_STRUCT(cr);
242         cr.in.oplock_flags = 0;
243         cr.in.access_mask = SEC_RIGHTS_FILE_ALL;
244         cr.in.file_attr   = FILE_ATTRIBUTE_NORMAL;
245         cr.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
246         cr.in.share_access = 
247                 NTCREATEX_SHARE_ACCESS_DELETE|
248                 NTCREATEX_SHARE_ACCESS_READ|
249                 NTCREATEX_SHARE_ACCESS_WRITE;
250         cr.in.create_options = 0;
251         cr.in.fname = s->fname;
252
253         status = smb2_create(tree, tree, &cr);
254         CHECK_STATUS(status, NT_STATUS_OK);
255
256         h2 = cr.out.file.handle;
257
258         ZERO_STRUCT(wr);
259         wr.in.file.handle = h1;
260         wr.in.offset      = ARRAY_SIZE(buf)/2;
261         wr.in.data        = data_blob_const(buf, ARRAY_SIZE(buf)/2);
262
263         status = smb2_write(tree, &wr);
264         CHECK_STATUS(status, s->write_h1_status);
265
266         ZERO_STRUCT(rd);
267         rd.in.file.handle = h1;
268         rd.in.offset      = ARRAY_SIZE(buf)/2;
269         rd.in.length      = ARRAY_SIZE(buf)/2;
270
271         status = smb2_read(tree, tree, &rd);
272         CHECK_STATUS(status, s->read_h1_status);
273
274         ZERO_STRUCT(wr);
275         wr.in.file.handle = h2;
276         wr.in.offset      = ARRAY_SIZE(buf)/2;
277         wr.in.data        = data_blob_const(buf, ARRAY_SIZE(buf)/2);
278
279         status = smb2_write(tree, &wr);
280         CHECK_STATUS(status, s->write_h2_status);
281
282         ZERO_STRUCT(rd);
283         rd.in.file.handle = h2;
284         rd.in.offset      = ARRAY_SIZE(buf)/2;
285         rd.in.length      = ARRAY_SIZE(buf)/2;
286
287         status = smb2_read(tree, tree, &rd);
288         CHECK_STATUS(status, s->read_h2_status);
289
290         lck.in.unknown1         = 0x0001;
291         lck.in.unknown2         = 0x00000000;
292         lck.in.file.handle      = h1;
293         lck.in.offset           = ARRAY_SIZE(buf)/2;
294         lck.in.count            = ARRAY_SIZE(buf)/2;
295         lck.in.unknown5         = 0x00000000;
296         lck.in.flags            = SMB2_LOCK_FLAG_UNLOCK;
297         status = smb2_lock(tree, &lck);
298         CHECK_STATUS(status, NT_STATUS_OK);
299         CHECK_VALUE(lck.out.unknown1, 0);
300
301         ZERO_STRUCT(wr);
302         wr.in.file.handle = h2;
303         wr.in.offset      = ARRAY_SIZE(buf)/2;
304         wr.in.data        = data_blob_const(buf, ARRAY_SIZE(buf)/2);
305
306         status = smb2_write(tree, &wr);
307         CHECK_STATUS(status, NT_STATUS_OK);
308
309         ZERO_STRUCT(rd);
310         rd.in.file.handle = h2;
311         rd.in.offset      = ARRAY_SIZE(buf)/2;
312         rd.in.length      = ARRAY_SIZE(buf)/2;
313
314         status = smb2_read(tree, tree, &rd);
315         CHECK_STATUS(status, NT_STATUS_OK);
316
317 done:
318         return ret;
319 }
320
321 static BOOL test_lock_rw_none(struct torture_context *torture, struct smb2_tree *tree)
322 {
323         struct test_lock_read_write_state s = {
324                 .fname                  = "lock_rw_none.dat",
325                 .lock_flags             = SMB2_LOCK_FLAG_NONE,
326                 .write_h1_status        = NT_STATUS_FILE_LOCK_CONFLICT,
327                 .read_h1_status         = NT_STATUS_OK,
328                 .write_h2_status        = NT_STATUS_FILE_LOCK_CONFLICT,
329                 .read_h2_status         = NT_STATUS_OK,
330         };
331
332         return test_lock_read_write(torture, tree, &s);
333 }
334
335 static BOOL test_lock_rw_shared(struct torture_context *torture, struct smb2_tree *tree)
336 {
337         struct test_lock_read_write_state s = {
338                 .fname                  = "lock_rw_shared.dat",
339                 .lock_flags             = SMB2_LOCK_FLAG_SHARED,
340                 .write_h1_status        = NT_STATUS_FILE_LOCK_CONFLICT,
341                 .read_h1_status         = NT_STATUS_OK,
342                 .write_h2_status        = NT_STATUS_FILE_LOCK_CONFLICT,
343                 .read_h2_status         = NT_STATUS_OK,
344         };
345
346         return test_lock_read_write(torture, tree, &s);
347 }
348
349 static BOOL test_lock_rw_exclusiv(struct torture_context *torture, struct smb2_tree *tree)
350 {
351         struct test_lock_read_write_state s = {
352                 .fname                  = "lock_rw_exclusiv.dat",
353                 .lock_flags             = SMB2_LOCK_FLAG_EXCLUSIV,
354                 .write_h1_status        = NT_STATUS_OK,
355                 .read_h1_status         = NT_STATUS_OK,
356                 .write_h2_status        = NT_STATUS_FILE_LOCK_CONFLICT,
357                 .read_h2_status         = NT_STATUS_FILE_LOCK_CONFLICT,
358         };
359
360         return test_lock_read_write(torture, tree, &s);
361 }
362
363 /* basic testing of SMB2 locking
364 */
365 struct torture_suite *torture_smb2_lock_init(void)
366 {
367         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "LOCK");
368
369         torture_suite_add_1smb2_test(suite, "VALID-REQUEST", test_valid_request);
370         torture_suite_add_1smb2_test(suite, "RW-NONE", test_lock_rw_none);
371         torture_suite_add_1smb2_test(suite, "RW-SHARED", test_lock_rw_shared);
372         torture_suite_add_1smb2_test(suite, "RW-EXCLUSIV", test_lock_rw_exclusiv);
373
374         suite->description = talloc_strdup(suite, "SMB2-LOCK tests");
375
376         return suite;
377 }
378