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 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)); \
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); \
47 static bool test_valid_request(struct torture_context *torture, struct smb2_tree *tree)
57 status = torture_smb2_testfile(tree, "lock1.txt", &h);
58 CHECK_STATUS(status, NT_STATUS_OK);
60 status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
61 CHECK_STATUS(status, NT_STATUS_OK);
63 lck.in.unknown1 = 0x0000;
64 lck.in.unknown2 = 0x00000000;
65 lck.in.file.handle = h;
66 lck.in.offset = 0x0000000000000000;
67 lck.in.count = 0x0000000000000000;
68 lck.in.unknown5 = 0x0000000000000000;
69 lck.in.flags = 0x00000000;
70 status = smb2_lock(tree, &lck);
71 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
73 lck.in.unknown1 = 0x0001;
74 lck.in.unknown2 = 0x00000000;
75 lck.in.file.handle = h;
78 lck.in.unknown5 = 0x00000000;
79 lck.in.flags = SMB2_LOCK_FLAG_NONE;
80 status = smb2_lock(tree, &lck);
81 CHECK_STATUS(status, NT_STATUS_OK);
82 CHECK_VALUE(lck.out.unknown1, 0);
84 lck.in.file.handle.data[0] +=1;
85 status = smb2_lock(tree, &lck);
86 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
87 lck.in.file.handle.data[0] -=1;
89 lck.in.unknown1 = 0x0001;
90 lck.in.unknown2 = 0xFFFFFFFF;
91 lck.in.file.handle = h;
92 lck.in.offset = UINT64_MAX;
93 lck.in.count = UINT64_MAX;
94 lck.in.unknown5 = 0x00000000;
95 lck.in.flags = SMB2_LOCK_FLAG_EXCLUSIV|SMB2_LOCK_FLAG_NO_PENDING;
96 status = smb2_lock(tree, &lck);
97 CHECK_STATUS(status, NT_STATUS_OK);
98 CHECK_VALUE(lck.out.unknown1, 0);
100 status = smb2_lock(tree, &lck);
101 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
103 status = smb2_lock(tree, &lck);
104 CHECK_STATUS(status, NT_STATUS_OK);
105 CHECK_VALUE(lck.out.unknown1, 0);
107 status = smb2_lock(tree, &lck);
108 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
110 status = smb2_lock(tree, &lck);
111 CHECK_STATUS(status, NT_STATUS_OK);
112 CHECK_VALUE(lck.out.unknown1, 0);
114 lck.in.unknown1 = 0x0001;
115 lck.in.unknown2 = 0x12345678;
116 lck.in.file.handle = h;
117 lck.in.offset = UINT32_MAX;
118 lck.in.count = UINT32_MAX;
119 lck.in.unknown5 = 0x87654321;
120 lck.in.flags = SMB2_LOCK_FLAG_EXCLUSIV|SMB2_LOCK_FLAG_NO_PENDING;
121 status = smb2_lock(tree, &lck);
122 CHECK_STATUS(status, NT_STATUS_OK);
123 CHECK_VALUE(lck.out.unknown1, 0);
125 status = smb2_lock(tree, &lck);
126 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
128 status = smb2_lock(tree, &lck);
129 CHECK_STATUS(status, NT_STATUS_OK);
130 CHECK_VALUE(lck.out.unknown1, 0);
132 status = smb2_lock(tree, &lck);
133 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
135 status = smb2_lock(tree, &lck);
136 CHECK_STATUS(status, NT_STATUS_OK);
137 CHECK_VALUE(lck.out.unknown1, 0);
139 lck.in.flags = 0x00000000;
140 status = smb2_lock(tree, &lck);
141 CHECK_STATUS(status, NT_STATUS_OK);
142 CHECK_VALUE(lck.out.unknown1, 0);
144 status = smb2_lock(tree, &lck);
145 CHECK_STATUS(status, NT_STATUS_OK);
146 CHECK_VALUE(lck.out.unknown1, 0);
148 lck.in.flags = 0x00000001;
149 status = smb2_lock(tree, &lck);
150 CHECK_STATUS(status, NT_STATUS_OK);
151 CHECK_VALUE(lck.out.unknown1, 0);
153 status = smb2_lock(tree, &lck);
154 CHECK_STATUS(status, NT_STATUS_OK);
155 CHECK_VALUE(lck.out.unknown1, 0);
157 lck.in.unknown1 = 0x0001;
158 lck.in.unknown2 = 0x87654321;
159 lck.in.file.handle = h;
160 lck.in.offset = 0x00000000FFFFFFFF;
161 lck.in.count = 0x00000000FFFFFFFF;
162 lck.in.unknown5 = 0x12345678;
163 lck.in.flags = SMB2_LOCK_FLAG_UNLOCK;
164 status = smb2_lock(tree, &lck);
165 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
167 lck.in.unknown1 = 0x0001;
168 lck.in.unknown2 = 0x12345678;
169 lck.in.file.handle = h;
170 lck.in.offset = 0x00000000FFFFFFFF;
171 lck.in.count = 0x00000000FFFFFFFF;
172 lck.in.unknown5 = 0x00000000;
173 lck.in.flags = SMB2_LOCK_FLAG_UNLOCK;
174 status = smb2_lock(tree, &lck);
175 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
177 status = smb2_lock(tree, &lck);
178 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
179 status = smb2_lock(tree, &lck);
180 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
181 status = smb2_lock(tree, &lck);
182 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
188 struct test_lock_read_write_state {
191 NTSTATUS write_h1_status;
192 NTSTATUS read_h1_status;
193 NTSTATUS write_h2_status;
194 NTSTATUS read_h2_status;
197 static bool test_lock_read_write(struct torture_context *torture,
198 struct smb2_tree *tree,
199 struct test_lock_read_write_state *s)
203 struct smb2_handle h1, h2;
205 struct smb2_lock lck;
206 struct smb2_create cr;
207 struct smb2_write wr;
212 status = torture_smb2_testfile(tree, s->fname, &h1);
213 CHECK_STATUS(status, NT_STATUS_OK);
215 status = smb2_util_write(tree, h1, buf, 0, ARRAY_SIZE(buf));
216 CHECK_STATUS(status, NT_STATUS_OK);
218 lck.in.unknown1 = 0x0001;
219 lck.in.unknown2 = 0x00000000;
220 lck.in.file.handle = h1;
222 lck.in.count = ARRAY_SIZE(buf)/2;
223 lck.in.unknown5 = 0x00000000;
224 lck.in.flags = s->lock_flags;
225 status = smb2_lock(tree, &lck);
226 CHECK_STATUS(status, NT_STATUS_OK);
227 CHECK_VALUE(lck.out.unknown1, 0);
229 lck.in.unknown1 = 0x0001;
230 lck.in.unknown2 = 0x00000000;
231 lck.in.file.handle = h1;
232 lck.in.offset = ARRAY_SIZE(buf)/2;
233 lck.in.count = ARRAY_SIZE(buf)/2;
234 lck.in.unknown5 = 0x00000000;
235 lck.in.flags = s->lock_flags;
236 status = smb2_lock(tree, &lck);
237 CHECK_STATUS(status, NT_STATUS_OK);
238 CHECK_VALUE(lck.out.unknown1, 0);
241 cr.in.oplock_level = 0;
242 cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
243 cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
244 cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
246 NTCREATEX_SHARE_ACCESS_DELETE|
247 NTCREATEX_SHARE_ACCESS_READ|
248 NTCREATEX_SHARE_ACCESS_WRITE;
249 cr.in.create_options = 0;
250 cr.in.fname = s->fname;
252 status = smb2_create(tree, tree, &cr);
253 CHECK_STATUS(status, NT_STATUS_OK);
255 h2 = cr.out.file.handle;
258 wr.in.file.handle = h1;
259 wr.in.offset = ARRAY_SIZE(buf)/2;
260 wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
262 status = smb2_write(tree, &wr);
263 CHECK_STATUS(status, s->write_h1_status);
266 rd.in.file.handle = h1;
267 rd.in.offset = ARRAY_SIZE(buf)/2;
268 rd.in.length = ARRAY_SIZE(buf)/2;
270 status = smb2_read(tree, tree, &rd);
271 CHECK_STATUS(status, s->read_h1_status);
274 wr.in.file.handle = h2;
275 wr.in.offset = ARRAY_SIZE(buf)/2;
276 wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
278 status = smb2_write(tree, &wr);
279 CHECK_STATUS(status, s->write_h2_status);
282 rd.in.file.handle = h2;
283 rd.in.offset = ARRAY_SIZE(buf)/2;
284 rd.in.length = ARRAY_SIZE(buf)/2;
286 status = smb2_read(tree, tree, &rd);
287 CHECK_STATUS(status, s->read_h2_status);
289 lck.in.unknown1 = 0x0001;
290 lck.in.unknown2 = 0x00000000;
291 lck.in.file.handle = h1;
292 lck.in.offset = ARRAY_SIZE(buf)/2;
293 lck.in.count = ARRAY_SIZE(buf)/2;
294 lck.in.unknown5 = 0x00000000;
295 lck.in.flags = SMB2_LOCK_FLAG_UNLOCK;
296 status = smb2_lock(tree, &lck);
297 CHECK_STATUS(status, NT_STATUS_OK);
298 CHECK_VALUE(lck.out.unknown1, 0);
301 wr.in.file.handle = h2;
302 wr.in.offset = ARRAY_SIZE(buf)/2;
303 wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
305 status = smb2_write(tree, &wr);
306 CHECK_STATUS(status, NT_STATUS_OK);
309 rd.in.file.handle = h2;
310 rd.in.offset = ARRAY_SIZE(buf)/2;
311 rd.in.length = ARRAY_SIZE(buf)/2;
313 status = smb2_read(tree, tree, &rd);
314 CHECK_STATUS(status, NT_STATUS_OK);
320 static bool test_lock_rw_none(struct torture_context *torture, struct smb2_tree *tree)
322 struct test_lock_read_write_state s = {
323 .fname = "lock_rw_none.dat",
324 .lock_flags = SMB2_LOCK_FLAG_NONE,
325 .write_h1_status = NT_STATUS_FILE_LOCK_CONFLICT,
326 .read_h1_status = NT_STATUS_OK,
327 .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
328 .read_h2_status = NT_STATUS_OK,
331 return test_lock_read_write(torture, tree, &s);
334 static bool test_lock_rw_shared(struct torture_context *torture, struct smb2_tree *tree)
336 struct test_lock_read_write_state s = {
337 .fname = "lock_rw_shared.dat",
338 .lock_flags = SMB2_LOCK_FLAG_SHARED,
339 .write_h1_status = NT_STATUS_FILE_LOCK_CONFLICT,
340 .read_h1_status = NT_STATUS_OK,
341 .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
342 .read_h2_status = NT_STATUS_OK,
345 return test_lock_read_write(torture, tree, &s);
348 static bool test_lock_rw_exclusiv(struct torture_context *torture, struct smb2_tree *tree)
350 struct test_lock_read_write_state s = {
351 .fname = "lock_rw_exclusiv.dat",
352 .lock_flags = SMB2_LOCK_FLAG_EXCLUSIV,
353 .write_h1_status = NT_STATUS_OK,
354 .read_h1_status = NT_STATUS_OK,
355 .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
356 .read_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
359 return test_lock_read_write(torture, tree, &s);
362 /* basic testing of SMB2 locking
364 struct torture_suite *torture_smb2_lock_init(void)
366 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "LOCK");
368 torture_suite_add_1smb2_test(suite, "VALID-REQUEST", test_valid_request);
369 torture_suite_add_1smb2_test(suite, "RW-NONE", test_lock_rw_none);
370 torture_suite_add_1smb2_test(suite, "RW-SHARED", test_lock_rw_shared);
371 torture_suite_add_1smb2_test(suite, "RW-EXCLUSIV", test_lock_rw_exclusiv);
373 suite->description = talloc_strdup(suite, "SMB2-LOCK tests");