source4/torture/basic: Fix prototypes for all functions.
[mdw/samba.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 #include "torture/basic/proto.h"
29
30 #define BASEDIR "\\locktest"
31
32 /*
33   This test checks for two things:
34
35   1) correct support for retaining locks over a close (ie. the server
36      must not use posix semantics)
37   2) support for lock timeouts
38  */
39 static bool torture_locktest1(struct torture_context *tctx, 
40                               struct smbcli_state *cli1,
41                               struct smbcli_state *cli2)
42 {
43         const char *fname = BASEDIR "\\lockt1.lck";
44         int fnum1, fnum2, fnum3;
45         time_t t1, t2;
46         unsigned int lock_timeout;
47
48         if (!torture_setup_dir(cli1, BASEDIR)) {
49                 return false;
50         }
51
52         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
53         torture_assert(tctx, fnum1 != -1,
54                                    talloc_asprintf(tctx, 
55                 "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
56         fnum2 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
57         torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, 
58                 "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
59         fnum3 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
60         torture_assert(tctx, fnum3 != -1, talloc_asprintf(tctx, 
61                 "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
62
63         torture_assert_ntstatus_ok(tctx, 
64                 smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK),
65                 talloc_asprintf(tctx, "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
66
67         torture_assert(tctx, 
68                 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
69                 "lock2 succeeded! This is a locking bug\n");
70
71         if (!check_error(__location__, cli2, ERRDOS, ERRlock, 
72                          NT_STATUS_LOCK_NOT_GRANTED)) return false;
73
74         torture_assert(tctx,
75                 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
76                 "lock2 succeeded! This is a locking bug\n");
77
78         if (!check_error(__location__, cli2, ERRDOS, ERRlock, 
79                                  NT_STATUS_FILE_LOCK_CONFLICT)) return false;
80
81         torture_assert_ntstatus_ok(tctx, 
82                 smbcli_lock(cli1->tree, fnum1, 5, 9, 0, WRITE_LOCK),
83                 talloc_asprintf(tctx, 
84                 "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
85
86         torture_assert(tctx, 
87                 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 5, 9, 0, WRITE_LOCK)),
88                 "lock2 succeeded! This is a locking bug");
89         
90         if (!check_error(__location__, cli2, ERRDOS, ERRlock, 
91                                  NT_STATUS_LOCK_NOT_GRANTED)) return false;
92
93         torture_assert(tctx, 
94                 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
95                 "lock2 succeeded! This is a locking bug");
96         
97         if (!check_error(__location__, cli2, ERRDOS, ERRlock, 
98                                  NT_STATUS_LOCK_NOT_GRANTED)) return false;
99
100         torture_assert(tctx, 
101                 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
102                 "lock2 succeeded! This is a locking bug");
103
104         if (!check_error(__location__, cli2, ERRDOS, ERRlock, 
105                          NT_STATUS_FILE_LOCK_CONFLICT)) return false;
106
107         lock_timeout = (6 + (random() % 20));
108         torture_comment(tctx, "Testing lock timeout with timeout=%u\n", 
109                                         lock_timeout);
110         t1 = time_mono(NULL);
111         torture_assert(tctx, 
112                 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, lock_timeout * 1000, WRITE_LOCK)),
113                 "lock3 succeeded! This is a locking bug\n");
114
115         if (!check_error(__location__, cli2, ERRDOS, ERRlock, 
116                                  NT_STATUS_FILE_LOCK_CONFLICT)) return false;
117         t2 = time_mono(NULL);
118
119         if (t2 - t1 < 5) {
120                 torture_fail(tctx, 
121                         "error: This server appears not to support timed lock requests");
122         }
123         torture_comment(tctx, "server slept for %u seconds for a %u second timeout\n",
124                (unsigned int)(t2-t1), lock_timeout);
125
126         torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum2),
127                 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
128
129         torture_assert(tctx, 
130                 !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
131                 "lock4 succeeded! This is a locking bug");
132                 
133         if (!check_error(__location__, cli2, ERRDOS, ERRlock, 
134                          NT_STATUS_FILE_LOCK_CONFLICT)) return false;
135
136         torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
137                 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli1->tree)));
138
139         torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum3),
140                 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli2->tree)));
141
142         torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
143                 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
144
145         return true;
146 }
147
148
149 /*
150   This test checks that 
151
152   1) the server supports multiple locking contexts on the one SMB
153   connection, distinguished by PID.  
154
155   2) the server correctly fails overlapping locks made by the same PID (this
156      goes against POSIX behaviour, which is why it is tricky to implement)
157
158   3) the server denies unlock requests by an incorrect client PID
159 */
160 static bool torture_locktest2(struct torture_context *tctx,
161                               struct smbcli_state *cli)
162 {
163         const char *fname = BASEDIR "\\lockt2.lck";
164         int fnum1, fnum2, fnum3;
165
166         if (!torture_setup_dir(cli, BASEDIR)) {
167                 return false;
168         }
169
170         torture_comment(tctx, "Testing pid context\n");
171         
172         cli->session->pid = 1;
173
174         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
175         torture_assert(tctx, fnum1 != -1, 
176                 talloc_asprintf(tctx, 
177                 "open of %s failed (%s)", fname, smbcli_errstr(cli->tree)));
178
179         fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
180         torture_assert(tctx, fnum2 != -1,
181                 talloc_asprintf(tctx, "open2 of %s failed (%s)", 
182                        fname, smbcli_errstr(cli->tree)));
183
184         cli->session->pid = 2;
185
186         fnum3 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
187         torture_assert(tctx, fnum3 != -1,
188                 talloc_asprintf(tctx, 
189                 "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)));
190
191         cli->session->pid = 1;
192
193         torture_assert_ntstatus_ok(tctx, 
194                 smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK),
195                 talloc_asprintf(tctx, 
196                 "lock1 failed (%s)", smbcli_errstr(cli->tree)));
197
198         torture_assert(tctx, 
199                 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK)),
200                 "WRITE lock1 succeeded! This is a locking bug");
201                 
202         if (!check_error(__location__, cli, ERRDOS, ERRlock, 
203                          NT_STATUS_LOCK_NOT_GRANTED)) return false;
204
205         torture_assert(tctx, 
206                 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, WRITE_LOCK)),
207                 "WRITE lock2 succeeded! This is a locking bug");
208
209         if (!check_error(__location__, cli, ERRDOS, ERRlock, 
210                          NT_STATUS_LOCK_NOT_GRANTED)) return false;
211
212         torture_assert(tctx, 
213                 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, READ_LOCK)),
214                 "READ lock2 succeeded! This is a locking bug");
215
216         if (!check_error(__location__, cli, ERRDOS, ERRlock, 
217                          NT_STATUS_FILE_LOCK_CONFLICT)) return false;
218
219         torture_assert_ntstatus_ok(tctx, 
220                 smbcli_lock(cli->tree, fnum1, 100, 4, 0, WRITE_LOCK),
221                 talloc_asprintf(tctx, 
222                 "lock at 100 failed (%s)", smbcli_errstr(cli->tree)));
223
224         cli->session->pid = 2;
225
226         torture_assert(tctx, 
227                 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 100, 4)),
228                 "unlock at 100 succeeded! This is a locking bug");
229
230         torture_assert(tctx, 
231                 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 4)),
232                 "unlock1 succeeded! This is a locking bug");
233
234         if (!check_error(__location__, cli, 
235                                  ERRDOS, ERRnotlocked, 
236                                  NT_STATUS_RANGE_NOT_LOCKED)) return false;
237
238         torture_assert(tctx, 
239                 !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 8)),
240                 "unlock2 succeeded! This is a locking bug");
241
242         if (!check_error(__location__, cli, 
243                          ERRDOS, ERRnotlocked, 
244                          NT_STATUS_RANGE_NOT_LOCKED)) return false;
245
246         torture_assert(tctx, 
247                 !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
248                 "lock3 succeeded! This is a locking bug");
249
250         if (!check_error(__location__, cli, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false;
251
252         cli->session->pid = 1;
253
254         torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum1), 
255                 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli->tree)));
256
257         torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum2),
258                 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli->tree)));
259
260         torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum3),
261                 talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli->tree)));
262
263         return true;
264 }
265
266
267 /*
268   This test checks that 
269
270   1) the server supports the full offset range in lock requests
271 */
272 static bool torture_locktest3(struct torture_context *tctx, 
273                               struct smbcli_state *cli1,
274                               struct smbcli_state *cli2)
275 {
276         const char *fname = BASEDIR "\\lockt3.lck";
277         int fnum1, fnum2, i;
278         uint32_t offset;
279         extern int torture_numops;
280
281 #define NEXT_OFFSET offset += (~(uint32_t)0) / torture_numops
282
283         torture_comment(tctx, "Testing 32 bit offset ranges");
284
285         if (!torture_setup_dir(cli1, BASEDIR)) {
286                 return false;
287         }
288
289         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
290         torture_assert(tctx, fnum1 != -1, 
291                 talloc_asprintf(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
292         fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
293         torture_assert(tctx, fnum2 != -1,
294                 talloc_asprintf(tctx, "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
295
296         torture_comment(tctx, "Establishing %d locks\n", torture_numops);
297
298         for (offset=i=0;i<torture_numops;i++) {
299                 NEXT_OFFSET;
300                 torture_assert_ntstatus_ok(tctx, 
301                         smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK),
302                         talloc_asprintf(tctx, "lock1 %d failed (%s)", i, smbcli_errstr(cli1->tree)));
303
304                 torture_assert_ntstatus_ok(tctx, 
305                         smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK),
306                         talloc_asprintf(tctx, "lock2 %d failed (%s)", 
307                                i, smbcli_errstr(cli1->tree)));
308         }
309
310         torture_comment(tctx, "Testing %d locks\n", torture_numops);
311
312         for (offset=i=0;i<torture_numops;i++) {
313                 NEXT_OFFSET;
314
315                 torture_assert(tctx, 
316                         !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-2, 1, 0, WRITE_LOCK)),
317                         talloc_asprintf(tctx, "error: lock1 %d succeeded!", i));
318
319                 torture_assert(tctx, 
320                         !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-1, 1, 0, WRITE_LOCK)),
321                         talloc_asprintf(tctx, "error: lock2 %d succeeded!", i));
322
323                 torture_assert(tctx, 
324                         !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK)),
325                         talloc_asprintf(tctx, "error: lock3 %d succeeded!", i));
326
327                 torture_assert(tctx, 
328                         !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK)),
329                         talloc_asprintf(tctx, "error: lock4 %d succeeded!", i));
330         }
331
332         torture_comment(tctx, "Removing %d locks\n", torture_numops);
333
334         for (offset=i=0;i<torture_numops;i++) {
335                 NEXT_OFFSET;
336
337                 torture_assert_ntstatus_ok(tctx, 
338                                         smbcli_unlock(cli1->tree, fnum1, offset-1, 1),
339                                         talloc_asprintf(tctx, "unlock1 %d failed (%s)", 
340                                i,
341                                smbcli_errstr(cli1->tree)));
342
343                 torture_assert_ntstatus_ok(tctx, 
344                         smbcli_unlock(cli2->tree, fnum2, offset-2, 1),
345                         talloc_asprintf(tctx, "unlock2 %d failed (%s)", 
346                                i,
347                                smbcli_errstr(cli1->tree)));
348         }
349
350         torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
351                 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
352
353         torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
354                 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
355
356         torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
357                 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
358
359         return true;
360 }
361
362 #define EXPECTED(ret, v) if ((ret) != (v)) { \
363         torture_comment(tctx, "** "); correct = false; \
364         }
365
366 /*
367   looks at overlapping locks
368 */
369 static bool torture_locktest4(struct torture_context *tctx, 
370                               struct smbcli_state *cli1,
371                               struct smbcli_state *cli2)
372 {
373         const char *fname = BASEDIR "\\lockt4.lck";
374         int fnum1, fnum2, f;
375         bool ret;
376         uint8_t buf[1000];
377         bool correct = true;
378
379         if (!torture_setup_dir(cli1, BASEDIR)) {
380                 return false;
381         }
382
383         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
384         fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
385
386         memset(buf, 0, sizeof(buf));
387
388         if (smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
389                 torture_comment(tctx, "Failed to create file\n");
390                 correct = false;
391                 goto fail;
392         }
393
394         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
395               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 2, 4, 0, WRITE_LOCK));
396         EXPECTED(ret, false);
397         torture_comment(tctx, "the same process %s set overlapping write locks\n", ret?"can":"cannot");
398             
399         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 10, 4, 0, READ_LOCK)) &&
400               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 12, 4, 0, READ_LOCK));
401         EXPECTED(ret, true);
402         torture_comment(tctx, "the same process %s set overlapping read locks\n", ret?"can":"cannot");
403
404         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 20, 4, 0, WRITE_LOCK)) &&
405               NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 22, 4, 0, WRITE_LOCK));
406         EXPECTED(ret, false);
407         torture_comment(tctx, "a different connection %s set overlapping write locks\n", ret?"can":"cannot");
408             
409         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 30, 4, 0, READ_LOCK)) &&
410                 NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 32, 4, 0, READ_LOCK));
411         EXPECTED(ret, true);
412         torture_comment(tctx, "a different connection %s set overlapping read locks\n", ret?"can":"cannot");
413         
414         ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 40, 4, 0, WRITE_LOCK))) &&
415               NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 42, 4, 0, WRITE_LOCK)));
416         EXPECTED(ret, false);
417         torture_comment(tctx, "a different pid %s set overlapping write locks\n", ret?"can":"cannot");
418             
419         ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 50, 4, 0, READ_LOCK))) &&
420               NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 52, 4, 0, READ_LOCK)));
421         EXPECTED(ret, true);
422         torture_comment(tctx, "a different pid %s set overlapping read locks\n", ret?"can":"cannot");
423
424         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK)) &&
425               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK));
426         EXPECTED(ret, true);
427         torture_comment(tctx, "the same process %s set the same read lock twice\n", ret?"can":"cannot");
428
429         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK)) &&
430               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK));
431         EXPECTED(ret, false);
432         torture_comment(tctx, "the same process %s set the same write lock twice\n", ret?"can":"cannot");
433
434         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, READ_LOCK)) &&
435               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, WRITE_LOCK));
436         EXPECTED(ret, false);
437         torture_comment(tctx, "the same process %s overlay a read lock with a write lock\n", ret?"can":"cannot");
438
439         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, WRITE_LOCK)) &&
440               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, READ_LOCK));
441         EXPECTED(ret, true);
442         torture_comment(tctx, "the same process %s overlay a write lock with a read lock\n", ret?"can":"cannot");
443
444         ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, WRITE_LOCK))) &&
445               NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, READ_LOCK)));
446         EXPECTED(ret, false);
447         torture_comment(tctx, "a different pid %s overlay a write lock with a read lock\n", ret?"can":"cannot");
448
449         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 110, 4, 0, READ_LOCK)) &&
450               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 112, 4, 0, READ_LOCK)) &&
451               NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 110, 6));
452         EXPECTED(ret, false);
453         torture_comment(tctx, "the same process %s coalesce read locks\n", ret?"can":"cannot");
454
455
456         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 120, 4, 0, WRITE_LOCK)) &&
457               (smbcli_read(cli2->tree, fnum2, buf, 120, 4) == 4);
458         EXPECTED(ret, false);
459         torture_comment(tctx, "this server %s strict write locking\n", ret?"doesn't do":"does");
460
461         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK)) &&
462               (smbcli_write(cli2->tree, fnum2, 0, buf, 130, 4) == 4);
463         EXPECTED(ret, false);
464         torture_comment(tctx, "this server %s strict read locking\n", ret?"doesn't do":"does");
465
466
467         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
468               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
469               NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4)) &&
470               NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4));
471         EXPECTED(ret, true);
472         torture_comment(tctx, "this server %s do recursive read locking\n", ret?"does":"doesn't");
473
474
475         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, WRITE_LOCK)) &&
476               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, READ_LOCK)) &&
477               NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4)) &&
478               (smbcli_read(cli2->tree, fnum2, buf, 150, 4) == 4) &&
479               !(smbcli_write(cli2->tree, fnum2, 0, buf, 150, 4) == 4) &&
480               NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4));
481         EXPECTED(ret, true);
482         torture_comment(tctx, "this server %s do recursive lock overlays\n", ret?"does":"doesn't");
483
484         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 160, 4, 0, READ_LOCK)) &&
485               NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 160, 4)) &&
486               (smbcli_write(cli2->tree, fnum2, 0, buf, 160, 4) == 4) &&         
487               (smbcli_read(cli2->tree, fnum2, buf, 160, 4) == 4);               
488         EXPECTED(ret, true);
489         torture_comment(tctx, "the same process %s remove a read lock using write locking\n", ret?"can":"cannot");
490
491         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 170, 4, 0, WRITE_LOCK)) &&
492               NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 170, 4)) &&
493               (smbcli_write(cli2->tree, fnum2, 0, buf, 170, 4) == 4) &&         
494               (smbcli_read(cli2->tree, fnum2, buf, 170, 4) == 4);               
495         EXPECTED(ret, true);
496         torture_comment(tctx, "the same process %s remove a write lock using read locking\n", ret?"can":"cannot");
497
498         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, WRITE_LOCK)) &&
499               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, READ_LOCK)) &&
500               NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 190, 4)) &&
501               !(smbcli_write(cli2->tree, fnum2, 0, buf, 190, 4) == 4) &&                
502               (smbcli_read(cli2->tree, fnum2, buf, 190, 4) == 4);               
503         EXPECTED(ret, true);
504         torture_comment(tctx, "the same process %s remove the first lock first\n", ret?"does":"doesn't");
505
506         smbcli_close(cli1->tree, fnum1);
507         smbcli_close(cli2->tree, fnum2);
508         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
509         f = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
510         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
511               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, f, 0, 1, 0, READ_LOCK)) &&
512               NT_STATUS_IS_OK(smbcli_close(cli1->tree, fnum1)) &&
513               ((fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE)) != -1) &&
514               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
515         smbcli_close(cli1->tree, f);
516         smbcli_close(cli1->tree, fnum1);
517         EXPECTED(ret, true);
518         torture_comment(tctx, "the server %s have the NT byte range lock bug\n", !ret?"does":"doesn't");
519
520  fail:
521         smbcli_close(cli1->tree, fnum1);
522         smbcli_close(cli2->tree, fnum2);
523         smbcli_unlink(cli1->tree, fname);
524
525         return correct;
526 }
527
528 /*
529   looks at lock upgrade/downgrade.
530 */
531 static bool torture_locktest5(struct torture_context *tctx, struct smbcli_state *cli1, 
532                               struct smbcli_state *cli2)
533 {
534         const char *fname = BASEDIR "\\lockt5.lck";
535         int fnum1, fnum2, fnum3;
536         bool ret;
537         uint8_t buf[1000];
538         bool correct = true;
539
540         if (!torture_setup_dir(cli1, BASEDIR)) {
541                 return false;
542         }
543
544         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
545         fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
546         fnum3 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
547
548         memset(buf, 0, sizeof(buf));
549
550         torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
551                 "Failed to create file");
552
553         /* Check for NT bug... */
554         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
555                   NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 1, 0, READ_LOCK));
556         smbcli_close(cli1->tree, fnum1);
557         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
558         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
559         EXPECTED(ret, true);
560         torture_comment(tctx, "this server %s the NT locking bug\n", ret ? "doesn't have" : "has");
561         smbcli_close(cli1->tree, fnum1);
562         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
563         smbcli_unlock(cli1->tree, fnum3, 0, 1);
564
565         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
566               NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 1, 1, 0, READ_LOCK));
567         EXPECTED(ret, true);
568         torture_comment(tctx, "the same process %s overlay a write with a read lock\n", ret?"can":"cannot");
569
570         ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
571         EXPECTED(ret, false);
572
573         torture_comment(tctx, "a different processs %s get a read lock on the first process lock stack\n", ret?"can":"cannot");
574
575         /* Unlock the process 2 lock. */
576         smbcli_unlock(cli2->tree, fnum2, 0, 4);
577
578         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 4, 0, READ_LOCK));
579         EXPECTED(ret, false);
580
581         torture_comment(tctx, "the same processs on a different fnum %s get a read lock\n", ret?"can":"cannot");
582
583         /* Unlock the process 1 fnum3 lock. */
584         smbcli_unlock(cli1->tree, fnum3, 0, 4);
585
586         /* Stack 2 more locks here. */
587         ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK)) &&
588                   NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK));
589
590         EXPECTED(ret, true);
591         torture_comment(tctx, "the same process %s stack read locks\n", ret?"can":"cannot");
592
593         /* Unlock the first process lock, then check this was the WRITE lock that was
594                 removed. */
595
596 ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
597         NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
598
599         EXPECTED(ret, true);
600         torture_comment(tctx, "the first unlock removes the %s lock\n", ret?"WRITE":"READ");
601
602         /* Unlock the process 2 lock. */
603         smbcli_unlock(cli2->tree, fnum2, 0, 4);
604
605         /* We should have 3 stacked locks here. Ensure we need to do 3 unlocks. */
606
607         ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 1, 1)) &&
608                   NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
609                   NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
610
611         EXPECTED(ret, true);
612         torture_comment(tctx, "the same process %s unlock the stack of 3 locks\n", ret?"can":"cannot");
613
614         /* Ensure the next unlock fails. */
615         ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
616         EXPECTED(ret, false);
617         torture_comment(tctx, "the same process %s count the lock stack\n", !ret?"can":"cannot"); 
618
619         /* Ensure connection 2 can get a write lock. */
620         ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, WRITE_LOCK));
621         EXPECTED(ret, true);
622
623         torture_comment(tctx, "a different processs %s get a write lock on the unlocked stack\n", ret?"can":"cannot");
624
625
626         torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
627                 talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
628
629         torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
630                 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
631
632         torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum3),
633                 talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
634
635         torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
636                 talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
637
638         return correct;
639 }
640
641 /*
642   tries the unusual lockingX locktype bits
643 */
644 static bool torture_locktest6(struct torture_context *tctx, 
645                               struct smbcli_state *cli)
646 {
647         const char *fname[1] = { "\\lock6.txt" };
648         int i;
649         int fnum;
650         NTSTATUS status;
651
652         if (!torture_setup_dir(cli, BASEDIR)) {
653                 return false;
654         }
655
656         for (i=0;i<1;i++) {
657                 torture_comment(tctx, "Testing %s\n", fname[i]);
658
659                 smbcli_unlink(cli->tree, fname[i]);
660
661                 fnum = smbcli_open(cli->tree, fname[i], O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
662                 status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CHANGE_LOCKTYPE);
663                 smbcli_close(cli->tree, fnum);
664                 torture_comment(tctx, "CHANGE_LOCKTYPE gave %s\n", nt_errstr(status));
665
666                 fnum = smbcli_open(cli->tree, fname[i], O_RDWR, DENY_NONE);
667                 status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CANCEL_LOCK);
668                 smbcli_close(cli->tree, fnum);
669                 torture_comment(tctx, "CANCEL_LOCK gave %s\n", nt_errstr(status));
670
671                 smbcli_unlink(cli->tree, fname[i]);
672         }
673
674         return true;
675 }
676
677 static bool torture_locktest7(struct torture_context *tctx, 
678                               struct smbcli_state *cli1)
679 {
680         const char *fname = BASEDIR "\\lockt7.lck";
681         int fnum1;
682         int fnum2 = -1;
683         size_t size;
684         uint8_t buf[200];
685         bool correct = false;
686
687         torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
688                                    talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
689
690         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
691
692         memset(buf, 0, sizeof(buf));
693
694         torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
695                 "Failed to create file");
696
697         cli1->session->pid = 1;
698
699         torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK),
700                 talloc_asprintf(tctx, "Unable to apply read lock on range 130:4, error was %s", 
701                        smbcli_errstr(cli1->tree)));
702
703         torture_comment(tctx, "pid1 successfully locked range 130:4 for READ\n");
704
705         torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4, 
706                         talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s)", 
707                        smbcli_errstr(cli1->tree)));
708
709         torture_comment(tctx, "pid1 successfully read the range 130:4\n");
710
711         if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
712                 torture_comment(tctx, "pid1 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
713                 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
714                         "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
715         } else {
716                 torture_fail(tctx, "pid1 successfully wrote to the range 130:4 (should be denied)");
717         }
718
719         cli1->session->pid = 2;
720
721         if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
722                 torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
723         } else {
724                 torture_comment(tctx, "pid2 successfully read the range 130:4\n");
725         }
726
727         if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
728                 torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
729                 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT, 
730                         "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
731         } else {
732                 torture_fail(tctx, "pid2 successfully wrote to the range 130:4 (should be denied)"); 
733         }
734
735         cli1->session->pid = 1;
736         smbcli_unlock(cli1->tree, fnum1, 130, 4);
737
738         torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, WRITE_LOCK),
739                 talloc_asprintf(tctx, "Unable to apply write lock on range 130:4, error was %s", 
740                        smbcli_errstr(cli1->tree)));
741         torture_comment(tctx, "pid1 successfully locked range 130:4 for WRITE\n");
742
743         torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4, 
744                 talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s", 
745                        smbcli_errstr(cli1->tree)));
746         torture_comment(tctx, "pid1 successfully read the range 130:4\n");
747
748         torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) == 4, 
749                 talloc_asprintf(tctx, "pid1 unable to write to the range 130:4, error was %s",
750                        smbcli_errstr(cli1->tree)));
751         torture_comment(tctx, "pid1 successfully wrote to the range 130:4\n");
752
753         cli1->session->pid = 2;
754
755         if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
756                 torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n", 
757                        smbcli_errstr(cli1->tree));
758                 torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT, 
759                         "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
760         } else {
761                 torture_fail(tctx, "pid2 successfully read the range 130:4 (should be denied)");
762         }
763
764         if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
765                 torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n", 
766                        smbcli_errstr(cli1->tree));
767                 if (!NT_STATUS_EQUAL(smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT)) {
768                         torture_comment(tctx, "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT) (%s)\n",
769                                __location__);
770                         goto fail;
771                 }
772         } else {
773                 torture_comment(tctx, "pid2 successfully wrote to the range 130:4 (should be denied) (%s)\n", 
774                        __location__);
775                 goto fail;
776         }
777
778         torture_comment(tctx, "Testing truncate of locked file.\n");
779
780         fnum2 = smbcli_open(cli1->tree, fname, O_RDWR|O_TRUNC, DENY_NONE);
781
782         torture_assert(tctx, fnum2 != -1, "Unable to truncate locked file");
783
784         torture_comment(tctx, "Truncated locked file.\n");
785
786         torture_assert_ntstatus_ok(tctx, smbcli_getatr(cli1->tree, fname, NULL, &size, NULL), 
787                 talloc_asprintf(tctx, "getatr failed (%s)", smbcli_errstr(cli1->tree)));
788
789         torture_assert(tctx, size == 0, talloc_asprintf(tctx, "Unable to truncate locked file. Size was %u", (unsigned)size));
790
791         cli1->session->pid = 1;
792
793         smbcli_unlock(cli1->tree, fnum1, 130, 4);
794         correct = true;
795
796 fail:
797         smbcli_close(cli1->tree, fnum1);
798         smbcli_close(cli1->tree, fnum2);
799         smbcli_unlink(cli1->tree, fname);
800
801         return correct;
802 }
803
804 struct torture_suite *torture_base_locktest(TALLOC_CTX *mem_ctx)
805 {
806         struct torture_suite *suite = torture_suite_create(mem_ctx, "lock");
807         torture_suite_add_2smb_test(suite, "LOCK1", torture_locktest1);
808         torture_suite_add_1smb_test(suite, "LOCK2", torture_locktest2);
809         torture_suite_add_2smb_test(suite, "LOCK3", torture_locktest3);
810         torture_suite_add_2smb_test(suite, "LOCK4",  torture_locktest4);
811         torture_suite_add_2smb_test(suite, "LOCK5",  torture_locktest5);
812         torture_suite_add_1smb_test(suite, "LOCK6",  torture_locktest6);
813         torture_suite_add_1smb_test(suite, "LOCK7",  torture_locktest7);
814
815         return suite;
816 }