71364ef578eb351383d1618bc881f95d79bd8223
[metze/samba/wip.git] / source4 / torture / basic / locking.c
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  */
38 static 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 */
159 static 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 */
271 static 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 */
368 static 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 */
530 static 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
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));
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 */
643 static 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
676 static 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
795 fail:
796         smbcli_close(cli1->tree, fnum1);
797         smbcli_close(cli1->tree, fnum2);
798         smbcli_unlink(cli1->tree, fname);
799
800         return correct;
801 }
802
803 struct 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 }