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