Add an entry for the "check" command to the tdbtool manpage.
[Samba/gebeck_regimport.git] / source4 / torture / basic / locking.c
blob3f399c97efd386457c393644131b99c4aefb6177
1 /*
2 Unix SMB/CIFS implementation.
4 basic locking tests
6 Copyright (C) Andrew Tridgell 2000-2004
7 Copyright (C) Jeremy Allison 2000-2004
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.
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.
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/>.
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"
31 #define BASEDIR "\\locktest"
34 This test checks for two things:
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
40 static bool torture_locktest1(struct torture_context *tctx,
41 struct smbcli_state *cli1,
42 struct smbcli_state *cli2)
44 const char *fname = BASEDIR "\\lockt1.lck";
45 int fnum1, fnum2, fnum3;
46 time_t t1, t2;
47 uint_t lock_timeout;
49 if (!torture_setup_dir(cli1, BASEDIR)) {
50 return false;
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)));
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)));
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");
72 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
73 NT_STATUS_LOCK_NOT_GRANTED)) return false;
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");
79 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
80 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
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)));
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");
91 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
92 NT_STATUS_LOCK_NOT_GRANTED)) return false;
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");
98 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
99 NT_STATUS_LOCK_NOT_GRANTED)) return false;
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");
105 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
106 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
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");
116 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
117 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
118 t2 = time(NULL);
120 if (t2 - t1 < 5) {
121 torture_fail(tctx,
122 "error: This server appears not to support timed lock requests");
124 torture_comment(tctx, "server slept for %u seconds for a %u second timeout\n",
125 (uint_t)(t2-t1), lock_timeout);
127 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum2),
128 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
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");
134 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
135 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
137 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
138 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli1->tree)));
140 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum3),
141 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli2->tree)));
143 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
144 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
146 return true;
151 This test checks that
153 1) the server supports multiple locking contexts on the one SMB
154 connection, distinguished by PID.
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)
159 3) the server denies unlock requests by an incorrect client PID
161 static bool torture_locktest2(struct torture_context *tctx,
162 struct smbcli_state *cli)
164 const char *fname = BASEDIR "\\lockt2.lck";
165 int fnum1, fnum2, fnum3;
167 if (!torture_setup_dir(cli, BASEDIR)) {
168 return false;
171 torture_comment(tctx, "Testing pid context\n");
173 cli->session->pid = 1;
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)));
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)));
185 cli->session->pid = 2;
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)));
192 cli->session->pid = 1;
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)));
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");
203 if (!check_error(__location__, cli, ERRDOS, ERRlock,
204 NT_STATUS_LOCK_NOT_GRANTED)) return false;
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");
210 if (!check_error(__location__, cli, ERRDOS, ERRlock,
211 NT_STATUS_LOCK_NOT_GRANTED)) return false;
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");
217 if (!check_error(__location__, cli, ERRDOS, ERRlock,
218 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
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)));
225 cli->session->pid = 2;
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");
231 torture_assert(tctx,
232 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 4)),
233 "unlock1 succeeded! This is a locking bug");
235 if (!check_error(__location__, cli,
236 ERRDOS, ERRnotlocked,
237 NT_STATUS_RANGE_NOT_LOCKED)) return false;
239 torture_assert(tctx,
240 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 8)),
241 "unlock2 succeeded! This is a locking bug");
243 if (!check_error(__location__, cli,
244 ERRDOS, ERRnotlocked,
245 NT_STATUS_RANGE_NOT_LOCKED)) return false;
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");
251 if (!check_error(__location__, cli, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false;
253 cli->session->pid = 1;
255 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum1),
256 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli->tree)));
258 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum2),
259 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli->tree)));
261 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum3),
262 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli->tree)));
264 return true;
269 This test checks that
271 1) the server supports the full offset range in lock requests
273 static bool torture_locktest3(struct torture_context *tctx,
274 struct smbcli_state *cli1,
275 struct smbcli_state *cli2)
277 const char *fname = BASEDIR "\\lockt3.lck";
278 int fnum1, fnum2, i;
279 uint32_t offset;
280 extern int torture_numops;
282 #define NEXT_OFFSET offset += (~(uint32_t)0) / torture_numops
284 torture_comment(tctx, "Testing 32 bit offset ranges");
286 if (!torture_setup_dir(cli1, BASEDIR)) {
287 return false;
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)));
297 torture_comment(tctx, "Establishing %d locks\n", torture_numops);
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)));
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)));
311 torture_comment(tctx, "Testing %d locks\n", torture_numops);
313 for (offset=i=0;i<torture_numops;i++) {
314 NEXT_OFFSET;
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));
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));
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));
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));
333 torture_comment(tctx, "Removing %d locks\n", torture_numops);
335 for (offset=i=0;i<torture_numops;i++) {
336 NEXT_OFFSET;
338 torture_assert_ntstatus_ok(tctx,
339 smbcli_unlock(cli1->tree, fnum1, offset-1, 1),
340 talloc_asprintf(tctx, "unlock1 %d failed (%s)",
342 smbcli_errstr(cli1->tree)));
344 torture_assert_ntstatus_ok(tctx,
345 smbcli_unlock(cli2->tree, fnum2, offset-2, 1),
346 talloc_asprintf(tctx, "unlock2 %d failed (%s)",
348 smbcli_errstr(cli1->tree)));
351 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
352 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
354 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
355 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
357 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
358 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
360 return true;
363 #define EXPECTED(ret, v) if ((ret) != (v)) { \
364 torture_comment(tctx, "** "); correct = false; \
368 looks at overlapping locks
370 static bool torture_locktest4(struct torture_context *tctx,
371 struct smbcli_state *cli1,
372 struct smbcli_state *cli2)
374 const char *fname = BASEDIR "\\lockt4.lck";
375 int fnum1, fnum2, f;
376 bool ret;
377 uint8_t buf[1000];
378 bool correct = true;
380 if (!torture_setup_dir(cli1, BASEDIR)) {
381 return false;
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);
387 memset(buf, 0, sizeof(buf));
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;
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
521 fail:
522 smbcli_close(cli1->tree, fnum1);
523 smbcli_close(cli2->tree, fnum2);
524 smbcli_unlink(cli1->tree, fname);
526 return correct;
530 looks at lock upgrade/downgrade.
532 static bool torture_locktest5(struct torture_context *tctx, struct smbcli_state *cli1,
533 struct smbcli_state *cli2)
535 const char *fname = BASEDIR "\\lockt5.lck";
536 int fnum1, fnum2, fnum3;
537 bool ret;
538 uint8_t buf[1000];
539 bool correct = true;
541 if (!torture_setup_dir(cli1, BASEDIR)) {
542 return false;
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);
549 memset(buf, 0, sizeof(buf));
551 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
552 "Failed to create file");
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);
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");
571 ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
572 EXPECTED(ret, false);
574 torture_comment(tctx, "a different processs %s get a read lock on the first process lock stack\n", ret?"can":"cannot");
576 /* Unlock the process 2 lock. */
577 smbcli_unlock(cli2->tree, fnum2, 0, 4);
579 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 4, 0, READ_LOCK));
580 EXPECTED(ret, false);
582 torture_comment(tctx, "the same processs on a different fnum %s get a read lock\n", ret?"can":"cannot");
584 /* Unlock the process 1 fnum3 lock. */
585 smbcli_unlock(cli1->tree, fnum3, 0, 4);
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));
591 EXPECTED(ret, true);
592 torture_comment(tctx, "the same process %s stack read locks\n", ret?"can":"cannot");
594 /* Unlock the first process lock, then check this was the WRITE lock that was
595 removed. */
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));
600 EXPECTED(ret, true);
601 torture_comment(tctx, "the first unlock removes the %s lock\n", ret?"WRITE":"READ");
603 /* Unlock the process 2 lock. */
604 smbcli_unlock(cli2->tree, fnum2, 0, 4);
606 /* We should have 3 stacked locks here. Ensure we need to do 3 unlocks. */
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));
612 EXPECTED(ret, true);
613 torture_comment(tctx, "the same process %s unlock the stack of 4 locks\n", ret?"can":"cannot");
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");
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);
624 torture_comment(tctx, "a different processs %s get a write lock on the unlocked stack\n", ret?"can":"cannot");
627 smbcli_close(cli1->tree, fnum1);
628 smbcli_close(cli2->tree, fnum2);
629 smbcli_unlink(cli1->tree, fname);
631 return correct;
635 tries the unusual lockingX locktype bits
637 static bool torture_locktest6(struct torture_context *tctx,
638 struct smbcli_state *cli)
640 const char *fname[1] = { "\\lock6.txt" };
641 int i;
642 int fnum;
643 NTSTATUS status;
645 if (!torture_setup_dir(cli, BASEDIR)) {
646 return false;
649 for (i=0;i<1;i++) {
650 torture_comment(tctx, "Testing %s\n", fname[i]);
652 smbcli_unlink(cli->tree, fname[i]);
654 fnum = smbcli_open(cli->tree, fname[i], O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
655 status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CHANGE_LOCKTYPE);
656 smbcli_close(cli->tree, fnum);
657 torture_comment(tctx, "CHANGE_LOCKTYPE gave %s\n", nt_errstr(status));
659 fnum = smbcli_open(cli->tree, fname[i], O_RDWR, DENY_NONE);
660 status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CANCEL_LOCK);
661 smbcli_close(cli->tree, fnum);
662 torture_comment(tctx, "CANCEL_LOCK gave %s\n", nt_errstr(status));
664 smbcli_unlink(cli->tree, fname[i]);
667 return true;
670 static bool torture_locktest7(struct torture_context *tctx,
671 struct smbcli_state *cli1)
673 const char *fname = BASEDIR "\\lockt7.lck";
674 int fnum1;
675 int fnum2 = -1;
676 size_t size;
677 uint8_t buf[200];
678 bool correct = false;
680 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
681 talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
683 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
685 memset(buf, 0, sizeof(buf));
687 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
688 "Failed to create file");
690 cli1->session->pid = 1;
692 torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK),
693 talloc_asprintf(tctx, "Unable to apply read lock on range 130:4, error was %s",
694 smbcli_errstr(cli1->tree)));
696 torture_comment(tctx, "pid1 successfully locked range 130:4 for READ\n");
698 torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
699 talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s)",
700 smbcli_errstr(cli1->tree)));
702 torture_comment(tctx, "pid1 successfully read the range 130:4\n");
704 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
705 torture_comment(tctx, "pid1 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
706 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
707 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
708 } else {
709 torture_fail(tctx, "pid1 successfully wrote to the range 130:4 (should be denied)");
712 cli1->session->pid = 2;
714 if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
715 torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
716 } else {
717 torture_comment(tctx, "pid2 successfully read the range 130:4\n");
720 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
721 torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
722 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
723 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
724 } else {
725 torture_fail(tctx, "pid2 successfully wrote to the range 130:4 (should be denied)");
728 cli1->session->pid = 1;
729 smbcli_unlock(cli1->tree, fnum1, 130, 4);
731 torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, WRITE_LOCK),
732 talloc_asprintf(tctx, "Unable to apply write lock on range 130:4, error was %s",
733 smbcli_errstr(cli1->tree)));
734 torture_comment(tctx, "pid1 successfully locked range 130:4 for WRITE\n");
736 torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
737 talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s",
738 smbcli_errstr(cli1->tree)));
739 torture_comment(tctx, "pid1 successfully read the range 130:4\n");
741 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) == 4,
742 talloc_asprintf(tctx, "pid1 unable to write to the range 130:4, error was %s",
743 smbcli_errstr(cli1->tree)));
744 torture_comment(tctx, "pid1 successfully wrote to the range 130:4\n");
746 cli1->session->pid = 2;
748 if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
749 torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n",
750 smbcli_errstr(cli1->tree));
751 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
752 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
753 } else {
754 torture_fail(tctx, "pid2 successfully read the range 130:4 (should be denied)");
757 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
758 torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n",
759 smbcli_errstr(cli1->tree));
760 if (!NT_STATUS_EQUAL(smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT)) {
761 torture_comment(tctx, "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT) (%s)\n",
762 __location__);
763 goto fail;
765 } else {
766 torture_comment(tctx, "pid2 successfully wrote to the range 130:4 (should be denied) (%s)\n",
767 __location__);
768 goto fail;
771 torture_comment(tctx, "Testing truncate of locked file.\n");
773 fnum2 = smbcli_open(cli1->tree, fname, O_RDWR|O_TRUNC, DENY_NONE);
775 torture_assert(tctx, fnum2 != -1, "Unable to truncate locked file");
777 torture_comment(tctx, "Truncated locked file.\n");
779 torture_assert_ntstatus_ok(tctx, smbcli_getatr(cli1->tree, fname, NULL, &size, NULL),
780 talloc_asprintf(tctx, "getatr failed (%s)", smbcli_errstr(cli1->tree)));
782 torture_assert(tctx, size == 0, talloc_asprintf(tctx, "Unable to truncate locked file. Size was %u", (unsigned)size));
784 cli1->session->pid = 1;
786 smbcli_unlock(cli1->tree, fnum1, 130, 4);
787 correct = true;
789 fail:
790 smbcli_close(cli1->tree, fnum1);
791 smbcli_close(cli1->tree, fnum2);
792 smbcli_unlink(cli1->tree, fname);
794 return correct;
797 struct torture_suite *torture_base_locktest(TALLOC_CTX *mem_ctx)
799 struct torture_suite *suite = torture_suite_create(mem_ctx, "LOCK");
800 torture_suite_add_2smb_test(suite, "LOCK1", torture_locktest1);
801 torture_suite_add_1smb_test(suite, "LOCK2", torture_locktest2);
802 torture_suite_add_2smb_test(suite, "LOCK3", torture_locktest3);
803 torture_suite_add_2smb_test(suite, "LOCK4", torture_locktest4);
804 torture_suite_add_2smb_test(suite, "LOCK5", torture_locktest5);
805 torture_suite_add_1smb_test(suite, "LOCK6", torture_locktest6);
806 torture_suite_add_1smb_test(suite, "LOCK7", torture_locktest7);
808 return suite;