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