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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "libcli/raw/libcliraw.h"
26 #include "libcli/libcli.h"
27 #include "torture/ui.h"
28 #include "torture/util.h"
29 #include "torture/torture.h"
30 #include "system/time.h"
31 #include "system/filesys.h"
33 #define BASEDIR "\\locktest"
36 This test checks for two things:
38 1) correct support for retaining locks over a close (ie. the server
39 must not use posix semantics)
40 2) support for lock timeouts
42 bool torture_locktest1(struct torture_context *tctx,
43 struct smbcli_state *cli1,
44 struct smbcli_state *cli2)
46 const char *fname = BASEDIR "\\lockt1.lck";
47 int fnum1, fnum2, fnum3;
51 if (!torture_setup_dir(cli1, BASEDIR)) {
55 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
56 torture_assert(tctx, fnum1 != -1,
58 "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
59 fnum2 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
60 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx,
61 "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
62 fnum3 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
63 torture_assert(tctx, fnum3 != -1, talloc_asprintf(tctx,
64 "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
66 torture_assert_ntstatus_ok(tctx,
67 smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK),
68 talloc_asprintf(tctx, "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
71 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
72 "lock2 succeeded! This is a locking bug\n");
74 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
75 NT_STATUS_LOCK_NOT_GRANTED)) return False;
78 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
79 "lock2 succeeded! This is a locking bug\n");
81 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
82 NT_STATUS_FILE_LOCK_CONFLICT)) return False;
84 torture_assert_ntstatus_ok(tctx,
85 smbcli_lock(cli1->tree, fnum1, 5, 9, 0, WRITE_LOCK),
87 "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
90 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 5, 9, 0, WRITE_LOCK)),
91 "lock2 succeeded! This is a locking bug");
93 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
94 NT_STATUS_LOCK_NOT_GRANTED)) return False;
97 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
98 "lock2 succeeded! This is a locking bug");
100 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
101 NT_STATUS_LOCK_NOT_GRANTED)) return False;
104 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
105 "lock2 succeeded! This is a locking bug");
107 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
108 NT_STATUS_FILE_LOCK_CONFLICT)) return False;
110 lock_timeout = (6 + (random() % 20));
111 torture_comment(tctx, "Testing lock timeout with timeout=%u\n",
115 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, lock_timeout * 1000, WRITE_LOCK)),
116 "lock3 succeeded! This is a locking bug\n");
118 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
119 NT_STATUS_FILE_LOCK_CONFLICT)) return False;
124 "error: This server appears not to support timed lock requests");
126 torture_comment(tctx, "server slept for %u seconds for a %u second timeout\n",
127 (uint_t)(t2-t1), lock_timeout);
129 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum2),
130 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
133 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
134 "lock4 succeeded! This is a locking bug");
136 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
137 NT_STATUS_FILE_LOCK_CONFLICT)) return False;
139 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
140 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli1->tree)));
142 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum3),
143 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli2->tree)));
145 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
146 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
153 This test checks that
155 1) the server supports multiple locking contexts on the one SMB
156 connection, distinguished by PID.
158 2) the server correctly fails overlapping locks made by the same PID (this
159 goes against POSIX behaviour, which is why it is tricky to implement)
161 3) the server denies unlock requests by an incorrect client PID
163 bool torture_locktest2(struct torture_context *tctx,
164 struct smbcli_state *cli)
166 const char *fname = BASEDIR "\\lockt2.lck";
167 int fnum1, fnum2, fnum3;
169 if (!torture_setup_dir(cli, BASEDIR)) {
173 torture_comment(tctx, "Testing pid context\n");
175 cli->session->pid = 1;
177 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
178 torture_assert(tctx, fnum1 != -1,
179 talloc_asprintf(tctx,
180 "open of %s failed (%s)", fname, smbcli_errstr(cli->tree)));
182 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
183 torture_assert(tctx, fnum2 != -1,
184 talloc_asprintf(tctx, "open2 of %s failed (%s)",
185 fname, smbcli_errstr(cli->tree)));
187 cli->session->pid = 2;
189 fnum3 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
190 torture_assert(tctx, fnum3 != -1,
191 talloc_asprintf(tctx,
192 "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)));
194 cli->session->pid = 1;
196 torture_assert_ntstatus_ok(tctx,
197 smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK),
198 talloc_asprintf(tctx,
199 "lock1 failed (%s)", smbcli_errstr(cli->tree)));
202 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK)),
203 "WRITE lock1 succeeded! This is a locking bug");
205 if (!check_error(__location__, cli, ERRDOS, ERRlock,
206 NT_STATUS_LOCK_NOT_GRANTED)) return False;
209 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, WRITE_LOCK)),
210 "WRITE lock2 succeeded! This is a locking bug");
212 if (!check_error(__location__, cli, ERRDOS, ERRlock,
213 NT_STATUS_LOCK_NOT_GRANTED)) return False;
216 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, READ_LOCK)),
217 "READ lock2 succeeded! This is a locking bug");
219 if (!check_error(__location__, cli, ERRDOS, ERRlock,
220 NT_STATUS_FILE_LOCK_CONFLICT)) return False;
222 torture_assert_ntstatus_ok(tctx,
223 smbcli_lock(cli->tree, fnum1, 100, 4, 0, WRITE_LOCK),
224 talloc_asprintf(tctx,
225 "lock at 100 failed (%s)", smbcli_errstr(cli->tree)));
227 cli->session->pid = 2;
230 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 100, 4)),
231 "unlock at 100 succeeded! This is a locking bug");
234 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 4)),
235 "unlock1 succeeded! This is a locking bug");
237 if (!check_error(__location__, cli,
238 ERRDOS, ERRnotlocked,
239 NT_STATUS_RANGE_NOT_LOCKED)) return False;
242 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 8)),
243 "unlock2 succeeded! This is a locking bug");
245 if (!check_error(__location__, cli,
246 ERRDOS, ERRnotlocked,
247 NT_STATUS_RANGE_NOT_LOCKED)) return False;
250 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
251 "lock3 succeeded! This is a locking bug");
253 if (!check_error(__location__, cli, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return False;
255 cli->session->pid = 1;
257 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum1),
258 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli->tree)));
260 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum2),
261 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli->tree)));
263 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum3),
264 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli->tree)));
271 This test checks that
273 1) the server supports the full offset range in lock requests
275 bool torture_locktest3(struct torture_context *tctx,
276 struct smbcli_state *cli1,
277 struct smbcli_state *cli2)
279 const char *fname = BASEDIR "\\lockt3.lck";
282 extern int torture_numops;
284 #define NEXT_OFFSET offset += (~(uint32_t)0) / torture_numops
286 torture_comment(tctx, "Testing 32 bit offset ranges");
288 if (!torture_setup_dir(cli1, BASEDIR)) {
292 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
293 torture_assert(tctx, fnum1 != -1,
294 talloc_asprintf(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
295 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
296 torture_assert(tctx, fnum2 != -1,
297 talloc_asprintf(tctx, "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
299 torture_comment(tctx, "Establishing %d locks\n", torture_numops);
301 for (offset=i=0;i<torture_numops;i++) {
303 torture_assert_ntstatus_ok(tctx,
304 smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK),
305 talloc_asprintf(tctx, "lock1 %d failed (%s)", i, smbcli_errstr(cli1->tree)));
307 torture_assert_ntstatus_ok(tctx,
308 smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK),
309 talloc_asprintf(tctx, "lock2 %d failed (%s)",
310 i, smbcli_errstr(cli1->tree)));
313 torture_comment(tctx, "Testing %d locks\n", torture_numops);
315 for (offset=i=0;i<torture_numops;i++) {
319 !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-2, 1, 0, WRITE_LOCK)),
320 talloc_asprintf(tctx, "error: lock1 %d succeeded!", i));
323 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-1, 1, 0, WRITE_LOCK)),
324 talloc_asprintf(tctx, "error: lock2 %d succeeded!", i));
327 !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK)),
328 talloc_asprintf(tctx, "error: lock3 %d succeeded!", i));
331 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK)),
332 talloc_asprintf(tctx, "error: lock4 %d succeeded!", i));
335 torture_comment(tctx, "Removing %d locks\n", torture_numops);
337 for (offset=i=0;i<torture_numops;i++) {
340 torture_assert_ntstatus_ok(tctx,
341 smbcli_unlock(cli1->tree, fnum1, offset-1, 1),
342 talloc_asprintf(tctx, "unlock1 %d failed (%s)",
344 smbcli_errstr(cli1->tree)));
346 torture_assert_ntstatus_ok(tctx,
347 smbcli_unlock(cli2->tree, fnum2, offset-2, 1),
348 talloc_asprintf(tctx, "unlock2 %d failed (%s)",
350 smbcli_errstr(cli1->tree)));
353 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
354 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
356 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
357 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
359 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
360 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
365 #define EXPECTED(ret, v) if ((ret) != (v)) { \
366 torture_comment(tctx, "** "); correct = False; \
370 looks at overlapping locks
372 BOOL torture_locktest4(struct torture_context *tctx,
373 struct smbcli_state *cli1,
374 struct smbcli_state *cli2)
376 const char *fname = BASEDIR "\\lockt4.lck";
382 if (!torture_setup_dir(cli1, BASEDIR)) {
386 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
387 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
389 memset(buf, 0, sizeof(buf));
391 if (smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
392 torture_comment(tctx, "Failed to create file\n");
397 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
398 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 2, 4, 0, WRITE_LOCK));
399 EXPECTED(ret, False);
400 torture_comment(tctx, "the same process %s set overlapping write locks\n", ret?"can":"cannot");
402 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 10, 4, 0, READ_LOCK)) &&
403 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 12, 4, 0, READ_LOCK));
405 torture_comment(tctx, "the same process %s set overlapping read locks\n", ret?"can":"cannot");
407 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 20, 4, 0, WRITE_LOCK)) &&
408 NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 22, 4, 0, WRITE_LOCK));
409 EXPECTED(ret, False);
410 torture_comment(tctx, "a different connection %s set overlapping write locks\n", ret?"can":"cannot");
412 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 30, 4, 0, READ_LOCK)) &&
413 NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 32, 4, 0, READ_LOCK));
415 torture_comment(tctx, "a different connection %s set overlapping read locks\n", ret?"can":"cannot");
417 ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 40, 4, 0, WRITE_LOCK))) &&
418 NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 42, 4, 0, WRITE_LOCK)));
419 EXPECTED(ret, False);
420 torture_comment(tctx, "a different pid %s set overlapping write locks\n", ret?"can":"cannot");
422 ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 50, 4, 0, READ_LOCK))) &&
423 NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 52, 4, 0, READ_LOCK)));
425 torture_comment(tctx, "a different pid %s set overlapping read locks\n", ret?"can":"cannot");
427 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK)) &&
428 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK));
430 torture_comment(tctx, "the same process %s set the same read lock twice\n", ret?"can":"cannot");
432 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK)) &&
433 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK));
434 EXPECTED(ret, False);
435 torture_comment(tctx, "the same process %s set the same write lock twice\n", ret?"can":"cannot");
437 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, READ_LOCK)) &&
438 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, WRITE_LOCK));
439 EXPECTED(ret, False);
440 torture_comment(tctx, "the same process %s overlay a read lock with a write lock\n", ret?"can":"cannot");
442 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, WRITE_LOCK)) &&
443 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, READ_LOCK));
445 torture_comment(tctx, "the same process %s overlay a write lock with a read lock\n", ret?"can":"cannot");
447 ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, WRITE_LOCK))) &&
448 NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, READ_LOCK)));
449 EXPECTED(ret, False);
450 torture_comment(tctx, "a different pid %s overlay a write lock with a read lock\n", ret?"can":"cannot");
452 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 110, 4, 0, READ_LOCK)) &&
453 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 112, 4, 0, READ_LOCK)) &&
454 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 110, 6));
455 EXPECTED(ret, False);
456 torture_comment(tctx, "the same process %s coalesce read locks\n", ret?"can":"cannot");
459 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 120, 4, 0, WRITE_LOCK)) &&
460 (smbcli_read(cli2->tree, fnum2, buf, 120, 4) == 4);
461 EXPECTED(ret, False);
462 torture_comment(tctx, "this server %s strict write locking\n", ret?"doesn't do":"does");
464 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK)) &&
465 (smbcli_write(cli2->tree, fnum2, 0, buf, 130, 4) == 4);
466 EXPECTED(ret, False);
467 torture_comment(tctx, "this server %s strict read locking\n", ret?"doesn't do":"does");
470 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
471 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
472 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4)) &&
473 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4));
475 torture_comment(tctx, "this server %s do recursive read locking\n", ret?"does":"doesn't");
478 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, WRITE_LOCK)) &&
479 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, READ_LOCK)) &&
480 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4)) &&
481 (smbcli_read(cli2->tree, fnum2, buf, 150, 4) == 4) &&
482 !(smbcli_write(cli2->tree, fnum2, 0, buf, 150, 4) == 4) &&
483 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4));
485 torture_comment(tctx, "this server %s do recursive lock overlays\n", ret?"does":"doesn't");
487 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 160, 4, 0, READ_LOCK)) &&
488 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 160, 4)) &&
489 (smbcli_write(cli2->tree, fnum2, 0, buf, 160, 4) == 4) &&
490 (smbcli_read(cli2->tree, fnum2, buf, 160, 4) == 4);
492 torture_comment(tctx, "the same process %s remove a read lock using write locking\n", ret?"can":"cannot");
494 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 170, 4, 0, WRITE_LOCK)) &&
495 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 170, 4)) &&
496 (smbcli_write(cli2->tree, fnum2, 0, buf, 170, 4) == 4) &&
497 (smbcli_read(cli2->tree, fnum2, buf, 170, 4) == 4);
499 torture_comment(tctx, "the same process %s remove a write lock using read locking\n", ret?"can":"cannot");
501 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, WRITE_LOCK)) &&
502 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, READ_LOCK)) &&
503 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 190, 4)) &&
504 !(smbcli_write(cli2->tree, fnum2, 0, buf, 190, 4) == 4) &&
505 (smbcli_read(cli2->tree, fnum2, buf, 190, 4) == 4);
507 torture_comment(tctx, "the same process %s remove the first lock first\n", ret?"does":"doesn't");
509 smbcli_close(cli1->tree, fnum1);
510 smbcli_close(cli2->tree, fnum2);
511 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
512 f = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
513 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
514 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, f, 0, 1, 0, READ_LOCK)) &&
515 NT_STATUS_IS_OK(smbcli_close(cli1->tree, fnum1)) &&
516 ((fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE)) != -1) &&
517 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
518 smbcli_close(cli1->tree, f);
519 smbcli_close(cli1->tree, fnum1);
521 torture_comment(tctx, "the server %s have the NT byte range lock bug\n", !ret?"does":"doesn't");
524 smbcli_close(cli1->tree, fnum1);
525 smbcli_close(cli2->tree, fnum2);
526 smbcli_unlink(cli1->tree, fname);
532 looks at lock upgrade/downgrade.
534 BOOL torture_locktest5(struct torture_context *tctx, struct smbcli_state *cli1,
535 struct smbcli_state *cli2)
537 const char *fname = BASEDIR "\\lockt5.lck";
538 int fnum1, fnum2, fnum3;
543 if (!torture_setup_dir(cli1, BASEDIR)) {
547 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
548 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
549 fnum3 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
551 memset(buf, 0, sizeof(buf));
553 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
554 "Failed to create file");
556 /* Check for NT bug... */
557 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
558 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 1, 0, READ_LOCK));
559 smbcli_close(cli1->tree, fnum1);
560 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
561 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
563 torture_comment(tctx, "this server %s the NT locking bug\n", ret ? "doesn't have" : "has");
564 smbcli_close(cli1->tree, fnum1);
565 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
566 smbcli_unlock(cli1->tree, fnum3, 0, 1);
568 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
569 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 1, 1, 0, READ_LOCK));
571 torture_comment(tctx, "the same process %s overlay a write with a read lock\n", ret?"can":"cannot");
573 ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
574 EXPECTED(ret, False);
576 torture_comment(tctx, "a different processs %s get a read lock on the first process lock stack\n", ret?"can":"cannot");
578 /* Unlock the process 2 lock. */
579 smbcli_unlock(cli2->tree, fnum2, 0, 4);
581 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 4, 0, READ_LOCK));
582 EXPECTED(ret, False);
584 torture_comment(tctx, "the same processs on a different fnum %s get a read lock\n", ret?"can":"cannot");
586 /* Unlock the process 1 fnum3 lock. */
587 smbcli_unlock(cli1->tree, fnum3, 0, 4);
589 /* Stack 2 more locks here. */
590 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK)) &&
591 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK));
594 torture_comment(tctx, "the same process %s stack read locks\n", ret?"can":"cannot");
596 /* Unlock the first process lock, then check this was the WRITE lock that was
599 ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
600 NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
603 torture_comment(tctx, "the first unlock removes the %s lock\n", ret?"WRITE":"READ");
605 /* Unlock the process 2 lock. */
606 smbcli_unlock(cli2->tree, fnum2, 0, 4);
608 /* We should have 3 stacked locks here. Ensure we need to do 3 unlocks. */
610 ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 1, 1)) &&
611 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
612 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
615 torture_comment(tctx, "the same process %s unlock the stack of 4 locks\n", ret?"can":"cannot");
617 /* Ensure the next unlock fails. */
618 ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
619 EXPECTED(ret, False);
620 torture_comment(tctx, "the same process %s count the lock stack\n", !ret?"can":"cannot");
622 /* Ensure connection 2 can get a write lock. */
623 ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, WRITE_LOCK));
626 torture_comment(tctx, "a different processs %s get a write lock on the unlocked stack\n", ret?"can":"cannot");
629 smbcli_close(cli1->tree, fnum1);
630 smbcli_close(cli2->tree, fnum2);
631 smbcli_unlink(cli1->tree, fname);
637 tries the unusual lockingX locktype bits
639 BOOL torture_locktest6(struct torture_context *tctx,
640 struct smbcli_state *cli)
642 const char *fname[1] = { "\\lock6.txt" };
647 if (!torture_setup_dir(cli, BASEDIR)) {
652 torture_comment(tctx, "Testing %s\n", fname[i]);
654 smbcli_unlink(cli->tree, fname[i]);
656 fnum = smbcli_open(cli->tree, fname[i], O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
657 status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CHANGE_LOCKTYPE);
658 smbcli_close(cli->tree, fnum);
659 torture_comment(tctx, "CHANGE_LOCKTYPE gave %s\n", nt_errstr(status));
661 fnum = smbcli_open(cli->tree, fname[i], O_RDWR, DENY_NONE);
662 status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CANCEL_LOCK);
663 smbcli_close(cli->tree, fnum);
664 torture_comment(tctx, "CANCEL_LOCK gave %s\n", nt_errstr(status));
666 smbcli_unlink(cli->tree, fname[i]);
672 BOOL torture_locktest7(struct torture_context *tctx,
673 struct smbcli_state *cli1)
675 const char *fname = BASEDIR "\\lockt7.lck";
680 BOOL correct = False;
682 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
683 talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
685 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
687 memset(buf, 0, sizeof(buf));
689 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
690 "Failed to create file");
692 cli1->session->pid = 1;
694 torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK),
695 talloc_asprintf(tctx, "Unable to apply read lock on range 130:4, error was %s",
696 smbcli_errstr(cli1->tree)));
698 torture_comment(tctx, "pid1 successfully locked range 130:4 for READ\n");
700 torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
701 talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s)",
702 smbcli_errstr(cli1->tree)));
704 torture_comment(tctx, "pid1 successfully read the range 130:4\n");
706 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
707 torture_comment(tctx, "pid1 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
708 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
709 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
711 torture_fail(tctx, "pid1 successfully wrote to the range 130:4 (should be denied)");
714 cli1->session->pid = 2;
716 if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
717 torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
719 torture_comment(tctx, "pid2 successfully read the range 130:4\n");
722 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
723 torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
724 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
725 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
727 torture_fail(tctx, "pid2 successfully wrote to the range 130:4 (should be denied)");
730 cli1->session->pid = 1;
731 smbcli_unlock(cli1->tree, fnum1, 130, 4);
733 torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, WRITE_LOCK),
734 talloc_asprintf(tctx, "Unable to apply write lock on range 130:4, error was %s",
735 smbcli_errstr(cli1->tree)));
736 torture_comment(tctx, "pid1 successfully locked range 130:4 for WRITE\n");
738 torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
739 talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s",
740 smbcli_errstr(cli1->tree)));
741 torture_comment(tctx, "pid1 successfully read the range 130:4\n");
743 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) == 4,
744 talloc_asprintf(tctx, "pid1 unable to write to the range 130:4, error was %s",
745 smbcli_errstr(cli1->tree)));
746 torture_comment(tctx, "pid1 successfully wrote to the range 130:4\n");
748 cli1->session->pid = 2;
750 if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
751 torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n",
752 smbcli_errstr(cli1->tree));
753 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
754 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
756 torture_fail(tctx, "pid2 successfully read the range 130:4 (should be denied)");
759 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
760 torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n",
761 smbcli_errstr(cli1->tree));
762 if (!NT_STATUS_EQUAL(smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT)) {
763 torture_comment(tctx, "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT) (%s)\n",
768 torture_comment(tctx, "pid2 successfully wrote to the range 130:4 (should be denied) (%s)\n",
773 torture_comment(tctx, "Testing truncate of locked file.\n");
775 fnum2 = smbcli_open(cli1->tree, fname, O_RDWR|O_TRUNC, DENY_NONE);
777 torture_assert(tctx, fnum2 != -1, "Unable to truncate locked file");
779 torture_comment(tctx, "Truncated locked file.\n");
781 torture_assert_ntstatus_ok(tctx, smbcli_getatr(cli1->tree, fname, NULL, &size, NULL),
782 talloc_asprintf(tctx, "getatr failed (%s)", smbcli_errstr(cli1->tree)));
784 torture_assert(tctx, size == 0, talloc_asprintf(tctx, "Unable to truncate locked file. Size was %u", (unsigned)size));
786 cli1->session->pid = 1;
788 smbcli_unlock(cli1->tree, fnum1, 130, 4);
792 smbcli_close(cli1->tree, fnum1);
793 smbcli_close(cli1->tree, fnum2);
794 smbcli_unlink(cli1->tree, fname);
799 struct torture_suite *torture_base_locktest(void)
801 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(),
803 torture_suite_add_2smb_test(suite, "LOCK1", torture_locktest1);
804 torture_suite_add_1smb_test(suite, "LOCK2", torture_locktest2);
805 torture_suite_add_2smb_test(suite, "LOCK3", torture_locktest3);
806 torture_suite_add_2smb_test(suite, "LOCK4", torture_locktest4);
807 torture_suite_add_2smb_test(suite, "LOCK5", torture_locktest5);
808 torture_suite_add_1smb_test(suite, "LOCK6", torture_locktest6);
809 torture_suite_add_1smb_test(suite, "LOCK7", torture_locktest7);