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