• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source4/torture/raw/
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
33#define CHECK_STATUS(status, correct) do { \
34	if (!NT_STATUS_EQUAL(status, correct)) { \
35		torture_result(tctx, TORTURE_FAIL, \
36			"(%s) Incorrect status %s - should be %s\n", \
37			__location__, nt_errstr(status), nt_errstr(correct)); \
38		ret = false; \
39		goto done; \
40	}} while (0)
41
42#define CHECK_STATUS_CONT(status, correct) do { \
43	if (!NT_STATUS_EQUAL(status, correct)) { \
44		torture_result(tctx, TORTURE_FAIL, \
45			"(%s) Incorrect status %s - should be %s\n", \
46			__location__, nt_errstr(status), nt_errstr(correct)); \
47		ret = false; \
48	}} while (0)
49
50#define CHECK_STATUS_OR(status, correct1, correct2) do { \
51	if ((!NT_STATUS_EQUAL(status, correct1)) && \
52	    (!NT_STATUS_EQUAL(status, correct2))) { \
53		torture_result(tctx, TORTURE_FAIL, \
54			"(%s) Incorrect status %s - should be %s or %s\n", \
55			__location__, nt_errstr(status), nt_errstr(correct1), \
56			nt_errstr(correct2)); \
57		ret = false; \
58		goto done; \
59	}} while (0)
60
61#define CHECK_STATUS_OR_CONT(status, correct1, correct2) do { \
62	if ((!NT_STATUS_EQUAL(status, correct1)) && \
63	    (!NT_STATUS_EQUAL(status, correct2))) { \
64		torture_result(tctx, TORTURE_FAIL, \
65			"(%s) Incorrect status %s - should be %s or %s\n", \
66			__location__, nt_errstr(status), nt_errstr(correct1), \
67			nt_errstr(correct2)); \
68		ret = false; \
69	}} while (0)
70#define BASEDIR "\\testlock"
71
72#define TARGET_IS_W2K8(_tctx) (torture_setting_bool(_tctx, "w2k8", false))
73#define TARGET_IS_WIN7(_tctx) (torture_setting_bool(_tctx, "win7", false))
74#define TARGET_IS_SAMBA3(_tctx) (torture_setting_bool(_tctx, "samba3", false))
75
76/*
77  test SMBlock and SMBunlock ops
78*/
79static bool test_lock(struct torture_context *tctx, struct smbcli_state *cli)
80{
81	union smb_lock io;
82	NTSTATUS status;
83	bool ret = true;
84	int fnum;
85	const char *fname = BASEDIR "\\test.txt";
86
87	if (!torture_setup_dir(cli, BASEDIR)) {
88		return false;
89	}
90
91	torture_comment(tctx, "Testing RAW_LOCK_LOCK\n");
92	io.generic.level = RAW_LOCK_LOCK;
93
94	fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
95	torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
96		       "Failed to create %s - %s\n",
97		       fname, smbcli_errstr(cli->tree)));
98
99	torture_comment(tctx, "Trying 0/0 lock\n");
100	io.lock.level = RAW_LOCK_LOCK;
101	io.lock.in.file.fnum = fnum;
102	io.lock.in.count = 0;
103	io.lock.in.offset = 0;
104	status = smb_raw_lock(cli->tree, &io);
105	CHECK_STATUS(status, NT_STATUS_OK);
106	cli->session->pid++;
107	status = smb_raw_lock(cli->tree, &io);
108	CHECK_STATUS(status, NT_STATUS_OK);
109	cli->session->pid--;
110	io.lock.level = RAW_LOCK_UNLOCK;
111	status = smb_raw_lock(cli->tree, &io);
112	CHECK_STATUS(status, NT_STATUS_OK);
113
114	torture_comment(tctx, "Trying 0/1 lock\n");
115	io.lock.level = RAW_LOCK_LOCK;
116	io.lock.in.file.fnum = fnum;
117	io.lock.in.count = 1;
118	io.lock.in.offset = 0;
119	status = smb_raw_lock(cli->tree, &io);
120	CHECK_STATUS(status, NT_STATUS_OK);
121	cli->session->pid++;
122	status = smb_raw_lock(cli->tree, &io);
123	CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
124	cli->session->pid--;
125	io.lock.level = RAW_LOCK_UNLOCK;
126	status = smb_raw_lock(cli->tree, &io);
127	CHECK_STATUS(status, NT_STATUS_OK);
128	io.lock.level = RAW_LOCK_UNLOCK;
129	status = smb_raw_lock(cli->tree, &io);
130	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
131
132	torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
133	io.lock.level = RAW_LOCK_LOCK;
134	io.lock.in.file.fnum = fnum;
135	io.lock.in.count = 4000;
136	io.lock.in.offset = 0xEEFFFFFF;
137	status = smb_raw_lock(cli->tree, &io);
138	CHECK_STATUS(status, NT_STATUS_OK);
139	cli->session->pid++;
140	status = smb_raw_lock(cli->tree, &io);
141	CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
142	cli->session->pid--;
143	io.lock.level = RAW_LOCK_UNLOCK;
144	status = smb_raw_lock(cli->tree, &io);
145	CHECK_STATUS(status, NT_STATUS_OK);
146	io.lock.level = RAW_LOCK_UNLOCK;
147	status = smb_raw_lock(cli->tree, &io);
148	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
149
150	torture_comment(tctx, "Trying 0xEF000000 lock\n");
151	io.lock.level = RAW_LOCK_LOCK;
152	io.lock.in.file.fnum = fnum;
153	io.lock.in.count = 4000;
154	io.lock.in.offset = 0xEEFFFFFF;
155	status = smb_raw_lock(cli->tree, &io);
156	CHECK_STATUS(status, NT_STATUS_OK);
157	cli->session->pid++;
158	status = smb_raw_lock(cli->tree, &io);
159	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
160	cli->session->pid--;
161	io.lock.level = RAW_LOCK_UNLOCK;
162	status = smb_raw_lock(cli->tree, &io);
163	CHECK_STATUS(status, NT_STATUS_OK);
164	io.lock.level = RAW_LOCK_UNLOCK;
165	status = smb_raw_lock(cli->tree, &io);
166	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
167
168	torture_comment(tctx, "Trying max lock\n");
169	io.lock.level = RAW_LOCK_LOCK;
170	io.lock.in.file.fnum = fnum;
171	io.lock.in.count = 4000;
172	io.lock.in.offset = 0xEF000000;
173	status = smb_raw_lock(cli->tree, &io);
174	CHECK_STATUS(status, NT_STATUS_OK);
175	cli->session->pid++;
176	status = smb_raw_lock(cli->tree, &io);
177	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
178	cli->session->pid--;
179	io.lock.level = RAW_LOCK_UNLOCK;
180	status = smb_raw_lock(cli->tree, &io);
181	CHECK_STATUS(status, NT_STATUS_OK);
182	io.lock.level = RAW_LOCK_UNLOCK;
183	status = smb_raw_lock(cli->tree, &io);
184	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
185
186	torture_comment(tctx, "Trying wrong pid unlock\n");
187	io.lock.level = RAW_LOCK_LOCK;
188	io.lock.in.file.fnum = fnum;
189	io.lock.in.count = 4002;
190	io.lock.in.offset = 10001;
191	status = smb_raw_lock(cli->tree, &io);
192	CHECK_STATUS(status, NT_STATUS_OK);
193	cli->session->pid++;
194	io.lock.level = RAW_LOCK_UNLOCK;
195	status = smb_raw_lock(cli->tree, &io);
196	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
197	cli->session->pid--;
198	status = smb_raw_lock(cli->tree, &io);
199	CHECK_STATUS(status, NT_STATUS_OK);
200
201done:
202	smbcli_close(cli->tree, fnum);
203	smb_raw_exit(cli->session);
204	smbcli_deltree(cli->tree, BASEDIR);
205	return ret;
206}
207
208
209/*
210  test locking&X ops
211*/
212static bool test_lockx(struct torture_context *tctx, struct smbcli_state *cli)
213{
214	union smb_lock io;
215	struct smb_lock_entry lock[1];
216	NTSTATUS status;
217	bool ret = true;
218	int fnum;
219	const char *fname = BASEDIR "\\test.txt";
220
221	if (!torture_setup_dir(cli, BASEDIR)) {
222		return false;
223	}
224
225	torture_comment(tctx, "Testing RAW_LOCK_LOCKX\n");
226	io.generic.level = RAW_LOCK_LOCKX;
227
228	fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
229	torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
230		       "Failed to create %s - %s\n",
231		       fname, smbcli_errstr(cli->tree)));
232
233	io.lockx.level = RAW_LOCK_LOCKX;
234	io.lockx.in.file.fnum = fnum;
235	io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
236	io.lockx.in.timeout = 0;
237	io.lockx.in.ulock_cnt = 0;
238	io.lockx.in.lock_cnt = 1;
239	lock[0].pid = cli->session->pid;
240	lock[0].offset = 10;
241	lock[0].count = 1;
242	io.lockx.in.locks = &lock[0];
243	status = smb_raw_lock(cli->tree, &io);
244	CHECK_STATUS(status, NT_STATUS_OK);
245
246
247	torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
248	io.lockx.in.ulock_cnt = 0;
249	io.lockx.in.lock_cnt = 1;
250	lock[0].count = 4000;
251	lock[0].offset = 0xEEFFFFFF;
252	status = smb_raw_lock(cli->tree, &io);
253	CHECK_STATUS(status, NT_STATUS_OK);
254	lock[0].pid++;
255	status = smb_raw_lock(cli->tree, &io);
256	CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
257	lock[0].pid--;
258	io.lockx.in.ulock_cnt = 1;
259	io.lockx.in.lock_cnt = 0;
260	status = smb_raw_lock(cli->tree, &io);
261	CHECK_STATUS(status, NT_STATUS_OK);
262	status = smb_raw_lock(cli->tree, &io);
263	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
264
265	torture_comment(tctx, "Trying 0xEF000000 lock\n");
266	io.lockx.in.ulock_cnt = 0;
267	io.lockx.in.lock_cnt = 1;
268	lock[0].count = 4000;
269	lock[0].offset = 0xEF000000;
270	status = smb_raw_lock(cli->tree, &io);
271	CHECK_STATUS(status, NT_STATUS_OK);
272	lock[0].pid++;
273	status = smb_raw_lock(cli->tree, &io);
274	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
275	lock[0].pid--;
276	io.lockx.in.ulock_cnt = 1;
277	io.lockx.in.lock_cnt = 0;
278	status = smb_raw_lock(cli->tree, &io);
279	CHECK_STATUS(status, NT_STATUS_OK);
280	status = smb_raw_lock(cli->tree, &io);
281	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
282
283	torture_comment(tctx, "Trying zero lock\n");
284	io.lockx.in.ulock_cnt = 0;
285	io.lockx.in.lock_cnt = 1;
286	lock[0].count = 0;
287	lock[0].offset = ~0;
288	status = smb_raw_lock(cli->tree, &io);
289	CHECK_STATUS(status, NT_STATUS_OK);
290	lock[0].pid++;
291	status = smb_raw_lock(cli->tree, &io);
292	CHECK_STATUS(status, NT_STATUS_OK);
293	lock[0].pid--;
294	io.lockx.in.ulock_cnt = 1;
295	io.lockx.in.lock_cnt = 0;
296	status = smb_raw_lock(cli->tree, &io);
297	CHECK_STATUS(status, NT_STATUS_OK);
298	status = smb_raw_lock(cli->tree, &io);
299	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
300
301	torture_comment(tctx, "Trying max lock\n");
302	io.lockx.in.ulock_cnt = 0;
303	io.lockx.in.lock_cnt = 1;
304	lock[0].count = 0;
305	lock[0].offset = ~0;
306	status = smb_raw_lock(cli->tree, &io);
307	CHECK_STATUS(status, NT_STATUS_OK);
308	lock[0].pid++;
309	status = smb_raw_lock(cli->tree, &io);
310	CHECK_STATUS(status, NT_STATUS_OK);
311	lock[0].pid--;
312	io.lockx.in.ulock_cnt = 1;
313	io.lockx.in.lock_cnt = 0;
314	status = smb_raw_lock(cli->tree, &io);
315	CHECK_STATUS(status, NT_STATUS_OK);
316	status = smb_raw_lock(cli->tree, &io);
317	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
318
319	torture_comment(tctx, "Trying 2^63\n");
320	io.lockx.in.ulock_cnt = 0;
321	io.lockx.in.lock_cnt = 1;
322	lock[0].count = 1;
323	lock[0].offset = 1;
324	lock[0].offset <<= 63;
325	status = smb_raw_lock(cli->tree, &io);
326	CHECK_STATUS(status, NT_STATUS_OK);
327	lock[0].pid++;
328	status = smb_raw_lock(cli->tree, &io);
329	CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
330	lock[0].pid--;
331	io.lockx.in.ulock_cnt = 1;
332	io.lockx.in.lock_cnt = 0;
333	status = smb_raw_lock(cli->tree, &io);
334	CHECK_STATUS(status, NT_STATUS_OK);
335	status = smb_raw_lock(cli->tree, &io);
336	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
337
338	torture_comment(tctx, "Trying 2^63 - 1\n");
339	io.lockx.in.ulock_cnt = 0;
340	io.lockx.in.lock_cnt = 1;
341	lock[0].count = 1;
342	lock[0].offset = 1;
343	lock[0].offset <<= 63;
344	lock[0].offset--;
345	status = smb_raw_lock(cli->tree, &io);
346	CHECK_STATUS(status, NT_STATUS_OK);
347	lock[0].pid++;
348	status = smb_raw_lock(cli->tree, &io);
349	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
350	lock[0].pid--;
351	io.lockx.in.ulock_cnt = 1;
352	io.lockx.in.lock_cnt = 0;
353	status = smb_raw_lock(cli->tree, &io);
354	CHECK_STATUS(status, NT_STATUS_OK);
355	status = smb_raw_lock(cli->tree, &io);
356	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
357
358	torture_comment(tctx, "Trying max lock 2\n");
359	io.lockx.in.ulock_cnt = 0;
360	io.lockx.in.lock_cnt = 1;
361	lock[0].count = 1;
362	lock[0].offset = ~0;
363	status = smb_raw_lock(cli->tree, &io);
364	CHECK_STATUS(status, NT_STATUS_OK);
365	lock[0].pid++;
366	lock[0].count = 2;
367	status = smb_raw_lock(cli->tree, &io);
368	if (TARGET_IS_WIN7(tctx))
369		CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
370	else
371		CHECK_STATUS(status, NT_STATUS_OK);
372	lock[0].pid--;
373	io.lockx.in.ulock_cnt = 1;
374	io.lockx.in.lock_cnt = 0;
375	lock[0].count = 1;
376	status = smb_raw_lock(cli->tree, &io);
377
378	CHECK_STATUS(status, NT_STATUS_OK);
379	status = smb_raw_lock(cli->tree, &io);
380	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
381
382done:
383	smbcli_close(cli->tree, fnum);
384	smb_raw_exit(cli->session);
385	smbcli_deltree(cli->tree, BASEDIR);
386	return ret;
387}
388
389/*
390  test high pid
391*/
392static bool test_pidhigh(struct torture_context *tctx,
393						 struct smbcli_state *cli)
394{
395	union smb_lock io;
396	struct smb_lock_entry lock[1];
397	NTSTATUS status;
398	bool ret = true;
399	int fnum;
400	const char *fname = BASEDIR "\\test.txt";
401	uint8_t c = 1;
402
403	if (!torture_setup_dir(cli, BASEDIR)) {
404		return false;
405	}
406
407	torture_comment(tctx, "Testing high pid\n");
408	io.generic.level = RAW_LOCK_LOCKX;
409
410	cli->session->pid = 1;
411
412	fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
413	torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
414		       "Failed to create %s - %s\n",
415		       fname, smbcli_errstr(cli->tree)));
416
417	if (smbcli_write(cli->tree, fnum, 0, &c, 0, 1) != 1) {
418		torture_result(tctx, TORTURE_FAIL,
419			"Failed to write 1 byte - %s\n",
420			smbcli_errstr(cli->tree));
421		ret = false;
422		goto done;
423	}
424
425	io.lockx.level = RAW_LOCK_LOCKX;
426	io.lockx.in.file.fnum = fnum;
427	io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
428	io.lockx.in.timeout = 0;
429	io.lockx.in.ulock_cnt = 0;
430	io.lockx.in.lock_cnt = 1;
431	lock[0].pid = cli->session->pid;
432	lock[0].offset = 0;
433	lock[0].count = 0xFFFFFFFF;
434	io.lockx.in.locks = &lock[0];
435	status = smb_raw_lock(cli->tree, &io);
436	CHECK_STATUS(status, NT_STATUS_OK);
437
438	if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
439		torture_result(tctx, TORTURE_FAIL,
440			"Failed to read 1 byte - %s\n",
441			smbcli_errstr(cli->tree));
442		ret = false;
443		goto done;
444	}
445
446	cli->session->pid = 2;
447
448	if (smbcli_read(cli->tree, fnum, &c, 0, 1) == 1) {
449		torture_result(tctx, TORTURE_FAIL,
450			"pid is incorrect handled for read with lock!\n");
451		ret = false;
452		goto done;
453	}
454
455	cli->session->pid = 0x10001;
456
457	if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
458		torture_result(tctx, TORTURE_FAIL,
459			"High pid is used on this server!\n");
460		ret = false;
461	} else {
462		torture_warning(tctx, "High pid is not used on this server (correct)\n");
463	}
464
465done:
466	smbcli_close(cli->tree, fnum);
467	smb_raw_exit(cli->session);
468	smbcli_deltree(cli->tree, BASEDIR);
469	return ret;
470}
471
472
473/*
474  test locking&X async operation
475*/
476static bool test_async(struct torture_context *tctx,
477					   struct smbcli_state *cli)
478{
479	struct smbcli_session *session;
480	struct smb_composite_sesssetup setup;
481	struct smbcli_tree *tree;
482	union smb_tcon tcon;
483	const char *host, *share;
484	union smb_lock io;
485	struct smb_lock_entry lock[2];
486	NTSTATUS status;
487	bool ret = true;
488	int fnum;
489	const char *fname = BASEDIR "\\test.txt";
490	time_t t;
491	struct smbcli_request *req;
492	struct smbcli_session_options options;
493
494	if (!torture_setup_dir(cli, BASEDIR)) {
495		return false;
496	}
497
498	lp_smbcli_session_options(tctx->lp_ctx, &options);
499
500	torture_comment(tctx, "Testing LOCKING_ANDX_CANCEL_LOCK\n");
501	io.generic.level = RAW_LOCK_LOCKX;
502
503	fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
504	torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
505		       "Failed to create %s - %s\n",
506		       fname, smbcli_errstr(cli->tree)));
507
508	io.lockx.level = RAW_LOCK_LOCKX;
509	io.lockx.in.file.fnum = fnum;
510	io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
511	io.lockx.in.timeout = 0;
512	io.lockx.in.ulock_cnt = 0;
513	io.lockx.in.lock_cnt = 1;
514	lock[0].pid = cli->session->pid;
515	lock[0].offset = 100;
516	lock[0].count = 10;
517	io.lockx.in.locks = &lock[0];
518	status = smb_raw_lock(cli->tree, &io);
519	CHECK_STATUS(status, NT_STATUS_OK);
520
521	t = time(NULL);
522
523	torture_comment(tctx, "testing cancel by CANCEL_LOCK\n");
524
525	/* setup a timed lock */
526	io.lockx.in.timeout = 10000;
527	req = smb_raw_lock_send(cli->tree, &io);
528	torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
529		       "Failed to setup timed lock (%s)\n", __location__));
530
531	/* cancel the wrong range */
532	lock[0].offset = 0;
533	io.lockx.in.timeout = 0;
534	io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
535	status = smb_raw_lock(cli->tree, &io);
536	CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
537
538	/* cancel with the wrong bits set */
539	lock[0].offset = 100;
540	io.lockx.in.timeout = 0;
541	io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
542	status = smb_raw_lock(cli->tree, &io);
543	CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
544
545	/* cancel the right range */
546	lock[0].offset = 100;
547	io.lockx.in.timeout = 0;
548	io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
549	status = smb_raw_lock(cli->tree, &io);
550	CHECK_STATUS(status, NT_STATUS_OK);
551
552	/* receive the failed lock request */
553	status = smbcli_request_simple_recv(req);
554	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
555
556	torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
557		       "lock cancel was not immediate (%s)\n", __location__));
558
559	torture_comment(tctx, "testing cancel by unlock\n");
560	io.lockx.in.ulock_cnt = 0;
561	io.lockx.in.lock_cnt = 1;
562	io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
563	io.lockx.in.timeout = 0;
564	status = smb_raw_lock(cli->tree, &io);
565	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
566
567	io.lockx.in.timeout = 5000;
568	req = smb_raw_lock_send(cli->tree, &io);
569	torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
570		       "Failed to setup timed lock (%s)\n", __location__));
571
572	io.lockx.in.ulock_cnt = 1;
573	io.lockx.in.lock_cnt = 0;
574	status = smb_raw_lock(cli->tree, &io);
575	CHECK_STATUS(status, NT_STATUS_OK);
576
577	t = time(NULL);
578	status = smbcli_request_simple_recv(req);
579	CHECK_STATUS(status, NT_STATUS_OK);
580
581	torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
582		       "lock cancel by unlock was not immediate (%s) - took %d secs\n",
583		       __location__, (int)(time(NULL)-t)));
584
585	torture_comment(tctx, "testing cancel by close\n");
586	io.lockx.in.ulock_cnt = 0;
587	io.lockx.in.lock_cnt = 1;
588	io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
589	io.lockx.in.timeout = 0;
590	status = smb_raw_lock(cli->tree, &io);
591	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
592
593	t = time(NULL);
594	io.lockx.in.timeout = 10000;
595	req = smb_raw_lock_send(cli->tree, &io);
596	torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
597		       "Failed to setup timed lock (%s)\n", __location__));
598
599	status = smbcli_close(cli->tree, fnum);
600	CHECK_STATUS(status, NT_STATUS_OK);
601
602	status = smbcli_request_simple_recv(req);
603	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
604
605	torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
606		       "lock cancel by close was not immediate (%s)\n", __location__));
607
608	torture_comment(tctx, "create a new sessions\n");
609	session = smbcli_session_init(cli->transport, tctx, false, options);
610	setup.in.sesskey = cli->transport->negotiate.sesskey;
611	setup.in.capabilities = cli->transport->negotiate.capabilities;
612	setup.in.workgroup = lp_workgroup(tctx->lp_ctx);
613	setup.in.credentials = cmdline_credentials;
614	setup.in.gensec_settings = lp_gensec_settings(tctx, tctx->lp_ctx);
615	status = smb_composite_sesssetup(session, &setup);
616	CHECK_STATUS(status, NT_STATUS_OK);
617	session->vuid = setup.out.vuid;
618
619	torture_comment(tctx, "create new tree context\n");
620	share = torture_setting_string(tctx, "share", NULL);
621	host  = torture_setting_string(tctx, "host", NULL);
622	tree = smbcli_tree_init(session, tctx, false);
623	tcon.generic.level = RAW_TCON_TCONX;
624	tcon.tconx.in.flags = 0;
625	tcon.tconx.in.password = data_blob(NULL, 0);
626	tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
627	tcon.tconx.in.device = "A:";
628	status = smb_raw_tcon(tree, tctx, &tcon);
629	CHECK_STATUS(status, NT_STATUS_OK);
630	tree->tid = tcon.tconx.out.tid;
631
632	torture_comment(tctx, "testing cancel by exit\n");
633	fname = BASEDIR "\\test_exit.txt";
634	fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
635	torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
636		       "Failed to reopen %s - %s\n",
637		       fname, smbcli_errstr(tree)));
638
639	io.lockx.level = RAW_LOCK_LOCKX;
640	io.lockx.in.file.fnum = fnum;
641	io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
642	io.lockx.in.timeout = 0;
643	io.lockx.in.ulock_cnt = 0;
644	io.lockx.in.lock_cnt = 1;
645	lock[0].pid = session->pid;
646	lock[0].offset = 100;
647	lock[0].count = 10;
648	io.lockx.in.locks = &lock[0];
649	status = smb_raw_lock(tree, &io);
650	CHECK_STATUS(status, NT_STATUS_OK);
651
652	io.lockx.in.ulock_cnt = 0;
653	io.lockx.in.lock_cnt = 1;
654	io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
655	io.lockx.in.timeout = 0;
656	status = smb_raw_lock(tree, &io);
657	CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
658
659	io.lockx.in.timeout = 10000;
660	t = time(NULL);
661	req = smb_raw_lock_send(tree, &io);
662	torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
663		       "Failed to setup timed lock (%s)\n", __location__));
664
665	status = smb_raw_exit(session);
666	CHECK_STATUS(status, NT_STATUS_OK);
667
668	status = smbcli_request_simple_recv(req);
669	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
670
671	torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
672		       "lock cancel by exit was not immediate (%s)\n", __location__));
673
674	torture_comment(tctx, "testing cancel by ulogoff\n");
675	fname = BASEDIR "\\test_ulogoff.txt";
676	fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
677	torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
678		       "Failed to reopen %s - %s\n",
679		       fname, smbcli_errstr(tree)));
680
681	io.lockx.level = RAW_LOCK_LOCKX;
682	io.lockx.in.file.fnum = fnum;
683	io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
684	io.lockx.in.timeout = 0;
685	io.lockx.in.ulock_cnt = 0;
686	io.lockx.in.lock_cnt = 1;
687	lock[0].pid = session->pid;
688	lock[0].offset = 100;
689	lock[0].count = 10;
690	io.lockx.in.locks = &lock[0];
691	status = smb_raw_lock(tree, &io);
692	CHECK_STATUS(status, NT_STATUS_OK);
693
694	io.lockx.in.ulock_cnt = 0;
695	io.lockx.in.lock_cnt = 1;
696	io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
697	io.lockx.in.timeout = 0;
698	status = smb_raw_lock(tree, &io);
699	CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
700
701	io.lockx.in.timeout = 10000;
702	t = time(NULL);
703	req = smb_raw_lock_send(tree, &io);
704	torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
705		       "Failed to setup timed lock (%s)\n", __location__));
706
707	status = smb_raw_ulogoff(session);
708	CHECK_STATUS(status, NT_STATUS_OK);
709
710	status = smbcli_request_simple_recv(req);
711	if (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status)) {
712		torture_result(tctx, TORTURE_FAIL,
713			"lock not canceled by ulogoff - %s (ignored because of vfs_vifs fails it)\n",
714			nt_errstr(status));
715		smb_tree_disconnect(tree);
716		smb_raw_exit(session);
717		goto done;
718	}
719	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
720
721	torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
722		       "lock cancel by ulogoff was not immediate (%s)\n", __location__));
723
724	torture_comment(tctx, "testing cancel by tdis\n");
725	tree->session = cli->session;
726
727	fname = BASEDIR "\\test_tdis.txt";
728	fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
729	torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
730		       "Failed to reopen %s - %s\n",
731		       fname, smbcli_errstr(tree)));
732
733	io.lockx.level = RAW_LOCK_LOCKX;
734	io.lockx.in.file.fnum = fnum;
735	io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
736	io.lockx.in.timeout = 0;
737	io.lockx.in.ulock_cnt = 0;
738	io.lockx.in.lock_cnt = 1;
739	lock[0].pid = cli->session->pid;
740	lock[0].offset = 100;
741	lock[0].count = 10;
742	io.lockx.in.locks = &lock[0];
743	status = smb_raw_lock(tree, &io);
744	CHECK_STATUS(status, NT_STATUS_OK);
745
746	status = smb_raw_lock(tree, &io);
747	CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
748
749	io.lockx.in.timeout = 10000;
750	t = time(NULL);
751	req = smb_raw_lock_send(tree, &io);
752	torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
753		       "Failed to setup timed lock (%s)\n", __location__));
754
755	status = smb_tree_disconnect(tree);
756	CHECK_STATUS(status, NT_STATUS_OK);
757
758	status = smbcli_request_simple_recv(req);
759	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
760
761	torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
762		       "lock cancel by tdis was not immediate (%s)\n", __location__));
763
764done:
765	smb_raw_exit(cli->session);
766	smbcli_deltree(cli->tree, BASEDIR);
767	return ret;
768}
769
770/*
771  test NT_STATUS_LOCK_NOT_GRANTED vs. NT_STATUS_FILE_LOCK_CONFLICT
772*/
773static bool test_errorcode(struct torture_context *tctx,
774						   struct smbcli_state *cli)
775{
776	union smb_lock io;
777	union smb_open op;
778	struct smb_lock_entry lock[2];
779	NTSTATUS status;
780	bool ret = true;
781	int fnum, fnum2;
782	const char *fname;
783	struct smbcli_request *req;
784	time_t start;
785	int t;
786	int delay;
787
788	if (!torture_setup_dir(cli, BASEDIR)) {
789		return false;
790	}
791
792	torture_comment(tctx, "Testing LOCK_NOT_GRANTED vs. FILE_LOCK_CONFLICT\n");
793
794	torture_comment(tctx, "testing with timeout = 0\n");
795	fname = BASEDIR "\\test0.txt";
796	t = 0;
797
798	/*
799	 * the first run is with t = 0,
800	 * the second with t > 0 (=1)
801	 */
802next_run:
803	/*
804	 * use the DENY_DOS mode, that creates two fnum's of one low-level file handle,
805	 * this demonstrates that the cache is per fnum
806	 */
807	op.openx.level = RAW_OPEN_OPENX;
808	op.openx.in.fname = fname;
809	op.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
810	op.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_DOS;
811	op.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
812	op.openx.in.search_attrs = 0;
813	op.openx.in.file_attrs = 0;
814	op.openx.in.write_time = 0;
815	op.openx.in.size = 0;
816	op.openx.in.timeout = 0;
817
818	status = smb_raw_open(cli->tree, tctx, &op);
819	CHECK_STATUS(status, NT_STATUS_OK);
820	fnum = op.openx.out.file.fnum;
821
822	status = smb_raw_open(cli->tree, tctx, &op);
823	CHECK_STATUS(status, NT_STATUS_OK);
824	fnum2 = op.openx.out.file.fnum;
825
826	io.lockx.level = RAW_LOCK_LOCKX;
827	io.lockx.in.file.fnum = fnum;
828	io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
829	io.lockx.in.timeout = t;
830	io.lockx.in.ulock_cnt = 0;
831	io.lockx.in.lock_cnt = 1;
832	lock[0].pid = cli->session->pid;
833	lock[0].offset = 100;
834	lock[0].count = 10;
835	io.lockx.in.locks = &lock[0];
836	status = smb_raw_lock(cli->tree, &io);
837	CHECK_STATUS(status, NT_STATUS_OK);
838
839	/*
840	 * demonstrate that the first conflicting lock on each handle give LOCK_NOT_GRANTED
841	 * this also demonstrates that the error code cache is per file handle
842	 * (LOCK_NOT_GRANTED is only be used when timeout is 0!)
843	 */
844	io.lockx.in.file.fnum = fnum2;
845	status = smb_raw_lock(cli->tree, &io);
846	CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
847
848	io.lockx.in.file.fnum = fnum;
849	status = smb_raw_lock(cli->tree, &io);
850	CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
851
852	/* demonstrate that each following conflict gives FILE_LOCK_CONFLICT */
853	io.lockx.in.file.fnum = fnum;
854	status = smb_raw_lock(cli->tree, &io);
855	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
856
857	io.lockx.in.file.fnum = fnum2;
858	status = smb_raw_lock(cli->tree, &io);
859	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
860
861	io.lockx.in.file.fnum = fnum;
862	status = smb_raw_lock(cli->tree, &io);
863	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
864
865	io.lockx.in.file.fnum = fnum2;
866	status = smb_raw_lock(cli->tree, &io);
867	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
868
869	/* demonstrate that the smbpid doesn't matter */
870	lock[0].pid++;
871	io.lockx.in.file.fnum = fnum;
872	status = smb_raw_lock(cli->tree, &io);
873	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
874
875	io.lockx.in.file.fnum = fnum2;
876	status = smb_raw_lock(cli->tree, &io);
877	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
878	lock[0].pid--;
879
880	/*
881	 * demonstrate the a successful lock with count = 0 and the same offset,
882	 * doesn't reset the error cache
883	 */
884	lock[0].offset = 100;
885	lock[0].count = 0;
886	io.lockx.in.file.fnum = fnum;
887	status = smb_raw_lock(cli->tree, &io);
888	CHECK_STATUS(status, NT_STATUS_OK);
889
890	io.lockx.in.file.fnum = fnum2;
891	status = smb_raw_lock(cli->tree, &io);
892	CHECK_STATUS(status, NT_STATUS_OK);
893
894	lock[0].offset = 100;
895	lock[0].count = 10;
896	io.lockx.in.file.fnum = fnum;
897	status = smb_raw_lock(cli->tree, &io);
898	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
899
900	io.lockx.in.file.fnum = fnum2;
901	status = smb_raw_lock(cli->tree, &io);
902	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
903
904	/*
905	 * demonstrate the a successful lock with count = 0 and outside the locked range,
906	 * doesn't reset the error cache
907	 */
908	lock[0].offset = 110;
909	lock[0].count = 0;
910	io.lockx.in.file.fnum = fnum;
911	status = smb_raw_lock(cli->tree, &io);
912	CHECK_STATUS(status, NT_STATUS_OK);
913
914	io.lockx.in.file.fnum = fnum2;
915	status = smb_raw_lock(cli->tree, &io);
916	CHECK_STATUS(status, NT_STATUS_OK);
917
918	lock[0].offset = 100;
919	lock[0].count = 10;
920	io.lockx.in.file.fnum = fnum;
921	status = smb_raw_lock(cli->tree, &io);
922	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
923
924	io.lockx.in.file.fnum = fnum2;
925	status = smb_raw_lock(cli->tree, &io);
926	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
927
928	lock[0].offset = 99;
929	lock[0].count = 0;
930	io.lockx.in.file.fnum = fnum;
931	status = smb_raw_lock(cli->tree, &io);
932	CHECK_STATUS(status, NT_STATUS_OK);
933
934	io.lockx.in.file.fnum = fnum2;
935	status = smb_raw_lock(cli->tree, &io);
936	CHECK_STATUS(status, NT_STATUS_OK);
937
938	lock[0].offset = 100;
939	lock[0].count = 10;
940	io.lockx.in.file.fnum = fnum;
941	status = smb_raw_lock(cli->tree, &io);
942	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
943
944	io.lockx.in.file.fnum = fnum2;
945	status = smb_raw_lock(cli->tree, &io);
946	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
947
948	/* demonstrate that a changing count doesn't reset the error cache */
949	lock[0].offset = 100;
950	lock[0].count = 5;
951	io.lockx.in.file.fnum = fnum;
952	status = smb_raw_lock(cli->tree, &io);
953	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
954
955	io.lockx.in.file.fnum = fnum2;
956	status = smb_raw_lock(cli->tree, &io);
957	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
958
959	lock[0].offset = 100;
960	lock[0].count = 15;
961	io.lockx.in.file.fnum = fnum;
962	status = smb_raw_lock(cli->tree, &io);
963	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
964
965	io.lockx.in.file.fnum = fnum2;
966	status = smb_raw_lock(cli->tree, &io);
967	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
968
969	/*
970	 * demonstrate the a lock with count = 0 and inside the locked range,
971	 * fails and resets the error cache
972	 */
973	lock[0].offset = 101;
974	lock[0].count = 0;
975	io.lockx.in.file.fnum = fnum;
976	status = smb_raw_lock(cli->tree, &io);
977	CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
978	status = smb_raw_lock(cli->tree, &io);
979	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
980
981	io.lockx.in.file.fnum = fnum2;
982	status = smb_raw_lock(cli->tree, &io);
983	CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
984	status = smb_raw_lock(cli->tree, &io);
985	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
986
987	lock[0].offset = 100;
988	lock[0].count = 10;
989	io.lockx.in.file.fnum = fnum;
990	status = smb_raw_lock(cli->tree, &io);
991	CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
992	status = smb_raw_lock(cli->tree, &io);
993	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
994
995	io.lockx.in.file.fnum = fnum2;
996	status = smb_raw_lock(cli->tree, &io);
997	CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
998	status = smb_raw_lock(cli->tree, &io);
999	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1000
1001	/* demonstrate the a changing offset, resets the error cache */
1002	lock[0].offset = 105;
1003	lock[0].count = 10;
1004	io.lockx.in.file.fnum = fnum;
1005	status = smb_raw_lock(cli->tree, &io);
1006	CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1007	status = smb_raw_lock(cli->tree, &io);
1008	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1009
1010	io.lockx.in.file.fnum = fnum2;
1011	status = smb_raw_lock(cli->tree, &io);
1012	CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1013	status = smb_raw_lock(cli->tree, &io);
1014	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1015
1016	lock[0].offset = 100;
1017	lock[0].count = 10;
1018	io.lockx.in.file.fnum = fnum;
1019	status = smb_raw_lock(cli->tree, &io);
1020	CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1021	status = smb_raw_lock(cli->tree, &io);
1022	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1023
1024	io.lockx.in.file.fnum = fnum2;
1025	status = smb_raw_lock(cli->tree, &io);
1026	CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1027	status = smb_raw_lock(cli->tree, &io);
1028	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1029
1030	lock[0].offset = 95;
1031	lock[0].count = 9;
1032	io.lockx.in.file.fnum = fnum;
1033	status = smb_raw_lock(cli->tree, &io);
1034	CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1035	status = smb_raw_lock(cli->tree, &io);
1036	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1037
1038	io.lockx.in.file.fnum = fnum2;
1039	status = smb_raw_lock(cli->tree, &io);
1040	CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1041	status = smb_raw_lock(cli->tree, &io);
1042	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1043
1044	lock[0].offset = 100;
1045	lock[0].count = 10;
1046	io.lockx.in.file.fnum = fnum;
1047	status = smb_raw_lock(cli->tree, &io);
1048	CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1049	status = smb_raw_lock(cli->tree, &io);
1050	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1051
1052	io.lockx.in.file.fnum = fnum2;
1053	status = smb_raw_lock(cli->tree, &io);
1054	CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1055	status = smb_raw_lock(cli->tree, &io);
1056	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1057
1058	/*
1059	 * demonstrate the a successful lock in a different range,
1060	 * doesn't reset the cache, the failing lock on the 2nd handle
1061	 * resets the resets the cache
1062	 */
1063	lock[0].offset = 120;
1064	lock[0].count = 15;
1065	io.lockx.in.file.fnum = fnum;
1066	status = smb_raw_lock(cli->tree, &io);
1067	CHECK_STATUS(status, NT_STATUS_OK);
1068
1069	io.lockx.in.file.fnum = fnum2;
1070	status = smb_raw_lock(cli->tree, &io);
1071	CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1072
1073	lock[0].offset = 100;
1074	lock[0].count = 10;
1075	io.lockx.in.file.fnum = fnum;
1076	status = smb_raw_lock(cli->tree, &io);
1077	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1078	status = smb_raw_lock(cli->tree, &io);
1079	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1080
1081	io.lockx.in.file.fnum = fnum2;
1082	status = smb_raw_lock(cli->tree, &io);
1083	CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1084	status = smb_raw_lock(cli->tree, &io);
1085	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1086
1087	/* end of the loop */
1088	if (t == 0) {
1089		smb_raw_exit(cli->session);
1090		t = 1;
1091		torture_comment(tctx, "testing with timeout > 0 (=%d)\n",
1092				t);
1093		fname = BASEDIR "\\test1.txt";
1094		goto next_run;
1095	}
1096
1097	t = 4000;
1098	torture_comment(tctx, "testing special cases with timeout > 0 (=%d)\n",
1099			t);
1100
1101	/*
1102	 * the following 3 test sections demonstrate that
1103	 * the cache is only set when the error is reported
1104	 * to the client (after the timeout went by)
1105	 */
1106	smb_raw_exit(cli->session);
1107	torture_comment(tctx, "testing a conflict while a lock is pending\n");
1108	fname = BASEDIR "\\test2.txt";
1109	fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1110	torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1111		       "Failed to reopen %s - %s\n",
1112		       fname, smbcli_errstr(cli->tree)));
1113
1114	io.lockx.level = RAW_LOCK_LOCKX;
1115	io.lockx.in.file.fnum = fnum;
1116	io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1117	io.lockx.in.timeout = 0;
1118	io.lockx.in.ulock_cnt = 0;
1119	io.lockx.in.lock_cnt = 1;
1120	lock[0].pid = cli->session->pid;
1121	lock[0].offset = 100;
1122	lock[0].count = 10;
1123	io.lockx.in.locks = &lock[0];
1124	status = smb_raw_lock(cli->tree, &io);
1125	CHECK_STATUS(status, NT_STATUS_OK);
1126
1127	start = time(NULL);
1128	io.lockx.in.timeout = t;
1129	req = smb_raw_lock_send(cli->tree, &io);
1130	torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1131		       "Failed to setup timed lock (%s)\n", __location__));
1132
1133	io.lockx.in.timeout = 0;
1134	lock[0].offset = 105;
1135	lock[0].count = 10;
1136	status = smb_raw_lock(cli->tree, &io);
1137	CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1138
1139	status = smbcli_request_simple_recv(req);
1140	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1141
1142	delay = t / 1000;
1143	if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1144		delay /= 2;
1145	}
1146
1147	torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx,
1148		       "lock comes back to early timeout[%d] delay[%d]"
1149		       "(%s)\n", t, delay, __location__));
1150
1151	status = smb_raw_lock(cli->tree, &io);
1152	CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1153
1154	smbcli_close(cli->tree, fnum);
1155	fname = BASEDIR "\\test3.txt";
1156	fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1157	torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1158		       "Failed to reopen %s - %s\n",
1159		       fname, smbcli_errstr(cli->tree)));
1160
1161	io.lockx.level = RAW_LOCK_LOCKX;
1162	io.lockx.in.file.fnum = fnum;
1163	io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1164	io.lockx.in.timeout = 0;
1165	io.lockx.in.ulock_cnt = 0;
1166	io.lockx.in.lock_cnt = 1;
1167	lock[0].pid = cli->session->pid;
1168	lock[0].offset = 100;
1169	lock[0].count = 10;
1170	io.lockx.in.locks = &lock[0];
1171	status = smb_raw_lock(cli->tree, &io);
1172	CHECK_STATUS(status, NT_STATUS_OK);
1173
1174	start = time(NULL);
1175	io.lockx.in.timeout = t;
1176	req = smb_raw_lock_send(cli->tree, &io);
1177	torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1178		       "Failed to setup timed lock (%s)\n", __location__));
1179
1180	io.lockx.in.timeout = 0;
1181	lock[0].offset = 105;
1182	lock[0].count = 10;
1183	status = smb_raw_lock(cli->tree, &io);
1184	CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1185
1186	status = smbcli_request_simple_recv(req);
1187	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1188
1189	delay = t / 1000;
1190	if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1191		delay /= 2;
1192	}
1193
1194	torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx,
1195		       "lock comes back to early timeout[%d] delay[%d]"
1196		       "(%s)\n", t, delay, __location__));
1197
1198	lock[0].offset = 100;
1199	lock[0].count = 10;
1200	status = smb_raw_lock(cli->tree, &io);
1201	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1202
1203	smbcli_close(cli->tree, fnum);
1204	fname = BASEDIR "\\test4.txt";
1205	fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1206	torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1207		       "Failed to reopen %s - %s\n",
1208		       fname, smbcli_errstr(cli->tree)));
1209
1210	io.lockx.level = RAW_LOCK_LOCKX;
1211	io.lockx.in.file.fnum = fnum;
1212	io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1213	io.lockx.in.timeout = 0;
1214	io.lockx.in.ulock_cnt = 0;
1215	io.lockx.in.lock_cnt = 1;
1216	lock[0].pid = cli->session->pid;
1217	lock[0].offset = 100;
1218	lock[0].count = 10;
1219	io.lockx.in.locks = &lock[0];
1220	status = smb_raw_lock(cli->tree, &io);
1221	CHECK_STATUS(status, NT_STATUS_OK);
1222
1223	start = time(NULL);
1224	io.lockx.in.timeout = t;
1225	req = smb_raw_lock_send(cli->tree, &io);
1226	torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1227		       "Failed to setup timed lock (%s)\n", __location__));
1228
1229	io.lockx.in.timeout = 0;
1230	status = smb_raw_lock(cli->tree, &io);
1231	CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1232
1233	status = smbcli_request_simple_recv(req);
1234	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1235
1236	delay = t / 1000;
1237	if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1238		delay /= 2;
1239	}
1240
1241	torture_assert(tctx,!(time(NULL) < start+delay), talloc_asprintf(tctx,
1242		       "lock comes back to early timeout[%d] delay[%d]"
1243		       "(%s)\n", t, delay, __location__));
1244
1245	status = smb_raw_lock(cli->tree, &io);
1246	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1247
1248done:
1249	smb_raw_exit(cli->session);
1250	smbcli_deltree(cli->tree, BASEDIR);
1251	return ret;
1252}
1253
1254
1255/*
1256  test LOCKING_ANDX_CHANGE_LOCKTYPE
1257*/
1258static bool test_changetype(struct torture_context *tctx,
1259							struct smbcli_state *cli)
1260{
1261	union smb_lock io;
1262	struct smb_lock_entry lock[2];
1263	NTSTATUS status;
1264	bool ret = true;
1265	int fnum;
1266	uint8_t c = 0;
1267	const char *fname = BASEDIR "\\test.txt";
1268
1269	if (!torture_setup_dir(cli, BASEDIR)) {
1270		return false;
1271	}
1272
1273	torture_comment(tctx, "Testing LOCKING_ANDX_CHANGE_LOCKTYPE\n");
1274	io.generic.level = RAW_LOCK_LOCKX;
1275
1276	fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1277	torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1278		       "Failed to create %s - %s\n",
1279		       fname, smbcli_errstr(cli->tree)));
1280
1281	io.lockx.level = RAW_LOCK_LOCKX;
1282	io.lockx.in.file.fnum = fnum;
1283	io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1284	io.lockx.in.timeout = 0;
1285	io.lockx.in.ulock_cnt = 0;
1286	io.lockx.in.lock_cnt = 1;
1287	lock[0].pid = cli->session->pid;
1288	lock[0].offset = 100;
1289	lock[0].count = 10;
1290	io.lockx.in.locks = &lock[0];
1291	status = smb_raw_lock(cli->tree, &io);
1292	CHECK_STATUS(status, NT_STATUS_OK);
1293
1294	if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1295		torture_result(tctx, TORTURE_FAIL,
1296			"allowed write on read locked region (%s)\n", __location__);
1297		ret = false;
1298		goto done;
1299	}
1300
1301	/* windows server don't seem to support this */
1302	io.lockx.in.mode = LOCKING_ANDX_CHANGE_LOCKTYPE;
1303	status = smb_raw_lock(cli->tree, &io);
1304	CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
1305
1306	if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1307		torture_result(tctx, TORTURE_FAIL,
1308			"allowed write after lock change (%s)\n", __location__);
1309		ret = false;
1310		goto done;
1311	}
1312
1313done:
1314	smbcli_close(cli->tree, fnum);
1315	smb_raw_exit(cli->session);
1316	smbcli_deltree(cli->tree, BASEDIR);
1317	return ret;
1318}
1319
1320struct double_lock_test {
1321	struct smb_lock_entry lock1;
1322	struct smb_lock_entry lock2;
1323	NTSTATUS exp_status;
1324};
1325
1326/**
1327 * Tests zero byte locks.
1328 */
1329static const struct double_lock_test zero_byte_tests[] = {
1330	/* {pid, offset, count}, {pid, offset, count}, status */
1331
1332	/** First, takes a zero byte lock at offset 10. Then:
1333	*   - Taking 0 byte lock at 10 should succeed.
1334	*   - Taking 1 byte locks at 9,10,11 should succeed.
1335	*   - Taking 2 byte lock at 9 should fail.
1336	*   - Taking 2 byte lock at 10 should succeed.
1337	*   - Taking 3 byte lock at 9 should fail.
1338	*/
1339	{{1000, 10, 0}, {1001, 10, 0}, NT_STATUS_OK},
1340	{{1000, 10, 0}, {1001, 9, 1},  NT_STATUS_OK},
1341	{{1000, 10, 0}, {1001, 10, 1}, NT_STATUS_OK},
1342	{{1000, 10, 0}, {1001, 11, 1}, NT_STATUS_OK},
1343	{{1000, 10, 0}, {1001, 9, 2},  NT_STATUS_LOCK_NOT_GRANTED},
1344	{{1000, 10, 0}, {1001, 10, 2}, NT_STATUS_OK},
1345	{{1000, 10, 0}, {1001, 9, 3},  NT_STATUS_LOCK_NOT_GRANTED},
1346
1347	/** Same, but opposite order. */
1348	{{1001, 10, 0}, {1000, 10, 0}, NT_STATUS_OK},
1349	{{1001, 9, 1},  {1000, 10, 0}, NT_STATUS_OK},
1350	{{1001, 10, 1}, {1000, 10, 0}, NT_STATUS_OK},
1351	{{1001, 11, 1}, {1000, 10, 0}, NT_STATUS_OK},
1352	{{1001, 9, 2},  {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1353	{{1001, 10, 2}, {1000, 10, 0}, NT_STATUS_OK},
1354	{{1001, 9, 3},  {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
1355
1356	/** Zero zero case. */
1357	{{1000, 0, 0},  {1001, 0, 0},  NT_STATUS_OK},
1358};
1359
1360static bool test_zerobytelocks(struct torture_context *tctx, struct smbcli_state *cli)
1361{
1362	union smb_lock io;
1363	NTSTATUS status;
1364	bool ret = true;
1365	int fnum, i;
1366	const char *fname = BASEDIR "\\zero.txt";
1367
1368	torture_comment(tctx, "Testing zero length byte range locks:\n");
1369
1370	if (!torture_setup_dir(cli, BASEDIR)) {
1371		return false;
1372	}
1373
1374	io.generic.level = RAW_LOCK_LOCKX;
1375
1376	fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1377	torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1378		       "Failed to create %s - %s\n",
1379		       fname, smbcli_errstr(cli->tree)));
1380
1381	/* Setup initial parameters */
1382	io.lockx.level = RAW_LOCK_LOCKX;
1383	io.lockx.in.file.fnum = fnum;
1384	io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; /* Exclusive */
1385	io.lockx.in.timeout = 0;
1386
1387	/* Try every combination of locks in zero_byte_tests. The first lock is
1388	 * assumed to succeed. The second lock may contend, depending on the
1389	 * expected status. */
1390	for (i = 0;
1391	     i < ARRAY_SIZE(zero_byte_tests);
1392	     i++) {
1393		torture_comment(tctx, "  ... {%d, %llu, %llu} + {%d, %llu, %llu} = %s\n",
1394		    zero_byte_tests[i].lock1.pid,
1395		    zero_byte_tests[i].lock1.offset,
1396		    zero_byte_tests[i].lock1.count,
1397		    zero_byte_tests[i].lock2.pid,
1398		    zero_byte_tests[i].lock2.offset,
1399		    zero_byte_tests[i].lock2.count,
1400		    nt_errstr(zero_byte_tests[i].exp_status));
1401
1402		/* Lock both locks. */
1403		io.lockx.in.ulock_cnt = 0;
1404		io.lockx.in.lock_cnt = 1;
1405
1406		io.lockx.in.locks = &zero_byte_tests[i].lock1;
1407		status = smb_raw_lock(cli->tree, &io);
1408		CHECK_STATUS(status, NT_STATUS_OK);
1409
1410		io.lockx.in.locks = &zero_byte_tests[i].lock2;
1411		status = smb_raw_lock(cli->tree, &io);
1412
1413		if (NT_STATUS_EQUAL(zero_byte_tests[i].exp_status,
1414			NT_STATUS_LOCK_NOT_GRANTED)) {
1415			/* Allow either of the failure messages and keep going
1416			 * if we see the wrong status. */
1417			CHECK_STATUS_OR_CONT(status,
1418			    NT_STATUS_LOCK_NOT_GRANTED,
1419			    NT_STATUS_FILE_LOCK_CONFLICT);
1420
1421		} else {
1422			CHECK_STATUS_CONT(status,
1423			    zero_byte_tests[i].exp_status);
1424		}
1425
1426		/* Unlock both locks. */
1427		io.lockx.in.ulock_cnt = 1;
1428		io.lockx.in.lock_cnt = 0;
1429
1430		if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1431			status = smb_raw_lock(cli->tree, &io);
1432			CHECK_STATUS(status, NT_STATUS_OK);
1433		}
1434
1435		io.lockx.in.locks = &zero_byte_tests[i].lock1;
1436		status = smb_raw_lock(cli->tree, &io);
1437		CHECK_STATUS(status, NT_STATUS_OK);
1438	}
1439
1440done:
1441	smbcli_close(cli->tree, fnum);
1442	smb_raw_exit(cli->session);
1443	smbcli_deltree(cli->tree, BASEDIR);
1444	return ret;
1445}
1446
1447static bool test_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1448{
1449	union smb_lock io;
1450	NTSTATUS status;
1451	bool ret = true;
1452	int fnum1, fnum2;
1453	const char *fname = BASEDIR "\\unlock.txt";
1454	struct smb_lock_entry lock1;
1455	struct smb_lock_entry lock2;
1456
1457	torture_comment(tctx, "Testing LOCKX unlock:\n");
1458
1459	if (!torture_setup_dir(cli, BASEDIR)) {
1460		return false;
1461	}
1462
1463	fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1464	torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1465		       "Failed to create %s - %s\n",
1466		       fname, smbcli_errstr(cli->tree)));
1467
1468	fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1469	torture_assert(tctx,(fnum2 != -1), talloc_asprintf(tctx,
1470		       "Failed to create %s - %s\n",
1471		       fname, smbcli_errstr(cli->tree)));
1472
1473	/* Setup initial parameters */
1474	io.lockx.level = RAW_LOCK_LOCKX;
1475	io.lockx.in.timeout = 0;
1476
1477	lock1.pid = cli->session->pid;
1478	lock1.offset = 0;
1479	lock1.count = 10;
1480	lock2.pid = cli->session->pid - 1;
1481	lock2.offset = 0;
1482	lock2.count = 10;
1483
1484	/**
1485	 * Take exclusive lock, then unlock it with a shared-unlock call.
1486	 */
1487	torture_comment(tctx, "  taking exclusive lock.\n");
1488	io.lockx.in.ulock_cnt = 0;
1489	io.lockx.in.lock_cnt = 1;
1490	io.lockx.in.mode = 0;
1491	io.lockx.in.file.fnum = fnum1;
1492	io.lockx.in.locks = &lock1;
1493	status = smb_raw_lock(cli->tree, &io);
1494	CHECK_STATUS(status, NT_STATUS_OK);
1495
1496	torture_comment(tctx, "  unlock the exclusive with a shared unlock call.\n");
1497	io.lockx.in.ulock_cnt = 1;
1498	io.lockx.in.lock_cnt = 0;
1499	io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1500	io.lockx.in.file.fnum = fnum1;
1501	io.lockx.in.locks = &lock1;
1502	status = smb_raw_lock(cli->tree, &io);
1503	CHECK_STATUS(status, NT_STATUS_OK);
1504
1505	torture_comment(tctx, "  try shared lock on pid2/fnum2, testing the unlock.\n");
1506	io.lockx.in.ulock_cnt = 0;
1507	io.lockx.in.lock_cnt = 1;
1508	io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1509	io.lockx.in.file.fnum = fnum2;
1510	io.lockx.in.locks = &lock2;
1511	status = smb_raw_lock(cli->tree, &io);
1512	CHECK_STATUS(status, NT_STATUS_OK);
1513
1514	/**
1515	 * Unlock a shared lock with an exclusive-unlock call.
1516	 */
1517	torture_comment(tctx, "  unlock new shared lock with exclusive unlock call.\n");
1518	io.lockx.in.ulock_cnt = 1;
1519	io.lockx.in.lock_cnt = 0;
1520	io.lockx.in.mode = 0;
1521	io.lockx.in.file.fnum = fnum2;
1522	io.lockx.in.locks = &lock2;
1523	status = smb_raw_lock(cli->tree, &io);
1524	CHECK_STATUS(status, NT_STATUS_OK);
1525
1526	torture_comment(tctx, "  try exclusive lock on pid1, testing the unlock.\n");
1527	io.lockx.in.ulock_cnt = 0;
1528	io.lockx.in.lock_cnt = 1;
1529	io.lockx.in.mode = 0;
1530	io.lockx.in.file.fnum = fnum1;
1531	io.lockx.in.locks = &lock1;
1532	status = smb_raw_lock(cli->tree, &io);
1533	CHECK_STATUS(status, NT_STATUS_OK);
1534
1535	/* cleanup */
1536	io.lockx.in.ulock_cnt = 1;
1537	io.lockx.in.lock_cnt = 0;
1538	status = smb_raw_lock(cli->tree, &io);
1539	CHECK_STATUS(status, NT_STATUS_OK);
1540
1541	/**
1542	 * Test unlocking of 0-byte locks.
1543	 */
1544
1545	torture_comment(tctx, "  lock shared and exclusive 0-byte locks, testing that Windows "
1546	    "always unlocks the exclusive first.\n");
1547	lock1.pid = cli->session->pid;
1548	lock1.offset = 10;
1549	lock1.count = 0;
1550	lock2.pid = cli->session->pid;
1551	lock2.offset = 5;
1552	lock2.count = 10;
1553	io.lockx.in.ulock_cnt = 0;
1554	io.lockx.in.lock_cnt = 1;
1555	io.lockx.in.file.fnum = fnum1;
1556	io.lockx.in.locks = &lock1;
1557
1558	/* lock 0-byte shared
1559	 * Note: Order of the shared/exclusive locks doesn't matter. */
1560	io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1561	status = smb_raw_lock(cli->tree, &io);
1562	CHECK_STATUS(status, NT_STATUS_OK);
1563
1564	/* lock 0-byte exclusive */
1565	io.lockx.in.mode = 0;
1566	status = smb_raw_lock(cli->tree, &io);
1567	CHECK_STATUS(status, NT_STATUS_OK);
1568
1569	/* test contention */
1570	io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1571	io.lockx.in.locks = &lock2;
1572	io.lockx.in.file.fnum = fnum2;
1573	status = smb_raw_lock(cli->tree, &io);
1574	CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1575	    NT_STATUS_FILE_LOCK_CONFLICT);
1576
1577	/* unlock */
1578	io.lockx.in.ulock_cnt = 1;
1579	io.lockx.in.lock_cnt = 0;
1580	io.lockx.in.file.fnum = fnum1;
1581	io.lockx.in.locks = &lock1;
1582	status = smb_raw_lock(cli->tree, &io);
1583	CHECK_STATUS(status, NT_STATUS_OK);
1584
1585	/* test - can we take a shared lock? */
1586	io.lockx.in.ulock_cnt = 0;
1587	io.lockx.in.lock_cnt = 1;
1588	io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1589	io.lockx.in.file.fnum = fnum2;
1590	io.lockx.in.locks = &lock2;
1591	status = smb_raw_lock(cli->tree, &io);
1592
1593	/* XXX Samba 3 will fail this test. This is temporary(because this isn't
1594	 * new to Win7, it succeeds in WinXP too), until I can come to a
1595	 * resolution as to whether Samba should support this or not. There is
1596	 * code to preference unlocking exclusive locks before shared locks,
1597	 * but its wrapped with "#ifdef ZERO_ZERO". -zkirsch */
1598	if (TARGET_IS_SAMBA3(tctx)) {
1599		CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1600		    NT_STATUS_FILE_LOCK_CONFLICT);
1601	} else {
1602		CHECK_STATUS(status, NT_STATUS_OK);
1603	}
1604
1605	/* cleanup */
1606	io.lockx.in.ulock_cnt = 1;
1607	io.lockx.in.lock_cnt = 0;
1608	status = smb_raw_lock(cli->tree, &io);
1609
1610	/* XXX Same as above. */
1611	if (TARGET_IS_SAMBA3(tctx)) {
1612		CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1613	} else {
1614		CHECK_STATUS(status, NT_STATUS_OK);
1615	}
1616
1617	io.lockx.in.file.fnum = fnum1;
1618	io.lockx.in.locks = &lock1;
1619	status = smb_raw_lock(cli->tree, &io);
1620	CHECK_STATUS(status, NT_STATUS_OK);
1621
1622done:
1623	smbcli_close(cli->tree, fnum1);
1624	smbcli_close(cli->tree, fnum2);
1625	smb_raw_exit(cli->session);
1626	smbcli_deltree(cli->tree, BASEDIR);
1627	return ret;
1628}
1629
1630static bool test_multiple_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1631{
1632	union smb_lock io;
1633	NTSTATUS status;
1634	bool ret = true;
1635	int fnum1;
1636	const char *fname = BASEDIR "\\unlock_multiple.txt";
1637	struct smb_lock_entry lock1;
1638	struct smb_lock_entry lock2;
1639	struct smb_lock_entry locks[2];
1640
1641	torture_comment(tctx, "Testing LOCKX multiple unlock:\n");
1642
1643	if (!torture_setup_dir(cli, BASEDIR)) {
1644		return false;
1645	}
1646
1647	fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1648	torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1649		       "Failed to create %s - %s\n",
1650		       fname, smbcli_errstr(cli->tree)));
1651
1652	/* Setup initial parameters */
1653	io.lockx.level = RAW_LOCK_LOCKX;
1654	io.lockx.in.timeout = 0;
1655
1656	lock1.pid = cli->session->pid;
1657	lock1.offset = 0;
1658	lock1.count = 10;
1659	lock2.pid = cli->session->pid;
1660	lock2.offset = 10;
1661	lock2.count = 10;
1662
1663	locks[0] = lock1;
1664	locks[1] = lock2;
1665
1666	io.lockx.in.file.fnum = fnum1;
1667	io.lockx.in.mode = 0; /* exclusive */
1668
1669	/** Test1: Take second lock, but not first. */
1670	torture_comment(tctx, "  unlock 2 locks, first one not locked. Expect no locks "
1671	    "unlocked. \n");
1672
1673	io.lockx.in.ulock_cnt = 0;
1674	io.lockx.in.lock_cnt = 1;
1675	io.lockx.in.locks = &lock2;
1676	status = smb_raw_lock(cli->tree, &io);
1677	CHECK_STATUS(status, NT_STATUS_OK);
1678
1679	/* Try to unlock both locks. */
1680	io.lockx.in.ulock_cnt = 2;
1681	io.lockx.in.lock_cnt = 0;
1682	io.lockx.in.locks = locks;
1683
1684	status = smb_raw_lock(cli->tree, &io);
1685	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1686
1687	/* Second lock should not be unlocked. */
1688	io.lockx.in.ulock_cnt = 0;
1689	io.lockx.in.lock_cnt = 1;
1690	io.lockx.in.locks = &lock2;
1691	status = smb_raw_lock(cli->tree, &io);
1692	CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1693
1694	/* cleanup */
1695	io.lockx.in.ulock_cnt = 1;
1696	io.lockx.in.lock_cnt = 0;
1697	io.lockx.in.locks = &lock2;
1698	status = smb_raw_lock(cli->tree, &io);
1699	CHECK_STATUS(status, NT_STATUS_OK);
1700
1701	/** Test2: Take first lock, but not second. */
1702	torture_comment(tctx, "  unlock 2 locks, second one not locked. Expect first lock "
1703	    "unlocked.\n");
1704
1705	io.lockx.in.ulock_cnt = 0;
1706	io.lockx.in.lock_cnt = 1;
1707	io.lockx.in.locks = &lock1;
1708	status = smb_raw_lock(cli->tree, &io);
1709	CHECK_STATUS(status, NT_STATUS_OK);
1710
1711	/* Try to unlock both locks. */
1712	io.lockx.in.ulock_cnt = 2;
1713	io.lockx.in.lock_cnt = 0;
1714	io.lockx.in.locks = locks;
1715
1716	status = smb_raw_lock(cli->tree, &io);
1717	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1718
1719	/* First lock should be unlocked. */
1720	io.lockx.in.ulock_cnt = 0;
1721	io.lockx.in.lock_cnt = 1;
1722	io.lockx.in.locks = &lock1;
1723	status = smb_raw_lock(cli->tree, &io);
1724	CHECK_STATUS(status, NT_STATUS_OK);
1725
1726	/* cleanup */
1727	io.lockx.in.ulock_cnt = 1;
1728	io.lockx.in.lock_cnt = 0;
1729	io.lockx.in.locks = &lock1;
1730	status = smb_raw_lock(cli->tree, &io);
1731	CHECK_STATUS(status, NT_STATUS_OK);
1732
1733done:
1734	smbcli_close(cli->tree, fnum1);
1735	smb_raw_exit(cli->session);
1736	smbcli_deltree(cli->tree, BASEDIR);
1737	return ret;
1738}
1739
1740/**
1741 * torture_locktest5 covers stacking pretty well, but its missing two tests:
1742 * - stacking an exclusive on top of shared fails
1743 * - stacking two exclusives fail
1744 */
1745static bool test_stacking(struct torture_context *tctx, struct smbcli_state *cli)
1746{
1747	union smb_lock io;
1748	NTSTATUS status;
1749	bool ret = true;
1750	int fnum1;
1751	const char *fname = BASEDIR "\\stacking.txt";
1752	struct smb_lock_entry lock1;
1753	struct smb_lock_entry lock2;
1754
1755	torture_comment(tctx, "Testing stacking:\n");
1756
1757	if (!torture_setup_dir(cli, BASEDIR)) {
1758		return false;
1759	}
1760
1761	io.generic.level = RAW_LOCK_LOCKX;
1762
1763	fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1764	torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1765		       "Failed to create %s - %s\n",
1766		       fname, smbcli_errstr(cli->tree)));
1767
1768	/* Setup initial parameters */
1769	io.lockx.level = RAW_LOCK_LOCKX;
1770	io.lockx.in.timeout = 0;
1771
1772	lock1.pid = cli->session->pid;
1773	lock1.offset = 0;
1774	lock1.count = 10;
1775	lock2.pid = cli->session->pid - 1;
1776	lock2.offset = 0;
1777	lock2.count = 10;
1778
1779	/**
1780	 * Try to take a shared lock, then stack an exclusive.
1781	 */
1782	torture_comment(tctx, "  stacking an exclusive on top of a shared lock fails.\n");
1783	io.lockx.in.file.fnum = fnum1;
1784	io.lockx.in.locks = &lock1;
1785
1786	io.lockx.in.ulock_cnt = 0;
1787	io.lockx.in.lock_cnt = 1;
1788	io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1789	status = smb_raw_lock(cli->tree, &io);
1790	CHECK_STATUS(status, NT_STATUS_OK);
1791
1792	io.lockx.in.ulock_cnt = 0;
1793	io.lockx.in.lock_cnt = 1;
1794	io.lockx.in.mode = 0;
1795	status = smb_raw_lock(cli->tree, &io);
1796	CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1797	    NT_STATUS_FILE_LOCK_CONFLICT);
1798
1799	/* cleanup */
1800	io.lockx.in.ulock_cnt = 1;
1801	io.lockx.in.lock_cnt = 0;
1802	status = smb_raw_lock(cli->tree, &io);
1803	CHECK_STATUS(status, NT_STATUS_OK);
1804
1805	/**
1806	 * Prove that two exclusive locks do not stack.
1807	 */
1808	torture_comment(tctx, "  two exclusive locks do not stack.\n");
1809	io.lockx.in.ulock_cnt = 0;
1810	io.lockx.in.lock_cnt = 1;
1811	io.lockx.in.mode = 0;
1812	status = smb_raw_lock(cli->tree, &io);
1813	CHECK_STATUS(status, NT_STATUS_OK);
1814	status = smb_raw_lock(cli->tree, &io);
1815	CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1816	    NT_STATUS_FILE_LOCK_CONFLICT);
1817
1818	/* cleanup */
1819	io.lockx.in.ulock_cnt = 1;
1820	io.lockx.in.lock_cnt = 0;
1821	status = smb_raw_lock(cli->tree, &io);
1822	CHECK_STATUS(status, NT_STATUS_OK);
1823
1824done:
1825	smbcli_close(cli->tree, fnum1);
1826	smb_raw_exit(cli->session);
1827	smbcli_deltree(cli->tree, BASEDIR);
1828	return ret;
1829}
1830
1831/*
1832   basic testing of lock calls
1833*/
1834struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx)
1835{
1836	struct torture_suite *suite = torture_suite_create(mem_ctx, "LOCK");
1837
1838	torture_suite_add_1smb_test(suite, "lockx", test_lockx);
1839	torture_suite_add_1smb_test(suite, "lock", test_lock);
1840	torture_suite_add_1smb_test(suite, "pidhigh", test_pidhigh);
1841	torture_suite_add_1smb_test(suite, "async", test_async);
1842	torture_suite_add_1smb_test(suite, "errorcode", test_errorcode);
1843	torture_suite_add_1smb_test(suite, "changetype", test_changetype);
1844
1845	torture_suite_add_1smb_test(suite, "stacking", test_stacking);
1846	torture_suite_add_1smb_test(suite, "unlock", test_unlock);
1847	torture_suite_add_1smb_test(suite, "multiple_unlock",
1848	    test_multiple_unlock);
1849	torture_suite_add_1smb_test(suite, "zerobytelocks",
1850	    test_zerobytelocks);
1851
1852	return suite;
1853}
1854