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/libcli.h"
25 #include "torture/util.h"
26 #include "system/time.h"
27 #include "system/filesys.h"
29 #define BASEDIR "\\locktest"
32 This test checks for two things:
34 1) correct support for retaining locks over a close (ie. the server
35 must not use posix semantics)
36 2) support for lock timeouts
38 static bool torture_locktest1(struct torture_context
*tctx
,
39 struct smbcli_state
*cli1
,
40 struct smbcli_state
*cli2
)
42 const char *fname
= BASEDIR
"\\lockt1.lck";
43 int fnum1
, fnum2
, fnum3
;
45 unsigned int lock_timeout
;
47 if (!torture_setup_dir(cli1
, BASEDIR
)) {
51 fnum1
= smbcli_open(cli1
->tree
, fname
, O_RDWR
|O_CREAT
|O_EXCL
, DENY_NONE
);
52 torture_assert(tctx
, fnum1
!= -1,
54 "open of %s failed (%s)\n", fname
, smbcli_errstr(cli1
->tree
)));
55 fnum2
= smbcli_open(cli1
->tree
, fname
, O_RDWR
, DENY_NONE
);
56 torture_assert(tctx
, fnum2
!= -1, talloc_asprintf(tctx
,
57 "open2 of %s failed (%s)\n", fname
, smbcli_errstr(cli1
->tree
)));
58 fnum3
= smbcli_open(cli2
->tree
, fname
, O_RDWR
, DENY_NONE
);
59 torture_assert(tctx
, fnum3
!= -1, talloc_asprintf(tctx
,
60 "open3 of %s failed (%s)\n", fname
, smbcli_errstr(cli2
->tree
)));
62 torture_assert_ntstatus_ok(tctx
,
63 smbcli_lock(cli1
->tree
, fnum1
, 0, 4, 0, WRITE_LOCK
),
64 talloc_asprintf(tctx
, "lock1 failed (%s)", smbcli_errstr(cli1
->tree
)));
67 !NT_STATUS_IS_OK(smbcli_lock(cli2
->tree
, fnum3
, 0, 4, 0, WRITE_LOCK
)),
68 "lock2 succeeded! This is a locking bug\n");
70 if (!check_error(__location__
, cli2
, ERRDOS
, ERRlock
,
71 NT_STATUS_LOCK_NOT_GRANTED
)) return false;
74 !NT_STATUS_IS_OK(smbcli_lock(cli2
->tree
, fnum3
, 0, 4, 0, WRITE_LOCK
)),
75 "lock2 succeeded! This is a locking bug\n");
77 if (!check_error(__location__
, cli2
, ERRDOS
, ERRlock
,
78 NT_STATUS_FILE_LOCK_CONFLICT
)) return false;
80 torture_assert_ntstatus_ok(tctx
,
81 smbcli_lock(cli1
->tree
, fnum1
, 5, 9, 0, WRITE_LOCK
),
83 "lock1 failed (%s)", smbcli_errstr(cli1
->tree
)));
86 !NT_STATUS_IS_OK(smbcli_lock(cli2
->tree
, fnum3
, 5, 9, 0, WRITE_LOCK
)),
87 "lock2 succeeded! This is a locking bug");
89 if (!check_error(__location__
, cli2
, ERRDOS
, ERRlock
,
90 NT_STATUS_LOCK_NOT_GRANTED
)) return false;
93 !NT_STATUS_IS_OK(smbcli_lock(cli2
->tree
, fnum3
, 0, 4, 0, WRITE_LOCK
)),
94 "lock2 succeeded! This is a locking bug");
96 if (!check_error(__location__
, cli2
, ERRDOS
, ERRlock
,
97 NT_STATUS_LOCK_NOT_GRANTED
)) return false;
100 !NT_STATUS_IS_OK(smbcli_lock(cli2
->tree
, fnum3
, 0, 4, 0, WRITE_LOCK
)),
101 "lock2 succeeded! This is a locking bug");
103 if (!check_error(__location__
, cli2
, ERRDOS
, ERRlock
,
104 NT_STATUS_FILE_LOCK_CONFLICT
)) return false;
106 lock_timeout
= (6 + (random() % 20));
107 torture_comment(tctx
, "Testing lock timeout with timeout=%u\n",
111 !NT_STATUS_IS_OK(smbcli_lock(cli2
->tree
, fnum3
, 0, 4, lock_timeout
* 1000, WRITE_LOCK
)),
112 "lock3 succeeded! This is a locking bug\n");
114 if (!check_error(__location__
, cli2
, ERRDOS
, ERRlock
,
115 NT_STATUS_FILE_LOCK_CONFLICT
)) return false;
120 "error: This server appears not to support timed lock requests");
122 torture_comment(tctx
, "server slept for %u seconds for a %u second timeout\n",
123 (unsigned int)(t2
-t1
), lock_timeout
);
125 torture_assert_ntstatus_ok(tctx
, smbcli_close(cli1
->tree
, fnum2
),
126 talloc_asprintf(tctx
, "close1 failed (%s)", smbcli_errstr(cli1
->tree
)));
129 !NT_STATUS_IS_OK(smbcli_lock(cli2
->tree
, fnum3
, 0, 4, 0, WRITE_LOCK
)),
130 "lock4 succeeded! This is a locking bug");
132 if (!check_error(__location__
, cli2
, ERRDOS
, ERRlock
,
133 NT_STATUS_FILE_LOCK_CONFLICT
)) return false;
135 torture_assert_ntstatus_ok(tctx
, smbcli_close(cli1
->tree
, fnum1
),
136 talloc_asprintf(tctx
, "close2 failed (%s)", smbcli_errstr(cli1
->tree
)));
138 torture_assert_ntstatus_ok(tctx
, smbcli_close(cli2
->tree
, fnum3
),
139 talloc_asprintf(tctx
, "close3 failed (%s)", smbcli_errstr(cli2
->tree
)));
141 torture_assert_ntstatus_ok(tctx
, smbcli_unlink(cli1
->tree
, fname
),
142 talloc_asprintf(tctx
, "unlink failed (%s)", smbcli_errstr(cli1
->tree
)));
149 This test checks that
151 1) the server supports multiple locking contexts on the one SMB
152 connection, distinguished by PID.
154 2) the server correctly fails overlapping locks made by the same PID (this
155 goes against POSIX behaviour, which is why it is tricky to implement)
157 3) the server denies unlock requests by an incorrect client PID
159 static bool torture_locktest2(struct torture_context
*tctx
,
160 struct smbcli_state
*cli
)
162 const char *fname
= BASEDIR
"\\lockt2.lck";
163 int fnum1
, fnum2
, fnum3
;
165 if (!torture_setup_dir(cli
, BASEDIR
)) {
169 torture_comment(tctx
, "Testing pid context\n");
171 cli
->session
->pid
= 1;
173 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
|O_EXCL
, DENY_NONE
);
174 torture_assert(tctx
, fnum1
!= -1,
175 talloc_asprintf(tctx
,
176 "open of %s failed (%s)", fname
, smbcli_errstr(cli
->tree
)));
178 fnum2
= smbcli_open(cli
->tree
, fname
, O_RDWR
, DENY_NONE
);
179 torture_assert(tctx
, fnum2
!= -1,
180 talloc_asprintf(tctx
, "open2 of %s failed (%s)",
181 fname
, smbcli_errstr(cli
->tree
)));
183 cli
->session
->pid
= 2;
185 fnum3
= smbcli_open(cli
->tree
, fname
, O_RDWR
, DENY_NONE
);
186 torture_assert(tctx
, fnum3
!= -1,
187 talloc_asprintf(tctx
,
188 "open3 of %s failed (%s)\n", fname
, smbcli_errstr(cli
->tree
)));
190 cli
->session
->pid
= 1;
192 torture_assert_ntstatus_ok(tctx
,
193 smbcli_lock(cli
->tree
, fnum1
, 0, 4, 0, WRITE_LOCK
),
194 talloc_asprintf(tctx
,
195 "lock1 failed (%s)", smbcli_errstr(cli
->tree
)));
198 !NT_STATUS_IS_OK(smbcli_lock(cli
->tree
, fnum1
, 0, 4, 0, WRITE_LOCK
)),
199 "WRITE lock1 succeeded! This is a locking bug");
201 if (!check_error(__location__
, cli
, ERRDOS
, ERRlock
,
202 NT_STATUS_LOCK_NOT_GRANTED
)) return false;
205 !NT_STATUS_IS_OK(smbcli_lock(cli
->tree
, fnum2
, 0, 4, 0, WRITE_LOCK
)),
206 "WRITE lock2 succeeded! This is a locking bug");
208 if (!check_error(__location__
, cli
, ERRDOS
, ERRlock
,
209 NT_STATUS_LOCK_NOT_GRANTED
)) return false;
212 !NT_STATUS_IS_OK(smbcli_lock(cli
->tree
, fnum2
, 0, 4, 0, READ_LOCK
)),
213 "READ lock2 succeeded! This is a locking bug");
215 if (!check_error(__location__
, cli
, ERRDOS
, ERRlock
,
216 NT_STATUS_FILE_LOCK_CONFLICT
)) return false;
218 torture_assert_ntstatus_ok(tctx
,
219 smbcli_lock(cli
->tree
, fnum1
, 100, 4, 0, WRITE_LOCK
),
220 talloc_asprintf(tctx
,
221 "lock at 100 failed (%s)", smbcli_errstr(cli
->tree
)));
223 cli
->session
->pid
= 2;
226 !NT_STATUS_IS_OK(smbcli_unlock(cli
->tree
, fnum1
, 100, 4)),
227 "unlock at 100 succeeded! This is a locking bug");
230 !NT_STATUS_IS_OK(smbcli_unlock(cli
->tree
, fnum1
, 0, 4)),
231 "unlock1 succeeded! This is a locking bug");
233 if (!check_error(__location__
, cli
,
234 ERRDOS
, ERRnotlocked
,
235 NT_STATUS_RANGE_NOT_LOCKED
)) return false;
238 !NT_STATUS_IS_OK(smbcli_unlock(cli
->tree
, fnum1
, 0, 8)),
239 "unlock2 succeeded! This is a locking bug");
241 if (!check_error(__location__
, cli
,
242 ERRDOS
, ERRnotlocked
,
243 NT_STATUS_RANGE_NOT_LOCKED
)) return false;
246 !NT_STATUS_IS_OK(smbcli_lock(cli
->tree
, fnum3
, 0, 4, 0, WRITE_LOCK
)),
247 "lock3 succeeded! This is a locking bug");
249 if (!check_error(__location__
, cli
, ERRDOS
, ERRlock
, NT_STATUS_LOCK_NOT_GRANTED
)) return false;
251 cli
->session
->pid
= 1;
253 torture_assert_ntstatus_ok(tctx
, smbcli_close(cli
->tree
, fnum1
),
254 talloc_asprintf(tctx
, "close1 failed (%s)", smbcli_errstr(cli
->tree
)));
256 torture_assert_ntstatus_ok(tctx
, smbcli_close(cli
->tree
, fnum2
),
257 talloc_asprintf(tctx
, "close2 failed (%s)", smbcli_errstr(cli
->tree
)));
259 torture_assert_ntstatus_ok(tctx
, smbcli_close(cli
->tree
, fnum3
),
260 talloc_asprintf(tctx
, "close3 failed (%s)", smbcli_errstr(cli
->tree
)));
267 This test checks that
269 1) the server supports the full offset range in lock requests
271 static bool torture_locktest3(struct torture_context
*tctx
,
272 struct smbcli_state
*cli1
,
273 struct smbcli_state
*cli2
)
275 const char *fname
= BASEDIR
"\\lockt3.lck";
278 extern int torture_numops
;
280 #define NEXT_OFFSET offset += (~(uint32_t)0) / torture_numops
282 torture_comment(tctx
, "Testing 32 bit offset ranges");
284 if (!torture_setup_dir(cli1
, BASEDIR
)) {
288 fnum1
= smbcli_open(cli1
->tree
, fname
, O_RDWR
|O_CREAT
|O_EXCL
, DENY_NONE
);
289 torture_assert(tctx
, fnum1
!= -1,
290 talloc_asprintf(tctx
, "open of %s failed (%s)\n", fname
, smbcli_errstr(cli1
->tree
)));
291 fnum2
= smbcli_open(cli2
->tree
, fname
, O_RDWR
, DENY_NONE
);
292 torture_assert(tctx
, fnum2
!= -1,
293 talloc_asprintf(tctx
, "open2 of %s failed (%s)\n", fname
, smbcli_errstr(cli2
->tree
)));
295 torture_comment(tctx
, "Establishing %d locks\n", torture_numops
);
297 for (offset
=i
=0;i
<torture_numops
;i
++) {
299 torture_assert_ntstatus_ok(tctx
,
300 smbcli_lock(cli1
->tree
, fnum1
, offset
-1, 1, 0, WRITE_LOCK
),
301 talloc_asprintf(tctx
, "lock1 %d failed (%s)", i
, smbcli_errstr(cli1
->tree
)));
303 torture_assert_ntstatus_ok(tctx
,
304 smbcli_lock(cli2
->tree
, fnum2
, offset
-2, 1, 0, WRITE_LOCK
),
305 talloc_asprintf(tctx
, "lock2 %d failed (%s)",
306 i
, smbcli_errstr(cli1
->tree
)));
309 torture_comment(tctx
, "Testing %d locks\n", torture_numops
);
311 for (offset
=i
=0;i
<torture_numops
;i
++) {
315 !NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, offset
-2, 1, 0, WRITE_LOCK
)),
316 talloc_asprintf(tctx
, "error: lock1 %d succeeded!", i
));
319 !NT_STATUS_IS_OK(smbcli_lock(cli2
->tree
, fnum2
, offset
-1, 1, 0, WRITE_LOCK
)),
320 talloc_asprintf(tctx
, "error: lock2 %d succeeded!", i
));
323 !NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, offset
-1, 1, 0, WRITE_LOCK
)),
324 talloc_asprintf(tctx
, "error: lock3 %d succeeded!", i
));
327 !NT_STATUS_IS_OK(smbcli_lock(cli2
->tree
, fnum2
, offset
-2, 1, 0, WRITE_LOCK
)),
328 talloc_asprintf(tctx
, "error: lock4 %d succeeded!", i
));
331 torture_comment(tctx
, "Removing %d locks\n", torture_numops
);
333 for (offset
=i
=0;i
<torture_numops
;i
++) {
336 torture_assert_ntstatus_ok(tctx
,
337 smbcli_unlock(cli1
->tree
, fnum1
, offset
-1, 1),
338 talloc_asprintf(tctx
, "unlock1 %d failed (%s)",
340 smbcli_errstr(cli1
->tree
)));
342 torture_assert_ntstatus_ok(tctx
,
343 smbcli_unlock(cli2
->tree
, fnum2
, offset
-2, 1),
344 talloc_asprintf(tctx
, "unlock2 %d failed (%s)",
346 smbcli_errstr(cli1
->tree
)));
349 torture_assert_ntstatus_ok(tctx
, smbcli_close(cli1
->tree
, fnum1
),
350 talloc_asprintf(tctx
, "close1 failed (%s)", smbcli_errstr(cli1
->tree
)));
352 torture_assert_ntstatus_ok(tctx
, smbcli_close(cli2
->tree
, fnum2
),
353 talloc_asprintf(tctx
, "close2 failed (%s)", smbcli_errstr(cli2
->tree
)));
355 torture_assert_ntstatus_ok(tctx
, smbcli_unlink(cli1
->tree
, fname
),
356 talloc_asprintf(tctx
, "unlink failed (%s)", smbcli_errstr(cli1
->tree
)));
361 #define EXPECTED(ret, v) if ((ret) != (v)) { \
362 torture_comment(tctx, "** "); correct = false; \
366 looks at overlapping locks
368 static bool torture_locktest4(struct torture_context
*tctx
,
369 struct smbcli_state
*cli1
,
370 struct smbcli_state
*cli2
)
372 const char *fname
= BASEDIR
"\\lockt4.lck";
378 if (!torture_setup_dir(cli1
, BASEDIR
)) {
382 fnum1
= smbcli_open(cli1
->tree
, fname
, O_RDWR
|O_CREAT
|O_EXCL
, DENY_NONE
);
383 fnum2
= smbcli_open(cli2
->tree
, fname
, O_RDWR
, DENY_NONE
);
385 memset(buf
, 0, sizeof(buf
));
387 if (smbcli_write(cli1
->tree
, fnum1
, 0, buf
, 0, sizeof(buf
)) != sizeof(buf
)) {
388 torture_comment(tctx
, "Failed to create file\n");
393 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 0, 4, 0, WRITE_LOCK
)) &&
394 NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 2, 4, 0, WRITE_LOCK
));
395 EXPECTED(ret
, false);
396 torture_comment(tctx
, "the same process %s set overlapping write locks\n", ret
?"can":"cannot");
398 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 10, 4, 0, READ_LOCK
)) &&
399 NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 12, 4, 0, READ_LOCK
));
401 torture_comment(tctx
, "the same process %s set overlapping read locks\n", ret
?"can":"cannot");
403 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 20, 4, 0, WRITE_LOCK
)) &&
404 NT_STATUS_IS_OK(smbcli_lock(cli2
->tree
, fnum2
, 22, 4, 0, WRITE_LOCK
));
405 EXPECTED(ret
, false);
406 torture_comment(tctx
, "a different connection %s set overlapping write locks\n", ret
?"can":"cannot");
408 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 30, 4, 0, READ_LOCK
)) &&
409 NT_STATUS_IS_OK(smbcli_lock(cli2
->tree
, fnum2
, 32, 4, 0, READ_LOCK
));
411 torture_comment(tctx
, "a different connection %s set overlapping read locks\n", ret
?"can":"cannot");
413 ret
= NT_STATUS_IS_OK((cli1
->session
->pid
= 1, smbcli_lock(cli1
->tree
, fnum1
, 40, 4, 0, WRITE_LOCK
))) &&
414 NT_STATUS_IS_OK((cli1
->session
->pid
= 2, smbcli_lock(cli1
->tree
, fnum1
, 42, 4, 0, WRITE_LOCK
)));
415 EXPECTED(ret
, false);
416 torture_comment(tctx
, "a different pid %s set overlapping write locks\n", ret
?"can":"cannot");
418 ret
= NT_STATUS_IS_OK((cli1
->session
->pid
= 1, smbcli_lock(cli1
->tree
, fnum1
, 50, 4, 0, READ_LOCK
))) &&
419 NT_STATUS_IS_OK((cli1
->session
->pid
= 2, smbcli_lock(cli1
->tree
, fnum1
, 52, 4, 0, READ_LOCK
)));
421 torture_comment(tctx
, "a different pid %s set overlapping read locks\n", ret
?"can":"cannot");
423 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 60, 4, 0, READ_LOCK
)) &&
424 NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 60, 4, 0, READ_LOCK
));
426 torture_comment(tctx
, "the same process %s set the same read lock twice\n", ret
?"can":"cannot");
428 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 70, 4, 0, WRITE_LOCK
)) &&
429 NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 70, 4, 0, WRITE_LOCK
));
430 EXPECTED(ret
, false);
431 torture_comment(tctx
, "the same process %s set the same write lock twice\n", ret
?"can":"cannot");
433 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 80, 4, 0, READ_LOCK
)) &&
434 NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 80, 4, 0, WRITE_LOCK
));
435 EXPECTED(ret
, false);
436 torture_comment(tctx
, "the same process %s overlay a read lock with a write lock\n", ret
?"can":"cannot");
438 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 90, 4, 0, WRITE_LOCK
)) &&
439 NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 90, 4, 0, READ_LOCK
));
441 torture_comment(tctx
, "the same process %s overlay a write lock with a read lock\n", ret
?"can":"cannot");
443 ret
= NT_STATUS_IS_OK((cli1
->session
->pid
= 1, smbcli_lock(cli1
->tree
, fnum1
, 100, 4, 0, WRITE_LOCK
))) &&
444 NT_STATUS_IS_OK((cli1
->session
->pid
= 2, smbcli_lock(cli1
->tree
, fnum1
, 100, 4, 0, READ_LOCK
)));
445 EXPECTED(ret
, false);
446 torture_comment(tctx
, "a different pid %s overlay a write lock with a read lock\n", ret
?"can":"cannot");
448 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 110, 4, 0, READ_LOCK
)) &&
449 NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 112, 4, 0, READ_LOCK
)) &&
450 NT_STATUS_IS_OK(smbcli_unlock(cli1
->tree
, fnum1
, 110, 6));
451 EXPECTED(ret
, false);
452 torture_comment(tctx
, "the same process %s coalesce read locks\n", ret
?"can":"cannot");
455 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 120, 4, 0, WRITE_LOCK
)) &&
456 (smbcli_read(cli2
->tree
, fnum2
, buf
, 120, 4) == 4);
457 EXPECTED(ret
, false);
458 torture_comment(tctx
, "this server %s strict write locking\n", ret
?"doesn't do":"does");
460 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 130, 4, 0, READ_LOCK
)) &&
461 (smbcli_write(cli2
->tree
, fnum2
, 0, buf
, 130, 4) == 4);
462 EXPECTED(ret
, false);
463 torture_comment(tctx
, "this server %s strict read locking\n", ret
?"doesn't do":"does");
466 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 140, 4, 0, READ_LOCK
)) &&
467 NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 140, 4, 0, READ_LOCK
)) &&
468 NT_STATUS_IS_OK(smbcli_unlock(cli1
->tree
, fnum1
, 140, 4)) &&
469 NT_STATUS_IS_OK(smbcli_unlock(cli1
->tree
, fnum1
, 140, 4));
471 torture_comment(tctx
, "this server %s do recursive read locking\n", ret
?"does":"doesn't");
474 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 150, 4, 0, WRITE_LOCK
)) &&
475 NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 150, 4, 0, READ_LOCK
)) &&
476 NT_STATUS_IS_OK(smbcli_unlock(cli1
->tree
, fnum1
, 150, 4)) &&
477 (smbcli_read(cli2
->tree
, fnum2
, buf
, 150, 4) == 4) &&
478 !(smbcli_write(cli2
->tree
, fnum2
, 0, buf
, 150, 4) == 4) &&
479 NT_STATUS_IS_OK(smbcli_unlock(cli1
->tree
, fnum1
, 150, 4));
481 torture_comment(tctx
, "this server %s do recursive lock overlays\n", ret
?"does":"doesn't");
483 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 160, 4, 0, READ_LOCK
)) &&
484 NT_STATUS_IS_OK(smbcli_unlock(cli1
->tree
, fnum1
, 160, 4)) &&
485 (smbcli_write(cli2
->tree
, fnum2
, 0, buf
, 160, 4) == 4) &&
486 (smbcli_read(cli2
->tree
, fnum2
, buf
, 160, 4) == 4);
488 torture_comment(tctx
, "the same process %s remove a read lock using write locking\n", ret
?"can":"cannot");
490 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 170, 4, 0, WRITE_LOCK
)) &&
491 NT_STATUS_IS_OK(smbcli_unlock(cli1
->tree
, fnum1
, 170, 4)) &&
492 (smbcli_write(cli2
->tree
, fnum2
, 0, buf
, 170, 4) == 4) &&
493 (smbcli_read(cli2
->tree
, fnum2
, buf
, 170, 4) == 4);
495 torture_comment(tctx
, "the same process %s remove a write lock using read locking\n", ret
?"can":"cannot");
497 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 190, 4, 0, WRITE_LOCK
)) &&
498 NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 190, 4, 0, READ_LOCK
)) &&
499 NT_STATUS_IS_OK(smbcli_unlock(cli1
->tree
, fnum1
, 190, 4)) &&
500 !(smbcli_write(cli2
->tree
, fnum2
, 0, buf
, 190, 4) == 4) &&
501 (smbcli_read(cli2
->tree
, fnum2
, buf
, 190, 4) == 4);
503 torture_comment(tctx
, "the same process %s remove the first lock first\n", ret
?"does":"doesn't");
505 smbcli_close(cli1
->tree
, fnum1
);
506 smbcli_close(cli2
->tree
, fnum2
);
507 fnum1
= smbcli_open(cli1
->tree
, fname
, O_RDWR
, DENY_NONE
);
508 f
= smbcli_open(cli1
->tree
, fname
, O_RDWR
, DENY_NONE
);
509 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 0, 8, 0, READ_LOCK
)) &&
510 NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, f
, 0, 1, 0, READ_LOCK
)) &&
511 NT_STATUS_IS_OK(smbcli_close(cli1
->tree
, fnum1
)) &&
512 ((fnum1
= smbcli_open(cli1
->tree
, fname
, O_RDWR
, DENY_NONE
)) != -1) &&
513 NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 7, 1, 0, WRITE_LOCK
));
514 smbcli_close(cli1
->tree
, f
);
515 smbcli_close(cli1
->tree
, fnum1
);
517 torture_comment(tctx
, "the server %s have the NT byte range lock bug\n", !ret
?"does":"doesn't");
520 smbcli_close(cli1
->tree
, fnum1
);
521 smbcli_close(cli2
->tree
, fnum2
);
522 smbcli_unlink(cli1
->tree
, fname
);
528 looks at lock upgrade/downgrade.
530 static bool torture_locktest5(struct torture_context
*tctx
, struct smbcli_state
*cli1
,
531 struct smbcli_state
*cli2
)
533 const char *fname
= BASEDIR
"\\lockt5.lck";
534 int fnum1
, fnum2
, fnum3
;
539 if (!torture_setup_dir(cli1
, BASEDIR
)) {
543 fnum1
= smbcli_open(cli1
->tree
, fname
, O_RDWR
|O_CREAT
|O_EXCL
, DENY_NONE
);
544 fnum2
= smbcli_open(cli2
->tree
, fname
, O_RDWR
, DENY_NONE
);
545 fnum3
= smbcli_open(cli1
->tree
, fname
, O_RDWR
, DENY_NONE
);
547 memset(buf
, 0, sizeof(buf
));
549 torture_assert(tctx
, smbcli_write(cli1
->tree
, fnum1
, 0, buf
, 0, sizeof(buf
)) == sizeof(buf
),
550 "Failed to create file");
552 /* Check for NT bug... */
553 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 0, 8, 0, READ_LOCK
)) &&
554 NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum3
, 0, 1, 0, READ_LOCK
));
555 smbcli_close(cli1
->tree
, fnum1
);
556 fnum1
= smbcli_open(cli1
->tree
, fname
, O_RDWR
, DENY_NONE
);
557 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 7, 1, 0, WRITE_LOCK
));
559 torture_comment(tctx
, "this server %s the NT locking bug\n", ret
? "doesn't have" : "has");
560 smbcli_close(cli1
->tree
, fnum1
);
561 fnum1
= smbcli_open(cli1
->tree
, fname
, O_RDWR
, DENY_NONE
);
562 smbcli_unlock(cli1
->tree
, fnum3
, 0, 1);
564 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 0, 4, 0, WRITE_LOCK
)) &&
565 NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 1, 1, 0, READ_LOCK
));
567 torture_comment(tctx
, "the same process %s overlay a write with a read lock\n", ret
?"can":"cannot");
569 ret
= NT_STATUS_IS_OK(smbcli_lock(cli2
->tree
, fnum2
, 0, 4, 0, READ_LOCK
));
570 EXPECTED(ret
, false);
572 torture_comment(tctx
, "a different processs %s get a read lock on the first process lock stack\n", ret
?"can":"cannot");
574 /* Unlock the process 2 lock. */
575 smbcli_unlock(cli2
->tree
, fnum2
, 0, 4);
577 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum3
, 0, 4, 0, READ_LOCK
));
578 EXPECTED(ret
, false);
580 torture_comment(tctx
, "the same processs on a different fnum %s get a read lock\n", ret
?"can":"cannot");
582 /* Unlock the process 1 fnum3 lock. */
583 smbcli_unlock(cli1
->tree
, fnum3
, 0, 4);
585 /* Stack 2 more locks here. */
586 ret
= NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 0, 4, 0, READ_LOCK
)) &&
587 NT_STATUS_IS_OK(smbcli_lock(cli1
->tree
, fnum1
, 0, 4, 0, READ_LOCK
));
590 torture_comment(tctx
, "the same process %s stack read locks\n", ret
?"can":"cannot");
592 /* Unlock the first process lock, then check this was the WRITE lock that was
595 ret
= NT_STATUS_IS_OK(smbcli_unlock(cli1
->tree
, fnum1
, 0, 4)) &&
596 NT_STATUS_IS_OK(smbcli_lock(cli2
->tree
, fnum2
, 0, 4, 0, READ_LOCK
));
599 torture_comment(tctx
, "the first unlock removes the %s lock\n", ret
?"WRITE":"READ");
601 /* Unlock the process 2 lock. */
602 smbcli_unlock(cli2
->tree
, fnum2
, 0, 4);
604 /* We should have 3 stacked locks here. Ensure we need to do 3 unlocks. */
606 ret
= NT_STATUS_IS_OK(smbcli_unlock(cli1
->tree
, fnum1
, 1, 1)) &&
607 NT_STATUS_IS_OK(smbcli_unlock(cli1
->tree
, fnum1
, 0, 4)) &&
608 NT_STATUS_IS_OK(smbcli_unlock(cli1
->tree
, fnum1
, 0, 4));
611 torture_comment(tctx
, "the same process %s unlock the stack of 3 locks\n", ret
?"can":"cannot");
613 /* Ensure the next unlock fails. */
614 ret
= NT_STATUS_IS_OK(smbcli_unlock(cli1
->tree
, fnum1
, 0, 4));
615 EXPECTED(ret
, false);
616 torture_comment(tctx
, "the same process %s count the lock stack\n", !ret
?"can":"cannot");
618 /* Ensure connection 2 can get a write lock. */
619 ret
= NT_STATUS_IS_OK(smbcli_lock(cli2
->tree
, fnum2
, 0, 4, 0, WRITE_LOCK
));
622 torture_comment(tctx
, "a different processs %s get a write lock on the unlocked stack\n", ret
?"can":"cannot");
625 torture_assert_ntstatus_ok(tctx
, smbcli_close(cli1
->tree
, fnum1
),
626 talloc_asprintf(tctx
, "close1 failed (%s)", smbcli_errstr(cli1
->tree
)));
628 torture_assert_ntstatus_ok(tctx
, smbcli_close(cli2
->tree
, fnum2
),
629 talloc_asprintf(tctx
, "close2 failed (%s)", smbcli_errstr(cli2
->tree
)));
631 torture_assert_ntstatus_ok(tctx
, smbcli_close(cli1
->tree
, fnum3
),
632 talloc_asprintf(tctx
, "close2 failed (%s)", smbcli_errstr(cli2
->tree
)));
634 torture_assert_ntstatus_ok(tctx
, smbcli_unlink(cli1
->tree
, fname
),
635 talloc_asprintf(tctx
, "unlink failed (%s)", smbcli_errstr(cli1
->tree
)));
641 tries the unusual lockingX locktype bits
643 static bool torture_locktest6(struct torture_context
*tctx
,
644 struct smbcli_state
*cli
)
646 const char *fname
[1] = { "\\lock6.txt" };
651 if (!torture_setup_dir(cli
, BASEDIR
)) {
656 torture_comment(tctx
, "Testing %s\n", fname
[i
]);
658 smbcli_unlink(cli
->tree
, fname
[i
]);
660 fnum
= smbcli_open(cli
->tree
, fname
[i
], O_RDWR
|O_CREAT
|O_EXCL
, DENY_NONE
);
661 status
= smbcli_locktype(cli
->tree
, fnum
, 0, 8, 0, LOCKING_ANDX_CHANGE_LOCKTYPE
);
662 smbcli_close(cli
->tree
, fnum
);
663 torture_comment(tctx
, "CHANGE_LOCKTYPE gave %s\n", nt_errstr(status
));
665 fnum
= smbcli_open(cli
->tree
, fname
[i
], O_RDWR
, DENY_NONE
);
666 status
= smbcli_locktype(cli
->tree
, fnum
, 0, 8, 0, LOCKING_ANDX_CANCEL_LOCK
);
667 smbcli_close(cli
->tree
, fnum
);
668 torture_comment(tctx
, "CANCEL_LOCK gave %s\n", nt_errstr(status
));
670 smbcli_unlink(cli
->tree
, fname
[i
]);
676 static bool torture_locktest7(struct torture_context
*tctx
,
677 struct smbcli_state
*cli1
)
679 const char *fname
= BASEDIR
"\\lockt7.lck";
684 bool correct
= false;
686 torture_assert(tctx
, torture_setup_dir(cli1
, BASEDIR
),
687 talloc_asprintf(tctx
, "Unable to set up %s", BASEDIR
));
689 fnum1
= smbcli_open(cli1
->tree
, fname
, O_RDWR
|O_CREAT
|O_EXCL
, DENY_NONE
);
691 memset(buf
, 0, sizeof(buf
));
693 torture_assert(tctx
, smbcli_write(cli1
->tree
, fnum1
, 0, buf
, 0, sizeof(buf
)) == sizeof(buf
),
694 "Failed to create file");
696 cli1
->session
->pid
= 1;
698 torture_assert_ntstatus_ok(tctx
, smbcli_lock(cli1
->tree
, fnum1
, 130, 4, 0, READ_LOCK
),
699 talloc_asprintf(tctx
, "Unable to apply read lock on range 130:4, error was %s",
700 smbcli_errstr(cli1
->tree
)));
702 torture_comment(tctx
, "pid1 successfully locked range 130:4 for READ\n");
704 torture_assert(tctx
, smbcli_read(cli1
->tree
, fnum1
, buf
, 130, 4) == 4,
705 talloc_asprintf(tctx
, "pid1 unable to read the range 130:4, error was %s)",
706 smbcli_errstr(cli1
->tree
)));
708 torture_comment(tctx
, "pid1 successfully read the range 130:4\n");
710 if (smbcli_write(cli1
->tree
, fnum1
, 0, buf
, 130, 4) != 4) {
711 torture_comment(tctx
, "pid1 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1
->tree
));
712 torture_assert_ntstatus_equal(tctx
, smbcli_nt_error(cli1
->tree
), NT_STATUS_FILE_LOCK_CONFLICT
,
713 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
715 torture_fail(tctx
, "pid1 successfully wrote to the range 130:4 (should be denied)");
718 cli1
->session
->pid
= 2;
720 if (smbcli_read(cli1
->tree
, fnum1
, buf
, 130, 4) != 4) {
721 torture_comment(tctx
, "pid2 unable to read the range 130:4, error was %s\n", smbcli_errstr(cli1
->tree
));
723 torture_comment(tctx
, "pid2 successfully read the range 130:4\n");
726 if (smbcli_write(cli1
->tree
, fnum1
, 0, buf
, 130, 4) != 4) {
727 torture_comment(tctx
, "pid2 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1
->tree
));
728 torture_assert_ntstatus_equal(tctx
, smbcli_nt_error(cli1
->tree
), NT_STATUS_FILE_LOCK_CONFLICT
,
729 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
731 torture_fail(tctx
, "pid2 successfully wrote to the range 130:4 (should be denied)");
734 cli1
->session
->pid
= 1;
735 smbcli_unlock(cli1
->tree
, fnum1
, 130, 4);
737 torture_assert_ntstatus_ok(tctx
, smbcli_lock(cli1
->tree
, fnum1
, 130, 4, 0, WRITE_LOCK
),
738 talloc_asprintf(tctx
, "Unable to apply write lock on range 130:4, error was %s",
739 smbcli_errstr(cli1
->tree
)));
740 torture_comment(tctx
, "pid1 successfully locked range 130:4 for WRITE\n");
742 torture_assert(tctx
, smbcli_read(cli1
->tree
, fnum1
, buf
, 130, 4) == 4,
743 talloc_asprintf(tctx
, "pid1 unable to read the range 130:4, error was %s",
744 smbcli_errstr(cli1
->tree
)));
745 torture_comment(tctx
, "pid1 successfully read the range 130:4\n");
747 torture_assert(tctx
, smbcli_write(cli1
->tree
, fnum1
, 0, buf
, 130, 4) == 4,
748 talloc_asprintf(tctx
, "pid1 unable to write to the range 130:4, error was %s",
749 smbcli_errstr(cli1
->tree
)));
750 torture_comment(tctx
, "pid1 successfully wrote to the range 130:4\n");
752 cli1
->session
->pid
= 2;
754 if (smbcli_read(cli1
->tree
, fnum1
, buf
, 130, 4) != 4) {
755 torture_comment(tctx
, "pid2 unable to read the range 130:4, error was %s\n",
756 smbcli_errstr(cli1
->tree
));
757 torture_assert_ntstatus_equal(tctx
, smbcli_nt_error(cli1
->tree
), NT_STATUS_FILE_LOCK_CONFLICT
,
758 "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
760 torture_fail(tctx
, "pid2 successfully read the range 130:4 (should be denied)");
763 if (smbcli_write(cli1
->tree
, fnum1
, 0, buf
, 130, 4) != 4) {
764 torture_comment(tctx
, "pid2 unable to write to the range 130:4, error was %s\n",
765 smbcli_errstr(cli1
->tree
));
766 if (!NT_STATUS_EQUAL(smbcli_nt_error(cli1
->tree
), NT_STATUS_FILE_LOCK_CONFLICT
)) {
767 torture_comment(tctx
, "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT) (%s)\n",
772 torture_comment(tctx
, "pid2 successfully wrote to the range 130:4 (should be denied) (%s)\n",
777 torture_comment(tctx
, "Testing truncate of locked file.\n");
779 fnum2
= smbcli_open(cli1
->tree
, fname
, O_RDWR
|O_TRUNC
, DENY_NONE
);
781 torture_assert(tctx
, fnum2
!= -1, "Unable to truncate locked file");
783 torture_comment(tctx
, "Truncated locked file.\n");
785 torture_assert_ntstatus_ok(tctx
, smbcli_getatr(cli1
->tree
, fname
, NULL
, &size
, NULL
),
786 talloc_asprintf(tctx
, "getatr failed (%s)", smbcli_errstr(cli1
->tree
)));
788 torture_assert(tctx
, size
== 0, talloc_asprintf(tctx
, "Unable to truncate locked file. Size was %u", (unsigned)size
));
790 cli1
->session
->pid
= 1;
792 smbcli_unlock(cli1
->tree
, fnum1
, 130, 4);
796 smbcli_close(cli1
->tree
, fnum1
);
797 smbcli_close(cli1
->tree
, fnum2
);
798 smbcli_unlink(cli1
->tree
, fname
);
803 struct torture_suite
*torture_base_locktest(TALLOC_CTX
*mem_ctx
)
805 struct torture_suite
*suite
= torture_suite_create(mem_ctx
, "LOCK");
806 torture_suite_add_2smb_test(suite
, "LOCK1", torture_locktest1
);
807 torture_suite_add_1smb_test(suite
, "LOCK2", torture_locktest2
);
808 torture_suite_add_2smb_test(suite
, "LOCK3", torture_locktest3
);
809 torture_suite_add_2smb_test(suite
, "LOCK4", torture_locktest4
);
810 torture_suite_add_2smb_test(suite
, "LOCK5", torture_locktest5
);
811 torture_suite_add_1smb_test(suite
, "LOCK6", torture_locktest6
);
812 torture_suite_add_1smb_test(suite
, "LOCK7", torture_locktest7
);