source: trunk/server/source4/torture/basic/locking.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 31.0 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 basic locking tests
5
6 Copyright (C) Andrew Tridgell 2000-2004
7 Copyright (C) Jeremy Allison 2000-2004
8
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.
13
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.
18
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/>.
21*/
22
23#include "includes.h"
24#include "libcli/libcli.h"
25#include "torture/util.h"
26#include "system/time.h"
27#include "system/filesys.h"
28
29#define BASEDIR "\\locktest"
30
31/*
32 This test checks for two things:
33
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
37 */
38static bool torture_locktest1(struct torture_context *tctx,
39 struct smbcli_state *cli1,
40 struct smbcli_state *cli2)
41{
42 const char *fname = BASEDIR "\\lockt1.lck";
43 int fnum1, fnum2, fnum3;
44 time_t t1, t2;
45 unsigned int lock_timeout;
46
47 if (!torture_setup_dir(cli1, BASEDIR)) {
48 return false;
49 }
50
51 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
52 torture_assert(tctx, fnum1 != -1,
53 talloc_asprintf(tctx,
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)));
61
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)));
65
66 torture_assert(tctx,
67 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
68 "lock2 succeeded! This is a locking bug\n");
69
70 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
71 NT_STATUS_LOCK_NOT_GRANTED)) return false;
72
73 torture_assert(tctx,
74 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
75 "lock2 succeeded! This is a locking bug\n");
76
77 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
78 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
79
80 torture_assert_ntstatus_ok(tctx,
81 smbcli_lock(cli1->tree, fnum1, 5, 9, 0, WRITE_LOCK),
82 talloc_asprintf(tctx,
83 "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
84
85 torture_assert(tctx,
86 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 5, 9, 0, WRITE_LOCK)),
87 "lock2 succeeded! This is a locking bug");
88
89 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
90 NT_STATUS_LOCK_NOT_GRANTED)) return false;
91
92 torture_assert(tctx,
93 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
94 "lock2 succeeded! This is a locking bug");
95
96 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
97 NT_STATUS_LOCK_NOT_GRANTED)) return false;
98
99 torture_assert(tctx,
100 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
101 "lock2 succeeded! This is a locking bug");
102
103 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
104 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
105
106 lock_timeout = (6 + (random() % 20));
107 torture_comment(tctx, "Testing lock timeout with timeout=%u\n",
108 lock_timeout);
109 t1 = time_mono(NULL);
110 torture_assert(tctx,
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");
113
114 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
115 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
116 t2 = time_mono(NULL);
117
118 if (t2 - t1 < 5) {
119 torture_fail(tctx,
120 "error: This server appears not to support timed lock requests");
121 }
122 torture_comment(tctx, "server slept for %u seconds for a %u second timeout\n",
123 (unsigned int)(t2-t1), lock_timeout);
124
125 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum2),
126 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
127
128 torture_assert(tctx,
129 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
130 "lock4 succeeded! This is a locking bug");
131
132 if (!check_error(__location__, cli2, ERRDOS, ERRlock,
133 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
134
135 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
136 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli1->tree)));
137
138 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum3),
139 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli2->tree)));
140
141 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
142 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
143
144 return true;
145}
146
147
148/*
149 This test checks that
150
151 1) the server supports multiple locking contexts on the one SMB
152 connection, distinguished by PID.
153
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)
156
157 3) the server denies unlock requests by an incorrect client PID
158*/
159static bool torture_locktest2(struct torture_context *tctx,
160 struct smbcli_state *cli)
161{
162 const char *fname = BASEDIR "\\lockt2.lck";
163 int fnum1, fnum2, fnum3;
164
165 if (!torture_setup_dir(cli, BASEDIR)) {
166 return false;
167 }
168
169 torture_comment(tctx, "Testing pid context\n");
170
171 cli->session->pid = 1;
172
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)));
177
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)));
182
183 cli->session->pid = 2;
184
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)));
189
190 cli->session->pid = 1;
191
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)));
196
197 torture_assert(tctx,
198 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK)),
199 "WRITE lock1 succeeded! This is a locking bug");
200
201 if (!check_error(__location__, cli, ERRDOS, ERRlock,
202 NT_STATUS_LOCK_NOT_GRANTED)) return false;
203
204 torture_assert(tctx,
205 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, WRITE_LOCK)),
206 "WRITE lock2 succeeded! This is a locking bug");
207
208 if (!check_error(__location__, cli, ERRDOS, ERRlock,
209 NT_STATUS_LOCK_NOT_GRANTED)) return false;
210
211 torture_assert(tctx,
212 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, READ_LOCK)),
213 "READ lock2 succeeded! This is a locking bug");
214
215 if (!check_error(__location__, cli, ERRDOS, ERRlock,
216 NT_STATUS_FILE_LOCK_CONFLICT)) return false;
217
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)));
222
223 cli->session->pid = 2;
224
225 torture_assert(tctx,
226 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 100, 4)),
227 "unlock at 100 succeeded! This is a locking bug");
228
229 torture_assert(tctx,
230 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 4)),
231 "unlock1 succeeded! This is a locking bug");
232
233 if (!check_error(__location__, cli,
234 ERRDOS, ERRnotlocked,
235 NT_STATUS_RANGE_NOT_LOCKED)) return false;
236
237 torture_assert(tctx,
238 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 8)),
239 "unlock2 succeeded! This is a locking bug");
240
241 if (!check_error(__location__, cli,
242 ERRDOS, ERRnotlocked,
243 NT_STATUS_RANGE_NOT_LOCKED)) return false;
244
245 torture_assert(tctx,
246 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
247 "lock3 succeeded! This is a locking bug");
248
249 if (!check_error(__location__, cli, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false;
250
251 cli->session->pid = 1;
252
253 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum1),
254 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli->tree)));
255
256 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum2),
257 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli->tree)));
258
259 torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum3),
260 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli->tree)));
261
262 return true;
263}
264
265
266/*
267 This test checks that
268
269 1) the server supports the full offset range in lock requests
270*/
271static bool torture_locktest3(struct torture_context *tctx,
272 struct smbcli_state *cli1,
273 struct smbcli_state *cli2)
274{
275 const char *fname = BASEDIR "\\lockt3.lck";
276 int fnum1, fnum2, i;
277 uint32_t offset;
278 extern int torture_numops;
279
280#define NEXT_OFFSET offset += (~(uint32_t)0) / torture_numops
281
282 torture_comment(tctx, "Testing 32 bit offset ranges");
283
284 if (!torture_setup_dir(cli1, BASEDIR)) {
285 return false;
286 }
287
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)));
294
295 torture_comment(tctx, "Establishing %d locks\n", torture_numops);
296
297 for (offset=i=0;i<torture_numops;i++) {
298 NEXT_OFFSET;
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)));
302
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)));
307 }
308
309 torture_comment(tctx, "Testing %d locks\n", torture_numops);
310
311 for (offset=i=0;i<torture_numops;i++) {
312 NEXT_OFFSET;
313
314 torture_assert(tctx,
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));
317
318 torture_assert(tctx,
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));
321
322 torture_assert(tctx,
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));
325
326 torture_assert(tctx,
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));
329 }
330
331 torture_comment(tctx, "Removing %d locks\n", torture_numops);
332
333 for (offset=i=0;i<torture_numops;i++) {
334 NEXT_OFFSET;
335
336 torture_assert_ntstatus_ok(tctx,
337 smbcli_unlock(cli1->tree, fnum1, offset-1, 1),
338 talloc_asprintf(tctx, "unlock1 %d failed (%s)",
339 i,
340 smbcli_errstr(cli1->tree)));
341
342 torture_assert_ntstatus_ok(tctx,
343 smbcli_unlock(cli2->tree, fnum2, offset-2, 1),
344 talloc_asprintf(tctx, "unlock2 %d failed (%s)",
345 i,
346 smbcli_errstr(cli1->tree)));
347 }
348
349 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
350 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
351
352 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
353 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
354
355 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
356 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
357
358 return true;
359}
360
361#define EXPECTED(ret, v) if ((ret) != (v)) { \
362 torture_comment(tctx, "** "); correct = false; \
363 }
364
365/*
366 looks at overlapping locks
367*/
368static bool torture_locktest4(struct torture_context *tctx,
369 struct smbcli_state *cli1,
370 struct smbcli_state *cli2)
371{
372 const char *fname = BASEDIR "\\lockt4.lck";
373 int fnum1, fnum2, f;
374 bool ret;
375 uint8_t buf[1000];
376 bool correct = true;
377
378 if (!torture_setup_dir(cli1, BASEDIR)) {
379 return false;
380 }
381
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);
384
385 memset(buf, 0, sizeof(buf));
386
387 if (smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
388 torture_comment(tctx, "Failed to create file\n");
389 correct = false;
390 goto fail;
391 }
392
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");
397
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));
400 EXPECTED(ret, true);
401 torture_comment(tctx, "the same process %s set overlapping read locks\n", ret?"can":"cannot");
402
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");
407
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));
410 EXPECTED(ret, true);
411 torture_comment(tctx, "a different connection %s set overlapping read locks\n", ret?"can":"cannot");
412
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");
417
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)));
420 EXPECTED(ret, true);
421 torture_comment(tctx, "a different pid %s set overlapping read locks\n", ret?"can":"cannot");
422
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));
425 EXPECTED(ret, true);
426 torture_comment(tctx, "the same process %s set the same read lock twice\n", ret?"can":"cannot");
427
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");
432
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");
437
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));
440 EXPECTED(ret, true);
441 torture_comment(tctx, "the same process %s overlay a write lock with a read lock\n", ret?"can":"cannot");
442
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");
447
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");
453
454
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");
459
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");
464
465
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));
470 EXPECTED(ret, true);
471 torture_comment(tctx, "this server %s do recursive read locking\n", ret?"does":"doesn't");
472
473
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));
480 EXPECTED(ret, true);
481 torture_comment(tctx, "this server %s do recursive lock overlays\n", ret?"does":"doesn't");
482
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);
487 EXPECTED(ret, true);
488 torture_comment(tctx, "the same process %s remove a read lock using write locking\n", ret?"can":"cannot");
489
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);
494 EXPECTED(ret, true);
495 torture_comment(tctx, "the same process %s remove a write lock using read locking\n", ret?"can":"cannot");
496
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);
502 EXPECTED(ret, true);
503 torture_comment(tctx, "the same process %s remove the first lock first\n", ret?"does":"doesn't");
504
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);
516 EXPECTED(ret, true);
517 torture_comment(tctx, "the server %s have the NT byte range lock bug\n", !ret?"does":"doesn't");
518
519 fail:
520 smbcli_close(cli1->tree, fnum1);
521 smbcli_close(cli2->tree, fnum2);
522 smbcli_unlink(cli1->tree, fname);
523
524 return correct;
525}
526
527/*
528 looks at lock upgrade/downgrade.
529*/
530static bool torture_locktest5(struct torture_context *tctx, struct smbcli_state *cli1,
531 struct smbcli_state *cli2)
532{
533 const char *fname = BASEDIR "\\lockt5.lck";
534 int fnum1, fnum2, fnum3;
535 bool ret;
536 uint8_t buf[1000];
537 bool correct = true;
538
539 if (!torture_setup_dir(cli1, BASEDIR)) {
540 return false;
541 }
542
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);
546
547 memset(buf, 0, sizeof(buf));
548
549 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
550 "Failed to create file");
551
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));
558 EXPECTED(ret, true);
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);
563
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));
566 EXPECTED(ret, true);
567 torture_comment(tctx, "the same process %s overlay a write with a read lock\n", ret?"can":"cannot");
568
569 ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
570 EXPECTED(ret, false);
571
572 torture_comment(tctx, "a different processs %s get a read lock on the first process lock stack\n", ret?"can":"cannot");
573
574 /* Unlock the process 2 lock. */
575 smbcli_unlock(cli2->tree, fnum2, 0, 4);
576
577 ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 4, 0, READ_LOCK));
578 EXPECTED(ret, false);
579
580 torture_comment(tctx, "the same processs on a different fnum %s get a read lock\n", ret?"can":"cannot");
581
582 /* Unlock the process 1 fnum3 lock. */
583 smbcli_unlock(cli1->tree, fnum3, 0, 4);
584
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));
588
589 EXPECTED(ret, true);
590 torture_comment(tctx, "the same process %s stack read locks\n", ret?"can":"cannot");
591
592 /* Unlock the first process lock, then check this was the WRITE lock that was
593 removed. */
594
595ret = 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));
597
598 EXPECTED(ret, true);
599 torture_comment(tctx, "the first unlock removes the %s lock\n", ret?"WRITE":"READ");
600
601 /* Unlock the process 2 lock. */
602 smbcli_unlock(cli2->tree, fnum2, 0, 4);
603
604 /* We should have 3 stacked locks here. Ensure we need to do 3 unlocks. */
605
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));
609
610 EXPECTED(ret, true);
611 torture_comment(tctx, "the same process %s unlock the stack of 3 locks\n", ret?"can":"cannot");
612
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");
617
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));
620 EXPECTED(ret, true);
621
622 torture_comment(tctx, "a different processs %s get a write lock on the unlocked stack\n", ret?"can":"cannot");
623
624
625 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
626 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
627
628 torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
629 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
630
631 torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum3),
632 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
633
634 torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
635 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
636
637 return correct;
638}
639
640/*
641 tries the unusual lockingX locktype bits
642*/
643static bool torture_locktest6(struct torture_context *tctx,
644 struct smbcli_state *cli)
645{
646 const char *fname[1] = { "\\lock6.txt" };
647 int i;
648 int fnum;
649 NTSTATUS status;
650
651 if (!torture_setup_dir(cli, BASEDIR)) {
652 return false;
653 }
654
655 for (i=0;i<1;i++) {
656 torture_comment(tctx, "Testing %s\n", fname[i]);
657
658 smbcli_unlink(cli->tree, fname[i]);
659
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));
664
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));
669
670 smbcli_unlink(cli->tree, fname[i]);
671 }
672
673 return true;
674}
675
676static bool torture_locktest7(struct torture_context *tctx,
677 struct smbcli_state *cli1)
678{
679 const char *fname = BASEDIR "\\lockt7.lck";
680 int fnum1;
681 int fnum2 = -1;
682 size_t size;
683 uint8_t buf[200];
684 bool correct = false;
685
686 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
687 talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
688
689 fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
690
691 memset(buf, 0, sizeof(buf));
692
693 torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
694 "Failed to create file");
695
696 cli1->session->pid = 1;
697
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)));
701
702 torture_comment(tctx, "pid1 successfully locked range 130:4 for READ\n");
703
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)));
707
708 torture_comment(tctx, "pid1 successfully read the range 130:4\n");
709
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)");
714 } else {
715 torture_fail(tctx, "pid1 successfully wrote to the range 130:4 (should be denied)");
716 }
717
718 cli1->session->pid = 2;
719
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));
722 } else {
723 torture_comment(tctx, "pid2 successfully read the range 130:4\n");
724 }
725
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)");
730 } else {
731 torture_fail(tctx, "pid2 successfully wrote to the range 130:4 (should be denied)");
732 }
733
734 cli1->session->pid = 1;
735 smbcli_unlock(cli1->tree, fnum1, 130, 4);
736
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");
741
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");
746
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");
751
752 cli1->session->pid = 2;
753
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)");
759 } else {
760 torture_fail(tctx, "pid2 successfully read the range 130:4 (should be denied)");
761 }
762
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",
768 __location__);
769 goto fail;
770 }
771 } else {
772 torture_comment(tctx, "pid2 successfully wrote to the range 130:4 (should be denied) (%s)\n",
773 __location__);
774 goto fail;
775 }
776
777 torture_comment(tctx, "Testing truncate of locked file.\n");
778
779 fnum2 = smbcli_open(cli1->tree, fname, O_RDWR|O_TRUNC, DENY_NONE);
780
781 torture_assert(tctx, fnum2 != -1, "Unable to truncate locked file");
782
783 torture_comment(tctx, "Truncated locked file.\n");
784
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)));
787
788 torture_assert(tctx, size == 0, talloc_asprintf(tctx, "Unable to truncate locked file. Size was %u", (unsigned)size));
789
790 cli1->session->pid = 1;
791
792 smbcli_unlock(cli1->tree, fnum1, 130, 4);
793 correct = true;
794
795fail:
796 smbcli_close(cli1->tree, fnum1);
797 smbcli_close(cli1->tree, fnum2);
798 smbcli_unlink(cli1->tree, fname);
799
800 return correct;
801}
802
803struct torture_suite *torture_base_locktest(TALLOC_CTX *mem_ctx)
804{
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);
813
814 return suite;
815}
Note: See TracBrowser for help on using the repository browser.