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