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/ui.h"
27 #include "torture/util.h"
28 #include "torture/torture.h"
29 #include "system/time.h"
30 #include "system/filesys.h"
32 #define BASEDIR "\\locktest"
35 This test checks for two things:
37 1) correct support for retaining locks over a close (ie. the server
38 must not use posix semantics)
39 2) support for lock timeouts
41 bool torture_locktest1(struct torture_context *tctx,
42 struct smbcli_state *cli1,
43 struct smbcli_state *cli2)
45 const char *fname = BASEDIR "\\lockt1.lck";
46 int fnum1, fnum2, fnum3;
50 if (!torture_setup_dir(cli1, BASEDIR)) {
54 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
55 torture_assert(tctx, fnum1 != -1,
57 "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
58 fnum2 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
59 torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx,
60 "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
61 fnum3 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
62 torture_assert(tctx, fnum3 != -1, talloc_asprintf(tctx,
63 "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
65 torture_assert_ntstatus_ok(tctx,
66 smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK),
67 talloc_asprintf(tctx, "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
70 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
71 "lock2 succeeded! This is a locking bug\n");
73 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
74 NT_STATUS_LOCK_NOT_GRANTED)) return False;
77 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
78 "lock2 succeeded! This is a locking bug\n");
80 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
81 NT_STATUS_FILE_LOCK_CONFLICT)) return False;
83 torture_assert_ntstatus_ok(tctx,
84 smbcli_lock(cli1->tree, fnum1, 5, 9, 0, WRITE_LOCK),
86 "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
89 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 5, 9, 0, WRITE_LOCK)),
90 "lock2 succeeded! This is a locking bug");
92 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
93 NT_STATUS_LOCK_NOT_GRANTED)) return False;
96 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
97 "lock2 succeeded! This is a locking bug");
99 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
100 NT_STATUS_LOCK_NOT_GRANTED)) return False;
103 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
104 "lock2 succeeded! This is a locking bug");
106 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
107 NT_STATUS_FILE_LOCK_CONFLICT)) return False;
109 lock_timeout = (6 + (random() % 20));
110 torture_comment(tctx, "Testing lock timeout with timeout=%u\n",
114 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, lock_timeout * 1000, WRITE_LOCK)),
115 "lock3 succeeded! This is a locking bug\n");
117 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
118 NT_STATUS_FILE_LOCK_CONFLICT)) return False;
123 "error: This server appears not to support timed lock requests");
125 torture_comment(tctx, "server slept for %u seconds for a %u second timeout\n",
126 (uint_t)(t2-t1), lock_timeout);
128 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum2),
129 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
132 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
133 "lock4 succeeded! This is a locking bug");
135 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
136 NT_STATUS_FILE_LOCK_CONFLICT)) return False;
138 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
139 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli1->tree)));
141 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum3),
142 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli2->tree)));
144 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
145 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
152 This test checks that
154 1) the server supports multiple locking contexts on the one SMB
155 connection, distinguished by PID.
157 2) the server correctly fails overlapping locks made by the same PID (this
158 goes against POSIX behaviour, which is why it is tricky to implement)
160 3) the server denies unlock requests by an incorrect client PID
162 bool torture_locktest2(struct torture_context *tctx,
163 struct smbcli_state *cli)
165 const char *fname = BASEDIR "\\lockt2.lck";
166 int fnum1, fnum2, fnum3;
168 if (!torture_setup_dir(cli, BASEDIR)) {
172 torture_comment(tctx, "Testing pid context\n");
174 cli->session->pid = 1;
176 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
177 torture_assert(tctx, fnum1 != -1,
178 talloc_asprintf(tctx,
179 "open of %s failed (%s)", fname, smbcli_errstr(cli->tree)));
181 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
182 torture_assert(tctx, fnum2 != -1,
183 talloc_asprintf(tctx, "open2 of %s failed (%s)",
184 fname, smbcli_errstr(cli->tree)));
186 cli->session->pid = 2;
188 fnum3 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
189 torture_assert(tctx, fnum3 != -1,
190 talloc_asprintf(tctx,
191 "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)));
193 cli->session->pid = 1;
195 torture_assert_ntstatus_ok(tctx,
196 smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK),
197 talloc_asprintf(tctx,
198 "lock1 failed (%s)", smbcli_errstr(cli->tree)));
201 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK)),
202 "WRITE lock1 succeeded! This is a locking bug");
204 if (!check_error(__location__, cli, ERRDOS, ERRlock,
205 NT_STATUS_LOCK_NOT_GRANTED)) return False;
208 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, WRITE_LOCK)),
209 "WRITE lock2 succeeded! This is a locking bug");
211 if (!check_error(__location__, cli, ERRDOS, ERRlock,
212 NT_STATUS_LOCK_NOT_GRANTED)) return False;
215 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, READ_LOCK)),
216 "READ lock2 succeeded! This is a locking bug");
218 if (!check_error(__location__, cli, ERRDOS, ERRlock,
219 NT_STATUS_FILE_LOCK_CONFLICT)) return False;
221 torture_assert_ntstatus_ok(tctx,
222 smbcli_lock(cli->tree, fnum1, 100, 4, 0, WRITE_LOCK),
223 talloc_asprintf(tctx,
224 "lock at 100 failed (%s)", smbcli_errstr(cli->tree)));
226 cli->session->pid = 2;
229 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 100, 4)),
230 "unlock at 100 succeeded! This is a locking bug");
233 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 4)),
234 "unlock1 succeeded! This is a locking bug");
236 if (!check_error(__location__, cli,
237 ERRDOS, ERRnotlocked,
238 NT_STATUS_RANGE_NOT_LOCKED)) return False;
241 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 8)),
242 "unlock2 succeeded! This is a locking bug");
244 if (!check_error(__location__, cli,
245 ERRDOS, ERRnotlocked,
246 NT_STATUS_RANGE_NOT_LOCKED)) return False;
249 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
250 "lock3 succeeded! This is a locking bug");
252 if (!check_error(__location__, cli, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return False;
254 cli->session->pid = 1;
256 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum1),
257 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli->tree)));
259 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum2),
260 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli->tree)));
262 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum3),
263 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli->tree)));
270 This test checks that
272 1) the server supports the full offset range in lock requests
274 bool torture_locktest3(struct torture_context *tctx,
275 struct smbcli_state *cli1,
276 struct smbcli_state *cli2)
278 const char *fname = BASEDIR "\\lockt3.lck";
281 extern int torture_numops;
283 #define NEXT_OFFSET offset += (~(uint32_t)0) / torture_numops
285 torture_comment(tctx, "Testing 32 bit offset ranges");
287 if (!torture_setup_dir(cli1, BASEDIR)) {
291 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
292 torture_assert(tctx, fnum1 != -1,
293 talloc_asprintf(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
294 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
295 torture_assert(tctx, fnum2 != -1,
296 talloc_asprintf(tctx, "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
298 torture_comment(tctx, "Establishing %d locks\n", torture_numops);
300 for (offset=i=0;i<torture_numops;i++) {
302 torture_assert_ntstatus_ok(tctx,
303 smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK),
304 talloc_asprintf(tctx, "lock1 %d failed (%s)", i, smbcli_errstr(cli1->tree)));
306 torture_assert_ntstatus_ok(tctx,
307 smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK),
308 talloc_asprintf(tctx, "lock2 %d failed (%s)",
309 i, smbcli_errstr(cli1->tree)));
312 torture_comment(tctx, "Testing %d locks\n", torture_numops);
314 for (offset=i=0;i<torture_numops;i++) {
318 !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-2, 1, 0, WRITE_LOCK)),
319 talloc_asprintf(tctx, "error: lock1 %d succeeded!", i));
322 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-1, 1, 0, WRITE_LOCK)),
323 talloc_asprintf(tctx, "error: lock2 %d succeeded!", i));
326 !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK)),
327 talloc_asprintf(tctx, "error: lock3 %d succeeded!", i));
330 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK)),
331 talloc_asprintf(tctx, "error: lock4 %d succeeded!", i));
334 torture_comment(tctx, "Removing %d locks\n", torture_numops);
336 for (offset=i=0;i<torture_numops;i++) {
339 torture_assert_ntstatus_ok(tctx,
340 smbcli_unlock(cli1->tree, fnum1, offset-1, 1),
341 talloc_asprintf(tctx, "unlock1 %d failed (%s)",
343 smbcli_errstr(cli1->tree)));
345 torture_assert_ntstatus_ok(tctx,
346 smbcli_unlock(cli2->tree, fnum2, offset-2, 1),
347 talloc_asprintf(tctx, "unlock2 %d failed (%s)",
349 smbcli_errstr(cli1->tree)));
352 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
353 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
355 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
356 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
358 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
359 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
364 #define EXPECTED(ret, v) if ((ret) != (v)) { \
365 torture_comment(tctx, "** "); correct = False; \
369 looks at overlapping locks
371 BOOL torture_locktest4(struct torture_context *tctx,
372 struct smbcli_state *cli1,
373 struct smbcli_state *cli2)
375 const char *fname = BASEDIR "\\lockt4.lck";
381 if (!torture_setup_dir(cli1, BASEDIR)) {
385 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
386 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
388 memset(buf, 0, sizeof(buf));
390 if (smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
391 torture_comment(tctx, "Failed to create file\n");
396 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
397 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 2, 4, 0, WRITE_LOCK));
398 EXPECTED(ret, False);
399 torture_comment(tctx, "the same process %s set overlapping write locks\n", ret?"can":"cannot");
401 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 10, 4, 0, READ_LOCK)) &&
402 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 12, 4, 0, READ_LOCK));
404 torture_comment(tctx, "the same process %s set overlapping read locks\n", ret?"can":"cannot");
406 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 20, 4, 0, WRITE_LOCK)) &&
407 NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 22, 4, 0, WRITE_LOCK));
408 EXPECTED(ret, False);
409 torture_comment(tctx, "a different connection %s set overlapping write locks\n", ret?"can":"cannot");
411 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 30, 4, 0, READ_LOCK)) &&
412 NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 32, 4, 0, READ_LOCK));
414 torture_comment(tctx, "a different connection %s set overlapping read locks\n", ret?"can":"cannot");
416 ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 40, 4, 0, WRITE_LOCK))) &&
417 NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 42, 4, 0, WRITE_LOCK)));
418 EXPECTED(ret, False);
419 torture_comment(tctx, "a different pid %s set overlapping write locks\n", ret?"can":"cannot");
421 ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 50, 4, 0, READ_LOCK))) &&
422 NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 52, 4, 0, READ_LOCK)));
424 torture_comment(tctx, "a different pid %s set overlapping read locks\n", ret?"can":"cannot");
426 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK)) &&
427 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK));
429 torture_comment(tctx, "the same process %s set the same read lock twice\n", ret?"can":"cannot");
431 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK)) &&
432 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK));
433 EXPECTED(ret, False);
434 torture_comment(tctx, "the same process %s set the same write lock twice\n", ret?"can":"cannot");
436 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, READ_LOCK)) &&
437 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, WRITE_LOCK));
438 EXPECTED(ret, False);
439 torture_comment(tctx, "the same process %s overlay a read lock with a write lock\n", ret?"can":"cannot");
441 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, WRITE_LOCK)) &&
442 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, READ_LOCK));
444 torture_comment(tctx, "the same process %s overlay a write lock with a read lock\n", ret?"can":"cannot");
446 ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, WRITE_LOCK))) &&
447 NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, READ_LOCK)));
448 EXPECTED(ret, False);
449 torture_comment(tctx, "a different pid %s overlay a write lock with a read lock\n", ret?"can":"cannot");
451 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 110, 4, 0, READ_LOCK)) &&
452 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 112, 4, 0, READ_LOCK)) &&
453 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 110, 6));
454 EXPECTED(ret, False);
455 torture_comment(tctx, "the same process %s coalesce read locks\n", ret?"can":"cannot");
458 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 120, 4, 0, WRITE_LOCK)) &&
459 (smbcli_read(cli2->tree, fnum2, buf, 120, 4) == 4);
460 EXPECTED(ret, False);
461 torture_comment(tctx, "this server %s strict write locking\n", ret?"doesn't do":"does");
463 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK)) &&
464 (smbcli_write(cli2->tree, fnum2, 0, buf, 130, 4) == 4);
465 EXPECTED(ret, False);
466 torture_comment(tctx, "this server %s strict read locking\n", ret?"doesn't do":"does");
469 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
470 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
471 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4)) &&
472 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4));
474 torture_comment(tctx, "this server %s do recursive read locking\n", ret?"does":"doesn't");
477 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, WRITE_LOCK)) &&
478 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, READ_LOCK)) &&
479 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4)) &&
480 (smbcli_read(cli2->tree, fnum2, buf, 150, 4) == 4) &&
481 !(smbcli_write(cli2->tree, fnum2, 0, buf, 150, 4) == 4) &&
482 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4));
484 torture_comment(tctx, "this server %s do recursive lock overlays\n", ret?"does":"doesn't");
486 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 160, 4, 0, READ_LOCK)) &&
487 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 160, 4)) &&
488 (smbcli_write(cli2->tree, fnum2, 0, buf, 160, 4) == 4) &&
489 (smbcli_read(cli2->tree, fnum2, buf, 160, 4) == 4);
491 torture_comment(tctx, "the same process %s remove a read lock using write locking\n", ret?"can":"cannot");
493 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 170, 4, 0, WRITE_LOCK)) &&
494 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 170, 4)) &&
495 (smbcli_write(cli2->tree, fnum2, 0, buf, 170, 4) == 4) &&
496 (smbcli_read(cli2->tree, fnum2, buf, 170, 4) == 4);
498 torture_comment(tctx, "the same process %s remove a write lock using read locking\n", ret?"can":"cannot");
500 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, WRITE_LOCK)) &&
501 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, READ_LOCK)) &&
502 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 190, 4)) &&
503 !(smbcli_write(cli2->tree, fnum2, 0, buf, 190, 4) == 4) &&
504 (smbcli_read(cli2->tree, fnum2, buf, 190, 4) == 4);
506 torture_comment(tctx, "the same process %s remove the first lock first\n", ret?"does":"doesn't");
508 smbcli_close(cli1->tree, fnum1);
509 smbcli_close(cli2->tree, fnum2);
510 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
511 f = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
512 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
513 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, f, 0, 1, 0, READ_LOCK)) &&
514 NT_STATUS_IS_OK(smbcli_close(cli1->tree, fnum1)) &&
515 ((fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE)) != -1) &&
516 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
517 smbcli_close(cli1->tree, f);
518 smbcli_close(cli1->tree, fnum1);
520 torture_comment(tctx, "the server %s have the NT byte range lock bug\n", !ret?"does":"doesn't");
523 smbcli_close(cli1->tree, fnum1);
524 smbcli_close(cli2->tree, fnum2);
525 smbcli_unlink(cli1->tree, fname);
531 looks at lock upgrade/downgrade.
533 BOOL torture_locktest5(struct torture_context *tctx, struct smbcli_state *cli1,
534 struct smbcli_state *cli2)
536 const char *fname = BASEDIR "\\lockt5.lck";
537 int fnum1, fnum2, fnum3;
542 if (!torture_setup_dir(cli1, BASEDIR)) {
546 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
547 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
548 fnum3 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
550 memset(buf, 0, sizeof(buf));
552 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
553 "Failed to create file");
555 /* Check for NT bug... */
556 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
557 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 1, 0, READ_LOCK));
558 smbcli_close(cli1->tree, fnum1);
559 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
560 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
562 torture_comment(tctx, "this server %s the NT locking bug\n", ret ? "doesn't have" : "has");
563 smbcli_close(cli1->tree, fnum1);
564 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
565 smbcli_unlock(cli1->tree, fnum3, 0, 1);
567 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
568 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 1, 1, 0, READ_LOCK));
570 torture_comment(tctx, "the same process %s overlay a write with a read lock\n", ret?"can":"cannot");
572 ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
573 EXPECTED(ret, False);
575 torture_comment(tctx, "a different processs %s get a read lock on the first process lock stack\n", ret?"can":"cannot");
577 /* Unlock the process 2 lock. */
578 smbcli_unlock(cli2->tree, fnum2, 0, 4);
580 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 4, 0, READ_LOCK));
581 EXPECTED(ret, False);
583 torture_comment(tctx, "the same processs on a different fnum %s get a read lock\n", ret?"can":"cannot");
585 /* Unlock the process 1 fnum3 lock. */
586 smbcli_unlock(cli1->tree, fnum3, 0, 4);
588 /* Stack 2 more locks here. */
589 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK)) &&
590 NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK));
593 torture_comment(tctx, "the same process %s stack read locks\n", ret?"can":"cannot");
595 /* Unlock the first process lock, then check this was the WRITE lock that was
598 ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
599 NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
602 torture_comment(tctx, "the first unlock removes the %s lock\n", ret?"WRITE":"READ");
604 /* Unlock the process 2 lock. */
605 smbcli_unlock(cli2->tree, fnum2, 0, 4);
607 /* We should have 3 stacked locks here. Ensure we need to do 3 unlocks. */
609 ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 1, 1)) &&
610 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
611 NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
614 torture_comment(tctx, "the same process %s unlock the stack of 4 locks\n", ret?"can":"cannot");
616 /* Ensure the next unlock fails. */
617 ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
618 EXPECTED(ret, False);
619 torture_comment(tctx, "the same process %s count the lock stack\n", !ret?"can":"cannot");
621 /* Ensure connection 2 can get a write lock. */
622 ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, WRITE_LOCK));
625 torture_comment(tctx, "a different processs %s get a write lock on the unlocked stack\n", ret?"can":"cannot");
628 smbcli_close(cli1->tree, fnum1);
629 smbcli_close(cli2->tree, fnum2);
630 smbcli_unlink(cli1->tree, fname);
636 tries the unusual lockingX locktype bits
638 BOOL torture_locktest6(struct torture_context *tctx,
639 struct smbcli_state *cli)
641 const char *fname[1] = { "\\lock6.txt" };
646 if (!torture_setup_dir(cli, BASEDIR)) {
651 torture_comment(tctx, "Testing %s\n", fname[i]);
653 smbcli_unlink(cli->tree, fname[i]);
655 fnum = smbcli_open(cli->tree, fname[i], O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
656 status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CHANGE_LOCKTYPE);
657 smbcli_close(cli->tree, fnum);
658 torture_comment(tctx, "CHANGE_LOCKTYPE gave %s\n", nt_errstr(status));
660 fnum = smbcli_open(cli->tree, fname[i], O_RDWR, DENY_NONE);
661 status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CANCEL_LOCK);
662 smbcli_close(cli->tree, fnum);
663 torture_comment(tctx, "CANCEL_LOCK gave %s\n", nt_errstr(status));
665 smbcli_unlink(cli->tree, fname[i]);
671 BOOL torture_locktest7(struct torture_context *tctx,
672 struct smbcli_state *cli1)
674 const char *fname = BASEDIR "\\lockt7.lck";
679 BOOL correct = False;
681 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
682 talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
684 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
686 memset(buf, 0, sizeof(buf));
688 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
689 "Failed to create file");
691 cli1->session->pid = 1;
693 torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK),
694 talloc_asprintf(tctx, "Unable to apply read lock on range 130:4, error was %s",
695 smbcli_errstr(cli1->tree)));
697 torture_comment(tctx, "pid1 successfully locked range 130:4 for READ\n");
699 torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
700 talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s)",
701 smbcli_errstr(cli1->tree)));
703 torture_comment(tctx, "pid1 successfully read the range 130:4\n");
705 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
706 torture_comment(tctx, "pid1 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
707 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
708 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
710 torture_fail(tctx, "pid1 successfully wrote to the range 130:4 (should be denied)");
713 cli1->session->pid = 2;
715 if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
716 torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
718 torture_comment(tctx, "pid2 successfully read the range 130:4\n");
721 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
722 torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
723 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
724 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
726 torture_fail(tctx, "pid2 successfully wrote to the range 130:4 (should be denied)");
729 cli1->session->pid = 1;
730 smbcli_unlock(cli1->tree, fnum1, 130, 4);
732 torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, WRITE_LOCK),
733 talloc_asprintf(tctx, "Unable to apply write lock on range 130:4, error was %s",
734 smbcli_errstr(cli1->tree)));
735 torture_comment(tctx, "pid1 successfully locked range 130:4 for WRITE\n");
737 torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
738 talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s",
739 smbcli_errstr(cli1->tree)));
740 torture_comment(tctx, "pid1 successfully read the range 130:4\n");
742 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) == 4,
743 talloc_asprintf(tctx, "pid1 unable to write to the range 130:4, error was %s",
744 smbcli_errstr(cli1->tree)));
745 torture_comment(tctx, "pid1 successfully wrote to the range 130:4\n");
747 cli1->session->pid = 2;
749 if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
750 torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n",
751 smbcli_errstr(cli1->tree));
752 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
753 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
755 torture_fail(tctx, "pid2 successfully read the range 130:4 (should be denied)");
758 if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
759 torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n",
760 smbcli_errstr(cli1->tree));
761 if (!NT_STATUS_EQUAL(smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT)) {
762 torture_comment(tctx, "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT) (%s)\n",
767 torture_comment(tctx, "pid2 successfully wrote to the range 130:4 (should be denied) (%s)\n",
772 torture_comment(tctx, "Testing truncate of locked file.\n");
774 fnum2 = smbcli_open(cli1->tree, fname, O_RDWR|O_TRUNC, DENY_NONE);
776 torture_assert(tctx, fnum2 != -1, "Unable to truncate locked file");
778 torture_comment(tctx, "Truncated locked file.\n");
780 torture_assert_ntstatus_ok(tctx, smbcli_getatr(cli1->tree, fname, NULL, &size, NULL),
781 talloc_asprintf(tctx, "getatr failed (%s)", smbcli_errstr(cli1->tree)));
783 torture_assert(tctx, size == 0, talloc_asprintf(tctx, "Unable to truncate locked file. Size was %u", (unsigned)size));
785 cli1->session->pid = 1;
787 smbcli_unlock(cli1->tree, fnum1, 130, 4);
791 smbcli_close(cli1->tree, fnum1);
792 smbcli_close(cli1->tree, fnum2);
793 smbcli_unlink(cli1->tree, fname);
798 struct torture_suite *torture_base_locktest(void)
800 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(),
802 torture_suite_add_2smb_test(suite, "LOCK1", torture_locktest1);
803 torture_suite_add_1smb_test(suite, "LOCK2", torture_locktest2);
804 torture_suite_add_2smb_test(suite, "LOCK3", torture_locktest3);
805 torture_suite_add_2smb_test(suite, "LOCK4", torture_locktest4);
806 torture_suite_add_2smb_test(suite, "LOCK5", torture_locktest5);
807 torture_suite_add_1smb_test(suite, "LOCK6", torture_locktest6);
808 torture_suite_add_1smb_test(suite, "LOCK7", torture_locktest7);