127745e38e8bb77bb4200bf1dd622679bd563c2c
[ddiss/samba.git] / source4 / torture / raw / lock.c
1 /* 
2    Unix SMB/CIFS implementation.
3    test suite for various lock operations
4    Copyright (C) Andrew Tridgell 2003
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "torture/torture.h"
22 #include "libcli/raw/libcliraw.h"
23 #include "libcli/raw/raw_proto.h"
24 #include "system/time.h"
25 #include "system/filesys.h"
26 #include "libcli/libcli.h"
27 #include "torture/util.h"
28 #include "libcli/composite/composite.h"
29 #include "libcli/smb_composite/smb_composite.h"
30 #include "lib/cmdline/popt_common.h"
31 #include "param/param.h"
32 #include "torture/raw/proto.h"
33
34 #define CHECK_STATUS(status, correct) do { \
35         if (!NT_STATUS_EQUAL(status, correct)) { \
36                 torture_result(tctx, TORTURE_FAIL, \
37                         "(%s) Incorrect status %s - should be %s\n", \
38                         __location__, nt_errstr(status), nt_errstr(correct)); \
39                 ret = false; \
40                 goto done; \
41         }} while (0)
42
43 #define CHECK_STATUS_CONT(status, correct) do { \
44         if (!NT_STATUS_EQUAL(status, correct)) { \
45                 torture_result(tctx, TORTURE_FAIL, \
46                         "(%s) Incorrect status %s - should be %s\n", \
47                         __location__, nt_errstr(status), nt_errstr(correct)); \
48                 ret = false; \
49         }} while (0)
50
51 #define CHECK_STATUS_OR(status, correct1, correct2) do { \
52         if ((!NT_STATUS_EQUAL(status, correct1)) && \
53             (!NT_STATUS_EQUAL(status, correct2))) { \
54                 torture_result(tctx, TORTURE_FAIL, \
55                         "(%s) Incorrect status %s - should be %s or %s\n", \
56                         __location__, nt_errstr(status), nt_errstr(correct1), \
57                         nt_errstr(correct2)); \
58                 ret = false; \
59                 goto done; \
60         }} while (0)
61
62 #define CHECK_STATUS_OR_CONT(status, correct1, correct2) do { \
63         if ((!NT_STATUS_EQUAL(status, correct1)) && \
64             (!NT_STATUS_EQUAL(status, correct2))) { \
65                 torture_result(tctx, TORTURE_FAIL, \
66                         "(%s) Incorrect status %s - should be %s or %s\n", \
67                         __location__, nt_errstr(status), nt_errstr(correct1), \
68                         nt_errstr(correct2)); \
69                 ret = false; \
70         }} while (0)
71 #define BASEDIR "\\testlock"
72
73 #define TARGET_IS_W2K8(_tctx) (torture_setting_bool(_tctx, "w2k8", false))
74 #define TARGET_IS_WIN7(_tctx) (torture_setting_bool(_tctx, "win7", false))
75 #define TARGET_IS_WINDOWS(_tctx) \
76         ((torture_setting_bool(_tctx, "w2k3", false)) || \
77          (torture_setting_bool(_tctx, "w2k8", false)) || \
78          (torture_setting_bool(_tctx, "win7", false)))
79 #define TARGET_IS_SAMBA3(_tctx) (torture_setting_bool(_tctx, "samba3", false))
80 #define TARGET_IS_SAMBA4(_tctx) (torture_setting_bool(_tctx, "samba4", false))
81
82 #define TARGET_SUPPORTS_INVALID_LOCK_RANGE(_tctx) \
83         (torture_setting_bool(_tctx, "invalid_lock_range_support", true))
84 #define TARGET_SUPPORTS_SMBEXIT(_tctx) \
85     (torture_setting_bool(_tctx, "smbexit_pdu_support", true))
86 #define TARGET_SUPPORTS_SMBLOCK(_tctx) \
87     (torture_setting_bool(_tctx, "smblock_pdu_support", true))
88 #define TARGET_SUPPORTS_OPENX_DENY_DOS(_tctx) \
89     (torture_setting_bool(_tctx, "openx_deny_dos_support", true))
90 #define TARGET_RETURNS_RANGE_NOT_LOCKED(_tctx) \
91     (torture_setting_bool(_tctx, "range_not_locked_on_file_close", true))
92 /*
93   test SMBlock and SMBunlock ops
94 */
95 static bool test_lock(struct torture_context *tctx, struct smbcli_state *cli)
96 {
97         union smb_lock io;
98         NTSTATUS status;
99         bool ret = true;
100         int fnum;
101         const char *fname = BASEDIR "\\test.txt";
102
103         if (!TARGET_SUPPORTS_SMBLOCK(tctx))
104                 torture_skip(tctx, "Target does not support the SMBlock PDU");
105
106         if (!torture_setup_dir(cli, BASEDIR)) {
107                 return false;
108         }
109
110         torture_comment(tctx, "Testing RAW_LOCK_LOCK\n");
111         io.generic.level = RAW_LOCK_LOCK;
112         
113         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
114         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
115                        "Failed to create %s - %s\n",
116                        fname, smbcli_errstr(cli->tree)));
117
118         torture_comment(tctx, "Trying 0/0 lock\n");
119         io.lock.level = RAW_LOCK_LOCK;
120         io.lock.in.file.fnum = fnum;
121         io.lock.in.count = 0;
122         io.lock.in.offset = 0;
123         status = smb_raw_lock(cli->tree, &io);
124         CHECK_STATUS(status, NT_STATUS_OK);
125         cli->session->pid++;
126         status = smb_raw_lock(cli->tree, &io);
127         CHECK_STATUS(status, NT_STATUS_OK);
128         cli->session->pid--;
129         io.lock.level = RAW_LOCK_UNLOCK;
130         status = smb_raw_lock(cli->tree, &io);
131         CHECK_STATUS(status, NT_STATUS_OK);
132
133         torture_comment(tctx, "Trying 0/1 lock\n");
134         io.lock.level = RAW_LOCK_LOCK;
135         io.lock.in.file.fnum = fnum;
136         io.lock.in.count = 1;
137         io.lock.in.offset = 0;
138         status = smb_raw_lock(cli->tree, &io);
139         CHECK_STATUS(status, NT_STATUS_OK);
140         cli->session->pid++;
141         status = smb_raw_lock(cli->tree, &io);
142         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
143         cli->session->pid--;
144         io.lock.level = RAW_LOCK_UNLOCK;
145         status = smb_raw_lock(cli->tree, &io);
146         CHECK_STATUS(status, NT_STATUS_OK);
147         io.lock.level = RAW_LOCK_UNLOCK;
148         status = smb_raw_lock(cli->tree, &io);
149         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
150
151         torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
152         io.lock.level = RAW_LOCK_LOCK;
153         io.lock.in.file.fnum = fnum;
154         io.lock.in.count = 4000;
155         io.lock.in.offset = 0xEEFFFFFF;
156         status = smb_raw_lock(cli->tree, &io);
157         CHECK_STATUS(status, NT_STATUS_OK);
158         cli->session->pid++;
159         status = smb_raw_lock(cli->tree, &io);
160         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
161         cli->session->pid--;
162         io.lock.level = RAW_LOCK_UNLOCK;
163         status = smb_raw_lock(cli->tree, &io);
164         CHECK_STATUS(status, NT_STATUS_OK);
165         io.lock.level = RAW_LOCK_UNLOCK;
166         status = smb_raw_lock(cli->tree, &io);
167         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
168
169         torture_comment(tctx, "Trying 0xEF000000 lock\n");
170         io.lock.level = RAW_LOCK_LOCK;
171         io.lock.in.file.fnum = fnum;
172         io.lock.in.count = 4000;
173         io.lock.in.offset = 0xEEFFFFFF;
174         status = smb_raw_lock(cli->tree, &io);
175         CHECK_STATUS(status, NT_STATUS_OK);
176         cli->session->pid++;
177         status = smb_raw_lock(cli->tree, &io);
178         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
179         cli->session->pid--;
180         io.lock.level = RAW_LOCK_UNLOCK;
181         status = smb_raw_lock(cli->tree, &io);
182         CHECK_STATUS(status, NT_STATUS_OK);
183         io.lock.level = RAW_LOCK_UNLOCK;
184         status = smb_raw_lock(cli->tree, &io);
185         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
186
187         torture_comment(tctx, "Trying max lock\n");
188         io.lock.level = RAW_LOCK_LOCK;
189         io.lock.in.file.fnum = fnum;
190         io.lock.in.count = 4000;
191         io.lock.in.offset = 0xEF000000;
192         status = smb_raw_lock(cli->tree, &io);
193         CHECK_STATUS(status, NT_STATUS_OK);
194         cli->session->pid++;
195         status = smb_raw_lock(cli->tree, &io);
196         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
197         cli->session->pid--;
198         io.lock.level = RAW_LOCK_UNLOCK;
199         status = smb_raw_lock(cli->tree, &io);
200         CHECK_STATUS(status, NT_STATUS_OK);
201         io.lock.level = RAW_LOCK_UNLOCK;
202         status = smb_raw_lock(cli->tree, &io);
203         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
204
205         torture_comment(tctx, "Trying wrong pid unlock\n");
206         io.lock.level = RAW_LOCK_LOCK;
207         io.lock.in.file.fnum = fnum;
208         io.lock.in.count = 4002;
209         io.lock.in.offset = 10001;
210         status = smb_raw_lock(cli->tree, &io);
211         CHECK_STATUS(status, NT_STATUS_OK);
212         cli->session->pid++;
213         io.lock.level = RAW_LOCK_UNLOCK;
214         status = smb_raw_lock(cli->tree, &io);
215         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
216         cli->session->pid--;
217         status = smb_raw_lock(cli->tree, &io);
218         CHECK_STATUS(status, NT_STATUS_OK);
219
220 done:
221         smbcli_close(cli->tree, fnum);
222         smb_raw_exit(cli->session);
223         smbcli_deltree(cli->tree, BASEDIR);
224         return ret;
225 }
226
227
228 /*
229   test locking&X ops
230 */
231 static bool test_lockx(struct torture_context *tctx, struct smbcli_state *cli)
232 {
233         union smb_lock io;
234         struct smb_lock_entry lock[1];
235         NTSTATUS status;
236         bool ret = true;
237         int fnum;
238         const char *fname = BASEDIR "\\test.txt";
239
240         if (!torture_setup_dir(cli, BASEDIR)) {
241                 return false;
242         }
243
244         torture_comment(tctx, "Testing RAW_LOCK_LOCKX\n");
245         io.generic.level = RAW_LOCK_LOCKX;
246         
247         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
248         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
249                        "Failed to create %s - %s\n",
250                        fname, smbcli_errstr(cli->tree)));
251
252         io.lockx.level = RAW_LOCK_LOCKX;
253         io.lockx.in.file.fnum = fnum;
254         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
255         io.lockx.in.timeout = 0;
256         io.lockx.in.ulock_cnt = 0;
257         io.lockx.in.lock_cnt = 1;
258         lock[0].pid = cli->session->pid;
259         lock[0].offset = 10;
260         lock[0].count = 1;
261         io.lockx.in.locks = &lock[0];
262         status = smb_raw_lock(cli->tree, &io);
263         CHECK_STATUS(status, NT_STATUS_OK);
264
265
266         torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
267         io.lockx.in.ulock_cnt = 0;
268         io.lockx.in.lock_cnt = 1;
269         lock[0].count = 4000;
270         lock[0].offset = 0xEEFFFFFF;
271         status = smb_raw_lock(cli->tree, &io);
272         CHECK_STATUS(status, NT_STATUS_OK);
273         lock[0].pid++;
274         status = smb_raw_lock(cli->tree, &io);
275         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
276         lock[0].pid--;
277         io.lockx.in.ulock_cnt = 1;
278         io.lockx.in.lock_cnt = 0;
279         status = smb_raw_lock(cli->tree, &io);
280         CHECK_STATUS(status, NT_STATUS_OK);
281         status = smb_raw_lock(cli->tree, &io);
282         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
283
284         torture_comment(tctx, "Trying 0xEF000000 lock\n");
285         io.lockx.in.ulock_cnt = 0;
286         io.lockx.in.lock_cnt = 1;
287         lock[0].count = 4000;
288         lock[0].offset = 0xEF000000;
289         status = smb_raw_lock(cli->tree, &io);
290         CHECK_STATUS(status, NT_STATUS_OK);
291         lock[0].pid++;
292         status = smb_raw_lock(cli->tree, &io);
293         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
294         lock[0].pid--;
295         io.lockx.in.ulock_cnt = 1;
296         io.lockx.in.lock_cnt = 0;
297         status = smb_raw_lock(cli->tree, &io);
298         CHECK_STATUS(status, NT_STATUS_OK);
299         status = smb_raw_lock(cli->tree, &io);
300         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
301
302         torture_comment(tctx, "Trying zero lock\n");
303         io.lockx.in.ulock_cnt = 0;
304         io.lockx.in.lock_cnt = 1;
305         lock[0].count = 0;
306         lock[0].offset = ~0;
307         status = smb_raw_lock(cli->tree, &io);
308         CHECK_STATUS(status, NT_STATUS_OK);
309         lock[0].pid++;
310         status = smb_raw_lock(cli->tree, &io);
311         CHECK_STATUS(status, NT_STATUS_OK);
312         lock[0].pid--;
313         io.lockx.in.ulock_cnt = 1;
314         io.lockx.in.lock_cnt = 0;
315         status = smb_raw_lock(cli->tree, &io);
316         CHECK_STATUS(status, NT_STATUS_OK);
317         status = smb_raw_lock(cli->tree, &io);
318         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
319
320         torture_comment(tctx, "Trying max lock\n");
321         io.lockx.in.ulock_cnt = 0;
322         io.lockx.in.lock_cnt = 1;
323         lock[0].count = 0;
324         lock[0].offset = ~0;
325         status = smb_raw_lock(cli->tree, &io);
326         CHECK_STATUS(status, NT_STATUS_OK);
327         lock[0].pid++;
328         status = smb_raw_lock(cli->tree, &io);
329         CHECK_STATUS(status, NT_STATUS_OK);
330         lock[0].pid--;
331         io.lockx.in.ulock_cnt = 1;
332         io.lockx.in.lock_cnt = 0;
333         status = smb_raw_lock(cli->tree, &io);
334         CHECK_STATUS(status, NT_STATUS_OK);
335         status = smb_raw_lock(cli->tree, &io);
336         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
337
338         torture_comment(tctx, "Trying 2^63\n");
339         io.lockx.in.ulock_cnt = 0;
340         io.lockx.in.lock_cnt = 1;
341         lock[0].count = 1;
342         lock[0].offset = 1;
343         lock[0].offset <<= 63;
344         status = smb_raw_lock(cli->tree, &io);
345         CHECK_STATUS(status, NT_STATUS_OK);
346         lock[0].pid++;
347         status = smb_raw_lock(cli->tree, &io);
348         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
349         lock[0].pid--;
350         io.lockx.in.ulock_cnt = 1;
351         io.lockx.in.lock_cnt = 0;
352         status = smb_raw_lock(cli->tree, &io);
353         CHECK_STATUS(status, NT_STATUS_OK);
354         status = smb_raw_lock(cli->tree, &io);
355         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
356
357         torture_comment(tctx, "Trying 2^63 - 1\n");
358         io.lockx.in.ulock_cnt = 0;
359         io.lockx.in.lock_cnt = 1;
360         lock[0].count = 1;
361         lock[0].offset = 1;
362         lock[0].offset <<= 63;
363         lock[0].offset--;
364         status = smb_raw_lock(cli->tree, &io);
365         CHECK_STATUS(status, NT_STATUS_OK);
366         lock[0].pid++;
367         status = smb_raw_lock(cli->tree, &io);
368         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
369         lock[0].pid--;
370         io.lockx.in.ulock_cnt = 1;
371         io.lockx.in.lock_cnt = 0;
372         status = smb_raw_lock(cli->tree, &io);
373         CHECK_STATUS(status, NT_STATUS_OK);
374         status = smb_raw_lock(cli->tree, &io);
375         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
376
377         torture_comment(tctx, "Trying max lock 2\n");
378         io.lockx.in.ulock_cnt = 0;
379         io.lockx.in.lock_cnt = 1;
380         lock[0].count = 1;
381         lock[0].offset = ~0;
382         status = smb_raw_lock(cli->tree, &io);
383         CHECK_STATUS(status, NT_STATUS_OK);
384         lock[0].pid++;
385         lock[0].count = 2;
386         status = smb_raw_lock(cli->tree, &io);
387         if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(tctx))
388                 CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
389         else
390                 CHECK_STATUS(status, NT_STATUS_OK);
391         lock[0].pid--;
392         io.lockx.in.ulock_cnt = 1;
393         io.lockx.in.lock_cnt = 0;
394         lock[0].count = 1;
395         status = smb_raw_lock(cli->tree, &io);
396
397         CHECK_STATUS(status, NT_STATUS_OK);
398         status = smb_raw_lock(cli->tree, &io);
399         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
400
401 done:
402         smbcli_close(cli->tree, fnum);
403         smb_raw_exit(cli->session);
404         smbcli_deltree(cli->tree, BASEDIR);
405         return ret;
406 }
407
408 /*
409   test high pid
410 */
411 static bool test_pidhigh(struct torture_context *tctx, 
412                                                  struct smbcli_state *cli)
413 {
414         union smb_lock io;
415         struct smb_lock_entry lock[1];
416         NTSTATUS status;
417         bool ret = true;
418         int fnum;
419         const char *fname = BASEDIR "\\test.txt";
420         uint8_t c = 1;
421
422         if (!torture_setup_dir(cli, BASEDIR)) {
423                 return false;
424         }
425
426         torture_comment(tctx, "Testing high pid\n");
427         io.generic.level = RAW_LOCK_LOCKX;
428
429         cli->session->pid = 1;
430         
431         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
432         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
433                        "Failed to create %s - %s\n",
434                        fname, smbcli_errstr(cli->tree)));
435
436         if (smbcli_write(cli->tree, fnum, 0, &c, 0, 1) != 1) {
437                 torture_result(tctx, TORTURE_FAIL,
438                         "Failed to write 1 byte - %s\n",
439                         smbcli_errstr(cli->tree));
440                 ret = false;
441                 goto done;
442         }
443
444         io.lockx.level = RAW_LOCK_LOCKX;
445         io.lockx.in.file.fnum = fnum;
446         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
447         io.lockx.in.timeout = 0;
448         io.lockx.in.ulock_cnt = 0;
449         io.lockx.in.lock_cnt = 1;
450         lock[0].pid = cli->session->pid;
451         lock[0].offset = 0;
452         lock[0].count = 0xFFFFFFFF;
453         io.lockx.in.locks = &lock[0];
454         status = smb_raw_lock(cli->tree, &io);
455         CHECK_STATUS(status, NT_STATUS_OK);
456
457         if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
458                 torture_result(tctx, TORTURE_FAIL,
459                         "Failed to read 1 byte - %s\n",
460                         smbcli_errstr(cli->tree));
461                 ret = false;
462                 goto done;
463         }
464
465         cli->session->pid = 2;
466
467         if (smbcli_read(cli->tree, fnum, &c, 0, 1) == 1) {
468                 torture_result(tctx, TORTURE_FAIL,
469                         "pid is incorrect handled for read with lock!\n");
470                 ret = false;
471                 goto done;
472         }
473
474         cli->session->pid = 0x10001;
475
476         if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
477                 torture_result(tctx, TORTURE_FAIL,
478                         "High pid is used on this server!\n");
479                 ret = false;
480         } else {
481                 torture_warning(tctx, "High pid is not used on this server (correct)\n");
482         }
483
484 done:
485         smbcli_close(cli->tree, fnum);
486         smb_raw_exit(cli->session);
487         smbcli_deltree(cli->tree, BASEDIR);
488         return ret;
489 }
490
491
492 /*
493   test locking&X async operation
494 */
495 static bool test_async(struct torture_context *tctx, 
496                                            struct smbcli_state *cli)
497 {
498         struct smbcli_session *session;
499         struct smb_composite_sesssetup setup;
500         struct smbcli_tree *tree;
501         union smb_tcon tcon;
502         const char *host, *share;
503         union smb_lock io;
504         struct smb_lock_entry lock[2];
505         NTSTATUS status;
506         bool ret = true;
507         int fnum;
508         const char *fname = BASEDIR "\\test.txt";
509         time_t t;
510         struct smbcli_request *req, *req2;
511         struct smbcli_session_options options;
512
513         if (!torture_setup_dir(cli, BASEDIR)) {
514                 return false;
515         }
516
517         lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
518
519         torture_comment(tctx, "Testing LOCKING_ANDX_CANCEL_LOCK\n");
520         io.generic.level = RAW_LOCK_LOCKX;
521
522         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
523         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
524                        "Failed to create %s - %s\n",
525                        fname, smbcli_errstr(cli->tree)));
526
527         io.lockx.level = RAW_LOCK_LOCKX;
528         io.lockx.in.file.fnum = fnum;
529         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
530         io.lockx.in.timeout = 0;
531         io.lockx.in.ulock_cnt = 0;
532         io.lockx.in.lock_cnt = 1;
533         lock[0].pid = cli->session->pid;
534         lock[0].offset = 100;
535         lock[0].count = 10;
536         lock[1].pid = cli->session->pid;
537         lock[1].offset = 110;
538         lock[1].count = 10;
539         io.lockx.in.locks = &lock[0];
540         status = smb_raw_lock(cli->tree, &io);
541         CHECK_STATUS(status, NT_STATUS_OK);
542
543         t = time_mono(NULL);
544
545         torture_comment(tctx, "Testing cancel by CANCEL_LOCK\n");
546
547         /* setup a timed lock */
548         io.lockx.in.timeout = 10000;
549         req = smb_raw_lock_send(cli->tree, &io);
550         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
551                        "Failed to setup timed lock (%s)\n", __location__));
552
553         /* cancel the wrong range */
554         lock[0].offset = 0;
555         io.lockx.in.timeout = 0;
556         io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
557         status = smb_raw_lock(cli->tree, &io);
558         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
559
560         /* cancel with the wrong bits set */
561         lock[0].offset = 100;
562         io.lockx.in.timeout = 0;
563         io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
564         status = smb_raw_lock(cli->tree, &io);
565         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
566
567         /* cancel the right range */
568         lock[0].offset = 100;
569         io.lockx.in.timeout = 0;
570         io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
571         status = smb_raw_lock(cli->tree, &io);
572         CHECK_STATUS(status, NT_STATUS_OK);
573
574         /* receive the failed lock request */
575         status = smbcli_request_simple_recv(req);
576         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
577
578         torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
579                        "lock cancel was not immediate (%s)\n", __location__));
580
581         /* MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
582          * if the lock vector contains one entry. When given mutliple cancel
583          * requests in a single PDU we expect the server to return an
584          * error. Samba4 handles this correctly. Windows servers seem to
585          * accept the request but only cancel the first lock.  Samba3
586          * now does what Windows does (JRA).
587          */
588         torture_comment(tctx, "Testing multiple cancel\n");
589
590         /* acquire second lock */
591         io.lockx.in.timeout = 0;
592         io.lockx.in.ulock_cnt = 0;
593         io.lockx.in.lock_cnt = 1;
594         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
595         io.lockx.in.locks = &lock[1];
596         status = smb_raw_lock(cli->tree, &io);
597         CHECK_STATUS(status, NT_STATUS_OK);
598
599         /* setup 2 timed locks */
600         t = time_mono(NULL);
601         io.lockx.in.timeout = 10000;
602         io.lockx.in.lock_cnt = 1;
603         io.lockx.in.locks = &lock[0];
604         req = smb_raw_lock_send(cli->tree, &io);
605         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
606                        "Failed to setup timed lock (%s)\n", __location__));
607         io.lockx.in.locks = &lock[1];
608         req2 = smb_raw_lock_send(cli->tree, &io);
609         torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
610                        "Failed to setup timed lock (%s)\n", __location__));
611
612         /* try to cancel both locks in the same packet */
613         io.lockx.in.timeout = 0;
614         io.lockx.in.lock_cnt = 2;
615         io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
616         io.lockx.in.locks = lock;
617         status = smb_raw_lock(cli->tree, &io);
618         CHECK_STATUS(status, NT_STATUS_OK);
619
620         torture_warning(tctx, "Target server accepted a lock cancel "
621                               "request with multiple locks. This violates "
622                               "MS-CIFS 2.2.4.32.1.\n");
623
624         /* receive the failed lock requests */
625         status = smbcli_request_simple_recv(req);
626         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
627
628         torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
629                        "first lock was not cancelled immediately (%s)\n",
630                        __location__));
631
632         /* send cancel to second lock */
633         io.lockx.in.timeout = 0;
634         io.lockx.in.lock_cnt = 1;
635         io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK |
636                            LOCKING_ANDX_LARGE_FILES;
637         io.lockx.in.locks = &lock[1];
638         status = smb_raw_lock(cli->tree, &io);
639         CHECK_STATUS(status, NT_STATUS_OK);
640
641         status = smbcli_request_simple_recv(req2);
642         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
643
644         torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
645                        "second lock was not cancelled immediately (%s)\n",
646                        __location__));
647
648         /* cleanup the second lock */
649         io.lockx.in.ulock_cnt = 1;
650         io.lockx.in.lock_cnt = 0;
651         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
652         io.lockx.in.locks = &lock[1];
653         status = smb_raw_lock(cli->tree, &io);
654         CHECK_STATUS(status, NT_STATUS_OK);
655
656         /* If a lock request contained multiple ranges and we are cancelling
657          * one while it's still pending, what happens? */
658         torture_comment(tctx, "Testing cancel 1/2 lock request\n");
659
660         /* Send request with two ranges */
661         io.lockx.in.timeout = -1;
662         io.lockx.in.ulock_cnt = 0;
663         io.lockx.in.lock_cnt = 2;
664         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
665         io.lockx.in.locks = lock;
666         req = smb_raw_lock_send(cli->tree, &io);
667         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
668                        "Failed to setup pending lock (%s)\n", __location__));
669
670         /* Try to cancel the first lock range */
671         io.lockx.in.timeout = 0;
672         io.lockx.in.lock_cnt = 1;
673         io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
674         io.lockx.in.locks = &lock[0];
675         status = smb_raw_lock(cli->tree, &io);
676         CHECK_STATUS(status, NT_STATUS_OK);
677
678         /* Locking request should've failed and second range should be
679          * unlocked */
680         status = smbcli_request_simple_recv(req);
681         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
682
683         io.lockx.in.timeout = 0;
684         io.lockx.in.ulock_cnt = 0;
685         io.lockx.in.lock_cnt = 1;
686         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
687         io.lockx.in.locks = &lock[1];
688         status = smb_raw_lock(cli->tree, &io);
689         CHECK_STATUS(status, NT_STATUS_OK);
690
691         /* Cleanup both locks */
692         io.lockx.in.ulock_cnt = 2;
693         io.lockx.in.lock_cnt = 0;
694         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
695         io.lockx.in.locks = lock;
696         status = smb_raw_lock(cli->tree, &io);
697         CHECK_STATUS(status, NT_STATUS_OK);
698
699         torture_comment(tctx, "Testing cancel 2/2 lock request\n");
700
701         /* Lock second range so it contends */
702         io.lockx.in.timeout = 0;
703         io.lockx.in.ulock_cnt = 0;
704         io.lockx.in.lock_cnt = 1;
705         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
706         io.lockx.in.locks = &lock[1];
707         status = smb_raw_lock(cli->tree, &io);
708         CHECK_STATUS(status, NT_STATUS_OK);
709
710         /* Send request with two ranges */
711         io.lockx.in.timeout = -1;
712         io.lockx.in.ulock_cnt = 0;
713         io.lockx.in.lock_cnt = 2;
714         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
715         io.lockx.in.locks = lock;
716         req = smb_raw_lock_send(cli->tree, &io);
717         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
718                        "Failed to setup pending lock (%s)\n", __location__));
719
720         /* Try to cancel the second lock range */
721         io.lockx.in.timeout = 0;
722         io.lockx.in.lock_cnt = 1;
723         io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
724         io.lockx.in.locks = &lock[1];
725         status = smb_raw_lock(cli->tree, &io);
726         CHECK_STATUS(status, NT_STATUS_OK);
727
728         /* Locking request should've failed and first range should be
729          * unlocked */
730         status = smbcli_request_simple_recv(req);
731         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
732
733         io.lockx.in.timeout = 0;
734         io.lockx.in.ulock_cnt = 0;
735         io.lockx.in.lock_cnt = 1;
736         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
737         io.lockx.in.locks = &lock[0];
738         status = smb_raw_lock(cli->tree, &io);
739         CHECK_STATUS(status, NT_STATUS_OK);
740
741         /* Cleanup both locks */
742         io.lockx.in.ulock_cnt = 2;
743         io.lockx.in.lock_cnt = 0;
744         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
745         io.lockx.in.locks = lock;
746         status = smb_raw_lock(cli->tree, &io);
747         CHECK_STATUS(status, NT_STATUS_OK);
748
749         torture_comment(tctx, "Testing cancel by unlock\n");
750         io.lockx.in.ulock_cnt = 0;
751         io.lockx.in.lock_cnt = 1;
752         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
753         io.lockx.in.timeout = 0;
754         io.lockx.in.locks = &lock[0];
755         status = smb_raw_lock(cli->tree, &io);
756         CHECK_STATUS(status, NT_STATUS_OK);
757
758         io.lockx.in.timeout = 5000;
759         req = smb_raw_lock_send(cli->tree, &io);
760         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
761                        "Failed to setup timed lock (%s)\n", __location__));
762
763         io.lockx.in.ulock_cnt = 1;
764         io.lockx.in.lock_cnt = 0;
765         status = smb_raw_lock(cli->tree, &io);
766         CHECK_STATUS(status, NT_STATUS_OK);
767
768         t = time_mono(NULL);
769         status = smbcli_request_simple_recv(req);
770         CHECK_STATUS(status, NT_STATUS_OK);
771
772         torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
773                        "lock cancel by unlock was not immediate (%s) - took %d secs\n",
774                        __location__, (int)(time_mono(NULL)-t)));
775
776         torture_comment(tctx, "Testing cancel by close\n");
777         io.lockx.in.ulock_cnt = 0;
778         io.lockx.in.lock_cnt = 1;
779         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
780         io.lockx.in.timeout = 0;
781         status = smb_raw_lock(cli->tree, &io);
782         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
783
784         t = time_mono(NULL);
785         io.lockx.in.timeout = 10000;
786         req = smb_raw_lock_send(cli->tree, &io);
787         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
788                        "Failed to setup timed lock (%s)\n", __location__));
789
790         status = smbcli_close(cli->tree, fnum);
791         CHECK_STATUS(status, NT_STATUS_OK);
792
793         status = smbcli_request_simple_recv(req);
794         if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx))
795                 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
796         else
797                 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
798
799         torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
800                        "lock cancel by close was not immediate (%s)\n", __location__));
801
802         torture_comment(tctx, "create a new sessions\n");
803         session = smbcli_session_init(cli->transport, tctx, false, options);
804         setup.in.sesskey = cli->transport->negotiate.sesskey;
805         setup.in.capabilities = cli->transport->negotiate.capabilities;
806         setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
807         setup.in.credentials = cmdline_credentials;
808         setup.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
809         status = smb_composite_sesssetup(session, &setup);
810         CHECK_STATUS(status, NT_STATUS_OK);
811         session->vuid = setup.out.vuid;
812
813         torture_comment(tctx, "create new tree context\n");
814         share = torture_setting_string(tctx, "share", NULL);
815         host  = torture_setting_string(tctx, "host", NULL);
816         tree = smbcli_tree_init(session, tctx, false);
817         tcon.generic.level = RAW_TCON_TCONX;
818         tcon.tconx.in.flags = 0;
819         tcon.tconx.in.password = data_blob(NULL, 0);
820         tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
821         tcon.tconx.in.device = "A:";
822         status = smb_raw_tcon(tree, tctx, &tcon);
823         CHECK_STATUS(status, NT_STATUS_OK);
824         tree->tid = tcon.tconx.out.tid;
825
826         torture_comment(tctx, "Testing cancel by exit\n");
827         if (TARGET_SUPPORTS_SMBEXIT(tctx)) {
828                 fname = BASEDIR "\\test_exit.txt";
829                 fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
830                 torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
831                                "Failed to reopen %s - %s\n",
832                                fname, smbcli_errstr(tree)));
833
834                 io.lockx.level = RAW_LOCK_LOCKX;
835                 io.lockx.in.file.fnum = fnum;
836                 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
837                 io.lockx.in.timeout = 0;
838                 io.lockx.in.ulock_cnt = 0;
839                 io.lockx.in.lock_cnt = 1;
840                 lock[0].pid = session->pid;
841                 lock[0].offset = 100;
842                 lock[0].count = 10;
843                 io.lockx.in.locks = &lock[0];
844                 status = smb_raw_lock(tree, &io);
845                 CHECK_STATUS(status, NT_STATUS_OK);
846
847                 io.lockx.in.ulock_cnt = 0;
848                 io.lockx.in.lock_cnt = 1;
849                 io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
850                 io.lockx.in.timeout = 0;
851                 status = smb_raw_lock(tree, &io);
852                 CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
853
854                 io.lockx.in.timeout = 10000;
855                 t = time_mono(NULL);
856                 req = smb_raw_lock_send(tree, &io);
857                 torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
858                                "Failed to setup timed lock (%s)\n",
859                                __location__));
860
861                 status = smb_raw_exit(session);
862                 CHECK_STATUS(status, NT_STATUS_OK);
863
864                 status = smbcli_request_simple_recv(req);
865                 if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx))
866                         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
867                 else
868                         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
869
870                 torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
871                                "lock cancel by exit was not immediate (%s)\n",
872                                __location__));
873         }
874         else {
875                 torture_comment(tctx,
876                                 "  skipping test, SMBExit not supported\n");
877         }
878
879         torture_comment(tctx, "Testing cancel by ulogoff\n");
880         fname = BASEDIR "\\test_ulogoff.txt";
881         fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
882         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
883                        "Failed to reopen %s - %s\n",
884                        fname, smbcli_errstr(tree)));
885
886         io.lockx.level = RAW_LOCK_LOCKX;
887         io.lockx.in.file.fnum = fnum;
888         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
889         io.lockx.in.timeout = 0;
890         io.lockx.in.ulock_cnt = 0;
891         io.lockx.in.lock_cnt = 1;
892         lock[0].pid = session->pid;
893         lock[0].offset = 100;
894         lock[0].count = 10;
895         io.lockx.in.locks = &lock[0];
896         status = smb_raw_lock(tree, &io);
897         CHECK_STATUS(status, NT_STATUS_OK);
898
899         io.lockx.in.ulock_cnt = 0;
900         io.lockx.in.lock_cnt = 1;
901         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
902         io.lockx.in.timeout = 0;
903         status = smb_raw_lock(tree, &io);
904         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
905
906         io.lockx.in.timeout = 10000;
907         t = time_mono(NULL);
908         req = smb_raw_lock_send(tree, &io);
909         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
910                        "Failed to setup timed lock (%s)\n", __location__));
911
912         status = smb_raw_ulogoff(session);
913         CHECK_STATUS(status, NT_STATUS_OK);
914
915         status = smbcli_request_simple_recv(req);
916         if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx)) {
917                 if (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status)) {
918                         torture_result(tctx, TORTURE_FAIL,
919                                 "lock not canceled by ulogoff - %s "
920                                 "(ignored because of vfs_vifs fails it)\n",
921                                 nt_errstr(status));
922                         smb_tree_disconnect(tree);
923                         smb_raw_exit(session);
924                         goto done;
925                 }
926                 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
927         } else {
928                 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
929         }
930
931         torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
932                        "lock cancel by ulogoff was not immediate (%s)\n", __location__));
933
934         torture_comment(tctx, "Testing cancel by tdis\n");
935         tree->session = cli->session;
936
937         fname = BASEDIR "\\test_tdis.txt";
938         fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
939         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
940                        "Failed to reopen %s - %s\n",
941                        fname, smbcli_errstr(tree)));
942
943         io.lockx.level = RAW_LOCK_LOCKX;
944         io.lockx.in.file.fnum = fnum;
945         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
946         io.lockx.in.timeout = 0;
947         io.lockx.in.ulock_cnt = 0;
948         io.lockx.in.lock_cnt = 1;
949         lock[0].pid = cli->session->pid;
950         lock[0].offset = 100;
951         lock[0].count = 10;
952         io.lockx.in.locks = &lock[0];
953         status = smb_raw_lock(tree, &io);
954         CHECK_STATUS(status, NT_STATUS_OK);
955
956         status = smb_raw_lock(tree, &io);
957         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
958
959         io.lockx.in.timeout = 10000;
960         t = time_mono(NULL);
961         req = smb_raw_lock_send(tree, &io);
962         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
963                        "Failed to setup timed lock (%s)\n", __location__));
964
965         status = smb_tree_disconnect(tree);
966         CHECK_STATUS(status, NT_STATUS_OK);
967
968         status = smbcli_request_simple_recv(req);
969         if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx))
970                 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
971         else
972                 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
973
974         torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
975                        "lock cancel by tdis was not immediate (%s)\n", __location__));
976
977 done:
978         smb_raw_exit(cli->session);
979         smbcli_deltree(cli->tree, BASEDIR);
980         return ret;
981 }
982
983 /*
984   test NT_STATUS_LOCK_NOT_GRANTED vs. NT_STATUS_FILE_LOCK_CONFLICT
985 */
986 static bool test_errorcode(struct torture_context *tctx, 
987                                                    struct smbcli_state *cli)
988 {
989         union smb_lock io;
990         union smb_open op;
991         struct smb_lock_entry lock[2];
992         NTSTATUS status;
993         bool ret = true;
994         int fnum, fnum2;
995         const char *fname;
996         struct smbcli_request *req;
997         time_t start;
998         int t;
999         int delay;
1000         uint16_t deny_mode = 0;
1001
1002         if (!torture_setup_dir(cli, BASEDIR)) {
1003                 return false;
1004         }
1005
1006         torture_comment(tctx, "Testing LOCK_NOT_GRANTED vs. FILE_LOCK_CONFLICT\n");
1007
1008         torture_comment(tctx, "Testing with timeout = 0\n");
1009         fname = BASEDIR "\\test0.txt";
1010         t = 0;
1011
1012         /*
1013          * the first run is with t = 0,
1014          * the second with t > 0 (=1)
1015          */
1016 next_run:
1017         /*
1018          * use the DENY_DOS mode, that creates two fnum's of one low-level
1019          * file handle, this demonstrates that the cache is per fnum, not
1020          * per file handle
1021          */
1022         if (TARGET_SUPPORTS_OPENX_DENY_DOS(tctx))
1023             deny_mode = OPENX_MODE_DENY_DOS;
1024         else
1025             deny_mode = OPENX_MODE_DENY_NONE;
1026
1027         op.openx.level = RAW_OPEN_OPENX;
1028         op.openx.in.fname = fname;
1029         op.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
1030         op.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | deny_mode;
1031         op.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
1032         op.openx.in.search_attrs = 0;
1033         op.openx.in.file_attrs = 0;
1034         op.openx.in.write_time = 0;
1035         op.openx.in.size = 0;
1036         op.openx.in.timeout = 0;
1037
1038         status = smb_raw_open(cli->tree, tctx, &op);
1039         CHECK_STATUS(status, NT_STATUS_OK);
1040         fnum = op.openx.out.file.fnum;
1041
1042         status = smb_raw_open(cli->tree, tctx, &op);
1043         CHECK_STATUS(status, NT_STATUS_OK);
1044         fnum2 = op.openx.out.file.fnum;
1045
1046         io.lockx.level = RAW_LOCK_LOCKX;
1047         io.lockx.in.file.fnum = fnum;
1048         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1049         io.lockx.in.timeout = t;
1050         io.lockx.in.ulock_cnt = 0;
1051         io.lockx.in.lock_cnt = 1;
1052         lock[0].pid = cli->session->pid;
1053         lock[0].offset = 100;
1054         lock[0].count = 10;
1055         io.lockx.in.locks = &lock[0];
1056         status = smb_raw_lock(cli->tree, &io);
1057         CHECK_STATUS(status, NT_STATUS_OK);
1058
1059         /*
1060          * demonstrate that the first conflicting lock on each handle give LOCK_NOT_GRANTED
1061          * this also demonstrates that the error code cache is per file handle
1062          * (LOCK_NOT_GRANTED is only be used when timeout is 0!)
1063          */
1064         io.lockx.in.file.fnum = fnum2;
1065         status = smb_raw_lock(cli->tree, &io);
1066         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1067
1068         io.lockx.in.file.fnum = fnum;
1069         status = smb_raw_lock(cli->tree, &io);
1070         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1071
1072         /* demonstrate that each following conflict gives FILE_LOCK_CONFLICT */
1073         io.lockx.in.file.fnum = fnum;
1074         status = smb_raw_lock(cli->tree, &io);
1075         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1076
1077         io.lockx.in.file.fnum = fnum2;
1078         status = smb_raw_lock(cli->tree, &io);
1079         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1080
1081         io.lockx.in.file.fnum = fnum;
1082         status = smb_raw_lock(cli->tree, &io);
1083         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1084
1085         io.lockx.in.file.fnum = fnum2;
1086         status = smb_raw_lock(cli->tree, &io);
1087         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1088
1089         /* demonstrate that the smbpid doesn't matter */
1090         lock[0].pid++;
1091         io.lockx.in.file.fnum = fnum;
1092         status = smb_raw_lock(cli->tree, &io);
1093         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1094
1095         io.lockx.in.file.fnum = fnum2;
1096         status = smb_raw_lock(cli->tree, &io);
1097         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1098         lock[0].pid--;
1099
1100         /* 
1101          * demonstrate the a successful lock with count = 0 and the same offset,
1102          * doesn't reset the error cache
1103          */
1104         lock[0].offset = 100;
1105         lock[0].count = 0;
1106         io.lockx.in.file.fnum = fnum;
1107         status = smb_raw_lock(cli->tree, &io);
1108         CHECK_STATUS(status, NT_STATUS_OK);
1109
1110         io.lockx.in.file.fnum = fnum2;
1111         status = smb_raw_lock(cli->tree, &io);
1112         CHECK_STATUS(status, NT_STATUS_OK);
1113
1114         lock[0].offset = 100;
1115         lock[0].count = 10;
1116         io.lockx.in.file.fnum = fnum;
1117         status = smb_raw_lock(cli->tree, &io);
1118         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1119
1120         io.lockx.in.file.fnum = fnum2;
1121         status = smb_raw_lock(cli->tree, &io);
1122         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1123
1124         /* 
1125          * demonstrate the a successful lock with count = 0 and outside the locked range,
1126          * doesn't reset the error cache
1127          */
1128         lock[0].offset = 110;
1129         lock[0].count = 0;
1130         io.lockx.in.file.fnum = fnum;
1131         status = smb_raw_lock(cli->tree, &io);
1132         CHECK_STATUS(status, NT_STATUS_OK);
1133
1134         io.lockx.in.file.fnum = fnum2;
1135         status = smb_raw_lock(cli->tree, &io);
1136         CHECK_STATUS(status, NT_STATUS_OK);
1137
1138         lock[0].offset = 100;
1139         lock[0].count = 10;
1140         io.lockx.in.file.fnum = fnum;
1141         status = smb_raw_lock(cli->tree, &io);
1142         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1143
1144         io.lockx.in.file.fnum = fnum2;
1145         status = smb_raw_lock(cli->tree, &io);
1146         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1147
1148         lock[0].offset = 99;
1149         lock[0].count = 0;
1150         io.lockx.in.file.fnum = fnum;
1151         status = smb_raw_lock(cli->tree, &io);
1152         CHECK_STATUS(status, NT_STATUS_OK);
1153
1154         io.lockx.in.file.fnum = fnum2;
1155         status = smb_raw_lock(cli->tree, &io);
1156         CHECK_STATUS(status, NT_STATUS_OK);
1157
1158         lock[0].offset = 100;
1159         lock[0].count = 10;
1160         io.lockx.in.file.fnum = fnum;
1161         status = smb_raw_lock(cli->tree, &io);
1162         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1163
1164         io.lockx.in.file.fnum = fnum2;
1165         status = smb_raw_lock(cli->tree, &io);
1166         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1167
1168         /* demonstrate that a changing count doesn't reset the error cache */
1169         lock[0].offset = 100;
1170         lock[0].count = 5;
1171         io.lockx.in.file.fnum = fnum;
1172         status = smb_raw_lock(cli->tree, &io);
1173         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1174
1175         io.lockx.in.file.fnum = fnum2;
1176         status = smb_raw_lock(cli->tree, &io);
1177         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1178
1179         lock[0].offset = 100;
1180         lock[0].count = 15;
1181         io.lockx.in.file.fnum = fnum;
1182         status = smb_raw_lock(cli->tree, &io);
1183         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1184
1185         io.lockx.in.file.fnum = fnum2;
1186         status = smb_raw_lock(cli->tree, &io);
1187         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1188
1189         /* 
1190          * demonstrate the a lock with count = 0 and inside the locked range,
1191          * fails and resets the error cache
1192          */
1193         lock[0].offset = 101;
1194         lock[0].count = 0;
1195         io.lockx.in.file.fnum = fnum;
1196         status = smb_raw_lock(cli->tree, &io);
1197         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1198         status = smb_raw_lock(cli->tree, &io);
1199         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1200
1201         io.lockx.in.file.fnum = fnum2;
1202         status = smb_raw_lock(cli->tree, &io);
1203         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1204         status = smb_raw_lock(cli->tree, &io);
1205         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1206
1207         lock[0].offset = 100;
1208         lock[0].count = 10;
1209         io.lockx.in.file.fnum = fnum;
1210         status = smb_raw_lock(cli->tree, &io);
1211         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1212         status = smb_raw_lock(cli->tree, &io);
1213         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1214
1215         io.lockx.in.file.fnum = fnum2;
1216         status = smb_raw_lock(cli->tree, &io);
1217         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1218         status = smb_raw_lock(cli->tree, &io);
1219         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1220
1221         /* demonstrate the a changing offset, resets the error cache */
1222         lock[0].offset = 105;
1223         lock[0].count = 10;
1224         io.lockx.in.file.fnum = fnum;
1225         status = smb_raw_lock(cli->tree, &io);
1226         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1227         status = smb_raw_lock(cli->tree, &io);
1228         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1229
1230         io.lockx.in.file.fnum = fnum2;
1231         status = smb_raw_lock(cli->tree, &io);
1232         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1233         status = smb_raw_lock(cli->tree, &io);
1234         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1235
1236         lock[0].offset = 100;
1237         lock[0].count = 10;
1238         io.lockx.in.file.fnum = fnum;
1239         status = smb_raw_lock(cli->tree, &io);
1240         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1241         status = smb_raw_lock(cli->tree, &io);
1242         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1243
1244         io.lockx.in.file.fnum = fnum2;
1245         status = smb_raw_lock(cli->tree, &io);
1246         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1247         status = smb_raw_lock(cli->tree, &io);
1248         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1249
1250         lock[0].offset = 95;
1251         lock[0].count = 9;
1252         io.lockx.in.file.fnum = fnum;
1253         status = smb_raw_lock(cli->tree, &io);
1254         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1255         status = smb_raw_lock(cli->tree, &io);
1256         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1257
1258         io.lockx.in.file.fnum = fnum2;
1259         status = smb_raw_lock(cli->tree, &io);
1260         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1261         status = smb_raw_lock(cli->tree, &io);
1262         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1263
1264         lock[0].offset = 100;
1265         lock[0].count = 10;
1266         io.lockx.in.file.fnum = fnum;
1267         status = smb_raw_lock(cli->tree, &io);
1268         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1269         status = smb_raw_lock(cli->tree, &io);
1270         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1271
1272         io.lockx.in.file.fnum = fnum2;
1273         status = smb_raw_lock(cli->tree, &io);
1274         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1275         status = smb_raw_lock(cli->tree, &io);
1276         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1277
1278         /* 
1279          * demonstrate the a successful lock in a different range, 
1280          * doesn't reset the cache, the failing lock on the 2nd handle
1281          * resets the cache
1282          */
1283         lock[0].offset = 120;
1284         lock[0].count = 15;
1285         io.lockx.in.file.fnum = fnum;
1286         status = smb_raw_lock(cli->tree, &io);
1287         CHECK_STATUS(status, NT_STATUS_OK);
1288
1289         io.lockx.in.file.fnum = fnum2;
1290         status = smb_raw_lock(cli->tree, &io);
1291         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1292
1293         lock[0].offset = 100;
1294         lock[0].count = 10;
1295         io.lockx.in.file.fnum = fnum;
1296         status = smb_raw_lock(cli->tree, &io);
1297         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1298         status = smb_raw_lock(cli->tree, &io);
1299         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1300
1301         io.lockx.in.file.fnum = fnum2;
1302         status = smb_raw_lock(cli->tree, &io);
1303         CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1304         status = smb_raw_lock(cli->tree, &io);
1305         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1306
1307         /* end of the loop */
1308         if (t == 0) {
1309                 smb_raw_exit(cli->session);
1310                 t = 1;
1311                 torture_comment(tctx, "Testing with timeout > 0 (=%d)\n",
1312                                 t);
1313                 fname = BASEDIR "\\test1.txt";
1314                 goto next_run;
1315         }
1316
1317         t = 4000;
1318         torture_comment(tctx, "Testing special cases with timeout > 0 (=%d)\n",
1319                         t);
1320
1321         /*
1322          * the following 3 test sections demonstrate that
1323          * the cache is only set when the error is reported
1324          * to the client (after the timeout went by)
1325          */
1326         smb_raw_exit(cli->session);
1327         torture_comment(tctx, "Testing a conflict while a lock is pending\n");
1328         fname = BASEDIR "\\test2.txt";
1329         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1330         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1331                        "Failed to reopen %s - %s\n",
1332                        fname, smbcli_errstr(cli->tree)));
1333
1334         io.lockx.level = RAW_LOCK_LOCKX;
1335         io.lockx.in.file.fnum = fnum;
1336         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1337         io.lockx.in.timeout = 0;
1338         io.lockx.in.ulock_cnt = 0;
1339         io.lockx.in.lock_cnt = 1;
1340         lock[0].pid = cli->session->pid;
1341         lock[0].offset = 100;
1342         lock[0].count = 10;
1343         io.lockx.in.locks = &lock[0];
1344         status = smb_raw_lock(cli->tree, &io);
1345         CHECK_STATUS(status, NT_STATUS_OK);
1346
1347         start = time_mono(NULL);
1348         io.lockx.in.timeout = t;
1349         req = smb_raw_lock_send(cli->tree, &io);
1350         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1351                        "Failed to setup timed lock (%s)\n", __location__));
1352
1353         io.lockx.in.timeout = 0;
1354         lock[0].offset = 105;
1355         lock[0].count = 10;
1356         status = smb_raw_lock(cli->tree, &io);
1357         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1358
1359         status = smbcli_request_simple_recv(req);
1360         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1361
1362         delay = t / 1000;
1363         if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1364                 delay /= 2;
1365         }
1366
1367         torture_assert(tctx,!(time_mono(NULL) < start+delay), talloc_asprintf(tctx,
1368                        "lock comes back to early timeout[%d] delay[%d]"
1369                        "(%s)\n", t, delay, __location__));
1370
1371         status = smb_raw_lock(cli->tree, &io);
1372         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1373
1374         smbcli_close(cli->tree, fnum);
1375         fname = BASEDIR "\\test3.txt";
1376         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1377         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1378                        "Failed to reopen %s - %s\n",
1379                        fname, smbcli_errstr(cli->tree)));
1380
1381         io.lockx.level = RAW_LOCK_LOCKX;
1382         io.lockx.in.file.fnum = fnum;
1383         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1384         io.lockx.in.timeout = 0;
1385         io.lockx.in.ulock_cnt = 0;
1386         io.lockx.in.lock_cnt = 1;
1387         lock[0].pid = cli->session->pid;
1388         lock[0].offset = 100;
1389         lock[0].count = 10;
1390         io.lockx.in.locks = &lock[0];
1391         status = smb_raw_lock(cli->tree, &io);
1392         CHECK_STATUS(status, NT_STATUS_OK);
1393
1394         start = time_mono(NULL);
1395         io.lockx.in.timeout = t;
1396         req = smb_raw_lock_send(cli->tree, &io);
1397         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1398                        "Failed to setup timed lock (%s)\n", __location__));
1399
1400         io.lockx.in.timeout = 0;
1401         lock[0].offset = 105;
1402         lock[0].count = 10;
1403         status = smb_raw_lock(cli->tree, &io);
1404         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1405
1406         status = smbcli_request_simple_recv(req);
1407         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1408
1409         delay = t / 1000;
1410         if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1411                 delay /= 2;
1412         }
1413
1414         torture_assert(tctx,!(time_mono(NULL) < start+delay), talloc_asprintf(tctx,
1415                        "lock comes back to early timeout[%d] delay[%d]"
1416                        "(%s)\n", t, delay, __location__));
1417
1418         lock[0].offset = 100;
1419         lock[0].count = 10;
1420         status = smb_raw_lock(cli->tree, &io);
1421         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1422
1423         smbcli_close(cli->tree, fnum);
1424         fname = BASEDIR "\\test4.txt";
1425         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1426         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1427                        "Failed to reopen %s - %s\n",
1428                        fname, smbcli_errstr(cli->tree)));
1429
1430         io.lockx.level = RAW_LOCK_LOCKX;
1431         io.lockx.in.file.fnum = fnum;
1432         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1433         io.lockx.in.timeout = 0;
1434         io.lockx.in.ulock_cnt = 0;
1435         io.lockx.in.lock_cnt = 1;
1436         lock[0].pid = cli->session->pid;
1437         lock[0].offset = 100;
1438         lock[0].count = 10;
1439         io.lockx.in.locks = &lock[0];
1440         status = smb_raw_lock(cli->tree, &io);
1441         CHECK_STATUS(status, NT_STATUS_OK);
1442
1443         start = time_mono(NULL);
1444         io.lockx.in.timeout = t;
1445         req = smb_raw_lock_send(cli->tree, &io);
1446         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1447                        "Failed to setup timed lock (%s)\n", __location__));
1448
1449         io.lockx.in.timeout = 0;
1450         status = smb_raw_lock(cli->tree, &io);
1451         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1452
1453         status = smbcli_request_simple_recv(req);
1454         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1455
1456         delay = t / 1000;
1457         if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1458                 delay /= 2;
1459         }
1460
1461         torture_assert(tctx,!(time_mono(NULL) < start+delay), talloc_asprintf(tctx,
1462                        "lock comes back to early timeout[%d] delay[%d]"
1463                        "(%s)\n", t, delay, __location__));
1464
1465         status = smb_raw_lock(cli->tree, &io);
1466         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1467
1468 done:
1469         smb_raw_exit(cli->session);
1470         smbcli_deltree(cli->tree, BASEDIR);
1471         return ret;
1472 }
1473
1474
1475 /*
1476   test LOCKING_ANDX_CHANGE_LOCKTYPE
1477 */
1478 static bool test_changetype(struct torture_context *tctx, 
1479                                                         struct smbcli_state *cli)
1480 {
1481         union smb_lock io;
1482         struct smb_lock_entry lock[2];
1483         NTSTATUS status;
1484         bool ret = true;
1485         int fnum;
1486         uint8_t c = 0;
1487         const char *fname = BASEDIR "\\test.txt";
1488
1489         if (!torture_setup_dir(cli, BASEDIR)) {
1490                 return false;
1491         }
1492
1493         torture_comment(tctx, "Testing LOCKING_ANDX_CHANGE_LOCKTYPE\n");
1494         io.generic.level = RAW_LOCK_LOCKX;
1495         
1496         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1497         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1498                        "Failed to create %s - %s\n",
1499                        fname, smbcli_errstr(cli->tree)));
1500
1501         io.lockx.level = RAW_LOCK_LOCKX;
1502         io.lockx.in.file.fnum = fnum;
1503         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1504         io.lockx.in.timeout = 0;
1505         io.lockx.in.ulock_cnt = 0;
1506         io.lockx.in.lock_cnt = 1;
1507         lock[0].pid = cli->session->pid;
1508         lock[0].offset = 100;
1509         lock[0].count = 10;
1510         io.lockx.in.locks = &lock[0];
1511         status = smb_raw_lock(cli->tree, &io);
1512         CHECK_STATUS(status, NT_STATUS_OK);
1513
1514         if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1515                 torture_result(tctx, TORTURE_FAIL,
1516                         "allowed write on read locked region (%s)\n", __location__);
1517                 ret = false;
1518                 goto done;
1519         }
1520
1521         /* windows server don't seem to support this */
1522         io.lockx.in.mode = LOCKING_ANDX_CHANGE_LOCKTYPE;
1523         status = smb_raw_lock(cli->tree, &io);
1524         CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
1525
1526         if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1527                 torture_result(tctx, TORTURE_FAIL,
1528                         "allowed write after lock change (%s)\n", __location__);
1529                 ret = false;
1530                 goto done;
1531         }
1532
1533 done:
1534         smbcli_close(cli->tree, fnum);
1535         smb_raw_exit(cli->session);
1536         smbcli_deltree(cli->tree, BASEDIR);
1537         return ret;
1538 }
1539
1540 struct double_lock_test {
1541         struct smb_lock_entry lock1;
1542         struct smb_lock_entry lock2;
1543         NTSTATUS exp_status;
1544 };
1545
1546 /**
1547  * Tests zero byte locks.
1548  */
1549 static struct double_lock_test zero_byte_tests[] = {
1550         /* {pid, offset, count}, {pid, offset, count}, status */
1551
1552         /** First, takes a zero byte lock at offset 10. Then:
1553         *   - Taking 0 byte lock at 10 should succeed.
1554         *   - Taking 1 byte locks at 9,10,11 should succeed.
1555         *   - Taking 2 byte lock at 9 should fail.
1556         *   - Taking 2 byte lock at 10 should succeed.
1557         *   - Taking 3 byte lock at 9 should fail.
1558         */
1559         {{1000, 10, 0}, {1001, 10, 0}, NT_STATUS_OK},
1560         {{1000, 10, 0}, {1001, 9, 1},  NT_STATUS_OK},
1561         {{1000, 10, 0}, {1001, 10, 1}, NT_STATUS_OK},
1562         {{1000, 10, 0}, {1001, 11, 1}, NT_STATUS_OK},
1563         {{1000, 10, 0}, {1001, 9, 2},  NT_STATUS_LOCK_NOT_GRANTED},
1564         {{1000, 10, 0}, {1001, 10, 2}, NT_STATUS_OK},
1565         {{1000, 10, 0}, {1001, 9, 3},  NT_STATUS_LOCK_NOT_GRANTED},
1566
1567         /** Same, but opposite order. */
1568         {{1001, 10, 0}, {1000, 10, 0}, NT_STATUS_OK},
1569         {{1001, 9, 1},  {1000, 10, 0}, NT_STATUS_OK},
1570         {{1001, 10, 1}, {1000, 10, 0}, NT_STATUS_OK},
1571         {{1001, 11, 1}, {1000, 10, 0}, NT_STATUS_OK},
1572         {{1001, 9, 2},  {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1573         {{1001, 10, 2}, {1000, 10, 0}, NT_STATUS_OK},
1574         {{1001, 9, 3},  {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1575
1576         /** Zero zero case. */
1577         {{1000, 0, 0},  {1001, 0, 0},  NT_STATUS_OK},
1578 };
1579
1580 static bool test_zerobytelocks(struct torture_context *tctx, struct smbcli_state *cli)
1581 {
1582         union smb_lock io;
1583         NTSTATUS status;
1584         bool ret = true;
1585         int fnum, i;
1586         const char *fname = BASEDIR "\\zero.txt";
1587
1588         torture_comment(tctx, "Testing zero length byte range locks:\n");
1589
1590         if (!torture_setup_dir(cli, BASEDIR)) {
1591                 return false;
1592         }
1593
1594         io.generic.level = RAW_LOCK_LOCKX;
1595
1596         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1597         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1598                        "Failed to create %s - %s\n",
1599                        fname, smbcli_errstr(cli->tree)));
1600
1601         /* Setup initial parameters */
1602         io.lockx.level = RAW_LOCK_LOCKX;
1603         io.lockx.in.file.fnum = fnum;
1604         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; /* Exclusive */
1605         io.lockx.in.timeout = 0;
1606
1607         /* Try every combination of locks in zero_byte_tests. The first lock is
1608          * assumed to succeed. The second lock may contend, depending on the
1609          * expected status. */
1610         for (i = 0;
1611              i < ARRAY_SIZE(zero_byte_tests);
1612              i++) {
1613                 torture_comment(tctx, "  ... {%d, %llu, %llu} + {%d, %llu, %llu} = %s\n",
1614                     zero_byte_tests[i].lock1.pid,
1615                     (unsigned long long) zero_byte_tests[i].lock1.offset,
1616                     (unsigned long long) zero_byte_tests[i].lock1.count,
1617                     zero_byte_tests[i].lock2.pid,
1618                     (unsigned long long) zero_byte_tests[i].lock2.offset,
1619                     (unsigned long long) zero_byte_tests[i].lock2.count,
1620                     nt_errstr(zero_byte_tests[i].exp_status));
1621
1622                 /* Lock both locks. */
1623                 io.lockx.in.ulock_cnt = 0;
1624                 io.lockx.in.lock_cnt = 1;
1625
1626                 io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1627                                                     &zero_byte_tests[i].lock1);
1628                 status = smb_raw_lock(cli->tree, &io);
1629                 CHECK_STATUS(status, NT_STATUS_OK);
1630
1631                 io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1632                                                     &zero_byte_tests[i].lock2);
1633                 status = smb_raw_lock(cli->tree, &io);
1634
1635                 if (NT_STATUS_EQUAL(zero_byte_tests[i].exp_status,
1636                         NT_STATUS_LOCK_NOT_GRANTED)) {
1637                         /* Allow either of the failure messages and keep going
1638                          * if we see the wrong status. */
1639                         CHECK_STATUS_OR_CONT(status,
1640                             NT_STATUS_LOCK_NOT_GRANTED,
1641                             NT_STATUS_FILE_LOCK_CONFLICT);
1642
1643                 } else {
1644                         CHECK_STATUS_CONT(status,
1645                             zero_byte_tests[i].exp_status);
1646                 }
1647
1648                 /* Unlock both locks. */
1649                 io.lockx.in.ulock_cnt = 1;
1650                 io.lockx.in.lock_cnt = 0;
1651
1652                 if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1653                         status = smb_raw_lock(cli->tree, &io);
1654                         CHECK_STATUS(status, NT_STATUS_OK);
1655                 }
1656
1657                 io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1658                                                     &zero_byte_tests[i].lock1);
1659                 status = smb_raw_lock(cli->tree, &io);
1660                 CHECK_STATUS(status, NT_STATUS_OK);
1661         }
1662
1663 done:
1664         smbcli_close(cli->tree, fnum);
1665         smb_raw_exit(cli->session);
1666         smbcli_deltree(cli->tree, BASEDIR);
1667         return ret;
1668 }
1669
1670 static bool test_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1671 {
1672         union smb_lock io;
1673         NTSTATUS status;
1674         bool ret = true;
1675         int fnum1, fnum2;
1676         const char *fname = BASEDIR "\\unlock.txt";
1677         struct smb_lock_entry lock1;
1678         struct smb_lock_entry lock2;
1679
1680         torture_comment(tctx, "Testing LOCKX unlock:\n");
1681
1682         if (!torture_setup_dir(cli, BASEDIR)) {
1683                 return false;
1684         }
1685
1686         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1687         torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1688                        "Failed to create %s - %s\n",
1689                        fname, smbcli_errstr(cli->tree)));
1690
1691         fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1692         torture_assert(tctx,(fnum2 != -1), talloc_asprintf(tctx,
1693                        "Failed to create %s - %s\n",
1694                        fname, smbcli_errstr(cli->tree)));
1695
1696         /* Setup initial parameters */
1697         io.lockx.level = RAW_LOCK_LOCKX;
1698         io.lockx.in.timeout = 0;
1699
1700         lock1.pid = cli->session->pid;
1701         lock1.offset = 0;
1702         lock1.count = 10;
1703         lock2.pid = cli->session->pid - 1;
1704         lock2.offset = 0;
1705         lock2.count = 10;
1706
1707         /**
1708          * Take exclusive lock, then unlock it with a shared-unlock call.
1709          */
1710         torture_comment(tctx, "  taking exclusive lock.\n");
1711         io.lockx.in.ulock_cnt = 0;
1712         io.lockx.in.lock_cnt = 1;
1713         io.lockx.in.mode = 0;
1714         io.lockx.in.file.fnum = fnum1;
1715         io.lockx.in.locks = &lock1;
1716         status = smb_raw_lock(cli->tree, &io);
1717         CHECK_STATUS(status, NT_STATUS_OK);
1718
1719         torture_comment(tctx, "  unlock the exclusive with a shared unlock call.\n");
1720         io.lockx.in.ulock_cnt = 1;
1721         io.lockx.in.lock_cnt = 0;
1722         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1723         io.lockx.in.file.fnum = fnum1;
1724         io.lockx.in.locks = &lock1;
1725         status = smb_raw_lock(cli->tree, &io);
1726         CHECK_STATUS(status, NT_STATUS_OK);
1727
1728         torture_comment(tctx, "  try shared lock on pid2/fnum2, testing the unlock.\n");
1729         io.lockx.in.ulock_cnt = 0;
1730         io.lockx.in.lock_cnt = 1;
1731         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1732         io.lockx.in.file.fnum = fnum2;
1733         io.lockx.in.locks = &lock2;
1734         status = smb_raw_lock(cli->tree, &io);
1735         CHECK_STATUS(status, NT_STATUS_OK);
1736
1737         /**
1738          * Unlock a shared lock with an exclusive-unlock call.
1739          */
1740         torture_comment(tctx, "  unlock new shared lock with exclusive unlock call.\n");
1741         io.lockx.in.ulock_cnt = 1;
1742         io.lockx.in.lock_cnt = 0;
1743         io.lockx.in.mode = 0;
1744         io.lockx.in.file.fnum = fnum2;
1745         io.lockx.in.locks = &lock2;
1746         status = smb_raw_lock(cli->tree, &io);
1747         CHECK_STATUS(status, NT_STATUS_OK);
1748
1749         torture_comment(tctx, "  try exclusive lock on pid1, testing the unlock.\n");
1750         io.lockx.in.ulock_cnt = 0;
1751         io.lockx.in.lock_cnt = 1;
1752         io.lockx.in.mode = 0;
1753         io.lockx.in.file.fnum = fnum1;
1754         io.lockx.in.locks = &lock1;
1755         status = smb_raw_lock(cli->tree, &io);
1756         CHECK_STATUS(status, NT_STATUS_OK);
1757
1758         /* cleanup */
1759         io.lockx.in.ulock_cnt = 1;
1760         io.lockx.in.lock_cnt = 0;
1761         status = smb_raw_lock(cli->tree, &io);
1762         CHECK_STATUS(status, NT_STATUS_OK);
1763
1764         /**
1765          * Test unlocking of 0-byte locks.
1766          */
1767
1768         torture_comment(tctx, "  lock shared and exclusive 0-byte locks, testing that Windows "
1769             "always unlocks the exclusive first.\n");
1770         lock1.pid = cli->session->pid;
1771         lock1.offset = 10;
1772         lock1.count = 0;
1773         lock2.pid = cli->session->pid;
1774         lock2.offset = 5;
1775         lock2.count = 10;
1776         io.lockx.in.ulock_cnt = 0;
1777         io.lockx.in.lock_cnt = 1;
1778         io.lockx.in.file.fnum = fnum1;
1779         io.lockx.in.locks = &lock1;
1780
1781         /* lock 0-byte shared
1782          * Note: Order of the shared/exclusive locks doesn't matter. */
1783         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1784         status = smb_raw_lock(cli->tree, &io);
1785         CHECK_STATUS(status, NT_STATUS_OK);
1786
1787         /* lock 0-byte exclusive */
1788         io.lockx.in.mode = 0;
1789         status = smb_raw_lock(cli->tree, &io);
1790         CHECK_STATUS(status, NT_STATUS_OK);
1791
1792         /* test contention */
1793         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1794         io.lockx.in.locks = &lock2;
1795         io.lockx.in.file.fnum = fnum2;
1796         status = smb_raw_lock(cli->tree, &io);
1797         CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1798             NT_STATUS_FILE_LOCK_CONFLICT);
1799
1800         /* unlock */
1801         io.lockx.in.ulock_cnt = 1;
1802         io.lockx.in.lock_cnt = 0;
1803         io.lockx.in.file.fnum = fnum1;
1804         io.lockx.in.locks = &lock1;
1805         status = smb_raw_lock(cli->tree, &io);
1806         CHECK_STATUS(status, NT_STATUS_OK);
1807
1808         /* test - can we take a shared lock? */
1809         io.lockx.in.ulock_cnt = 0;
1810         io.lockx.in.lock_cnt = 1;
1811         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1812         io.lockx.in.file.fnum = fnum2;
1813         io.lockx.in.locks = &lock2;
1814         status = smb_raw_lock(cli->tree, &io);
1815
1816         /* XXX Samba 3 will fail this test. This is temporary(because this isn't
1817          * new to Win7, it succeeds in WinXP too), until I can come to a
1818          * resolution as to whether Samba should support this or not. There is
1819          * code to preference unlocking exclusive locks before shared locks,
1820          * but its wrapped with "#ifdef ZERO_ZERO". -zkirsch */
1821         if (TARGET_IS_SAMBA3(tctx)) {
1822                 CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1823                     NT_STATUS_FILE_LOCK_CONFLICT);
1824         } else {
1825                 CHECK_STATUS(status, NT_STATUS_OK);
1826         }
1827
1828         /* cleanup */
1829         io.lockx.in.ulock_cnt = 1;
1830         io.lockx.in.lock_cnt = 0;
1831         status = smb_raw_lock(cli->tree, &io);
1832
1833         /* XXX Same as above. */
1834         if (TARGET_IS_SAMBA3(tctx)) {
1835                 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1836         } else {
1837                 CHECK_STATUS(status, NT_STATUS_OK);
1838         }
1839
1840         io.lockx.in.file.fnum = fnum1;
1841         io.lockx.in.locks = &lock1;
1842         status = smb_raw_lock(cli->tree, &io);
1843         CHECK_STATUS(status, NT_STATUS_OK);
1844
1845 done:
1846         smbcli_close(cli->tree, fnum1);
1847         smbcli_close(cli->tree, fnum2);
1848         smb_raw_exit(cli->session);
1849         smbcli_deltree(cli->tree, BASEDIR);
1850         return ret;
1851 }
1852
1853 static bool test_multiple_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1854 {
1855         union smb_lock io;
1856         NTSTATUS status;
1857         bool ret = true;
1858         int fnum1;
1859         const char *fname = BASEDIR "\\unlock_multiple.txt";
1860         struct smb_lock_entry lock1;
1861         struct smb_lock_entry lock2;
1862         struct smb_lock_entry locks[2];
1863
1864         torture_comment(tctx, "Testing LOCKX multiple unlock:\n");
1865
1866         if (!torture_setup_dir(cli, BASEDIR)) {
1867                 return false;
1868         }
1869
1870         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1871         torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1872                        "Failed to create %s - %s\n",
1873                        fname, smbcli_errstr(cli->tree)));
1874
1875         /* Setup initial parameters */
1876         io.lockx.level = RAW_LOCK_LOCKX;
1877         io.lockx.in.timeout = 0;
1878
1879         lock1.pid = cli->session->pid;
1880         lock1.offset = 0;
1881         lock1.count = 10;
1882         lock2.pid = cli->session->pid;
1883         lock2.offset = 10;
1884         lock2.count = 10;
1885
1886         locks[0] = lock1;
1887         locks[1] = lock2;
1888
1889         io.lockx.in.file.fnum = fnum1;
1890         io.lockx.in.mode = 0; /* exclusive */
1891
1892         /** Test1: Take second lock, but not first. */
1893         torture_comment(tctx, "  unlock 2 locks, first one not locked. Expect no locks "
1894             "unlocked. \n");
1895
1896         io.lockx.in.ulock_cnt = 0;
1897         io.lockx.in.lock_cnt = 1;
1898         io.lockx.in.locks = &lock2;
1899         status = smb_raw_lock(cli->tree, &io);
1900         CHECK_STATUS(status, NT_STATUS_OK);
1901
1902         /* Try to unlock both locks. */
1903         io.lockx.in.ulock_cnt = 2;
1904         io.lockx.in.lock_cnt = 0;
1905         io.lockx.in.locks = locks;
1906
1907         status = smb_raw_lock(cli->tree, &io);
1908         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1909
1910         /* Second lock should not be unlocked. */
1911         io.lockx.in.ulock_cnt = 0;
1912         io.lockx.in.lock_cnt = 1;
1913         io.lockx.in.locks = &lock2;
1914         status = smb_raw_lock(cli->tree, &io);
1915         CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1916
1917         /* cleanup */
1918         io.lockx.in.ulock_cnt = 1;
1919         io.lockx.in.lock_cnt = 0;
1920         io.lockx.in.locks = &lock2;
1921         status = smb_raw_lock(cli->tree, &io);
1922         CHECK_STATUS(status, NT_STATUS_OK);
1923
1924         /** Test2: Take first lock, but not second. */
1925         torture_comment(tctx, "  unlock 2 locks, second one not locked. Expect first lock "
1926             "unlocked.\n");
1927
1928         io.lockx.in.ulock_cnt = 0;
1929         io.lockx.in.lock_cnt = 1;
1930         io.lockx.in.locks = &lock1;
1931         status = smb_raw_lock(cli->tree, &io);
1932         CHECK_STATUS(status, NT_STATUS_OK);
1933
1934         /* Try to unlock both locks. */
1935         io.lockx.in.ulock_cnt = 2;
1936         io.lockx.in.lock_cnt = 0;
1937         io.lockx.in.locks = locks;
1938
1939         status = smb_raw_lock(cli->tree, &io);
1940         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1941
1942         /* First lock should be unlocked. */
1943         io.lockx.in.ulock_cnt = 0;
1944         io.lockx.in.lock_cnt = 1;
1945         io.lockx.in.locks = &lock1;
1946         status = smb_raw_lock(cli->tree, &io);
1947         CHECK_STATUS(status, NT_STATUS_OK);
1948
1949         /* cleanup */
1950         io.lockx.in.ulock_cnt = 1;
1951         io.lockx.in.lock_cnt = 0;
1952         io.lockx.in.locks = &lock1;
1953         status = smb_raw_lock(cli->tree, &io);
1954         CHECK_STATUS(status, NT_STATUS_OK);
1955
1956         /* Test3: Request 2 locks, second will contend.  What happens to the
1957          * first? */
1958         torture_comment(tctx, "  request 2 locks, second one will contend. "
1959            "Expect both to fail.\n");
1960
1961         /* Lock the second range */
1962         io.lockx.in.ulock_cnt = 0;
1963         io.lockx.in.lock_cnt = 1;
1964         io.lockx.in.locks = &lock2;
1965         status = smb_raw_lock(cli->tree, &io);
1966         CHECK_STATUS(status, NT_STATUS_OK);
1967
1968         /* Request both locks */
1969         io.lockx.in.ulock_cnt = 0;
1970         io.lockx.in.lock_cnt = 2;
1971         io.lockx.in.locks = locks;
1972
1973         status = smb_raw_lock(cli->tree, &io);
1974         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1975
1976         /* First lock should be unlocked. */
1977         io.lockx.in.ulock_cnt = 0;
1978         io.lockx.in.lock_cnt = 1;
1979         io.lockx.in.locks = &lock1;
1980         status = smb_raw_lock(cli->tree, &io);
1981         CHECK_STATUS(status, NT_STATUS_OK);
1982
1983         /* cleanup */
1984         io.lockx.in.ulock_cnt = 2;
1985         io.lockx.in.lock_cnt = 0;
1986         io.lockx.in.locks = locks;
1987         status = smb_raw_lock(cli->tree, &io);
1988         CHECK_STATUS(status, NT_STATUS_OK);
1989
1990         /* Test4: Request unlock and lock. The lock contends, is the unlock
1991          * then re-locked? */
1992         torture_comment(tctx, "  request unlock and lock, second one will "
1993            "contend. Expect the unlock to succeed.\n");
1994
1995         /* Lock both ranges */
1996         io.lockx.in.ulock_cnt = 0;
1997         io.lockx.in.lock_cnt = 2;
1998         io.lockx.in.locks = locks;
1999         status = smb_raw_lock(cli->tree, &io);
2000         CHECK_STATUS(status, NT_STATUS_OK);
2001
2002         /* Attempt to unlock the first range and lock the second */
2003         io.lockx.in.ulock_cnt = 1;
2004         io.lockx.in.lock_cnt = 1;
2005         io.lockx.in.locks = locks;
2006         status = smb_raw_lock(cli->tree, &io);
2007         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2008
2009         /* The first lock should've been unlocked */
2010         io.lockx.in.ulock_cnt = 0;
2011         io.lockx.in.lock_cnt = 1;
2012         io.lockx.in.locks = &lock1;
2013         status = smb_raw_lock(cli->tree, &io);
2014         CHECK_STATUS(status, NT_STATUS_OK);
2015
2016         /* cleanup */
2017         io.lockx.in.ulock_cnt = 2;
2018         io.lockx.in.lock_cnt = 0;
2019         io.lockx.in.locks = locks;
2020         status = smb_raw_lock(cli->tree, &io);
2021         CHECK_STATUS(status, NT_STATUS_OK);
2022
2023 done:
2024         smbcli_close(cli->tree, fnum1);
2025         smb_raw_exit(cli->session);
2026         smbcli_deltree(cli->tree, BASEDIR);
2027         return ret;
2028 }
2029
2030 /**
2031  * torture_locktest5 covers stacking pretty well, but its missing two tests:
2032  * - stacking an exclusive on top of shared fails
2033  * - stacking two exclusives fail
2034  */
2035 static bool test_stacking(struct torture_context *tctx, struct smbcli_state *cli)
2036 {
2037         union smb_lock io;
2038         NTSTATUS status;
2039         bool ret = true;
2040         int fnum1;
2041         const char *fname = BASEDIR "\\stacking.txt";
2042         struct smb_lock_entry lock1;
2043         struct smb_lock_entry lock2;
2044
2045         torture_comment(tctx, "Testing stacking:\n");
2046
2047         if (!torture_setup_dir(cli, BASEDIR)) {
2048                 return false;
2049         }
2050
2051         io.generic.level = RAW_LOCK_LOCKX;
2052
2053         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2054         torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
2055                        "Failed to create %s - %s\n",
2056                        fname, smbcli_errstr(cli->tree)));
2057
2058         /* Setup initial parameters */
2059         io.lockx.level = RAW_LOCK_LOCKX;
2060         io.lockx.in.timeout = 0;
2061
2062         lock1.pid = cli->session->pid;
2063         lock1.offset = 0;
2064         lock1.count = 10;
2065         lock2.pid = cli->session->pid - 1;
2066         lock2.offset = 0;
2067         lock2.count = 10;
2068
2069         /**
2070          * Try to take a shared lock, then stack an exclusive.
2071          */
2072         torture_comment(tctx, "  stacking an exclusive on top of a shared lock fails.\n");
2073         io.lockx.in.file.fnum = fnum1;
2074         io.lockx.in.locks = &lock1;
2075
2076         io.lockx.in.ulock_cnt = 0;
2077         io.lockx.in.lock_cnt = 1;
2078         io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
2079         status = smb_raw_lock(cli->tree, &io);
2080         CHECK_STATUS(status, NT_STATUS_OK);
2081
2082         io.lockx.in.ulock_cnt = 0;
2083         io.lockx.in.lock_cnt = 1;
2084         io.lockx.in.mode = 0;
2085         status = smb_raw_lock(cli->tree, &io);
2086         CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
2087             NT_STATUS_FILE_LOCK_CONFLICT);
2088
2089         /* cleanup */
2090         io.lockx.in.ulock_cnt = 1;
2091         io.lockx.in.lock_cnt = 0;
2092         status = smb_raw_lock(cli->tree, &io);
2093         CHECK_STATUS(status, NT_STATUS_OK);
2094
2095         /**
2096          * Prove that two exclusive locks do not stack.
2097          */
2098         torture_comment(tctx, "  two exclusive locks do not stack.\n");
2099         io.lockx.in.ulock_cnt = 0;
2100         io.lockx.in.lock_cnt = 1;
2101         io.lockx.in.mode = 0;
2102         status = smb_raw_lock(cli->tree, &io);
2103         CHECK_STATUS(status, NT_STATUS_OK);
2104         status = smb_raw_lock(cli->tree, &io);
2105         CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
2106             NT_STATUS_FILE_LOCK_CONFLICT);
2107
2108         /* cleanup */
2109         io.lockx.in.ulock_cnt = 1;
2110         io.lockx.in.lock_cnt = 0;
2111         status = smb_raw_lock(cli->tree, &io);
2112         CHECK_STATUS(status, NT_STATUS_OK);
2113
2114 done:
2115         smbcli_close(cli->tree, fnum1);
2116         smb_raw_exit(cli->session);
2117         smbcli_deltree(cli->tree, BASEDIR);
2118         return ret;
2119 }
2120
2121 /**
2122  * Test how 0-byte read requests contend with byte range locks
2123  */
2124 static bool test_zerobyteread(struct torture_context *tctx,
2125                               struct smbcli_state *cli)
2126 {
2127         union smb_lock io;
2128         union smb_read rd;
2129         NTSTATUS status;
2130         bool ret = true;
2131         int fnum1, fnum2;
2132         const char *fname = BASEDIR "\\zerobyteread.txt";
2133         struct smb_lock_entry lock1;
2134         uint8_t c = 1;
2135
2136         if (!torture_setup_dir(cli, BASEDIR)) {
2137                 return false;
2138         }
2139
2140         io.generic.level = RAW_LOCK_LOCKX;
2141
2142         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2143         torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
2144                        "Failed to create %s - %s\n",
2145                        fname, smbcli_errstr(cli->tree)));
2146
2147         fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2148         torture_assert(tctx,(fnum2 != -1), talloc_asprintf(tctx,
2149                        "Failed to create %s - %s\n",
2150                        fname, smbcli_errstr(cli->tree)));
2151
2152         /* Setup initial parameters */
2153         io.lockx.level = RAW_LOCK_LOCKX;
2154         io.lockx.in.timeout = 0;
2155
2156         lock1.pid = cli->session->pid;
2157         lock1.offset = 0;
2158         lock1.count = 10;
2159
2160         ZERO_STRUCT(rd);
2161         rd.readx.level = RAW_READ_READX;
2162
2163         torture_comment(tctx, "Testing zero byte read on lock range:\n");
2164
2165         /* Take an exclusive lock */
2166         torture_comment(tctx, "  taking exclusive lock.\n");
2167         io.lockx.in.ulock_cnt = 0;
2168         io.lockx.in.lock_cnt = 1;
2169         io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2170         io.lockx.in.file.fnum = fnum1;
2171         io.lockx.in.locks = &lock1;
2172         status = smb_raw_lock(cli->tree, &io);
2173         CHECK_STATUS(status, NT_STATUS_OK);
2174
2175         /* Try a zero byte read */
2176         torture_comment(tctx, "  reading 0 bytes.\n");
2177         rd.readx.in.file.fnum = fnum2;
2178         rd.readx.in.offset    = 5;
2179         rd.readx.in.mincnt    = 0;
2180         rd.readx.in.maxcnt    = 0;
2181         rd.readx.in.remaining = 0;
2182         rd.readx.in.read_for_execute = false;
2183         rd.readx.out.data     = &c;
2184         status = smb_raw_read(cli->tree, &rd);
2185         torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2186                                       "zero byte read did not return 0 bytes");
2187         CHECK_STATUS(status, NT_STATUS_OK);
2188
2189         /* Unlock lock */
2190         io.lockx.in.ulock_cnt = 1;
2191         io.lockx.in.lock_cnt = 0;
2192         io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2193         io.lockx.in.file.fnum = fnum1;
2194         io.lockx.in.locks = &lock1;
2195         status = smb_raw_lock(cli->tree, &io);
2196         CHECK_STATUS(status, NT_STATUS_OK);
2197
2198         torture_comment(tctx, "Testing zero byte read on zero byte lock "
2199                               "range:\n");
2200
2201         /* Take an exclusive lock */
2202         torture_comment(tctx, "  taking exclusive 0-byte lock.\n");
2203         io.lockx.in.ulock_cnt = 0;
2204         io.lockx.in.lock_cnt = 1;
2205         io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2206         io.lockx.in.file.fnum = fnum1;
2207         io.lockx.in.locks = &lock1;
2208         lock1.offset = 5;
2209         lock1.count = 0;
2210         status = smb_raw_lock(cli->tree, &io);
2211         CHECK_STATUS(status, NT_STATUS_OK);
2212
2213         /* Try a zero byte read before the lock */
2214         torture_comment(tctx, "  reading 0 bytes before the lock.\n");
2215         rd.readx.in.file.fnum = fnum2;
2216         rd.readx.in.offset    = 4;
2217         rd.readx.in.mincnt    = 0;
2218         rd.readx.in.maxcnt    = 0;
2219         rd.readx.in.remaining = 0;
2220         rd.readx.in.read_for_execute = false;
2221         rd.readx.out.data     = &c;
2222         status = smb_raw_read(cli->tree, &rd);
2223         torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2224                                       "zero byte read did not return 0 bytes");
2225         CHECK_STATUS(status, NT_STATUS_OK);
2226
2227         /* Try a zero byte read on the lock */
2228         torture_comment(tctx, "  reading 0 bytes on the lock.\n");
2229         rd.readx.in.file.fnum = fnum2;
2230         rd.readx.in.offset    = 5;
2231         rd.readx.in.mincnt    = 0;
2232         rd.readx.in.maxcnt    = 0;
2233         rd.readx.in.remaining = 0;
2234         rd.readx.in.read_for_execute = false;
2235         rd.readx.out.data     = &c;
2236         status = smb_raw_read(cli->tree, &rd);
2237         torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2238                                       "zero byte read did not return 0 bytes");
2239         CHECK_STATUS(status, NT_STATUS_OK);
2240
2241         /* Try a zero byte read after the lock */
2242         torture_comment(tctx, "  reading 0 bytes after the lock.\n");
2243         rd.readx.in.file.fnum = fnum2;
2244         rd.readx.in.offset    = 6;
2245         rd.readx.in.mincnt    = 0;
2246         rd.readx.in.maxcnt    = 0;
2247         rd.readx.in.remaining = 0;
2248         rd.readx.in.read_for_execute = false;
2249         rd.readx.out.data     = &c;
2250         status = smb_raw_read(cli->tree, &rd);
2251         torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2252                                       "zero byte read did not return 0 bytes");
2253         CHECK_STATUS(status, NT_STATUS_OK);
2254
2255         /* Unlock lock */
2256         io.lockx.in.ulock_cnt = 1;
2257         io.lockx.in.lock_cnt = 0;
2258         io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2259         io.lockx.in.file.fnum = fnum1;
2260         io.lockx.in.locks = &lock1;
2261         status = smb_raw_lock(cli->tree, &io);
2262         CHECK_STATUS(status, NT_STATUS_OK);
2263
2264 done:
2265         smbcli_close(cli->tree, fnum1);
2266         smbcli_close(cli->tree, fnum2);
2267         smb_raw_exit(cli->session);
2268         smbcli_deltree(cli->tree, BASEDIR);
2269         return ret;
2270 }
2271
2272 /*
2273    basic testing of lock calls
2274 */
2275 struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx)
2276 {
2277         struct torture_suite *suite = torture_suite_create(mem_ctx, "lock");
2278
2279         torture_suite_add_1smb_test(suite, "lockx", test_lockx);
2280         torture_suite_add_1smb_test(suite, "lock", test_lock);
2281         torture_suite_add_1smb_test(suite, "pidhigh", test_pidhigh);
2282         torture_suite_add_1smb_test(suite, "async", test_async);
2283         torture_suite_add_1smb_test(suite, "errorcode", test_errorcode);
2284         torture_suite_add_1smb_test(suite, "changetype", test_changetype);
2285
2286         torture_suite_add_1smb_test(suite, "stacking", test_stacking);
2287         torture_suite_add_1smb_test(suite, "unlock", test_unlock);
2288         torture_suite_add_1smb_test(suite, "multiple_unlock",
2289             test_multiple_unlock);
2290         torture_suite_add_1smb_test(suite, "zerobytelocks", test_zerobytelocks);
2291         torture_suite_add_1smb_test(suite, "zerobyteread", test_zerobyteread);
2292
2293         return suite;
2294 }