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 3 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
torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
628
talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
630
torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
631
talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
633
torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum3),
634
talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
636
torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
637
talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
643
tries the unusual lockingX locktype bits
645
static bool torture_locktest6(struct torture_context *tctx,
646
struct smbcli_state *cli)
648
const char *fname[1] = { "\\lock6.txt" };
653
if (!torture_setup_dir(cli, BASEDIR)) {
658
torture_comment(tctx, "Testing %s\n", fname[i]);
660
smbcli_unlink(cli->tree, fname[i]);
662
fnum = smbcli_open(cli->tree, fname[i], O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
663
status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CHANGE_LOCKTYPE);
664
smbcli_close(cli->tree, fnum);
665
torture_comment(tctx, "CHANGE_LOCKTYPE gave %s\n", nt_errstr(status));
667
fnum = smbcli_open(cli->tree, fname[i], O_RDWR, DENY_NONE);
668
status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CANCEL_LOCK);
669
smbcli_close(cli->tree, fnum);
670
torture_comment(tctx, "CANCEL_LOCK gave %s\n", nt_errstr(status));
672
smbcli_unlink(cli->tree, fname[i]);
678
static bool torture_locktest7(struct torture_context *tctx,
679
struct smbcli_state *cli1)
681
const char *fname = BASEDIR "\\lockt7.lck";
686
bool correct = false;
688
torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
689
talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
691
fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
693
memset(buf, 0, sizeof(buf));
695
torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
696
"Failed to create file");
698
cli1->session->pid = 1;
700
torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK),
701
talloc_asprintf(tctx, "Unable to apply read lock on range 130:4, error was %s",
702
smbcli_errstr(cli1->tree)));
704
torture_comment(tctx, "pid1 successfully locked range 130:4 for READ\n");
706
torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
707
talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s)",
708
smbcli_errstr(cli1->tree)));
710
torture_comment(tctx, "pid1 successfully read the range 130:4\n");
712
if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
713
torture_comment(tctx, "pid1 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
714
torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
715
"Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
717
torture_fail(tctx, "pid1 successfully wrote to the range 130:4 (should be denied)");
720
cli1->session->pid = 2;
722
if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
723
torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
725
torture_comment(tctx, "pid2 successfully read the range 130:4\n");
728
if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
729
torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
730
torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
731
"Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
733
torture_fail(tctx, "pid2 successfully wrote to the range 130:4 (should be denied)");
736
cli1->session->pid = 1;
737
smbcli_unlock(cli1->tree, fnum1, 130, 4);
739
torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, WRITE_LOCK),
740
talloc_asprintf(tctx, "Unable to apply write lock on range 130:4, error was %s",
741
smbcli_errstr(cli1->tree)));
742
torture_comment(tctx, "pid1 successfully locked range 130:4 for WRITE\n");
744
torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
745
talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s",
746
smbcli_errstr(cli1->tree)));
747
torture_comment(tctx, "pid1 successfully read the range 130:4\n");
749
torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) == 4,
750
talloc_asprintf(tctx, "pid1 unable to write to the range 130:4, error was %s",
751
smbcli_errstr(cli1->tree)));
752
torture_comment(tctx, "pid1 successfully wrote to the range 130:4\n");
754
cli1->session->pid = 2;
756
if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
757
torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n",
758
smbcli_errstr(cli1->tree));
759
torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
760
"Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
762
torture_fail(tctx, "pid2 successfully read the range 130:4 (should be denied)");
765
if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
766
torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n",
767
smbcli_errstr(cli1->tree));
768
if (!NT_STATUS_EQUAL(smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT)) {
769
torture_comment(tctx, "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT) (%s)\n",
774
torture_comment(tctx, "pid2 successfully wrote to the range 130:4 (should be denied) (%s)\n",
779
torture_comment(tctx, "Testing truncate of locked file.\n");
781
fnum2 = smbcli_open(cli1->tree, fname, O_RDWR|O_TRUNC, DENY_NONE);
783
torture_assert(tctx, fnum2 != -1, "Unable to truncate locked file");
785
torture_comment(tctx, "Truncated locked file.\n");
787
torture_assert_ntstatus_ok(tctx, smbcli_getatr(cli1->tree, fname, NULL, &size, NULL),
788
talloc_asprintf(tctx, "getatr failed (%s)", smbcli_errstr(cli1->tree)));
790
torture_assert(tctx, size == 0, talloc_asprintf(tctx, "Unable to truncate locked file. Size was %u", (unsigned)size));
792
cli1->session->pid = 1;
794
smbcli_unlock(cli1->tree, fnum1, 130, 4);
798
smbcli_close(cli1->tree, fnum1);
799
smbcli_close(cli1->tree, fnum2);
800
smbcli_unlink(cli1->tree, fname);
805
struct torture_suite *torture_base_locktest(TALLOC_CTX *mem_ctx)
807
struct torture_suite *suite = torture_suite_create(mem_ctx, "LOCK");
808
torture_suite_add_2smb_test(suite, "LOCK1", torture_locktest1);
809
torture_suite_add_1smb_test(suite, "LOCK2", torture_locktest2);
810
torture_suite_add_2smb_test(suite, "LOCK3", torture_locktest3);
811
torture_suite_add_2smb_test(suite, "LOCK4", torture_locktest4);
812
torture_suite_add_2smb_test(suite, "LOCK5", torture_locktest5);
813
torture_suite_add_1smb_test(suite, "LOCK6", torture_locktest6);
814
torture_suite_add_1smb_test(suite, "LOCK7", torture_locktest7);