2 Unix SMB/CIFS implementation.
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/>.
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;
49 if (!torture_setup_dir(cli1, BASEDIR)) {
53 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
54 torture_assert(tctx, fnum1 != -1,
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)));
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;
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),
85 "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
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;
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;
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",
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;
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)));
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)));
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)) {
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)));
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;
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;
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;
228 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 100, 4)),
229 "unlock at 100 succeeded! This is a locking bug");
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;
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;
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)));
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";
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)) {
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++) {
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++) {
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));
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));
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));
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++) {
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)));
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";
380 if (!torture_setup_dir(cli1, BASEDIR)) {
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");
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));
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));
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)));
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));
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));
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));
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));
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);
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);
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);
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);
519 torture_comment(tctx, "the server %s have the NT byte range lock bug\n", !ret?"does":"doesn't");
522 smbcli_close(cli1->tree, fnum1);
523 smbcli_close(cli2->tree, fnum2);
524 smbcli_unlink(cli1->tree, fname);
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;
541 if (!torture_setup_dir(cli1, BASEDIR)) {
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));
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));
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));
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
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));
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));
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));
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);
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" };
645 if (!torture_setup_dir(cli, BASEDIR)) {
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]);
670 static bool torture_locktest7(struct torture_context *tctx,
671 struct smbcli_state *cli1)
673 const char *fname = BASEDIR "\\lockt7.lck";
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)");
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));
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)");
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)");
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",
766 torture_comment(tctx, "pid2 successfully wrote to the range 130:4 (should be denied) (%s)\n",
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);
790 smbcli_close(cli1->tree, fnum1);
791 smbcli_close(cli1->tree, fnum2);
792 smbcli_unlink(cli1->tree, fname);
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);