s4: popt: Global replace of cmdline_credentials -> popt_get_cmdline_credentials().
[gd/samba-autobuild/.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 = popt_get_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, 120->129 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 = 20000;
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   test multi2 Locking&X operation
2364   This test is designed to show that
2365   lock precedence on the server is based
2366   on the order received, not on the ability
2367   to grant. For example:
2368
2369   A blocked lock request containing 2 locks
2370   will be satified before a subsequent blocked
2371   lock request over one of the same regions,
2372   even if that region is then unlocked. E.g.
2373
2374   (a) lock 100->109, 120->129 (granted)
2375   (b) lock 100->109, 120-129 (blocks)
2376   (c) lock 100->109          (blocks)
2377   (d) unlock 100->109
2378
2379   lock (c) will not be granted as lock (b)
2380   will take precedence.
2381 */
2382 static bool test_multilock2(struct torture_context *tctx,
2383                                            struct smbcli_state *cli)
2384 {
2385         union smb_lock io;
2386         struct smb_lock_entry lock[2];
2387         NTSTATUS status;
2388         bool ret = true;
2389         int fnum;
2390         const char *fname = BASEDIR "\\multilock2_test.txt";
2391         time_t t;
2392         struct smbcli_request *req;
2393         struct smbcli_request *req2;
2394         struct smbcli_session_options options;
2395
2396         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2397
2398         lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
2399
2400         torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 2\n");
2401         io.generic.level = RAW_LOCK_LOCKX;
2402
2403         /* Create the test file. */
2404         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2405         torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
2406                        "Failed to create %s - %s\n",
2407                        fname, smbcli_errstr(cli->tree)));
2408
2409         /*
2410          * Lock regions 100->109, 120->129 as
2411          * two separate write locks in one request.
2412          */
2413         io.lockx.level = RAW_LOCK_LOCKX;
2414         io.lockx.in.file.fnum = fnum;
2415         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
2416         io.lockx.in.timeout = 0;
2417         io.lockx.in.ulock_cnt = 0;
2418         io.lockx.in.lock_cnt = 2;
2419         io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2420         lock[0].pid = cli->session->pid;
2421         lock[0].offset = 100;
2422         lock[0].count = 10;
2423         lock[1].pid = cli->session->pid;
2424         lock[1].offset = 120;
2425         lock[1].count = 10;
2426         io.lockx.in.locks = &lock[0];
2427         status = smb_raw_lock(cli->tree, &io);
2428         CHECK_STATUS(status, NT_STATUS_OK);
2429
2430         /*
2431          * Now request the same locks on a different
2432          * context as blocking locks.
2433          */
2434
2435         io.lockx.in.timeout = 20000;
2436         lock[0].pid = cli->session->pid+1;
2437         lock[1].pid = cli->session->pid+1;
2438         req = smb_raw_lock_send(cli->tree, &io);
2439         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
2440                        "Failed to setup timed locks (%s)\n", __location__));
2441
2442         /*
2443          * Request the first lock again on a separate context.
2444          * Wait 2 seconds. This should time out (the previous
2445          * multi-lock request should take precedence).
2446          */
2447
2448         io.lockx.in.timeout = 2000;
2449         lock[0].pid = cli->session->pid+2;
2450         io.lockx.in.lock_cnt = 1;
2451         req2 = smb_raw_lock_send(cli->tree, &io);
2452         torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
2453                        "Failed to setup timed locks (%s)\n", __location__));
2454
2455         /* Unlock lock[0] */
2456         io.lockx.in.timeout = 0;
2457         io.lockx.in.ulock_cnt = 1;
2458         io.lockx.in.lock_cnt = 0;
2459         io.lockx.in.locks = &lock[0];
2460         lock[0].pid = cli->session->pid;
2461         status = smb_raw_lock(cli->tree, &io);
2462         CHECK_STATUS(status, NT_STATUS_OK);
2463
2464         /* Did the second lock complete (should time out) ? */
2465         status = smbcli_request_simple_recv(req2);
2466         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2467
2468         /* Start the clock. */
2469         t = time_mono(NULL);
2470
2471         /* Unlock lock[1] */
2472         io.lockx.in.timeout = 0;
2473         io.lockx.in.ulock_cnt = 1;
2474         io.lockx.in.lock_cnt = 0;
2475         io.lockx.in.locks = &lock[1];
2476         lock[1].pid = cli->session->pid;
2477         status = smb_raw_lock(cli->tree, &io);
2478         CHECK_STATUS(status, NT_STATUS_OK);
2479
2480         /* receive the successful blocked lock requests */
2481         status = smbcli_request_simple_recv(req);
2482         CHECK_STATUS(status, NT_STATUS_OK);
2483
2484         /* Fail if this took more than 2 seconds. */
2485         torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
2486                        "Blocking locks were not granted immediately (%s)\n",
2487                        __location__));
2488 done:
2489         smb_raw_exit(cli->session);
2490         smbcli_deltree(cli->tree, BASEDIR);
2491         return ret;
2492 }
2493
2494
2495 /*
2496    basic testing of lock calls
2497 */
2498 struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx)
2499 {
2500         struct torture_suite *suite = torture_suite_create(mem_ctx, "lock");
2501
2502         torture_suite_add_1smb_test(suite, "lockx", test_lockx);
2503         torture_suite_add_1smb_test(suite, "lock", test_lock);
2504         torture_suite_add_1smb_test(suite, "pidhigh", test_pidhigh);
2505         torture_suite_add_1smb_test(suite, "async", test_async);
2506         torture_suite_add_1smb_test(suite, "errorcode", test_errorcode);
2507         torture_suite_add_1smb_test(suite, "changetype", test_changetype);
2508
2509         torture_suite_add_1smb_test(suite, "stacking", test_stacking);
2510         torture_suite_add_1smb_test(suite, "unlock", test_unlock);
2511         torture_suite_add_1smb_test(suite, "multiple_unlock",
2512             test_multiple_unlock);
2513         torture_suite_add_1smb_test(suite, "zerobytelocks", test_zerobytelocks);
2514         torture_suite_add_1smb_test(suite, "zerobyteread", test_zerobyteread);
2515         torture_suite_add_1smb_test(suite, "multilock", test_multilock);
2516         torture_suite_add_1smb_test(suite, "multilock2", test_multilock2);
2517
2518         return suite;
2519 }