/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- torture_locktest1
- torture_locktest2
- torture_locktest3
- torture_locktest4
- torture_locktest5
- torture_locktest6
- torture_locktest7
- torture_base_locktest
1 /*
2 Unix SMB/CIFS implementation.
3
4 basic locking tests
5
6 Copyright (C) Andrew Tridgell 2000-2004
7 Copyright (C) Jeremy Allison 2000-2004
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "libcli/raw/libcliraw.h"
25 #include "libcli/libcli.h"
26 #include "torture/smbtorture.h"
27 #include "torture/util.h"
28 #include "system/time.h"
29 #include "system/filesys.h"
30
31 #define BASEDIR "\\locktest"
32
33 /*
34 This test checks for two things:
35
36 1) correct support for retaining locks over a close (ie. the server
37 must not use posix semantics)
38 2) support for lock timeouts
39 */
40 static bool torture_locktest1(struct torture_context *tctx,
/* [<][>][^][v][top][bottom][index][help] */
41 struct smbcli_state *cli1,
42 struct smbcli_state *cli2)
43 {
44 const char *fname = BASEDIR "\\lockt1.lck";
45 int fnum1, fnum2, fnum3;
46 time_t t1, t2;
47 uint_t lock_timeout;
48
49 if (!torture_setup_dir(cli1, BASEDIR)) {
50 return false;
51 }
52
53 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
54 torture_assert(tctx, fnum1 != -1,
55 talloc_asprintf(tctx,
56 "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
57 fnum2 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
58 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx,
59 "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
60 fnum3 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
61 torture_assert(tctx, fnum3 != -1, talloc_asprintf(tctx,
62 "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
63
64 torture_assert_ntstatus_ok(tctx,
65 smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK),
66 talloc_asprintf(tctx, "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
67
68 torture_assert(tctx,
69 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
70 "lock2 succeeded! This is a locking bug\n");
71
72 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
73 NT_STATUS_LOCK_NOT_GRANTED)) return false;
74
75 torture_assert(tctx,
76 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
77 "lock2 succeeded! This is a locking bug\n");
78
79 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
80 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
81
82 torture_assert_ntstatus_ok(tctx,
83 smbcli_lock(cli1->tree, fnum1, 5, 9, 0, WRITE_LOCK),
84 talloc_asprintf(tctx,
85 "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
86
87 torture_assert(tctx,
88 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 5, 9, 0, WRITE_LOCK)),
89 "lock2 succeeded! This is a locking bug");
90
91 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
92 NT_STATUS_LOCK_NOT_GRANTED)) return false;
93
94 torture_assert(tctx,
95 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
96 "lock2 succeeded! This is a locking bug");
97
98 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
99 NT_STATUS_LOCK_NOT_GRANTED)) return false;
100
101 torture_assert(tctx,
102 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
103 "lock2 succeeded! This is a locking bug");
104
105 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
106 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
107
108 lock_timeout = (6 + (random() % 20));
109 torture_comment(tctx, "Testing lock timeout with timeout=%u\n",
110 lock_timeout);
111 t1 = time(NULL);
112 torture_assert(tctx,
113 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, lock_timeout * 1000, WRITE_LOCK)),
114 "lock3 succeeded! This is a locking bug\n");
115
116 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
117 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
118 t2 = time(NULL);
119
120 if (t2 - t1 < 5) {
121 torture_fail(tctx,
122 "error: This server appears not to support timed lock requests");
123 }
124 torture_comment(tctx, "server slept for %u seconds for a %u second timeout\n",
125 (uint_t)(t2-t1), lock_timeout);
126
127 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum2),
128 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
129
130 torture_assert(tctx,
131 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
132 "lock4 succeeded! This is a locking bug");
133
134 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
135 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
136
137 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
138 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli1->tree)));
139
140 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum3),
141 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli2->tree)));
142
143 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
144 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
145
146 return true;
147 }
148
149
150 /*
151 This test checks that
152
153 1) the server supports multiple locking contexts on the one SMB
154 connection, distinguished by PID.
155
156 2) the server correctly fails overlapping locks made by the same PID (this
157 goes against POSIX behaviour, which is why it is tricky to implement)
158
159 3) the server denies unlock requests by an incorrect client PID
160 */
161 static bool torture_locktest2(struct torture_context *tctx,
/* [<][>][^][v][top][bottom][index][help] */
162 struct smbcli_state *cli)
163 {
164 const char *fname = BASEDIR "\\lockt2.lck";
165 int fnum1, fnum2, fnum3;
166
167 if (!torture_setup_dir(cli, BASEDIR)) {
168 return false;
169 }
170
171 torture_comment(tctx, "Testing pid context\n");
172
173 cli->session->pid = 1;
174
175 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
176 torture_assert(tctx, fnum1 != -1,
177 talloc_asprintf(tctx,
178 "open of %s failed (%s)", fname, smbcli_errstr(cli->tree)));
179
180 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
181 torture_assert(tctx, fnum2 != -1,
182 talloc_asprintf(tctx, "open2 of %s failed (%s)",
183 fname, smbcli_errstr(cli->tree)));
184
185 cli->session->pid = 2;
186
187 fnum3 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
188 torture_assert(tctx, fnum3 != -1,
189 talloc_asprintf(tctx,
190 "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)));
191
192 cli->session->pid = 1;
193
194 torture_assert_ntstatus_ok(tctx,
195 smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK),
196 talloc_asprintf(tctx,
197 "lock1 failed (%s)", smbcli_errstr(cli->tree)));
198
199 torture_assert(tctx,
200 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK)),
201 "WRITE lock1 succeeded! This is a locking bug");
202
203 if (!check_error(__location__, cli, ERRDOS, ERRlock,
204 NT_STATUS_LOCK_NOT_GRANTED)) return false;
205
206 torture_assert(tctx,
207 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, WRITE_LOCK)),
208 "WRITE lock2 succeeded! This is a locking bug");
209
210 if (!check_error(__location__, cli, ERRDOS, ERRlock,
211 NT_STATUS_LOCK_NOT_GRANTED)) return false;
212
213 torture_assert(tctx,
214 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, READ_LOCK)),
215 "READ lock2 succeeded! This is a locking bug");
216
217 if (!check_error(__location__, cli, ERRDOS, ERRlock,
218 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
219
220 torture_assert_ntstatus_ok(tctx,
221 smbcli_lock(cli->tree, fnum1, 100, 4, 0, WRITE_LOCK),
222 talloc_asprintf(tctx,
223 "lock at 100 failed (%s)", smbcli_errstr(cli->tree)));
224
225 cli->session->pid = 2;
226
227 torture_assert(tctx,
228 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 100, 4)),
229 "unlock at 100 succeeded! This is a locking bug");
230
231 torture_assert(tctx,
232 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 4)),
233 "unlock1 succeeded! This is a locking bug");
234
235 if (!check_error(__location__, cli,
236 ERRDOS, ERRnotlocked,
237 NT_STATUS_RANGE_NOT_LOCKED)) return false;
238
239 torture_assert(tctx,
240 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 8)),
241 "unlock2 succeeded! This is a locking bug");
242
243 if (!check_error(__location__, cli,
244 ERRDOS, ERRnotlocked,
245 NT_STATUS_RANGE_NOT_LOCKED)) return false;
246
247 torture_assert(tctx,
248 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
249 "lock3 succeeded! This is a locking bug");
250
251 if (!check_error(__location__, cli, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false;
252
253 cli->session->pid = 1;
254
255 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum1),
256 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli->tree)));
257
258 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum2),
259 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli->tree)));
260
261 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum3),
262 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli->tree)));
263
264 return true;
265 }
266
267
268 /*
269 This test checks that
270
271 1) the server supports the full offset range in lock requests
272 */
273 static bool torture_locktest3(struct torture_context *tctx,
/* [<][>][^][v][top][bottom][index][help] */
274 struct smbcli_state *cli1,
275 struct smbcli_state *cli2)
276 {
277 const char *fname = BASEDIR "\\lockt3.lck";
278 int fnum1, fnum2, i;
279 uint32_t offset;
280 extern int torture_numops;
281
282 #define NEXT_OFFSET offset += (~(uint32_t)0) / torture_numops
283
284 torture_comment(tctx, "Testing 32 bit offset ranges");
285
286 if (!torture_setup_dir(cli1, BASEDIR)) {
287 return false;
288 }
289
290 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
291 torture_assert(tctx, fnum1 != -1,
292 talloc_asprintf(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
293 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
294 torture_assert(tctx, fnum2 != -1,
295 talloc_asprintf(tctx, "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
296
297 torture_comment(tctx, "Establishing %d locks\n", torture_numops);
298
299 for (offset=i=0;i<torture_numops;i++) {
300 NEXT_OFFSET;
301 torture_assert_ntstatus_ok(tctx,
302 smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK),
303 talloc_asprintf(tctx, "lock1 %d failed (%s)", i, smbcli_errstr(cli1->tree)));
304
305 torture_assert_ntstatus_ok(tctx,
306 smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK),
307 talloc_asprintf(tctx, "lock2 %d failed (%s)",
308 i, smbcli_errstr(cli1->tree)));
309 }
310
311 torture_comment(tctx, "Testing %d locks\n", torture_numops);
312
313 for (offset=i=0;i<torture_numops;i++) {
314 NEXT_OFFSET;
315
316 torture_assert(tctx,
317 !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-2, 1, 0, WRITE_LOCK)),
318 talloc_asprintf(tctx, "error: lock1 %d succeeded!", i));
319
320 torture_assert(tctx,
321 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-1, 1, 0, WRITE_LOCK)),
322 talloc_asprintf(tctx, "error: lock2 %d succeeded!", i));
323
324 torture_assert(tctx,
325 !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK)),
326 talloc_asprintf(tctx, "error: lock3 %d succeeded!", i));
327
328 torture_assert(tctx,
329 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK)),
330 talloc_asprintf(tctx, "error: lock4 %d succeeded!", i));
331 }
332
333 torture_comment(tctx, "Removing %d locks\n", torture_numops);
334
335 for (offset=i=0;i<torture_numops;i++) {
336 NEXT_OFFSET;
337
338 torture_assert_ntstatus_ok(tctx,
339 smbcli_unlock(cli1->tree, fnum1, offset-1, 1),
340 talloc_asprintf(tctx, "unlock1 %d failed (%s)",
341 i,
342 smbcli_errstr(cli1->tree)));
343
344 torture_assert_ntstatus_ok(tctx,
345 smbcli_unlock(cli2->tree, fnum2, offset-2, 1),
346 talloc_asprintf(tctx, "unlock2 %d failed (%s)",
347 i,
348 smbcli_errstr(cli1->tree)));
349 }
350
351 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
352 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
353
354 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
355 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
356
357 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
358 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
359
360 return true;
361 }
362
363 #define EXPECTED(ret, v) if ((ret) != (v)) { \
364 torture_comment(tctx, "** "); correct = false; \
365 }
366
367 /*
368 looks at overlapping locks
369 */
370 static bool torture_locktest4(struct torture_context *tctx,
/* [<][>][^][v][top][bottom][index][help] */
371 struct smbcli_state *cli1,
372 struct smbcli_state *cli2)
373 {
374 const char *fname = BASEDIR "\\lockt4.lck";
375 int fnum1, fnum2, f;
376 bool ret;
377 uint8_t buf[1000];
378 bool correct = true;
379
380 if (!torture_setup_dir(cli1, BASEDIR)) {
381 return false;
382 }
383
384 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
385 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
386
387 memset(buf, 0, sizeof(buf));
388
389 if (smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
390 torture_comment(tctx, "Failed to create file\n");
391 correct = false;
392 goto fail;
393 }
394
395 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
396 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 2, 4, 0, WRITE_LOCK));
397 EXPECTED(ret, false);
398 torture_comment(tctx, "the same process %s set overlapping write locks\n", ret?"can":"cannot");
399
400 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 10, 4, 0, READ_LOCK)) &&
401 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 12, 4, 0, READ_LOCK));
402 EXPECTED(ret, true);
403 torture_comment(tctx, "the same process %s set overlapping read locks\n", ret?"can":"cannot");
404
405 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 20, 4, 0, WRITE_LOCK)) &&
406 NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 22, 4, 0, WRITE_LOCK));
407 EXPECTED(ret, false);
408 torture_comment(tctx, "a different connection %s set overlapping write locks\n", ret?"can":"cannot");
409
410 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 30, 4, 0, READ_LOCK)) &&
411 NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 32, 4, 0, READ_LOCK));
412 EXPECTED(ret, true);
413 torture_comment(tctx, "a different connection %s set overlapping read locks\n", ret?"can":"cannot");
414
415 ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 40, 4, 0, WRITE_LOCK))) &&
416 NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 42, 4, 0, WRITE_LOCK)));
417 EXPECTED(ret, false);
418 torture_comment(tctx, "a different pid %s set overlapping write locks\n", ret?"can":"cannot");
419
420 ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 50, 4, 0, READ_LOCK))) &&
421 NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 52, 4, 0, READ_LOCK)));
422 EXPECTED(ret, true);
423 torture_comment(tctx, "a different pid %s set overlapping read locks\n", ret?"can":"cannot");
424
425 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK)) &&
426 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK));
427 EXPECTED(ret, true);
428 torture_comment(tctx, "the same process %s set the same read lock twice\n", ret?"can":"cannot");
429
430 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK)) &&
431 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK));
432 EXPECTED(ret, false);
433 torture_comment(tctx, "the same process %s set the same write lock twice\n", ret?"can":"cannot");
434
435 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, READ_LOCK)) &&
436 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, WRITE_LOCK));
437 EXPECTED(ret, false);
438 torture_comment(tctx, "the same process %s overlay a read lock with a write lock\n", ret?"can":"cannot");
439
440 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, WRITE_LOCK)) &&
441 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, READ_LOCK));
442 EXPECTED(ret, true);
443 torture_comment(tctx, "the same process %s overlay a write lock with a read lock\n", ret?"can":"cannot");
444
445 ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, WRITE_LOCK))) &&
446 NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, READ_LOCK)));
447 EXPECTED(ret, false);
448 torture_comment(tctx, "a different pid %s overlay a write lock with a read lock\n", ret?"can":"cannot");
449
450 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 110, 4, 0, READ_LOCK)) &&
451 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 112, 4, 0, READ_LOCK)) &&
452 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 110, 6));
453 EXPECTED(ret, false);
454 torture_comment(tctx, "the same process %s coalesce read locks\n", ret?"can":"cannot");
455
456
457 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 120, 4, 0, WRITE_LOCK)) &&
458 (smbcli_read(cli2->tree, fnum2, buf, 120, 4) == 4);
459 EXPECTED(ret, false);
460 torture_comment(tctx, "this server %s strict write locking\n", ret?"doesn't do":"does");
461
462 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK)) &&
463 (smbcli_write(cli2->tree, fnum2, 0, buf, 130, 4) == 4);
464 EXPECTED(ret, false);
465 torture_comment(tctx, "this server %s strict read locking\n", ret?"doesn't do":"does");
466
467
468 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
469 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
470 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4)) &&
471 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4));
472 EXPECTED(ret, true);
473 torture_comment(tctx, "this server %s do recursive read locking\n", ret?"does":"doesn't");
474
475
476 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, WRITE_LOCK)) &&
477 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, READ_LOCK)) &&
478 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4)) &&
479 (smbcli_read(cli2->tree, fnum2, buf, 150, 4) == 4) &&
480 !(smbcli_write(cli2->tree, fnum2, 0, buf, 150, 4) == 4) &&
481 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4));
482 EXPECTED(ret, true);
483 torture_comment(tctx, "this server %s do recursive lock overlays\n", ret?"does":"doesn't");
484
485 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 160, 4, 0, READ_LOCK)) &&
486 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 160, 4)) &&
487 (smbcli_write(cli2->tree, fnum2, 0, buf, 160, 4) == 4) &&
488 (smbcli_read(cli2->tree, fnum2, buf, 160, 4) == 4);
489 EXPECTED(ret, true);
490 torture_comment(tctx, "the same process %s remove a read lock using write locking\n", ret?"can":"cannot");
491
492 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 170, 4, 0, WRITE_LOCK)) &&
493 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 170, 4)) &&
494 (smbcli_write(cli2->tree, fnum2, 0, buf, 170, 4) == 4) &&
495 (smbcli_read(cli2->tree, fnum2, buf, 170, 4) == 4);
496 EXPECTED(ret, true);
497 torture_comment(tctx, "the same process %s remove a write lock using read locking\n", ret?"can":"cannot");
498
499 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, WRITE_LOCK)) &&
500 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, READ_LOCK)) &&
501 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 190, 4)) &&
502 !(smbcli_write(cli2->tree, fnum2, 0, buf, 190, 4) == 4) &&
503 (smbcli_read(cli2->tree, fnum2, buf, 190, 4) == 4);
504 EXPECTED(ret, true);
505 torture_comment(tctx, "the same process %s remove the first lock first\n", ret?"does":"doesn't");
506
507 smbcli_close(cli1->tree, fnum1);
508 smbcli_close(cli2->tree, fnum2);
509 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
510 f = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
511 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
512 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, f, 0, 1, 0, READ_LOCK)) &&
513 NT_STATUS_IS_OK(smbcli_close(cli1->tree, fnum1)) &&
514 ((fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE)) != -1) &&
515 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
516 smbcli_close(cli1->tree, f);
517 smbcli_close(cli1->tree, fnum1);
518 EXPECTED(ret, true);
519 torture_comment(tctx, "the server %s have the NT byte range lock bug\n", !ret?"does":"doesn't");
520
521 fail:
522 smbcli_close(cli1->tree, fnum1);
523 smbcli_close(cli2->tree, fnum2);
524 smbcli_unlink(cli1->tree, fname);
525
526 return correct;
527 }
528
529 /*
530 looks at lock upgrade/downgrade.
531 */
532 static bool torture_locktest5(struct torture_context *tctx, struct smbcli_state *cli1,
/* [<][>][^][v][top][bottom][index][help] */
533 struct smbcli_state *cli2)
534 {
535 const char *fname = BASEDIR "\\lockt5.lck";
536 int fnum1, fnum2, fnum3;
537 bool ret;
538 uint8_t buf[1000];
539 bool correct = true;
540
541 if (!torture_setup_dir(cli1, BASEDIR)) {
542 return false;
543 }
544
545 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
546 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
547 fnum3 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
548
549 memset(buf, 0, sizeof(buf));
550
551 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
552 "Failed to create file");
553
554 /* Check for NT bug... */
555 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
556 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 1, 0, READ_LOCK));
557 smbcli_close(cli1->tree, fnum1);
558 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
559 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
560 EXPECTED(ret, true);
561 torture_comment(tctx, "this server %s the NT locking bug\n", ret ? "doesn't have" : "has");
562 smbcli_close(cli1->tree, fnum1);
563 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
564 smbcli_unlock(cli1->tree, fnum3, 0, 1);
565
566 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
567 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 1, 1, 0, READ_LOCK));
568 EXPECTED(ret, true);
569 torture_comment(tctx, "the same process %s overlay a write with a read lock\n", ret?"can":"cannot");
570
571 ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
572 EXPECTED(ret, false);
573
574 torture_comment(tctx, "a different processs %s get a read lock on the first process lock stack\n", ret?"can":"cannot");
575
576 /* Unlock the process 2 lock. */
577 smbcli_unlock(cli2->tree, fnum2, 0, 4);
578
579 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 4, 0, READ_LOCK));
580 EXPECTED(ret, false);
581
582 torture_comment(tctx, "the same processs on a different fnum %s get a read lock\n", ret?"can":"cannot");
583
584 /* Unlock the process 1 fnum3 lock. */
585 smbcli_unlock(cli1->tree, fnum3, 0, 4);
586
587 /* Stack 2 more locks here. */
588 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK)) &&
589 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK));
590
591 EXPECTED(ret, true);
592 torture_comment(tctx, "the same process %s stack read locks\n", ret?"can":"cannot");
593
594 /* Unlock the first process lock, then check this was the WRITE lock that was
595 removed. */
596
597 ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
598 NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
599
600 EXPECTED(ret, true);
601 torture_comment(tctx, "the first unlock removes the %s lock\n", ret?"WRITE":"READ");
602
603 /* Unlock the process 2 lock. */
604 smbcli_unlock(cli2->tree, fnum2, 0, 4);
605
606 /* We should have 3 stacked locks here. Ensure we need to do 3 unlocks. */
607
608 ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 1, 1)) &&
609 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
610 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
611
612 EXPECTED(ret, true);
613 torture_comment(tctx, "the same process %s unlock the stack of 3 locks\n", ret?"can":"cannot");
614
615 /* Ensure the next unlock fails. */
616 ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
617 EXPECTED(ret, false);
618 torture_comment(tctx, "the same process %s count the lock stack\n", !ret?"can":"cannot");
619
620 /* Ensure connection 2 can get a write lock. */
621 ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, WRITE_LOCK));
622 EXPECTED(ret, true);
623
624 torture_comment(tctx, "a different processs %s get a write lock on the unlocked stack\n", ret?"can":"cannot");
625
626
627 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
628 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
629
630 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
631 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
632
633 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum3),
634 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
635
636 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
637 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
638
639 return correct;
640 }
641
642 /*
643 tries the unusual lockingX locktype bits
644 */
645 static bool torture_locktest6(struct torture_context *tctx,
/* [<][>][^][v][top][bottom][index][help] */
646 struct smbcli_state *cli)
647 {
648 const char *fname[1] = { "\\lock6.txt" };
649 int i;
650 int fnum;
651 NTSTATUS status;
652
653 if (!torture_setup_dir(cli, BASEDIR)) {
654 return false;
655 }
656
657 for (i=0;i<1;i++) {
658 torture_comment(tctx, "Testing %s\n", fname[i]);
659
660 smbcli_unlink(cli->tree, fname[i]);
661
662 fnum = smbcli_open(cli->tree, fname[i], O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
663 status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CHANGE_LOCKTYPE);
664 smbcli_close(cli->tree, fnum);
665 torture_comment(tctx, "CHANGE_LOCKTYPE gave %s\n", nt_errstr(status));
666
667 fnum = smbcli_open(cli->tree, fname[i], O_RDWR, DENY_NONE);
668 status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CANCEL_LOCK);
669 smbcli_close(cli->tree, fnum);
670 torture_comment(tctx, "CANCEL_LOCK gave %s\n", nt_errstr(status));
671
672 smbcli_unlink(cli->tree, fname[i]);
673 }
674
675 return true;
676 }
677
678 static bool torture_locktest7(struct torture_context *tctx,
/* [<][>][^][v][top][bottom][index][help] */
679 struct smbcli_state *cli1)
680 {
681 const char *fname = BASEDIR "\\lockt7.lck";
682 int fnum1;
683 int fnum2 = -1;
684 size_t size;
685 uint8_t buf[200];
686 bool correct = false;
687
688 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
689 talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
690
691 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
692
693 memset(buf, 0, sizeof(buf));
694
695 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
696 "Failed to create file");
697
698 cli1->session->pid = 1;
699
700 torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK),
701 talloc_asprintf(tctx, "Unable to apply read lock on range 130:4, error was %s",
702 smbcli_errstr(cli1->tree)));
703
704 torture_comment(tctx, "pid1 successfully locked range 130:4 for READ\n");
705
706 torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
707 talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s)",
708 smbcli_errstr(cli1->tree)));
709
710 torture_comment(tctx, "pid1 successfully read the range 130:4\n");
711
712 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
713 torture_comment(tctx, "pid1 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
714 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
715 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
716 } else {
717 torture_fail(tctx, "pid1 successfully wrote to the range 130:4 (should be denied)");
718 }
719
720 cli1->session->pid = 2;
721
722 if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
723 torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
724 } else {
725 torture_comment(tctx, "pid2 successfully read the range 130:4\n");
726 }
727
728 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
729 torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
730 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
731 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
732 } else {
733 torture_fail(tctx, "pid2 successfully wrote to the range 130:4 (should be denied)");
734 }
735
736 cli1->session->pid = 1;
737 smbcli_unlock(cli1->tree, fnum1, 130, 4);
738
739 torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, WRITE_LOCK),
740 talloc_asprintf(tctx, "Unable to apply write lock on range 130:4, error was %s",
741 smbcli_errstr(cli1->tree)));
742 torture_comment(tctx, "pid1 successfully locked range 130:4 for WRITE\n");
743
744 torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
745 talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s",
746 smbcli_errstr(cli1->tree)));
747 torture_comment(tctx, "pid1 successfully read the range 130:4\n");
748
749 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) == 4,
750 talloc_asprintf(tctx, "pid1 unable to write to the range 130:4, error was %s",
751 smbcli_errstr(cli1->tree)));
752 torture_comment(tctx, "pid1 successfully wrote to the range 130:4\n");
753
754 cli1->session->pid = 2;
755
756 if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
757 torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n",
758 smbcli_errstr(cli1->tree));
759 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
760 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
761 } else {
762 torture_fail(tctx, "pid2 successfully read the range 130:4 (should be denied)");
763 }
764
765 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
766 torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n",
767 smbcli_errstr(cli1->tree));
768 if (!NT_STATUS_EQUAL(smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT)) {
769 torture_comment(tctx, "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT) (%s)\n",
770 __location__);
771 goto fail;
772 }
773 } else {
774 torture_comment(tctx, "pid2 successfully wrote to the range 130:4 (should be denied) (%s)\n",
775 __location__);
776 goto fail;
777 }
778
779 torture_comment(tctx, "Testing truncate of locked file.\n");
780
781 fnum2 = smbcli_open(cli1->tree, fname, O_RDWR|O_TRUNC, DENY_NONE);
782
783 torture_assert(tctx, fnum2 != -1, "Unable to truncate locked file");
784
785 torture_comment(tctx, "Truncated locked file.\n");
786
787 torture_assert_ntstatus_ok(tctx, smbcli_getatr(cli1->tree, fname, NULL, &size, NULL),
788 talloc_asprintf(tctx, "getatr failed (%s)", smbcli_errstr(cli1->tree)));
789
790 torture_assert(tctx, size == 0, talloc_asprintf(tctx, "Unable to truncate locked file. Size was %u", (unsigned)size));
791
792 cli1->session->pid = 1;
793
794 smbcli_unlock(cli1->tree, fnum1, 130, 4);
795 correct = true;
796
797 fail:
798 smbcli_close(cli1->tree, fnum1);
799 smbcli_close(cli1->tree, fnum2);
800 smbcli_unlink(cli1->tree, fname);
801
802 return correct;
803 }
804
805 struct torture_suite *torture_base_locktest(TALLOC_CTX *mem_ctx)
/* [<][>][^][v][top][bottom][index][help] */
806 {
807 struct torture_suite *suite = torture_suite_create(mem_ctx, "LOCK");
808 torture_suite_add_2smb_test(suite, "LOCK1", torture_locktest1);
809 torture_suite_add_1smb_test(suite, "LOCK2", torture_locktest2);
810 torture_suite_add_2smb_test(suite, "LOCK3", torture_locktest3);
811 torture_suite_add_2smb_test(suite, "LOCK4", torture_locktest4);
812 torture_suite_add_2smb_test(suite, "LOCK5", torture_locktest5);
813 torture_suite_add_1smb_test(suite, "LOCK6", torture_locktest6);
814 torture_suite_add_1smb_test(suite, "LOCK7", torture_locktest7);
815
816 return suite;
817 }