Line data Source code
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/cmdline.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 1 : static bool test_lock(struct torture_context *tctx, struct smbcli_state *cli)
96 : {
97 : union smb_lock io;
98 : NTSTATUS status;
99 1 : bool ret = true;
100 : int fnum;
101 1 : const char *fname = BASEDIR "\\test.txt";
102 :
103 1 : if (!TARGET_SUPPORTS_SMBLOCK(tctx))
104 0 : torture_skip(tctx, "Target does not support the SMBlock PDU");
105 :
106 1 : torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
107 :
108 1 : torture_comment(tctx, "Testing RAW_LOCK_LOCK\n");
109 1 : io.generic.level = RAW_LOCK_LOCK;
110 :
111 1 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
112 1 : torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
113 : "Failed to create %s - %s\n",
114 : fname, smbcli_errstr(cli->tree)));
115 :
116 1 : torture_comment(tctx, "Trying 0/0 lock\n");
117 1 : io.lock.level = RAW_LOCK_LOCK;
118 1 : io.lock.in.file.fnum = fnum;
119 1 : io.lock.in.count = 0;
120 1 : io.lock.in.offset = 0;
121 1 : status = smb_raw_lock(cli->tree, &io);
122 1 : CHECK_STATUS(status, NT_STATUS_OK);
123 1 : cli->session->pid++;
124 1 : status = smb_raw_lock(cli->tree, &io);
125 1 : CHECK_STATUS(status, NT_STATUS_OK);
126 1 : cli->session->pid--;
127 1 : io.lock.level = RAW_LOCK_UNLOCK;
128 1 : status = smb_raw_lock(cli->tree, &io);
129 1 : CHECK_STATUS(status, NT_STATUS_OK);
130 :
131 1 : torture_comment(tctx, "Trying 0/1 lock\n");
132 1 : io.lock.level = RAW_LOCK_LOCK;
133 1 : io.lock.in.file.fnum = fnum;
134 1 : io.lock.in.count = 1;
135 1 : io.lock.in.offset = 0;
136 1 : status = smb_raw_lock(cli->tree, &io);
137 1 : CHECK_STATUS(status, NT_STATUS_OK);
138 1 : cli->session->pid++;
139 1 : status = smb_raw_lock(cli->tree, &io);
140 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
141 1 : cli->session->pid--;
142 1 : io.lock.level = RAW_LOCK_UNLOCK;
143 1 : status = smb_raw_lock(cli->tree, &io);
144 1 : CHECK_STATUS(status, NT_STATUS_OK);
145 1 : io.lock.level = RAW_LOCK_UNLOCK;
146 1 : status = smb_raw_lock(cli->tree, &io);
147 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
148 :
149 1 : torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
150 1 : io.lock.level = RAW_LOCK_LOCK;
151 1 : io.lock.in.file.fnum = fnum;
152 1 : io.lock.in.count = 4000;
153 1 : io.lock.in.offset = 0xEEFFFFFF;
154 1 : status = smb_raw_lock(cli->tree, &io);
155 1 : CHECK_STATUS(status, NT_STATUS_OK);
156 1 : cli->session->pid++;
157 1 : status = smb_raw_lock(cli->tree, &io);
158 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
159 1 : cli->session->pid--;
160 1 : io.lock.level = RAW_LOCK_UNLOCK;
161 1 : status = smb_raw_lock(cli->tree, &io);
162 1 : CHECK_STATUS(status, NT_STATUS_OK);
163 1 : io.lock.level = RAW_LOCK_UNLOCK;
164 1 : status = smb_raw_lock(cli->tree, &io);
165 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
166 :
167 1 : torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
168 1 : io.lock.level = RAW_LOCK_LOCK;
169 1 : io.lock.in.file.fnum = fnum;
170 1 : io.lock.in.count = 4000;
171 1 : io.lock.in.offset = 0xEEFFFFFF;
172 1 : status = smb_raw_lock(cli->tree, &io);
173 1 : CHECK_STATUS(status, NT_STATUS_OK);
174 1 : cli->session->pid++;
175 1 : status = smb_raw_lock(cli->tree, &io);
176 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
177 1 : cli->session->pid--;
178 1 : io.lock.level = RAW_LOCK_UNLOCK;
179 1 : status = smb_raw_lock(cli->tree, &io);
180 1 : CHECK_STATUS(status, NT_STATUS_OK);
181 1 : io.lock.level = RAW_LOCK_UNLOCK;
182 1 : status = smb_raw_lock(cli->tree, &io);
183 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
184 :
185 1 : torture_comment(tctx, "Trying max lock\n");
186 1 : io.lock.level = RAW_LOCK_LOCK;
187 1 : io.lock.in.file.fnum = fnum;
188 1 : io.lock.in.count = 4000;
189 1 : io.lock.in.offset = 0xEF000000;
190 1 : status = smb_raw_lock(cli->tree, &io);
191 1 : CHECK_STATUS(status, NT_STATUS_OK);
192 1 : cli->session->pid++;
193 1 : status = smb_raw_lock(cli->tree, &io);
194 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
195 1 : cli->session->pid--;
196 1 : io.lock.level = RAW_LOCK_UNLOCK;
197 1 : status = smb_raw_lock(cli->tree, &io);
198 1 : CHECK_STATUS(status, NT_STATUS_OK);
199 1 : io.lock.level = RAW_LOCK_UNLOCK;
200 1 : status = smb_raw_lock(cli->tree, &io);
201 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
202 :
203 1 : torture_comment(tctx, "Trying wrong pid unlock\n");
204 1 : io.lock.level = RAW_LOCK_LOCK;
205 1 : io.lock.in.file.fnum = fnum;
206 1 : io.lock.in.count = 4002;
207 1 : io.lock.in.offset = 10001;
208 1 : status = smb_raw_lock(cli->tree, &io);
209 1 : CHECK_STATUS(status, NT_STATUS_OK);
210 1 : cli->session->pid++;
211 1 : io.lock.level = RAW_LOCK_UNLOCK;
212 1 : status = smb_raw_lock(cli->tree, &io);
213 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
214 1 : cli->session->pid--;
215 1 : status = smb_raw_lock(cli->tree, &io);
216 1 : CHECK_STATUS(status, NT_STATUS_OK);
217 :
218 2 : done:
219 1 : smbcli_close(cli->tree, fnum);
220 1 : smb_raw_exit(cli->session);
221 1 : smbcli_deltree(cli->tree, BASEDIR);
222 1 : return ret;
223 : }
224 :
225 :
226 : /*
227 : test locking&X ops
228 : */
229 1 : 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 1 : bool ret = true;
235 : int fnum;
236 1 : const char *fname = BASEDIR "\\test.txt";
237 :
238 1 : torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
239 :
240 1 : torture_comment(tctx, "Testing RAW_LOCK_LOCKX\n");
241 1 : io.generic.level = RAW_LOCK_LOCKX;
242 :
243 1 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
244 1 : torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
245 : "Failed to create %s - %s\n",
246 : fname, smbcli_errstr(cli->tree)));
247 :
248 1 : io.lockx.level = RAW_LOCK_LOCKX;
249 1 : io.lockx.in.file.fnum = fnum;
250 1 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
251 1 : io.lockx.in.timeout = 0;
252 1 : io.lockx.in.ulock_cnt = 0;
253 1 : io.lockx.in.lock_cnt = 1;
254 1 : lock[0].pid = cli->session->pid;
255 1 : lock[0].offset = 10;
256 1 : lock[0].count = 1;
257 1 : io.lockx.in.locks = &lock[0];
258 1 : status = smb_raw_lock(cli->tree, &io);
259 1 : CHECK_STATUS(status, NT_STATUS_OK);
260 :
261 :
262 1 : torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
263 1 : io.lockx.in.ulock_cnt = 0;
264 1 : io.lockx.in.lock_cnt = 1;
265 1 : lock[0].count = 4000;
266 1 : lock[0].offset = 0xEEFFFFFF;
267 1 : status = smb_raw_lock(cli->tree, &io);
268 1 : CHECK_STATUS(status, NT_STATUS_OK);
269 1 : lock[0].pid++;
270 1 : status = smb_raw_lock(cli->tree, &io);
271 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
272 1 : lock[0].pid--;
273 1 : io.lockx.in.ulock_cnt = 1;
274 1 : io.lockx.in.lock_cnt = 0;
275 1 : status = smb_raw_lock(cli->tree, &io);
276 1 : CHECK_STATUS(status, NT_STATUS_OK);
277 1 : status = smb_raw_lock(cli->tree, &io);
278 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
279 :
280 1 : torture_comment(tctx, "Trying 0xEF000000 lock\n");
281 1 : io.lockx.in.ulock_cnt = 0;
282 1 : io.lockx.in.lock_cnt = 1;
283 1 : lock[0].count = 4000;
284 1 : lock[0].offset = 0xEF000000;
285 1 : status = smb_raw_lock(cli->tree, &io);
286 1 : CHECK_STATUS(status, NT_STATUS_OK);
287 1 : lock[0].pid++;
288 1 : status = smb_raw_lock(cli->tree, &io);
289 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
290 1 : lock[0].pid--;
291 1 : io.lockx.in.ulock_cnt = 1;
292 1 : io.lockx.in.lock_cnt = 0;
293 1 : status = smb_raw_lock(cli->tree, &io);
294 1 : CHECK_STATUS(status, NT_STATUS_OK);
295 1 : status = smb_raw_lock(cli->tree, &io);
296 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
297 :
298 1 : torture_comment(tctx, "Trying zero lock\n");
299 1 : io.lockx.in.ulock_cnt = 0;
300 1 : io.lockx.in.lock_cnt = 1;
301 1 : lock[0].count = 0;
302 1 : lock[0].offset = ~0;
303 1 : status = smb_raw_lock(cli->tree, &io);
304 1 : CHECK_STATUS(status, NT_STATUS_OK);
305 1 : lock[0].pid++;
306 1 : status = smb_raw_lock(cli->tree, &io);
307 1 : CHECK_STATUS(status, NT_STATUS_OK);
308 1 : lock[0].pid--;
309 1 : io.lockx.in.ulock_cnt = 1;
310 1 : io.lockx.in.lock_cnt = 0;
311 1 : status = smb_raw_lock(cli->tree, &io);
312 1 : CHECK_STATUS(status, NT_STATUS_OK);
313 1 : status = smb_raw_lock(cli->tree, &io);
314 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
315 :
316 1 : torture_comment(tctx, "Trying max lock\n");
317 1 : io.lockx.in.ulock_cnt = 0;
318 1 : io.lockx.in.lock_cnt = 1;
319 1 : lock[0].count = 0;
320 1 : lock[0].offset = ~0;
321 1 : status = smb_raw_lock(cli->tree, &io);
322 1 : CHECK_STATUS(status, NT_STATUS_OK);
323 1 : lock[0].pid++;
324 1 : status = smb_raw_lock(cli->tree, &io);
325 1 : CHECK_STATUS(status, NT_STATUS_OK);
326 1 : lock[0].pid--;
327 1 : io.lockx.in.ulock_cnt = 1;
328 1 : io.lockx.in.lock_cnt = 0;
329 1 : status = smb_raw_lock(cli->tree, &io);
330 1 : CHECK_STATUS(status, NT_STATUS_OK);
331 1 : status = smb_raw_lock(cli->tree, &io);
332 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
333 :
334 1 : torture_comment(tctx, "Trying 2^63\n");
335 1 : io.lockx.in.ulock_cnt = 0;
336 1 : io.lockx.in.lock_cnt = 1;
337 1 : lock[0].count = 1;
338 1 : lock[0].offset = 1;
339 1 : lock[0].offset <<= 63;
340 1 : status = smb_raw_lock(cli->tree, &io);
341 1 : CHECK_STATUS(status, NT_STATUS_OK);
342 1 : lock[0].pid++;
343 1 : status = smb_raw_lock(cli->tree, &io);
344 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
345 1 : lock[0].pid--;
346 1 : io.lockx.in.ulock_cnt = 1;
347 1 : io.lockx.in.lock_cnt = 0;
348 1 : status = smb_raw_lock(cli->tree, &io);
349 1 : CHECK_STATUS(status, NT_STATUS_OK);
350 1 : status = smb_raw_lock(cli->tree, &io);
351 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
352 :
353 1 : torture_comment(tctx, "Trying 2^63 - 1\n");
354 1 : io.lockx.in.ulock_cnt = 0;
355 1 : io.lockx.in.lock_cnt = 1;
356 1 : lock[0].count = 1;
357 1 : lock[0].offset = 1;
358 1 : lock[0].offset <<= 63;
359 1 : lock[0].offset--;
360 1 : status = smb_raw_lock(cli->tree, &io);
361 1 : CHECK_STATUS(status, NT_STATUS_OK);
362 1 : lock[0].pid++;
363 1 : status = smb_raw_lock(cli->tree, &io);
364 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
365 1 : lock[0].pid--;
366 1 : io.lockx.in.ulock_cnt = 1;
367 1 : io.lockx.in.lock_cnt = 0;
368 1 : status = smb_raw_lock(cli->tree, &io);
369 1 : CHECK_STATUS(status, NT_STATUS_OK);
370 1 : status = smb_raw_lock(cli->tree, &io);
371 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
372 :
373 1 : torture_comment(tctx, "Trying max lock 2\n");
374 1 : io.lockx.in.ulock_cnt = 0;
375 1 : io.lockx.in.lock_cnt = 1;
376 1 : lock[0].count = 1;
377 1 : lock[0].offset = ~0;
378 1 : status = smb_raw_lock(cli->tree, &io);
379 1 : CHECK_STATUS(status, NT_STATUS_OK);
380 1 : lock[0].pid++;
381 1 : lock[0].count = 2;
382 1 : status = smb_raw_lock(cli->tree, &io);
383 1 : if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(tctx))
384 1 : CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
385 : else
386 0 : CHECK_STATUS(status, NT_STATUS_OK);
387 1 : lock[0].pid--;
388 1 : io.lockx.in.ulock_cnt = 1;
389 1 : io.lockx.in.lock_cnt = 0;
390 1 : lock[0].count = 1;
391 1 : status = smb_raw_lock(cli->tree, &io);
392 :
393 1 : CHECK_STATUS(status, NT_STATUS_OK);
394 1 : status = smb_raw_lock(cli->tree, &io);
395 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
396 :
397 2 : done:
398 1 : smbcli_close(cli->tree, fnum);
399 1 : smb_raw_exit(cli->session);
400 1 : smbcli_deltree(cli->tree, BASEDIR);
401 1 : return ret;
402 : }
403 :
404 : /*
405 : test high pid
406 : */
407 1 : 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 1 : bool ret = true;
414 : int fnum;
415 1 : const char *fname = BASEDIR "\\test.txt";
416 1 : uint8_t c = 1;
417 :
418 1 : torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
419 :
420 1 : torture_comment(tctx, "Testing high pid\n");
421 1 : io.generic.level = RAW_LOCK_LOCKX;
422 :
423 1 : cli->session->pid = 1;
424 :
425 1 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
426 1 : torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
427 : "Failed to create %s - %s\n",
428 : fname, smbcli_errstr(cli->tree)));
429 :
430 1 : if (smbcli_write(cli->tree, fnum, 0, &c, 0, 1) != 1) {
431 0 : torture_result(tctx, TORTURE_FAIL,
432 : "Failed to write 1 byte - %s\n",
433 : smbcli_errstr(cli->tree));
434 0 : ret = false;
435 0 : goto done;
436 : }
437 :
438 1 : io.lockx.level = RAW_LOCK_LOCKX;
439 1 : io.lockx.in.file.fnum = fnum;
440 1 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
441 1 : io.lockx.in.timeout = 0;
442 1 : io.lockx.in.ulock_cnt = 0;
443 1 : io.lockx.in.lock_cnt = 1;
444 1 : lock[0].pid = cli->session->pid;
445 1 : lock[0].offset = 0;
446 1 : lock[0].count = 0xFFFFFFFF;
447 1 : io.lockx.in.locks = &lock[0];
448 1 : status = smb_raw_lock(cli->tree, &io);
449 1 : CHECK_STATUS(status, NT_STATUS_OK);
450 :
451 1 : if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
452 0 : torture_result(tctx, TORTURE_FAIL,
453 : "Failed to read 1 byte - %s\n",
454 : smbcli_errstr(cli->tree));
455 0 : ret = false;
456 0 : goto done;
457 : }
458 :
459 1 : cli->session->pid = 2;
460 :
461 1 : if (smbcli_read(cli->tree, fnum, &c, 0, 1) == 1) {
462 0 : torture_result(tctx, TORTURE_FAIL,
463 : "pid is incorrect handled for read with lock!\n");
464 0 : ret = false;
465 0 : goto done;
466 : }
467 :
468 1 : cli->session->pid = 0x10001;
469 :
470 1 : if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
471 0 : torture_result(tctx, TORTURE_FAIL,
472 : "High pid is used on this server!\n");
473 0 : ret = false;
474 : } else {
475 1 : torture_warning(tctx, "High pid is not used on this server (correct)\n");
476 : }
477 :
478 1 : done:
479 1 : smbcli_close(cli->tree, fnum);
480 1 : smb_raw_exit(cli->session);
481 1 : smbcli_deltree(cli->tree, BASEDIR);
482 1 : return ret;
483 : }
484 :
485 :
486 : /*
487 : test locking&X async operation
488 : */
489 1 : 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 1 : bool ret = true;
501 : int fnum;
502 1 : const char *fname = BASEDIR "\\test.txt";
503 : time_t t;
504 : struct smbcli_request *req, *req2;
505 : struct smbcli_session_options options;
506 :
507 1 : torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
508 :
509 1 : lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
510 :
511 1 : torture_comment(tctx, "Testing LOCKING_ANDX_CANCEL_LOCK\n");
512 1 : io.generic.level = RAW_LOCK_LOCKX;
513 :
514 1 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
515 1 : torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
516 : "Failed to create %s - %s\n",
517 : fname, smbcli_errstr(cli->tree)));
518 :
519 1 : io.lockx.level = RAW_LOCK_LOCKX;
520 1 : io.lockx.in.file.fnum = fnum;
521 1 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
522 1 : io.lockx.in.timeout = 0;
523 1 : io.lockx.in.ulock_cnt = 0;
524 1 : io.lockx.in.lock_cnt = 1;
525 1 : lock[0].pid = cli->session->pid;
526 1 : lock[0].offset = 100;
527 1 : lock[0].count = 10;
528 1 : lock[1].pid = cli->session->pid;
529 1 : lock[1].offset = 110;
530 1 : lock[1].count = 10;
531 1 : io.lockx.in.locks = &lock[0];
532 1 : status = smb_raw_lock(cli->tree, &io);
533 1 : CHECK_STATUS(status, NT_STATUS_OK);
534 :
535 1 : t = time_mono(NULL);
536 :
537 1 : torture_comment(tctx, "Testing cancel by CANCEL_LOCK\n");
538 :
539 : /* setup a timed lock */
540 1 : io.lockx.in.timeout = 10000;
541 1 : req = smb_raw_lock_send(cli->tree, &io);
542 1 : torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
543 : "Failed to setup timed lock (%s)\n", __location__));
544 :
545 : /* cancel the wrong range */
546 1 : lock[0].offset = 0;
547 1 : io.lockx.in.timeout = 0;
548 1 : io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
549 1 : status = smb_raw_lock(cli->tree, &io);
550 1 : CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
551 :
552 : /* cancel with the wrong bits set */
553 1 : lock[0].offset = 100;
554 1 : io.lockx.in.timeout = 0;
555 1 : io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
556 1 : status = smb_raw_lock(cli->tree, &io);
557 1 : CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
558 :
559 : /* cancel the right range */
560 1 : lock[0].offset = 100;
561 1 : io.lockx.in.timeout = 0;
562 1 : io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
563 1 : status = smb_raw_lock(cli->tree, &io);
564 1 : CHECK_STATUS(status, NT_STATUS_OK);
565 :
566 : /* receive the failed lock request */
567 1 : status = smbcli_request_simple_recv(req);
568 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
569 :
570 1 : 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 multiple 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 1 : torture_comment(tctx, "Testing multiple cancel\n");
581 :
582 : /* acquire second lock */
583 1 : io.lockx.in.timeout = 0;
584 1 : io.lockx.in.ulock_cnt = 0;
585 1 : io.lockx.in.lock_cnt = 1;
586 1 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
587 1 : io.lockx.in.locks = &lock[1];
588 1 : status = smb_raw_lock(cli->tree, &io);
589 1 : CHECK_STATUS(status, NT_STATUS_OK);
590 :
591 : /* setup 2 timed locks */
592 1 : t = time_mono(NULL);
593 1 : io.lockx.in.timeout = 10000;
594 1 : io.lockx.in.lock_cnt = 1;
595 1 : io.lockx.in.locks = &lock[0];
596 1 : req = smb_raw_lock_send(cli->tree, &io);
597 1 : torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
598 : "Failed to setup timed lock (%s)\n", __location__));
599 1 : io.lockx.in.locks = &lock[1];
600 1 : req2 = smb_raw_lock_send(cli->tree, &io);
601 1 : 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 1 : io.lockx.in.timeout = 0;
606 1 : io.lockx.in.lock_cnt = 2;
607 1 : io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
608 1 : io.lockx.in.locks = lock;
609 1 : status = smb_raw_lock(cli->tree, &io);
610 1 : CHECK_STATUS(status, NT_STATUS_OK);
611 :
612 0 : 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 0 : status = smbcli_request_simple_recv(req);
618 0 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
619 :
620 0 : 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 0 : io.lockx.in.timeout = 0;
626 0 : io.lockx.in.lock_cnt = 1;
627 0 : io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK |
628 : LOCKING_ANDX_LARGE_FILES;
629 0 : io.lockx.in.locks = &lock[1];
630 0 : status = smb_raw_lock(cli->tree, &io);
631 0 : CHECK_STATUS(status, NT_STATUS_OK);
632 :
633 0 : status = smbcli_request_simple_recv(req2);
634 0 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
635 :
636 0 : 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 0 : io.lockx.in.ulock_cnt = 1;
642 0 : io.lockx.in.lock_cnt = 0;
643 0 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
644 0 : io.lockx.in.locks = &lock[1];
645 0 : status = smb_raw_lock(cli->tree, &io);
646 0 : 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 0 : torture_comment(tctx, "Testing cancel 1/2 lock request\n");
651 :
652 : /* Send request with two ranges */
653 0 : io.lockx.in.timeout = -1;
654 0 : io.lockx.in.ulock_cnt = 0;
655 0 : io.lockx.in.lock_cnt = 2;
656 0 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
657 0 : io.lockx.in.locks = lock;
658 0 : req = smb_raw_lock_send(cli->tree, &io);
659 0 : 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 0 : io.lockx.in.timeout = 0;
664 0 : io.lockx.in.lock_cnt = 1;
665 0 : io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
666 0 : io.lockx.in.locks = &lock[0];
667 0 : status = smb_raw_lock(cli->tree, &io);
668 0 : CHECK_STATUS(status, NT_STATUS_OK);
669 :
670 : /* Locking request should've failed and second range should be
671 : * unlocked */
672 0 : status = smbcli_request_simple_recv(req);
673 0 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
674 :
675 0 : io.lockx.in.timeout = 0;
676 0 : io.lockx.in.ulock_cnt = 0;
677 0 : io.lockx.in.lock_cnt = 1;
678 0 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
679 0 : io.lockx.in.locks = &lock[1];
680 0 : status = smb_raw_lock(cli->tree, &io);
681 0 : CHECK_STATUS(status, NT_STATUS_OK);
682 :
683 : /* Cleanup both locks */
684 0 : io.lockx.in.ulock_cnt = 2;
685 0 : io.lockx.in.lock_cnt = 0;
686 0 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
687 0 : io.lockx.in.locks = lock;
688 0 : status = smb_raw_lock(cli->tree, &io);
689 0 : CHECK_STATUS(status, NT_STATUS_OK);
690 :
691 0 : torture_comment(tctx, "Testing cancel 2/2 lock request\n");
692 :
693 : /* Lock second range so it contends */
694 0 : io.lockx.in.timeout = 0;
695 0 : io.lockx.in.ulock_cnt = 0;
696 0 : io.lockx.in.lock_cnt = 1;
697 0 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
698 0 : io.lockx.in.locks = &lock[1];
699 0 : status = smb_raw_lock(cli->tree, &io);
700 0 : CHECK_STATUS(status, NT_STATUS_OK);
701 :
702 : /* Send request with two ranges */
703 0 : io.lockx.in.timeout = -1;
704 0 : io.lockx.in.ulock_cnt = 0;
705 0 : io.lockx.in.lock_cnt = 2;
706 0 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
707 0 : io.lockx.in.locks = lock;
708 0 : req = smb_raw_lock_send(cli->tree, &io);
709 0 : 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 0 : io.lockx.in.timeout = 0;
714 0 : io.lockx.in.lock_cnt = 1;
715 0 : io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
716 0 : io.lockx.in.locks = &lock[1];
717 0 : status = smb_raw_lock(cli->tree, &io);
718 0 : CHECK_STATUS(status, NT_STATUS_OK);
719 :
720 : /* Locking request should've failed and first range should be
721 : * unlocked */
722 0 : status = smbcli_request_simple_recv(req);
723 0 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
724 :
725 0 : io.lockx.in.timeout = 0;
726 0 : io.lockx.in.ulock_cnt = 0;
727 0 : io.lockx.in.lock_cnt = 1;
728 0 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
729 0 : io.lockx.in.locks = &lock[0];
730 0 : status = smb_raw_lock(cli->tree, &io);
731 0 : CHECK_STATUS(status, NT_STATUS_OK);
732 :
733 : /* Cleanup both locks */
734 0 : io.lockx.in.ulock_cnt = 2;
735 0 : io.lockx.in.lock_cnt = 0;
736 0 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
737 0 : io.lockx.in.locks = lock;
738 0 : status = smb_raw_lock(cli->tree, &io);
739 0 : CHECK_STATUS(status, NT_STATUS_OK);
740 :
741 0 : torture_comment(tctx, "Testing cancel by unlock\n");
742 0 : io.lockx.in.ulock_cnt = 0;
743 0 : io.lockx.in.lock_cnt = 1;
744 0 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
745 0 : io.lockx.in.timeout = 0;
746 0 : io.lockx.in.locks = &lock[0];
747 0 : status = smb_raw_lock(cli->tree, &io);
748 0 : CHECK_STATUS(status, NT_STATUS_OK);
749 :
750 0 : io.lockx.in.timeout = 5000;
751 0 : req = smb_raw_lock_send(cli->tree, &io);
752 0 : torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
753 : "Failed to setup timed lock (%s)\n", __location__));
754 :
755 0 : io.lockx.in.ulock_cnt = 1;
756 0 : io.lockx.in.lock_cnt = 0;
757 0 : status = smb_raw_lock(cli->tree, &io);
758 0 : CHECK_STATUS(status, NT_STATUS_OK);
759 :
760 0 : t = time_mono(NULL);
761 0 : status = smbcli_request_simple_recv(req);
762 0 : CHECK_STATUS(status, NT_STATUS_OK);
763 :
764 0 : 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 0 : torture_comment(tctx, "Testing cancel by close\n");
769 0 : io.lockx.in.ulock_cnt = 0;
770 0 : io.lockx.in.lock_cnt = 1;
771 0 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
772 0 : io.lockx.in.timeout = 0;
773 0 : status = smb_raw_lock(cli->tree, &io);
774 0 : 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 0 : uint64_t tmp = lock[1].offset;
782 0 : lock[1].offset = lock[0].offset;
783 0 : lock[0].offset = tmp;
784 : }
785 :
786 0 : t = time_mono(NULL);
787 0 : io.lockx.in.timeout = 10000;
788 0 : io.lockx.in.lock_cnt = 2;
789 0 : req = smb_raw_lock_send(cli->tree, &io);
790 0 : torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
791 : "Failed to setup timed lock (%s)\n", __location__));
792 :
793 0 : status = smbcli_close(cli->tree, fnum);
794 0 : CHECK_STATUS(status, NT_STATUS_OK);
795 :
796 0 : status = smbcli_request_simple_recv(req);
797 0 : if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx))
798 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
799 : else
800 0 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
801 :
802 0 : 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 0 : uint64_t tmp = lock[1].offset;
810 0 : lock[1].offset = lock[0].offset;
811 0 : lock[0].offset = tmp;
812 : }
813 :
814 0 : torture_comment(tctx, "create a new sessions\n");
815 0 : session = smbcli_session_init(cli->transport, tctx, false, options);
816 0 : setup.in.sesskey = cli->transport->negotiate.sesskey;
817 0 : setup.in.capabilities = cli->transport->negotiate.capabilities;
818 0 : setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
819 0 : setup.in.credentials = samba_cmdline_get_creds();
820 0 : setup.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
821 0 : status = smb_composite_sesssetup(session, &setup);
822 0 : CHECK_STATUS(status, NT_STATUS_OK);
823 0 : session->vuid = setup.out.vuid;
824 :
825 0 : torture_comment(tctx, "create new tree context\n");
826 0 : share = torture_setting_string(tctx, "share", NULL);
827 0 : host = torture_setting_string(tctx, "host", NULL);
828 0 : tree = smbcli_tree_init(session, tctx, false);
829 0 : tcon.generic.level = RAW_TCON_TCONX;
830 0 : tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
831 0 : tcon.tconx.in.password = data_blob(NULL, 0);
832 0 : tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
833 0 : tcon.tconx.in.device = "A:";
834 0 : status = smb_raw_tcon(tree, tctx, &tcon);
835 0 : CHECK_STATUS(status, NT_STATUS_OK);
836 0 : tree->tid = tcon.tconx.out.tid;
837 :
838 0 : torture_comment(tctx, "Testing cancel by exit\n");
839 0 : if (TARGET_SUPPORTS_SMBEXIT(tctx)) {
840 0 : fname = BASEDIR "\\test_exit.txt";
841 0 : fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
842 0 : torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
843 : "Failed to reopen %s - %s\n",
844 : fname, smbcli_errstr(tree)));
845 :
846 0 : io.lockx.level = RAW_LOCK_LOCKX;
847 0 : io.lockx.in.file.fnum = fnum;
848 0 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
849 0 : io.lockx.in.timeout = 0;
850 0 : io.lockx.in.ulock_cnt = 0;
851 0 : io.lockx.in.lock_cnt = 1;
852 0 : lock[0].pid = session->pid;
853 0 : lock[0].offset = 100;
854 0 : lock[0].count = 10;
855 0 : io.lockx.in.locks = &lock[0];
856 0 : status = smb_raw_lock(tree, &io);
857 0 : CHECK_STATUS(status, NT_STATUS_OK);
858 :
859 0 : io.lockx.in.ulock_cnt = 0;
860 0 : io.lockx.in.lock_cnt = 1;
861 0 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
862 0 : io.lockx.in.timeout = 0;
863 0 : status = smb_raw_lock(tree, &io);
864 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
865 :
866 0 : io.lockx.in.timeout = 10000;
867 0 : t = time_mono(NULL);
868 0 : req = smb_raw_lock_send(tree, &io);
869 0 : torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
870 : "Failed to setup timed lock (%s)\n",
871 : __location__));
872 :
873 0 : status = smb_raw_exit(session);
874 0 : CHECK_STATUS(status, NT_STATUS_OK);
875 :
876 0 : status = smbcli_request_simple_recv(req);
877 0 : if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx))
878 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
879 : else
880 0 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
881 :
882 0 : 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 0 : torture_comment(tctx,
888 : " skipping test, SMBExit not supported\n");
889 : }
890 :
891 0 : torture_comment(tctx, "Testing cancel by ulogoff\n");
892 0 : fname = BASEDIR "\\test_ulogoff.txt";
893 0 : fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
894 0 : torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
895 : "Failed to reopen %s - %s\n",
896 : fname, smbcli_errstr(tree)));
897 :
898 0 : io.lockx.level = RAW_LOCK_LOCKX;
899 0 : io.lockx.in.file.fnum = fnum;
900 0 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
901 0 : io.lockx.in.timeout = 0;
902 0 : io.lockx.in.ulock_cnt = 0;
903 0 : io.lockx.in.lock_cnt = 1;
904 0 : lock[0].pid = session->pid;
905 0 : lock[0].offset = 100;
906 0 : lock[0].count = 10;
907 0 : io.lockx.in.locks = &lock[0];
908 0 : status = smb_raw_lock(tree, &io);
909 0 : CHECK_STATUS(status, NT_STATUS_OK);
910 :
911 0 : io.lockx.in.ulock_cnt = 0;
912 0 : io.lockx.in.lock_cnt = 1;
913 0 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
914 0 : io.lockx.in.timeout = 0;
915 0 : status = smb_raw_lock(tree, &io);
916 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
917 :
918 0 : io.lockx.in.timeout = 10000;
919 0 : t = time_mono(NULL);
920 0 : req = smb_raw_lock_send(tree, &io);
921 0 : torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
922 : "Failed to setup timed lock (%s)\n", __location__));
923 :
924 0 : status = smb_raw_ulogoff(session);
925 0 : CHECK_STATUS(status, NT_STATUS_OK);
926 :
927 0 : status = smbcli_request_simple_recv(req);
928 0 : if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx)) {
929 0 : if (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status)) {
930 0 : 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 0 : smb_tree_disconnect(tree);
935 0 : smb_raw_exit(session);
936 0 : goto done;
937 : }
938 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
939 : } else {
940 0 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
941 : }
942 :
943 0 : torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
944 : "lock cancel by ulogoff was not immediate (%s)\n", __location__));
945 :
946 0 : torture_comment(tctx, "Testing cancel by tdis\n");
947 0 : tree->session = cli->session;
948 :
949 0 : fname = BASEDIR "\\test_tdis.txt";
950 0 : fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
951 0 : torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
952 : "Failed to reopen %s - %s\n",
953 : fname, smbcli_errstr(tree)));
954 :
955 0 : io.lockx.level = RAW_LOCK_LOCKX;
956 0 : io.lockx.in.file.fnum = fnum;
957 0 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
958 0 : io.lockx.in.timeout = 0;
959 0 : io.lockx.in.ulock_cnt = 0;
960 0 : io.lockx.in.lock_cnt = 1;
961 0 : lock[0].pid = cli->session->pid;
962 0 : lock[0].offset = 100;
963 0 : lock[0].count = 10;
964 0 : io.lockx.in.locks = &lock[0];
965 0 : status = smb_raw_lock(tree, &io);
966 0 : CHECK_STATUS(status, NT_STATUS_OK);
967 :
968 0 : status = smb_raw_lock(tree, &io);
969 0 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
970 :
971 0 : io.lockx.in.timeout = 10000;
972 0 : t = time_mono(NULL);
973 0 : req = smb_raw_lock_send(tree, &io);
974 0 : torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
975 : "Failed to setup timed lock (%s)\n", __location__));
976 :
977 0 : status = smb_tree_disconnect(tree);
978 0 : CHECK_STATUS(status, NT_STATUS_OK);
979 :
980 0 : status = smbcli_request_simple_recv(req);
981 0 : if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx))
982 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
983 : else
984 0 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
985 :
986 0 : torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
987 : "lock cancel by tdis was not immediate (%s)\n", __location__));
988 :
989 1 : done:
990 1 : smb_raw_exit(cli->session);
991 1 : smbcli_deltree(cli->tree, BASEDIR);
992 1 : return ret;
993 : }
994 :
995 : /*
996 : test NT_STATUS_LOCK_NOT_GRANTED vs. NT_STATUS_FILE_LOCK_CONFLICT
997 : */
998 1 : 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 1 : 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 1 : uint16_t deny_mode = 0;
1013 :
1014 1 : torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1015 :
1016 1 : torture_comment(tctx, "Testing LOCK_NOT_GRANTED vs. FILE_LOCK_CONFLICT\n");
1017 :
1018 1 : torture_comment(tctx, "Testing with timeout = 0\n");
1019 1 : fname = BASEDIR "\\test0.txt";
1020 1 : t = 0;
1021 :
1022 : /*
1023 : * the first run is with t = 0,
1024 : * the second with t > 0 (=1)
1025 : */
1026 2 : 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 2 : if (TARGET_SUPPORTS_OPENX_DENY_DOS(tctx))
1033 2 : deny_mode = OPENX_MODE_DENY_DOS;
1034 : else
1035 0 : deny_mode = OPENX_MODE_DENY_NONE;
1036 :
1037 2 : op.openx.level = RAW_OPEN_OPENX;
1038 2 : op.openx.in.fname = fname;
1039 2 : op.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
1040 2 : op.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | deny_mode;
1041 2 : op.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
1042 2 : op.openx.in.search_attrs = 0;
1043 2 : op.openx.in.file_attrs = 0;
1044 2 : op.openx.in.write_time = 0;
1045 2 : op.openx.in.size = 0;
1046 2 : op.openx.in.timeout = 0;
1047 :
1048 2 : status = smb_raw_open(cli->tree, tctx, &op);
1049 2 : CHECK_STATUS(status, NT_STATUS_OK);
1050 2 : fnum = op.openx.out.file.fnum;
1051 :
1052 2 : status = smb_raw_open(cli->tree, tctx, &op);
1053 2 : CHECK_STATUS(status, NT_STATUS_OK);
1054 2 : fnum2 = op.openx.out.file.fnum;
1055 :
1056 2 : io.lockx.level = RAW_LOCK_LOCKX;
1057 2 : io.lockx.in.file.fnum = fnum;
1058 2 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1059 2 : io.lockx.in.timeout = t;
1060 2 : io.lockx.in.ulock_cnt = 0;
1061 2 : io.lockx.in.lock_cnt = 1;
1062 2 : lock[0].pid = cli->session->pid;
1063 2 : lock[0].offset = 100;
1064 2 : lock[0].count = 10;
1065 2 : io.lockx.in.locks = &lock[0];
1066 2 : status = smb_raw_lock(cli->tree, &io);
1067 2 : 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 2 : io.lockx.in.file.fnum = fnum2;
1075 2 : status = smb_raw_lock(cli->tree, &io);
1076 2 : CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1077 :
1078 2 : io.lockx.in.file.fnum = fnum;
1079 2 : status = smb_raw_lock(cli->tree, &io);
1080 2 : 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 2 : io.lockx.in.file.fnum = fnum;
1084 2 : status = smb_raw_lock(cli->tree, &io);
1085 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1086 :
1087 2 : io.lockx.in.file.fnum = fnum2;
1088 2 : status = smb_raw_lock(cli->tree, &io);
1089 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1090 :
1091 2 : io.lockx.in.file.fnum = fnum;
1092 2 : status = smb_raw_lock(cli->tree, &io);
1093 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1094 :
1095 2 : io.lockx.in.file.fnum = fnum2;
1096 2 : status = smb_raw_lock(cli->tree, &io);
1097 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1098 :
1099 : /* demonstrate that the smbpid doesn't matter */
1100 2 : lock[0].pid++;
1101 2 : io.lockx.in.file.fnum = fnum;
1102 2 : status = smb_raw_lock(cli->tree, &io);
1103 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1104 :
1105 2 : io.lockx.in.file.fnum = fnum2;
1106 2 : status = smb_raw_lock(cli->tree, &io);
1107 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1108 2 : 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 2 : lock[0].offset = 100;
1115 2 : lock[0].count = 0;
1116 2 : io.lockx.in.file.fnum = fnum;
1117 2 : status = smb_raw_lock(cli->tree, &io);
1118 2 : CHECK_STATUS(status, NT_STATUS_OK);
1119 :
1120 2 : io.lockx.in.file.fnum = fnum2;
1121 2 : status = smb_raw_lock(cli->tree, &io);
1122 2 : CHECK_STATUS(status, NT_STATUS_OK);
1123 :
1124 2 : lock[0].offset = 100;
1125 2 : lock[0].count = 10;
1126 2 : io.lockx.in.file.fnum = fnum;
1127 2 : status = smb_raw_lock(cli->tree, &io);
1128 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1129 :
1130 2 : io.lockx.in.file.fnum = fnum2;
1131 2 : status = smb_raw_lock(cli->tree, &io);
1132 2 : 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 2 : lock[0].offset = 110;
1139 2 : lock[0].count = 0;
1140 2 : io.lockx.in.file.fnum = fnum;
1141 2 : status = smb_raw_lock(cli->tree, &io);
1142 2 : CHECK_STATUS(status, NT_STATUS_OK);
1143 :
1144 2 : io.lockx.in.file.fnum = fnum2;
1145 2 : status = smb_raw_lock(cli->tree, &io);
1146 2 : CHECK_STATUS(status, NT_STATUS_OK);
1147 :
1148 2 : lock[0].offset = 100;
1149 2 : lock[0].count = 10;
1150 2 : io.lockx.in.file.fnum = fnum;
1151 2 : status = smb_raw_lock(cli->tree, &io);
1152 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1153 :
1154 2 : io.lockx.in.file.fnum = fnum2;
1155 2 : status = smb_raw_lock(cli->tree, &io);
1156 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1157 :
1158 2 : lock[0].offset = 99;
1159 2 : lock[0].count = 0;
1160 2 : io.lockx.in.file.fnum = fnum;
1161 2 : status = smb_raw_lock(cli->tree, &io);
1162 2 : CHECK_STATUS(status, NT_STATUS_OK);
1163 :
1164 2 : io.lockx.in.file.fnum = fnum2;
1165 2 : status = smb_raw_lock(cli->tree, &io);
1166 2 : CHECK_STATUS(status, NT_STATUS_OK);
1167 :
1168 2 : lock[0].offset = 100;
1169 2 : lock[0].count = 10;
1170 2 : io.lockx.in.file.fnum = fnum;
1171 2 : status = smb_raw_lock(cli->tree, &io);
1172 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1173 :
1174 2 : io.lockx.in.file.fnum = fnum2;
1175 2 : status = smb_raw_lock(cli->tree, &io);
1176 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1177 :
1178 : /* demonstrate that a changing count doesn't reset the error cache */
1179 2 : lock[0].offset = 100;
1180 2 : lock[0].count = 5;
1181 2 : io.lockx.in.file.fnum = fnum;
1182 2 : status = smb_raw_lock(cli->tree, &io);
1183 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1184 :
1185 2 : io.lockx.in.file.fnum = fnum2;
1186 2 : status = smb_raw_lock(cli->tree, &io);
1187 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1188 :
1189 2 : lock[0].offset = 100;
1190 2 : lock[0].count = 15;
1191 2 : io.lockx.in.file.fnum = fnum;
1192 2 : status = smb_raw_lock(cli->tree, &io);
1193 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1194 :
1195 2 : io.lockx.in.file.fnum = fnum2;
1196 2 : status = smb_raw_lock(cli->tree, &io);
1197 2 : 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 2 : lock[0].offset = 101;
1204 2 : lock[0].count = 0;
1205 2 : io.lockx.in.file.fnum = fnum;
1206 2 : status = smb_raw_lock(cli->tree, &io);
1207 2 : CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1208 2 : status = smb_raw_lock(cli->tree, &io);
1209 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1210 :
1211 2 : io.lockx.in.file.fnum = fnum2;
1212 2 : status = smb_raw_lock(cli->tree, &io);
1213 2 : CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1214 2 : status = smb_raw_lock(cli->tree, &io);
1215 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1216 :
1217 2 : lock[0].offset = 100;
1218 2 : lock[0].count = 10;
1219 2 : io.lockx.in.file.fnum = fnum;
1220 2 : status = smb_raw_lock(cli->tree, &io);
1221 2 : CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1222 2 : status = smb_raw_lock(cli->tree, &io);
1223 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1224 :
1225 2 : io.lockx.in.file.fnum = fnum2;
1226 2 : status = smb_raw_lock(cli->tree, &io);
1227 2 : CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1228 2 : status = smb_raw_lock(cli->tree, &io);
1229 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1230 :
1231 : /* demonstrate the a changing offset, resets the error cache */
1232 2 : lock[0].offset = 105;
1233 2 : lock[0].count = 10;
1234 2 : io.lockx.in.file.fnum = fnum;
1235 2 : status = smb_raw_lock(cli->tree, &io);
1236 2 : CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1237 2 : status = smb_raw_lock(cli->tree, &io);
1238 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1239 :
1240 2 : io.lockx.in.file.fnum = fnum2;
1241 2 : status = smb_raw_lock(cli->tree, &io);
1242 2 : CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1243 2 : status = smb_raw_lock(cli->tree, &io);
1244 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1245 :
1246 2 : lock[0].offset = 100;
1247 2 : lock[0].count = 10;
1248 2 : io.lockx.in.file.fnum = fnum;
1249 2 : status = smb_raw_lock(cli->tree, &io);
1250 2 : CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1251 2 : status = smb_raw_lock(cli->tree, &io);
1252 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1253 :
1254 2 : io.lockx.in.file.fnum = fnum2;
1255 2 : status = smb_raw_lock(cli->tree, &io);
1256 2 : CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1257 2 : status = smb_raw_lock(cli->tree, &io);
1258 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1259 :
1260 2 : lock[0].offset = 95;
1261 2 : lock[0].count = 9;
1262 2 : io.lockx.in.file.fnum = fnum;
1263 2 : status = smb_raw_lock(cli->tree, &io);
1264 2 : CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1265 2 : status = smb_raw_lock(cli->tree, &io);
1266 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1267 :
1268 2 : io.lockx.in.file.fnum = fnum2;
1269 2 : status = smb_raw_lock(cli->tree, &io);
1270 2 : CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1271 2 : status = smb_raw_lock(cli->tree, &io);
1272 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1273 :
1274 2 : lock[0].offset = 100;
1275 2 : lock[0].count = 10;
1276 2 : io.lockx.in.file.fnum = fnum;
1277 2 : status = smb_raw_lock(cli->tree, &io);
1278 2 : CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1279 2 : status = smb_raw_lock(cli->tree, &io);
1280 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1281 :
1282 2 : io.lockx.in.file.fnum = fnum2;
1283 2 : status = smb_raw_lock(cli->tree, &io);
1284 2 : CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1285 2 : status = smb_raw_lock(cli->tree, &io);
1286 2 : 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 2 : lock[0].offset = 120;
1294 2 : lock[0].count = 15;
1295 2 : io.lockx.in.file.fnum = fnum;
1296 2 : status = smb_raw_lock(cli->tree, &io);
1297 2 : CHECK_STATUS(status, NT_STATUS_OK);
1298 :
1299 2 : io.lockx.in.file.fnum = fnum2;
1300 2 : status = smb_raw_lock(cli->tree, &io);
1301 2 : CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1302 :
1303 2 : lock[0].offset = 100;
1304 2 : lock[0].count = 10;
1305 2 : io.lockx.in.file.fnum = fnum;
1306 2 : status = smb_raw_lock(cli->tree, &io);
1307 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1308 2 : status = smb_raw_lock(cli->tree, &io);
1309 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1310 :
1311 2 : io.lockx.in.file.fnum = fnum2;
1312 2 : status = smb_raw_lock(cli->tree, &io);
1313 2 : CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
1314 2 : status = smb_raw_lock(cli->tree, &io);
1315 2 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1316 :
1317 : /* end of the loop */
1318 2 : if (t == 0) {
1319 1 : smb_raw_exit(cli->session);
1320 1 : t = 1;
1321 1 : torture_comment(tctx, "Testing with timeout > 0 (=%d)\n",
1322 : t);
1323 1 : fname = BASEDIR "\\test1.txt";
1324 1 : goto next_run;
1325 : }
1326 :
1327 1 : t = 4000;
1328 1 : 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 1 : smb_raw_exit(cli->session);
1337 1 : torture_comment(tctx, "Testing a conflict while a lock is pending\n");
1338 1 : fname = BASEDIR "\\test2.txt";
1339 1 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1340 1 : torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1341 : "Failed to reopen %s - %s\n",
1342 : fname, smbcli_errstr(cli->tree)));
1343 :
1344 1 : io.lockx.level = RAW_LOCK_LOCKX;
1345 1 : io.lockx.in.file.fnum = fnum;
1346 1 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1347 1 : io.lockx.in.timeout = 0;
1348 1 : io.lockx.in.ulock_cnt = 0;
1349 1 : io.lockx.in.lock_cnt = 1;
1350 1 : lock[0].pid = cli->session->pid;
1351 1 : lock[0].offset = 100;
1352 1 : lock[0].count = 10;
1353 1 : io.lockx.in.locks = &lock[0];
1354 1 : status = smb_raw_lock(cli->tree, &io);
1355 1 : CHECK_STATUS(status, NT_STATUS_OK);
1356 :
1357 1 : start = time_mono(NULL);
1358 1 : io.lockx.in.timeout = t;
1359 1 : req = smb_raw_lock_send(cli->tree, &io);
1360 1 : torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1361 : "Failed to setup timed lock (%s)\n", __location__));
1362 :
1363 1 : io.lockx.in.timeout = 0;
1364 1 : lock[0].offset = 105;
1365 1 : lock[0].count = 10;
1366 1 : status = smb_raw_lock(cli->tree, &io);
1367 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1368 :
1369 1 : status = smbcli_request_simple_recv(req);
1370 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1371 :
1372 1 : delay = t / 1000;
1373 1 : if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1374 0 : delay /= 2;
1375 : }
1376 :
1377 1 : 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 1 : status = smb_raw_lock(cli->tree, &io);
1382 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1383 :
1384 1 : smbcli_close(cli->tree, fnum);
1385 1 : fname = BASEDIR "\\test3.txt";
1386 1 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1387 1 : torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1388 : "Failed to reopen %s - %s\n",
1389 : fname, smbcli_errstr(cli->tree)));
1390 :
1391 1 : io.lockx.level = RAW_LOCK_LOCKX;
1392 1 : io.lockx.in.file.fnum = fnum;
1393 1 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1394 1 : io.lockx.in.timeout = 0;
1395 1 : io.lockx.in.ulock_cnt = 0;
1396 1 : io.lockx.in.lock_cnt = 1;
1397 1 : lock[0].pid = cli->session->pid;
1398 1 : lock[0].offset = 100;
1399 1 : lock[0].count = 10;
1400 1 : io.lockx.in.locks = &lock[0];
1401 1 : status = smb_raw_lock(cli->tree, &io);
1402 1 : CHECK_STATUS(status, NT_STATUS_OK);
1403 :
1404 1 : start = time_mono(NULL);
1405 1 : io.lockx.in.timeout = t;
1406 1 : req = smb_raw_lock_send(cli->tree, &io);
1407 1 : torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1408 : "Failed to setup timed lock (%s)\n", __location__));
1409 :
1410 1 : io.lockx.in.timeout = 0;
1411 1 : lock[0].offset = 105;
1412 1 : lock[0].count = 10;
1413 1 : status = smb_raw_lock(cli->tree, &io);
1414 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1415 :
1416 1 : status = smbcli_request_simple_recv(req);
1417 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1418 :
1419 1 : delay = t / 1000;
1420 1 : if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1421 0 : delay /= 2;
1422 : }
1423 :
1424 1 : 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 1 : lock[0].offset = 100;
1429 1 : lock[0].count = 10;
1430 1 : status = smb_raw_lock(cli->tree, &io);
1431 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1432 :
1433 1 : smbcli_close(cli->tree, fnum);
1434 1 : fname = BASEDIR "\\test4.txt";
1435 1 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1436 1 : torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1437 : "Failed to reopen %s - %s\n",
1438 : fname, smbcli_errstr(cli->tree)));
1439 :
1440 1 : io.lockx.level = RAW_LOCK_LOCKX;
1441 1 : io.lockx.in.file.fnum = fnum;
1442 1 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
1443 1 : io.lockx.in.timeout = 0;
1444 1 : io.lockx.in.ulock_cnt = 0;
1445 1 : io.lockx.in.lock_cnt = 1;
1446 1 : lock[0].pid = cli->session->pid;
1447 1 : lock[0].offset = 100;
1448 1 : lock[0].count = 10;
1449 1 : io.lockx.in.locks = &lock[0];
1450 1 : status = smb_raw_lock(cli->tree, &io);
1451 1 : CHECK_STATUS(status, NT_STATUS_OK);
1452 :
1453 1 : start = time_mono(NULL);
1454 1 : io.lockx.in.timeout = t;
1455 1 : req = smb_raw_lock_send(cli->tree, &io);
1456 1 : torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
1457 : "Failed to setup timed lock (%s)\n", __location__));
1458 :
1459 1 : io.lockx.in.timeout = 0;
1460 1 : status = smb_raw_lock(cli->tree, &io);
1461 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1462 :
1463 1 : status = smbcli_request_simple_recv(req);
1464 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1465 :
1466 1 : delay = t / 1000;
1467 1 : if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
1468 0 : delay /= 2;
1469 : }
1470 :
1471 1 : 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 1 : status = smb_raw_lock(cli->tree, &io);
1476 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1477 :
1478 2 : done:
1479 1 : smb_raw_exit(cli->session);
1480 1 : smbcli_deltree(cli->tree, BASEDIR);
1481 1 : return ret;
1482 : }
1483 :
1484 :
1485 : /*
1486 : test LOCKING_ANDX_CHANGE_LOCKTYPE
1487 : */
1488 1 : 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 1 : bool ret = true;
1495 : int fnum;
1496 1 : uint8_t c = 0;
1497 1 : const char *fname = BASEDIR "\\test.txt";
1498 :
1499 1 : torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1500 :
1501 1 : torture_comment(tctx, "Testing LOCKING_ANDX_CHANGE_LOCKTYPE\n");
1502 1 : io.generic.level = RAW_LOCK_LOCKX;
1503 :
1504 1 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1505 1 : torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
1506 : "Failed to create %s - %s\n",
1507 : fname, smbcli_errstr(cli->tree)));
1508 :
1509 1 : io.lockx.level = RAW_LOCK_LOCKX;
1510 1 : io.lockx.in.file.fnum = fnum;
1511 1 : io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1512 1 : io.lockx.in.timeout = 0;
1513 1 : io.lockx.in.ulock_cnt = 0;
1514 1 : io.lockx.in.lock_cnt = 1;
1515 1 : lock[0].pid = cli->session->pid;
1516 1 : lock[0].offset = 100;
1517 1 : lock[0].count = 10;
1518 1 : io.lockx.in.locks = &lock[0];
1519 1 : status = smb_raw_lock(cli->tree, &io);
1520 1 : CHECK_STATUS(status, NT_STATUS_OK);
1521 :
1522 1 : if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1523 0 : torture_result(tctx, TORTURE_FAIL,
1524 : "allowed write on read locked region (%s)\n", __location__);
1525 0 : ret = false;
1526 0 : goto done;
1527 : }
1528 :
1529 : /* windows server don't seem to support this */
1530 1 : io.lockx.in.mode = LOCKING_ANDX_CHANGE_LOCKTYPE;
1531 1 : status = smb_raw_lock(cli->tree, &io);
1532 1 : CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
1533 :
1534 1 : if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
1535 0 : torture_result(tctx, TORTURE_FAIL,
1536 : "allowed write after lock change (%s)\n", __location__);
1537 0 : ret = false;
1538 0 : goto done;
1539 : }
1540 :
1541 2 : done:
1542 1 : smbcli_close(cli->tree, fnum);
1543 1 : smb_raw_exit(cli->session);
1544 1 : smbcli_deltree(cli->tree, BASEDIR);
1545 1 : 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 1 : static bool test_zerobytelocks(struct torture_context *tctx, struct smbcli_state *cli)
1589 : {
1590 : union smb_lock io;
1591 : NTSTATUS status;
1592 1 : bool ret = true;
1593 : int fnum, i;
1594 1 : const char *fname = BASEDIR "\\zero.txt";
1595 :
1596 1 : torture_comment(tctx, "Testing zero length byte range locks:\n");
1597 :
1598 1 : torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1599 :
1600 1 : io.generic.level = RAW_LOCK_LOCKX;
1601 :
1602 1 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1603 1 : 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 1 : io.lockx.level = RAW_LOCK_LOCKX;
1609 1 : io.lockx.in.file.fnum = fnum;
1610 1 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; /* Exclusive */
1611 1 : 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 17 : for (i = 0;
1617 16 : i < ARRAY_SIZE(zero_byte_tests);
1618 15 : i++) {
1619 45 : torture_comment(tctx, " ... {%d, %llu, %llu} + {%d, %llu, %llu} = %s\n",
1620 : zero_byte_tests[i].lock1.pid,
1621 15 : (unsigned long long) zero_byte_tests[i].lock1.offset,
1622 15 : (unsigned long long) zero_byte_tests[i].lock1.count,
1623 : zero_byte_tests[i].lock2.pid,
1624 15 : (unsigned long long) zero_byte_tests[i].lock2.offset,
1625 15 : (unsigned long long) zero_byte_tests[i].lock2.count,
1626 : nt_errstr(zero_byte_tests[i].exp_status));
1627 :
1628 : /* Lock both locks. */
1629 15 : io.lockx.in.ulock_cnt = 0;
1630 15 : io.lockx.in.lock_cnt = 1;
1631 :
1632 15 : io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1633 : &zero_byte_tests[i].lock1);
1634 15 : status = smb_raw_lock(cli->tree, &io);
1635 15 : CHECK_STATUS(status, NT_STATUS_OK);
1636 :
1637 15 : io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1638 : &zero_byte_tests[i].lock2);
1639 15 : status = smb_raw_lock(cli->tree, &io);
1640 :
1641 15 : 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 4 : CHECK_STATUS_OR_CONT(status,
1646 : NT_STATUS_LOCK_NOT_GRANTED,
1647 : NT_STATUS_FILE_LOCK_CONFLICT);
1648 :
1649 : } else {
1650 11 : CHECK_STATUS_CONT(status,
1651 : zero_byte_tests[i].exp_status);
1652 : }
1653 :
1654 : /* Unlock both locks. */
1655 15 : io.lockx.in.ulock_cnt = 1;
1656 15 : io.lockx.in.lock_cnt = 0;
1657 :
1658 15 : if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
1659 11 : status = smb_raw_lock(cli->tree, &io);
1660 11 : CHECK_STATUS(status, NT_STATUS_OK);
1661 : }
1662 :
1663 15 : io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
1664 : &zero_byte_tests[i].lock1);
1665 15 : status = smb_raw_lock(cli->tree, &io);
1666 15 : CHECK_STATUS(status, NT_STATUS_OK);
1667 : }
1668 :
1669 1 : done:
1670 1 : smbcli_close(cli->tree, fnum);
1671 1 : smb_raw_exit(cli->session);
1672 1 : smbcli_deltree(cli->tree, BASEDIR);
1673 1 : return ret;
1674 : }
1675 :
1676 1 : static bool test_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1677 : {
1678 : union smb_lock io;
1679 : NTSTATUS status;
1680 1 : bool ret = true;
1681 : int fnum1, fnum2;
1682 1 : const char *fname = BASEDIR "\\unlock.txt";
1683 : struct smb_lock_entry lock1;
1684 : struct smb_lock_entry lock2;
1685 :
1686 1 : torture_comment(tctx, "Testing LOCKX unlock:\n");
1687 :
1688 1 : torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1689 :
1690 1 : fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1691 1 : torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
1692 : "Failed to create %s - %s\n",
1693 : fname, smbcli_errstr(cli->tree)));
1694 :
1695 1 : fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1696 1 : 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 1 : io.lockx.level = RAW_LOCK_LOCKX;
1702 1 : io.lockx.in.timeout = 0;
1703 :
1704 1 : lock1.pid = cli->session->pid;
1705 1 : lock1.offset = 0;
1706 1 : lock1.count = 10;
1707 1 : lock2.pid = cli->session->pid - 1;
1708 1 : lock2.offset = 0;
1709 1 : lock2.count = 10;
1710 :
1711 : /**
1712 : * Take exclusive lock, then unlock it with a shared-unlock call.
1713 : */
1714 1 : torture_comment(tctx, " taking exclusive lock.\n");
1715 1 : io.lockx.in.ulock_cnt = 0;
1716 1 : io.lockx.in.lock_cnt = 1;
1717 1 : io.lockx.in.mode = 0;
1718 1 : io.lockx.in.file.fnum = fnum1;
1719 1 : io.lockx.in.locks = &lock1;
1720 1 : status = smb_raw_lock(cli->tree, &io);
1721 1 : CHECK_STATUS(status, NT_STATUS_OK);
1722 :
1723 1 : torture_comment(tctx, " unlock the exclusive with a shared unlock call.\n");
1724 1 : io.lockx.in.ulock_cnt = 1;
1725 1 : io.lockx.in.lock_cnt = 0;
1726 1 : io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1727 1 : io.lockx.in.file.fnum = fnum1;
1728 1 : io.lockx.in.locks = &lock1;
1729 1 : status = smb_raw_lock(cli->tree, &io);
1730 1 : CHECK_STATUS(status, NT_STATUS_OK);
1731 :
1732 1 : torture_comment(tctx, " try shared lock on pid2/fnum2, testing the unlock.\n");
1733 1 : io.lockx.in.ulock_cnt = 0;
1734 1 : io.lockx.in.lock_cnt = 1;
1735 1 : io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1736 1 : io.lockx.in.file.fnum = fnum2;
1737 1 : io.lockx.in.locks = &lock2;
1738 1 : status = smb_raw_lock(cli->tree, &io);
1739 1 : CHECK_STATUS(status, NT_STATUS_OK);
1740 :
1741 : /**
1742 : * Unlock a shared lock with an exclusive-unlock call.
1743 : */
1744 1 : torture_comment(tctx, " unlock new shared lock with exclusive unlock call.\n");
1745 1 : io.lockx.in.ulock_cnt = 1;
1746 1 : io.lockx.in.lock_cnt = 0;
1747 1 : io.lockx.in.mode = 0;
1748 1 : io.lockx.in.file.fnum = fnum2;
1749 1 : io.lockx.in.locks = &lock2;
1750 1 : status = smb_raw_lock(cli->tree, &io);
1751 1 : CHECK_STATUS(status, NT_STATUS_OK);
1752 :
1753 1 : torture_comment(tctx, " try exclusive lock on pid1, testing the unlock.\n");
1754 1 : io.lockx.in.ulock_cnt = 0;
1755 1 : io.lockx.in.lock_cnt = 1;
1756 1 : io.lockx.in.mode = 0;
1757 1 : io.lockx.in.file.fnum = fnum1;
1758 1 : io.lockx.in.locks = &lock1;
1759 1 : status = smb_raw_lock(cli->tree, &io);
1760 1 : CHECK_STATUS(status, NT_STATUS_OK);
1761 :
1762 : /* cleanup */
1763 1 : io.lockx.in.ulock_cnt = 1;
1764 1 : io.lockx.in.lock_cnt = 0;
1765 1 : status = smb_raw_lock(cli->tree, &io);
1766 1 : CHECK_STATUS(status, NT_STATUS_OK);
1767 :
1768 : /**
1769 : * Test unlocking of 0-byte locks.
1770 : */
1771 :
1772 1 : torture_comment(tctx, " lock shared and exclusive 0-byte locks, testing that Windows "
1773 : "always unlocks the exclusive first.\n");
1774 1 : lock1.pid = cli->session->pid;
1775 1 : lock1.offset = 10;
1776 1 : lock1.count = 0;
1777 1 : lock2.pid = cli->session->pid;
1778 1 : lock2.offset = 5;
1779 1 : lock2.count = 10;
1780 1 : io.lockx.in.ulock_cnt = 0;
1781 1 : io.lockx.in.lock_cnt = 1;
1782 1 : io.lockx.in.file.fnum = fnum1;
1783 1 : io.lockx.in.locks = &lock1;
1784 :
1785 : /* lock 0-byte shared
1786 : * Note: Order of the shared/exclusive locks doesn't matter. */
1787 1 : io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1788 1 : status = smb_raw_lock(cli->tree, &io);
1789 1 : CHECK_STATUS(status, NT_STATUS_OK);
1790 :
1791 : /* lock 0-byte exclusive */
1792 1 : io.lockx.in.mode = 0;
1793 1 : status = smb_raw_lock(cli->tree, &io);
1794 1 : CHECK_STATUS(status, NT_STATUS_OK);
1795 :
1796 : /* test contention */
1797 1 : io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1798 1 : io.lockx.in.locks = &lock2;
1799 1 : io.lockx.in.file.fnum = fnum2;
1800 1 : status = smb_raw_lock(cli->tree, &io);
1801 1 : CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1802 : NT_STATUS_FILE_LOCK_CONFLICT);
1803 :
1804 : /* unlock */
1805 1 : io.lockx.in.ulock_cnt = 1;
1806 1 : io.lockx.in.lock_cnt = 0;
1807 1 : io.lockx.in.file.fnum = fnum1;
1808 1 : io.lockx.in.locks = &lock1;
1809 1 : status = smb_raw_lock(cli->tree, &io);
1810 1 : CHECK_STATUS(status, NT_STATUS_OK);
1811 :
1812 : /* test - can we take a shared lock? */
1813 1 : io.lockx.in.ulock_cnt = 0;
1814 1 : io.lockx.in.lock_cnt = 1;
1815 1 : io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
1816 1 : io.lockx.in.file.fnum = fnum2;
1817 1 : io.lockx.in.locks = &lock2;
1818 1 : 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 1 : if (TARGET_IS_SAMBA3(tctx)) {
1826 0 : CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
1827 : NT_STATUS_FILE_LOCK_CONFLICT);
1828 : } else {
1829 1 : CHECK_STATUS(status, NT_STATUS_OK);
1830 : }
1831 :
1832 : /* cleanup */
1833 1 : io.lockx.in.ulock_cnt = 1;
1834 1 : io.lockx.in.lock_cnt = 0;
1835 1 : status = smb_raw_lock(cli->tree, &io);
1836 :
1837 : /* XXX Same as above. */
1838 1 : if (TARGET_IS_SAMBA3(tctx)) {
1839 0 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1840 : } else {
1841 1 : CHECK_STATUS(status, NT_STATUS_OK);
1842 : }
1843 :
1844 1 : io.lockx.in.file.fnum = fnum1;
1845 1 : io.lockx.in.locks = &lock1;
1846 1 : status = smb_raw_lock(cli->tree, &io);
1847 1 : CHECK_STATUS(status, NT_STATUS_OK);
1848 :
1849 2 : done:
1850 1 : smbcli_close(cli->tree, fnum1);
1851 1 : smbcli_close(cli->tree, fnum2);
1852 1 : smb_raw_exit(cli->session);
1853 1 : smbcli_deltree(cli->tree, BASEDIR);
1854 1 : return ret;
1855 : }
1856 :
1857 1 : static bool test_multiple_unlock(struct torture_context *tctx, struct smbcli_state *cli)
1858 : {
1859 : union smb_lock io;
1860 : NTSTATUS status;
1861 1 : bool ret = true;
1862 : int fnum1;
1863 1 : 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 1 : torture_comment(tctx, "Testing LOCKX multiple unlock:\n");
1869 :
1870 1 : torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1871 :
1872 1 : fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1873 1 : 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 1 : io.lockx.level = RAW_LOCK_LOCKX;
1879 1 : io.lockx.in.timeout = 0;
1880 :
1881 1 : lock1.pid = cli->session->pid;
1882 1 : lock1.offset = 0;
1883 1 : lock1.count = 10;
1884 1 : lock2.pid = cli->session->pid;
1885 1 : lock2.offset = 10;
1886 1 : lock2.count = 10;
1887 :
1888 1 : locks[0] = lock1;
1889 1 : locks[1] = lock2;
1890 :
1891 1 : io.lockx.in.file.fnum = fnum1;
1892 1 : io.lockx.in.mode = 0; /* exclusive */
1893 :
1894 : /** Test1: Take second lock, but not first. */
1895 1 : torture_comment(tctx, " unlock 2 locks, first one not locked. Expect no locks "
1896 : "unlocked. \n");
1897 :
1898 1 : io.lockx.in.ulock_cnt = 0;
1899 1 : io.lockx.in.lock_cnt = 1;
1900 1 : io.lockx.in.locks = &lock2;
1901 1 : status = smb_raw_lock(cli->tree, &io);
1902 1 : CHECK_STATUS(status, NT_STATUS_OK);
1903 :
1904 : /* Try to unlock both locks. */
1905 1 : io.lockx.in.ulock_cnt = 2;
1906 1 : io.lockx.in.lock_cnt = 0;
1907 1 : io.lockx.in.locks = locks;
1908 :
1909 1 : status = smb_raw_lock(cli->tree, &io);
1910 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1911 :
1912 : /* Second lock should not be unlocked. */
1913 1 : io.lockx.in.ulock_cnt = 0;
1914 1 : io.lockx.in.lock_cnt = 1;
1915 1 : io.lockx.in.locks = &lock2;
1916 1 : status = smb_raw_lock(cli->tree, &io);
1917 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
1918 :
1919 : /* cleanup */
1920 1 : io.lockx.in.ulock_cnt = 1;
1921 1 : io.lockx.in.lock_cnt = 0;
1922 1 : io.lockx.in.locks = &lock2;
1923 1 : status = smb_raw_lock(cli->tree, &io);
1924 1 : CHECK_STATUS(status, NT_STATUS_OK);
1925 :
1926 : /** Test2: Take first lock, but not second. */
1927 1 : torture_comment(tctx, " unlock 2 locks, second one not locked. Expect first lock "
1928 : "unlocked.\n");
1929 :
1930 1 : io.lockx.in.ulock_cnt = 0;
1931 1 : io.lockx.in.lock_cnt = 1;
1932 1 : io.lockx.in.locks = &lock1;
1933 1 : status = smb_raw_lock(cli->tree, &io);
1934 1 : CHECK_STATUS(status, NT_STATUS_OK);
1935 :
1936 : /* Try to unlock both locks. */
1937 1 : io.lockx.in.ulock_cnt = 2;
1938 1 : io.lockx.in.lock_cnt = 0;
1939 1 : io.lockx.in.locks = locks;
1940 :
1941 1 : status = smb_raw_lock(cli->tree, &io);
1942 1 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
1943 :
1944 : /* First lock should be unlocked. */
1945 1 : io.lockx.in.ulock_cnt = 0;
1946 1 : io.lockx.in.lock_cnt = 1;
1947 1 : io.lockx.in.locks = &lock1;
1948 1 : status = smb_raw_lock(cli->tree, &io);
1949 1 : CHECK_STATUS(status, NT_STATUS_OK);
1950 :
1951 : /* cleanup */
1952 1 : io.lockx.in.ulock_cnt = 1;
1953 1 : io.lockx.in.lock_cnt = 0;
1954 1 : io.lockx.in.locks = &lock1;
1955 1 : status = smb_raw_lock(cli->tree, &io);
1956 1 : CHECK_STATUS(status, NT_STATUS_OK);
1957 :
1958 : /* Test3: Request 2 locks, second will contend. What happens to the
1959 : * first? */
1960 1 : torture_comment(tctx, " request 2 locks, second one will contend. "
1961 : "Expect both to fail.\n");
1962 :
1963 : /* Lock the second range */
1964 1 : io.lockx.in.ulock_cnt = 0;
1965 1 : io.lockx.in.lock_cnt = 1;
1966 1 : io.lockx.in.locks = &lock2;
1967 1 : status = smb_raw_lock(cli->tree, &io);
1968 1 : CHECK_STATUS(status, NT_STATUS_OK);
1969 :
1970 : /* Request both locks */
1971 1 : io.lockx.in.ulock_cnt = 0;
1972 1 : io.lockx.in.lock_cnt = 2;
1973 1 : io.lockx.in.locks = locks;
1974 :
1975 1 : status = smb_raw_lock(cli->tree, &io);
1976 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
1977 :
1978 : /* First lock should be unlocked. */
1979 1 : io.lockx.in.ulock_cnt = 0;
1980 1 : io.lockx.in.lock_cnt = 1;
1981 1 : io.lockx.in.locks = &lock1;
1982 1 : status = smb_raw_lock(cli->tree, &io);
1983 1 : CHECK_STATUS(status, NT_STATUS_OK);
1984 :
1985 : /* cleanup */
1986 1 : io.lockx.in.ulock_cnt = 2;
1987 1 : io.lockx.in.lock_cnt = 0;
1988 1 : io.lockx.in.locks = locks;
1989 1 : status = smb_raw_lock(cli->tree, &io);
1990 1 : CHECK_STATUS(status, NT_STATUS_OK);
1991 :
1992 : /* Test4: Request unlock and lock. The lock contends, is the unlock
1993 : * then re-locked? */
1994 1 : torture_comment(tctx, " request unlock and lock, second one will "
1995 : "contend. Expect the unlock to succeed.\n");
1996 :
1997 : /* Lock both ranges */
1998 1 : io.lockx.in.ulock_cnt = 0;
1999 1 : io.lockx.in.lock_cnt = 2;
2000 1 : io.lockx.in.locks = locks;
2001 1 : status = smb_raw_lock(cli->tree, &io);
2002 1 : CHECK_STATUS(status, NT_STATUS_OK);
2003 :
2004 : /* Attempt to unlock the first range and lock the second */
2005 1 : io.lockx.in.ulock_cnt = 1;
2006 1 : io.lockx.in.lock_cnt = 1;
2007 1 : io.lockx.in.locks = locks;
2008 1 : status = smb_raw_lock(cli->tree, &io);
2009 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2010 :
2011 : /* The first lock should've been unlocked */
2012 1 : io.lockx.in.ulock_cnt = 0;
2013 1 : io.lockx.in.lock_cnt = 1;
2014 1 : io.lockx.in.locks = &lock1;
2015 1 : status = smb_raw_lock(cli->tree, &io);
2016 1 : CHECK_STATUS(status, NT_STATUS_OK);
2017 :
2018 : /* cleanup */
2019 1 : io.lockx.in.ulock_cnt = 2;
2020 1 : io.lockx.in.lock_cnt = 0;
2021 1 : io.lockx.in.locks = locks;
2022 1 : status = smb_raw_lock(cli->tree, &io);
2023 1 : CHECK_STATUS(status, NT_STATUS_OK);
2024 :
2025 2 : done:
2026 1 : smbcli_close(cli->tree, fnum1);
2027 1 : smb_raw_exit(cli->session);
2028 1 : smbcli_deltree(cli->tree, BASEDIR);
2029 1 : 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 1 : static bool test_stacking(struct torture_context *tctx, struct smbcli_state *cli)
2038 : {
2039 : union smb_lock io;
2040 : NTSTATUS status;
2041 1 : bool ret = true;
2042 : int fnum1;
2043 1 : const char *fname = BASEDIR "\\stacking.txt";
2044 : struct smb_lock_entry lock1;
2045 :
2046 1 : torture_comment(tctx, "Testing stacking:\n");
2047 :
2048 1 : torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2049 :
2050 1 : io.generic.level = RAW_LOCK_LOCKX;
2051 :
2052 1 : fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2053 1 : 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 1 : io.lockx.level = RAW_LOCK_LOCKX;
2059 1 : io.lockx.in.timeout = 0;
2060 :
2061 1 : lock1.pid = cli->session->pid;
2062 1 : lock1.offset = 0;
2063 1 : lock1.count = 10;
2064 :
2065 : /**
2066 : * Try to take a shared lock, then stack an exclusive.
2067 : */
2068 1 : torture_comment(tctx, " stacking an exclusive on top of a shared lock fails.\n");
2069 1 : io.lockx.in.file.fnum = fnum1;
2070 1 : io.lockx.in.locks = &lock1;
2071 :
2072 1 : io.lockx.in.ulock_cnt = 0;
2073 1 : io.lockx.in.lock_cnt = 1;
2074 1 : io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
2075 1 : status = smb_raw_lock(cli->tree, &io);
2076 1 : CHECK_STATUS(status, NT_STATUS_OK);
2077 :
2078 1 : io.lockx.in.ulock_cnt = 0;
2079 1 : io.lockx.in.lock_cnt = 1;
2080 1 : io.lockx.in.mode = 0;
2081 1 : status = smb_raw_lock(cli->tree, &io);
2082 1 : CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
2083 : NT_STATUS_FILE_LOCK_CONFLICT);
2084 :
2085 : /* cleanup */
2086 1 : io.lockx.in.ulock_cnt = 1;
2087 1 : io.lockx.in.lock_cnt = 0;
2088 1 : status = smb_raw_lock(cli->tree, &io);
2089 1 : CHECK_STATUS(status, NT_STATUS_OK);
2090 :
2091 : /**
2092 : * Prove that two exclusive locks do not stack.
2093 : */
2094 1 : torture_comment(tctx, " two exclusive locks do not stack.\n");
2095 1 : io.lockx.in.ulock_cnt = 0;
2096 1 : io.lockx.in.lock_cnt = 1;
2097 1 : io.lockx.in.mode = 0;
2098 1 : status = smb_raw_lock(cli->tree, &io);
2099 1 : CHECK_STATUS(status, NT_STATUS_OK);
2100 1 : status = smb_raw_lock(cli->tree, &io);
2101 1 : CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
2102 : NT_STATUS_FILE_LOCK_CONFLICT);
2103 :
2104 : /* cleanup */
2105 1 : io.lockx.in.ulock_cnt = 1;
2106 1 : io.lockx.in.lock_cnt = 0;
2107 1 : status = smb_raw_lock(cli->tree, &io);
2108 1 : CHECK_STATUS(status, NT_STATUS_OK);
2109 :
2110 2 : done:
2111 1 : smbcli_close(cli->tree, fnum1);
2112 1 : smb_raw_exit(cli->session);
2113 1 : smbcli_deltree(cli->tree, BASEDIR);
2114 1 : return ret;
2115 : }
2116 :
2117 : /**
2118 : * Test how 0-byte read requests contend with byte range locks
2119 : */
2120 1 : 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 1 : bool ret = true;
2127 : int fnum1, fnum2;
2128 1 : const char *fname = BASEDIR "\\zerobyteread.txt";
2129 : struct smb_lock_entry lock1;
2130 1 : uint8_t c = 1;
2131 :
2132 1 : torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2133 :
2134 1 : io.generic.level = RAW_LOCK_LOCKX;
2135 :
2136 1 : fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2137 1 : torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
2138 : "Failed to create %s - %s\n",
2139 : fname, smbcli_errstr(cli->tree)));
2140 :
2141 1 : fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2142 1 : 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 1 : io.lockx.level = RAW_LOCK_LOCKX;
2148 1 : io.lockx.in.timeout = 0;
2149 :
2150 1 : lock1.pid = cli->session->pid;
2151 1 : lock1.offset = 0;
2152 1 : lock1.count = 10;
2153 :
2154 1 : ZERO_STRUCT(rd);
2155 1 : rd.readx.level = RAW_READ_READX;
2156 :
2157 1 : torture_comment(tctx, "Testing zero byte read on lock range:\n");
2158 :
2159 : /* Take an exclusive lock */
2160 1 : torture_comment(tctx, " taking exclusive lock.\n");
2161 1 : io.lockx.in.ulock_cnt = 0;
2162 1 : io.lockx.in.lock_cnt = 1;
2163 1 : io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2164 1 : io.lockx.in.file.fnum = fnum1;
2165 1 : io.lockx.in.locks = &lock1;
2166 1 : status = smb_raw_lock(cli->tree, &io);
2167 1 : CHECK_STATUS(status, NT_STATUS_OK);
2168 :
2169 : /* Try a zero byte read */
2170 1 : torture_comment(tctx, " reading 0 bytes.\n");
2171 1 : rd.readx.in.file.fnum = fnum2;
2172 1 : rd.readx.in.offset = 5;
2173 1 : rd.readx.in.mincnt = 0;
2174 1 : rd.readx.in.maxcnt = 0;
2175 1 : rd.readx.in.remaining = 0;
2176 1 : rd.readx.in.read_for_execute = false;
2177 1 : rd.readx.out.data = &c;
2178 1 : status = smb_raw_read(cli->tree, &rd);
2179 1 : torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2180 : "zero byte read did not return 0 bytes");
2181 1 : CHECK_STATUS(status, NT_STATUS_OK);
2182 :
2183 : /* Unlock lock */
2184 0 : io.lockx.in.ulock_cnt = 1;
2185 0 : io.lockx.in.lock_cnt = 0;
2186 0 : io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2187 0 : io.lockx.in.file.fnum = fnum1;
2188 0 : io.lockx.in.locks = &lock1;
2189 0 : status = smb_raw_lock(cli->tree, &io);
2190 0 : CHECK_STATUS(status, NT_STATUS_OK);
2191 :
2192 0 : torture_comment(tctx, "Testing zero byte read on zero byte lock "
2193 : "range:\n");
2194 :
2195 : /* Take an exclusive lock */
2196 0 : torture_comment(tctx, " taking exclusive 0-byte lock.\n");
2197 0 : io.lockx.in.ulock_cnt = 0;
2198 0 : io.lockx.in.lock_cnt = 1;
2199 0 : io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2200 0 : io.lockx.in.file.fnum = fnum1;
2201 0 : io.lockx.in.locks = &lock1;
2202 0 : lock1.offset = 5;
2203 0 : lock1.count = 0;
2204 0 : status = smb_raw_lock(cli->tree, &io);
2205 0 : CHECK_STATUS(status, NT_STATUS_OK);
2206 :
2207 : /* Try a zero byte read before the lock */
2208 0 : torture_comment(tctx, " reading 0 bytes before the lock.\n");
2209 0 : rd.readx.in.file.fnum = fnum2;
2210 0 : rd.readx.in.offset = 4;
2211 0 : rd.readx.in.mincnt = 0;
2212 0 : rd.readx.in.maxcnt = 0;
2213 0 : rd.readx.in.remaining = 0;
2214 0 : rd.readx.in.read_for_execute = false;
2215 0 : rd.readx.out.data = &c;
2216 0 : status = smb_raw_read(cli->tree, &rd);
2217 0 : torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2218 : "zero byte read did not return 0 bytes");
2219 0 : CHECK_STATUS(status, NT_STATUS_OK);
2220 :
2221 : /* Try a zero byte read on the lock */
2222 0 : torture_comment(tctx, " reading 0 bytes on the lock.\n");
2223 0 : rd.readx.in.file.fnum = fnum2;
2224 0 : rd.readx.in.offset = 5;
2225 0 : rd.readx.in.mincnt = 0;
2226 0 : rd.readx.in.maxcnt = 0;
2227 0 : rd.readx.in.remaining = 0;
2228 0 : rd.readx.in.read_for_execute = false;
2229 0 : rd.readx.out.data = &c;
2230 0 : status = smb_raw_read(cli->tree, &rd);
2231 0 : torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2232 : "zero byte read did not return 0 bytes");
2233 0 : CHECK_STATUS(status, NT_STATUS_OK);
2234 :
2235 : /* Try a zero byte read after the lock */
2236 0 : torture_comment(tctx, " reading 0 bytes after the lock.\n");
2237 0 : rd.readx.in.file.fnum = fnum2;
2238 0 : rd.readx.in.offset = 6;
2239 0 : rd.readx.in.mincnt = 0;
2240 0 : rd.readx.in.maxcnt = 0;
2241 0 : rd.readx.in.remaining = 0;
2242 0 : rd.readx.in.read_for_execute = false;
2243 0 : rd.readx.out.data = &c;
2244 0 : status = smb_raw_read(cli->tree, &rd);
2245 0 : torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
2246 : "zero byte read did not return 0 bytes");
2247 0 : CHECK_STATUS(status, NT_STATUS_OK);
2248 :
2249 : /* Unlock lock */
2250 0 : io.lockx.in.ulock_cnt = 1;
2251 0 : io.lockx.in.lock_cnt = 0;
2252 0 : io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2253 0 : io.lockx.in.file.fnum = fnum1;
2254 0 : io.lockx.in.locks = &lock1;
2255 0 : status = smb_raw_lock(cli->tree, &io);
2256 0 : CHECK_STATUS(status, NT_STATUS_OK);
2257 :
2258 1 : done:
2259 1 : smbcli_close(cli->tree, fnum1);
2260 1 : smbcli_close(cli->tree, fnum2);
2261 1 : smb_raw_exit(cli->session);
2262 1 : smbcli_deltree(cli->tree, BASEDIR);
2263 1 : return ret;
2264 : }
2265 : /*
2266 : test multi Locking&X operation
2267 : */
2268 1 : 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 1 : bool ret = true;
2275 : int fnum;
2276 1 : const char *fname = BASEDIR "\\multilock_test.txt";
2277 : time_t t;
2278 : struct smbcli_request *req;
2279 : struct smbcli_session_options options;
2280 :
2281 1 : torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2282 :
2283 1 : lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
2284 :
2285 1 : torture_comment(tctx, "Testing LOCKING_ANDX multi-lock\n");
2286 1 : io.generic.level = RAW_LOCK_LOCKX;
2287 :
2288 : /* Create the test file. */
2289 1 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2290 1 : 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 1 : io.lockx.level = RAW_LOCK_LOCKX;
2299 1 : io.lockx.in.file.fnum = fnum;
2300 1 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
2301 1 : io.lockx.in.timeout = 0;
2302 1 : io.lockx.in.ulock_cnt = 0;
2303 1 : io.lockx.in.lock_cnt = 2;
2304 1 : io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2305 1 : lock[0].pid = cli->session->pid;
2306 1 : lock[0].offset = 100;
2307 1 : lock[0].count = 10;
2308 1 : lock[1].pid = cli->session->pid;
2309 1 : lock[1].offset = 120;
2310 1 : lock[1].count = 10;
2311 1 : io.lockx.in.locks = &lock[0];
2312 1 : status = smb_raw_lock(cli->tree, &io);
2313 1 : 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 1 : io.lockx.in.timeout = 20000;
2321 1 : lock[0].pid = cli->session->pid+1;
2322 1 : lock[1].pid = cli->session->pid+1;
2323 1 : req = smb_raw_lock_send(cli->tree, &io);
2324 1 : torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
2325 : "Failed to setup timed locks (%s)\n", __location__));
2326 :
2327 : /* Unlock lock[0] */
2328 1 : io.lockx.in.timeout = 0;
2329 1 : io.lockx.in.ulock_cnt = 1;
2330 1 : io.lockx.in.lock_cnt = 0;
2331 1 : io.lockx.in.locks = &lock[0];
2332 1 : lock[0].pid = cli->session->pid;
2333 1 : status = smb_raw_lock(cli->tree, &io);
2334 1 : CHECK_STATUS(status, NT_STATUS_OK);
2335 :
2336 : /* Start the clock. */
2337 1 : t = time_mono(NULL);
2338 :
2339 : /* Unlock lock[1] */
2340 1 : io.lockx.in.timeout = 0;
2341 1 : io.lockx.in.ulock_cnt = 1;
2342 1 : io.lockx.in.lock_cnt = 0;
2343 1 : io.lockx.in.locks = &lock[1];
2344 1 : lock[1].pid = cli->session->pid;
2345 1 : status = smb_raw_lock(cli->tree, &io);
2346 1 : CHECK_STATUS(status, NT_STATUS_OK);
2347 :
2348 : /* receive the successful blocked lock requests */
2349 1 : status = smbcli_request_simple_recv(req);
2350 1 : CHECK_STATUS(status, NT_STATUS_OK);
2351 :
2352 : /* Fail if this took more than 2 seconds. */
2353 1 : torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
2354 : "Blocking locks were not granted immediately (%s)\n",
2355 : __location__));
2356 1 : done:
2357 1 : smb_raw_exit(cli->session);
2358 1 : smbcli_deltree(cli->tree, BASEDIR);
2359 1 : 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 1 : 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 1 : bool ret = true;
2389 : int fnum;
2390 1 : 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 1 : torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2397 :
2398 1 : lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
2399 :
2400 1 : torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 2\n");
2401 1 : io.generic.level = RAW_LOCK_LOCKX;
2402 :
2403 : /* Create the test file. */
2404 1 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2405 1 : 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 1 : io.lockx.level = RAW_LOCK_LOCKX;
2414 1 : io.lockx.in.file.fnum = fnum;
2415 1 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
2416 1 : io.lockx.in.timeout = 0;
2417 1 : io.lockx.in.ulock_cnt = 0;
2418 1 : io.lockx.in.lock_cnt = 2;
2419 1 : io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2420 1 : lock[0].pid = cli->session->pid;
2421 1 : lock[0].offset = 100;
2422 1 : lock[0].count = 10;
2423 1 : lock[1].pid = cli->session->pid;
2424 1 : lock[1].offset = 120;
2425 1 : lock[1].count = 10;
2426 1 : io.lockx.in.locks = &lock[0];
2427 1 : status = smb_raw_lock(cli->tree, &io);
2428 1 : 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 1 : io.lockx.in.timeout = 20000;
2436 1 : lock[0].pid = cli->session->pid+1;
2437 1 : lock[1].pid = cli->session->pid+1;
2438 1 : req = smb_raw_lock_send(cli->tree, &io);
2439 1 : 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 1 : io.lockx.in.timeout = 2000;
2449 1 : lock[0].pid = cli->session->pid+2;
2450 1 : io.lockx.in.lock_cnt = 1;
2451 1 : req2 = smb_raw_lock_send(cli->tree, &io);
2452 1 : torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
2453 : "Failed to setup timed locks (%s)\n", __location__));
2454 :
2455 : /* Unlock lock[0] */
2456 1 : io.lockx.in.timeout = 0;
2457 1 : io.lockx.in.ulock_cnt = 1;
2458 1 : io.lockx.in.lock_cnt = 0;
2459 1 : io.lockx.in.locks = &lock[0];
2460 1 : lock[0].pid = cli->session->pid;
2461 1 : status = smb_raw_lock(cli->tree, &io);
2462 1 : CHECK_STATUS(status, NT_STATUS_OK);
2463 :
2464 : /* Did the second lock complete (should time out) ? */
2465 1 : status = smbcli_request_simple_recv(req2);
2466 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2467 :
2468 1 : torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
2469 : "req should still wait");
2470 :
2471 : /* Start the clock. */
2472 1 : t = time_mono(NULL);
2473 :
2474 : /* Unlock lock[1] */
2475 1 : io.lockx.in.timeout = 0;
2476 1 : io.lockx.in.ulock_cnt = 1;
2477 1 : io.lockx.in.lock_cnt = 0;
2478 1 : io.lockx.in.locks = &lock[1];
2479 1 : lock[1].pid = cli->session->pid;
2480 1 : status = smb_raw_lock(cli->tree, &io);
2481 1 : CHECK_STATUS(status, NT_STATUS_OK);
2482 :
2483 : /* receive the successful blocked lock requests */
2484 1 : status = smbcli_request_simple_recv(req);
2485 1 : CHECK_STATUS(status, NT_STATUS_OK);
2486 :
2487 : /* Fail if this took more than 2 seconds. */
2488 1 : torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
2489 : "Blocking locks were not granted immediately (%s)\n",
2490 : __location__));
2491 1 : done:
2492 1 : smb_raw_exit(cli->session);
2493 1 : smbcli_deltree(cli->tree, BASEDIR);
2494 1 : return ret;
2495 : }
2496 :
2497 : /*
2498 : test multi3 Locking&X operation
2499 : This test is designed to show that
2500 : lock precedence on the server is based
2501 : on the order received, not on the ability
2502 : to grant.
2503 :
2504 : Compared to test_multilock2() (above)
2505 : this test demonstrates that completely
2506 : unrelated ranges work independently.
2507 :
2508 : For example:
2509 :
2510 : A blocked lock request containing 2 locks
2511 : will be satified before a subsequent blocked
2512 : lock request over one of the same regions,
2513 : even if that region is then unlocked. But
2514 : a lock of a different region goes through. E.g.
2515 :
2516 : All locks are LOCKING_ANDX_EXCLUSIVE_LOCK (rw).
2517 :
2518 : (a) lock 100->109, 120->129 (granted)
2519 : (b) lock 100->109, 120->129 (blocks, timeout=20s)
2520 : (c) lock 100->109 (blocks, timeout=2s)
2521 : (d) lock 110->119 (granted)
2522 : (e) lock 110->119 (blocks, timeout=20s)
2523 : (f) unlock 100->109 (a)
2524 : (g) lock 100->109 (not granted, blocked by (b))
2525 : (h) lock 100->109 (not granted, blocked by itself (b))
2526 : (i) lock (c) will not be granted(conflict, times out)
2527 : as lock (b) will take precedence.
2528 : (j) unlock 110-119 (d)
2529 : (k) lock (e) completes and is not blocked by (a) nor (b)
2530 : (l) lock 100->109 (not granted(conflict), blocked by (b))
2531 : (m) lock 100->109 (not granted(conflict), blocked by itself (b))
2532 : (n) unlock 120-129 (a)
2533 : (o) lock (b) completes
2534 : */
2535 1 : static bool test_multilock3(struct torture_context *tctx,
2536 : struct smbcli_state *cli)
2537 : {
2538 : union smb_lock io;
2539 : struct smb_lock_entry lock[2];
2540 : union smb_lock io3;
2541 : struct smb_lock_entry lock3[1];
2542 : NTSTATUS status;
2543 1 : bool ret = true;
2544 : int fnum;
2545 1 : const char *fname = BASEDIR "\\multilock3_test.txt";
2546 : time_t t;
2547 1 : struct smbcli_request *req = NULL;
2548 1 : struct smbcli_request *req2 = NULL;
2549 1 : struct smbcli_request *req4 = NULL;
2550 :
2551 1 : torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
2552 : "Failed to setup up test directory: " BASEDIR);
2553 :
2554 1 : torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 3\n");
2555 1 : io.generic.level = RAW_LOCK_LOCKX;
2556 :
2557 : /* Create the test file. */
2558 1 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2559 1 : torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
2560 : "Failed to create %s - %s\n",
2561 : fname, smbcli_errstr(cli->tree)));
2562 :
2563 : /*
2564 : * a)
2565 : * Lock regions 100->109, 120->129 as
2566 : * two separate write locks in one request.
2567 : */
2568 1 : io.lockx.level = RAW_LOCK_LOCKX;
2569 1 : io.lockx.in.file.fnum = fnum;
2570 1 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
2571 1 : io.lockx.in.timeout = 0;
2572 1 : io.lockx.in.ulock_cnt = 0;
2573 1 : io.lockx.in.lock_cnt = 2;
2574 1 : io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2575 1 : lock[0].pid = cli->session->pid;
2576 1 : lock[0].offset = 100;
2577 1 : lock[0].count = 10;
2578 1 : lock[1].pid = cli->session->pid;
2579 1 : lock[1].offset = 120;
2580 1 : lock[1].count = 10;
2581 1 : io.lockx.in.locks = &lock[0];
2582 1 : status = smb_raw_lock(cli->tree, &io);
2583 1 : CHECK_STATUS(status, NT_STATUS_OK);
2584 :
2585 : /*
2586 : * b)
2587 : * Now request the same locks on a different
2588 : * context as blocking locks.
2589 : */
2590 1 : io.lockx.in.timeout = 20000;
2591 1 : lock[0].pid = cli->session->pid+1;
2592 1 : lock[1].pid = cli->session->pid+1;
2593 1 : req = smb_raw_lock_send(cli->tree, &io);
2594 1 : torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
2595 : "Failed to setup timed locks (%s)\n", __location__));
2596 :
2597 : /*
2598 : * c)
2599 : * Request the first lock again on a separate context.
2600 : * Wait 2 seconds. This should time out (the previous
2601 : * multi-lock request should take precedence).
2602 : */
2603 1 : io.lockx.in.timeout = 2000;
2604 1 : lock[0].pid = cli->session->pid+2;
2605 1 : io.lockx.in.lock_cnt = 1;
2606 1 : req2 = smb_raw_lock_send(cli->tree, &io);
2607 1 : torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
2608 : "Failed to setup timed locks (%s)\n", __location__));
2609 :
2610 : /*
2611 : * d)
2612 : * Lock regions 110->119
2613 : */
2614 1 : io3.lockx.level = RAW_LOCK_LOCKX;
2615 1 : io3.lockx.in.file.fnum = fnum;
2616 1 : io3.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
2617 1 : io3.lockx.in.timeout = 0;
2618 1 : io3.lockx.in.ulock_cnt = 0;
2619 1 : io3.lockx.in.lock_cnt = 1;
2620 1 : io3.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2621 1 : lock3[0].pid = cli->session->pid+3;
2622 1 : lock3[0].offset = 110;
2623 1 : lock3[0].count = 10;
2624 1 : io3.lockx.in.locks = &lock3[0];
2625 1 : status = smb_raw_lock(cli->tree, &io3);
2626 1 : CHECK_STATUS(status, NT_STATUS_OK);
2627 :
2628 : /*
2629 : * e)
2630 : * try 110-119 again
2631 : */
2632 1 : io3.lockx.in.timeout = 20000;
2633 1 : lock3[0].pid = cli->session->pid+4;
2634 1 : req4 = smb_raw_lock_send(cli->tree, &io3);
2635 1 : torture_assert(tctx,(req4 != NULL), talloc_asprintf(tctx,
2636 : "Failed to setup timed locks (%s)\n", __location__));
2637 :
2638 : /*
2639 : * f)
2640 : * Unlock (a) lock[0] 100-109
2641 : */
2642 1 : io.lockx.in.timeout = 0;
2643 1 : io.lockx.in.ulock_cnt = 1;
2644 1 : io.lockx.in.lock_cnt = 0;
2645 1 : io.lockx.in.locks = &lock[0];
2646 1 : lock[0].pid = cli->session->pid;
2647 1 : status = smb_raw_lock(cli->tree, &io);
2648 1 : CHECK_STATUS(status, NT_STATUS_OK);
2649 :
2650 : /*
2651 : * g)
2652 : * try to lock lock[0] 100-109 again
2653 : */
2654 1 : lock[0].pid = cli->session->pid+5;
2655 1 : io.lockx.in.ulock_cnt = 0;
2656 1 : io.lockx.in.lock_cnt = 1;
2657 1 : status = smb_raw_lock(cli->tree, &io);
2658 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2659 :
2660 : /*
2661 : * h)
2662 : * try to lock lock[0] 100-109 again with
2663 : * the pid that's still waiting
2664 : */
2665 1 : lock[0].pid = cli->session->pid+1;
2666 1 : io.lockx.in.ulock_cnt = 0;
2667 1 : io.lockx.in.lock_cnt = 1;
2668 1 : status = smb_raw_lock(cli->tree, &io);
2669 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2670 :
2671 1 : torture_assert(tctx, req2->state <= SMBCLI_REQUEST_RECV,
2672 : "req2 should still wait");
2673 :
2674 : /*
2675 : * i)
2676 : * Did the second lock complete (should time out) ?
2677 : */
2678 1 : status = smbcli_request_simple_recv(req2);
2679 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2680 :
2681 1 : torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
2682 : "req should still wait");
2683 1 : torture_assert(tctx, req4->state <= SMBCLI_REQUEST_RECV,
2684 : "req4 should still wait");
2685 :
2686 : /*
2687 : * j)
2688 : * Unlock (d) lock[0] 110-119
2689 : */
2690 1 : io3.lockx.in.timeout = 0;
2691 1 : io3.lockx.in.ulock_cnt = 1;
2692 1 : io3.lockx.in.lock_cnt = 0;
2693 1 : lock3[0].pid = cli->session->pid+3;
2694 1 : status = smb_raw_lock(cli->tree, &io3);
2695 1 : CHECK_STATUS(status, NT_STATUS_OK);
2696 :
2697 : /*
2698 : * k)
2699 : * receive the successful blocked lock request (e)
2700 : * on 110-119 while the 100-109/120-129 is still waiting.
2701 : */
2702 1 : status = smbcli_request_simple_recv(req4);
2703 1 : CHECK_STATUS(status, NT_STATUS_OK);
2704 :
2705 : /*
2706 : * l)
2707 : * try to lock lock[0] 100-109 again
2708 : */
2709 1 : lock[0].pid = cli->session->pid+6;
2710 1 : io.lockx.in.ulock_cnt = 0;
2711 1 : io.lockx.in.lock_cnt = 1;
2712 1 : status = smb_raw_lock(cli->tree, &io);
2713 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2714 :
2715 1 : torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
2716 : "req should still wait");
2717 :
2718 : /*
2719 : * m)
2720 : * try to lock lock[0] 100-109 again with
2721 : * the pid that's still waiting
2722 : */
2723 1 : lock[0].pid = cli->session->pid+1;
2724 1 : io.lockx.in.ulock_cnt = 0;
2725 1 : io.lockx.in.lock_cnt = 1;
2726 1 : status = smb_raw_lock(cli->tree, &io);
2727 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2728 :
2729 1 : torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
2730 : "req should still wait");
2731 :
2732 : /* Start the clock. */
2733 1 : t = time_mono(NULL);
2734 :
2735 : /*
2736 : * n)
2737 : * Unlock lock[1] 120-129 */
2738 1 : io.lockx.in.timeout = 0;
2739 1 : io.lockx.in.ulock_cnt = 1;
2740 1 : io.lockx.in.lock_cnt = 0;
2741 1 : io.lockx.in.locks = &lock[1];
2742 1 : lock[1].pid = cli->session->pid;
2743 1 : status = smb_raw_lock(cli->tree, &io);
2744 1 : CHECK_STATUS(status, NT_STATUS_OK);
2745 :
2746 : /*
2747 : * o)
2748 : * receive the successful blocked lock request (b)
2749 : */
2750 1 : status = smbcli_request_simple_recv(req);
2751 1 : CHECK_STATUS(status, NT_STATUS_OK);
2752 :
2753 : /* Fail if this took more than 2 seconds. */
2754 1 : torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
2755 : "Blocking locks were not granted immediately (%s)\n",
2756 : __location__));
2757 1 : done:
2758 1 : smb_raw_exit(cli->session);
2759 1 : smbcli_deltree(cli->tree, BASEDIR);
2760 1 : return ret;
2761 : }
2762 :
2763 : /*
2764 : test multi4 Locking&X operation
2765 : This test is designed to show that
2766 : lock precedence on the server is based
2767 : on the order received, not on the ability
2768 : to grant.
2769 :
2770 : Compared to test_multilock3() (above)
2771 : this test demonstrates that pending read-only/shared
2772 : locks doesn't block shared locks others.
2773 :
2774 : The outstanding requests build an implicit
2775 : database that's checked before checking
2776 : the already granted locks in the real database.
2777 :
2778 : For example:
2779 :
2780 : A blocked read-lock request containing 2 locks
2781 : will be still be blocked, while one region
2782 : is still write-locked. While it doesn't block
2783 : other read-lock requests for the other region. E.g.
2784 :
2785 : (a) lock(rw) 100->109, 120->129 (granted)
2786 : (b) lock(ro) 100->109, 120->129 (blocks, timeout=20s)
2787 : (c) lock(ro) 100->109 (blocks, timeout=MAX)
2788 : (d) lock(rw) 110->119 (granted)
2789 : (e) lock(rw) 110->119 (blocks, timeout=20s)
2790 : (f) unlock 100->109 (a)
2791 : (g) lock(ro) (c) completes and is not blocked by (a) nor (b)
2792 : (h) lock(rw) 100->109 (not granted, blocked by (c))
2793 : (i) lock(rw) 100->109 (pid (b)) (not granted(conflict), blocked by (c))
2794 : (j) unlock 110-119
2795 : (k) lock (e) completes and is not blocked by (a) nor (b)
2796 : (l) lock 100->109 (not granted(conflict), blocked by (b))
2797 : (m) lock 100->109 (pid (b)) (not granted(conflict), blocked by itself (b))
2798 : (n) unlock 120-129 (a)
2799 : (o) lock (b) completes
2800 : */
2801 1 : static bool test_multilock4(struct torture_context *tctx,
2802 : struct smbcli_state *cli)
2803 : {
2804 : union smb_lock io;
2805 : struct smb_lock_entry lock[2];
2806 : union smb_lock io3;
2807 : struct smb_lock_entry lock3[1];
2808 : NTSTATUS status;
2809 1 : bool ret = true;
2810 : int fnum;
2811 1 : const char *fname = BASEDIR "\\multilock4_test.txt";
2812 : time_t t;
2813 1 : struct smbcli_request *req = NULL;
2814 1 : struct smbcli_request *req2 = NULL;
2815 1 : struct smbcli_request *req4 = NULL;
2816 :
2817 1 : torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
2818 : "Failed to setup up test directory: " BASEDIR);
2819 :
2820 1 : torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 4\n");
2821 1 : io.generic.level = RAW_LOCK_LOCKX;
2822 :
2823 : /* Create the test file. */
2824 1 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2825 1 : torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
2826 : "Failed to create %s - %s\n",
2827 : fname, smbcli_errstr(cli->tree)));
2828 :
2829 : /*
2830 : * a)
2831 : * Lock regions 100->109, 120->129 as
2832 : * two separate write locks in one request.
2833 : */
2834 1 : io.lockx.level = RAW_LOCK_LOCKX;
2835 1 : io.lockx.in.file.fnum = fnum;
2836 1 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
2837 1 : io.lockx.in.timeout = 0;
2838 1 : io.lockx.in.ulock_cnt = 0;
2839 1 : io.lockx.in.lock_cnt = 2;
2840 1 : io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2841 1 : lock[0].pid = cli->session->pid;
2842 1 : lock[0].offset = 100;
2843 1 : lock[0].count = 10;
2844 1 : lock[1].pid = cli->session->pid;
2845 1 : lock[1].offset = 120;
2846 1 : lock[1].count = 10;
2847 1 : io.lockx.in.locks = &lock[0];
2848 1 : status = smb_raw_lock(cli->tree, &io);
2849 1 : CHECK_STATUS(status, NT_STATUS_OK);
2850 :
2851 : /*
2852 : * b)
2853 : * Now request the same locks on a different
2854 : * context as blocking locks. But readonly.
2855 : */
2856 1 : io.lockx.in.timeout = 20000;
2857 1 : io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
2858 1 : lock[0].pid = cli->session->pid+1;
2859 1 : lock[1].pid = cli->session->pid+1;
2860 1 : req = smb_raw_lock_send(cli->tree, &io);
2861 1 : torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
2862 : "Failed to setup timed locks (%s)\n", __location__));
2863 :
2864 : /*
2865 : * c)
2866 : * Request the first lock again on a separate context.
2867 : * Wait forever. The previous multi-lock request (b)
2868 : * should take precedence. Also readonly.
2869 : */
2870 1 : io.lockx.in.timeout = UINT32_MAX;
2871 1 : lock[0].pid = cli->session->pid+2;
2872 1 : io.lockx.in.lock_cnt = 1;
2873 1 : req2 = smb_raw_lock_send(cli->tree, &io);
2874 1 : torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
2875 : "Failed to setup timed locks (%s)\n", __location__));
2876 :
2877 : /*
2878 : * d)
2879 : * Lock regions 110->119
2880 : */
2881 1 : io3.lockx.level = RAW_LOCK_LOCKX;
2882 1 : io3.lockx.in.file.fnum = fnum;
2883 1 : io3.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
2884 1 : io3.lockx.in.timeout = 0;
2885 1 : io3.lockx.in.ulock_cnt = 0;
2886 1 : io3.lockx.in.lock_cnt = 1;
2887 1 : io3.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2888 1 : lock3[0].pid = cli->session->pid+3;
2889 1 : lock3[0].offset = 110;
2890 1 : lock3[0].count = 10;
2891 1 : io3.lockx.in.locks = &lock3[0];
2892 1 : status = smb_raw_lock(cli->tree, &io3);
2893 1 : CHECK_STATUS(status, NT_STATUS_OK);
2894 :
2895 : /*
2896 : * e)
2897 : * try 110-119 again
2898 : */
2899 1 : io3.lockx.in.timeout = 20000;
2900 1 : lock3[0].pid = cli->session->pid+4;
2901 1 : req4 = smb_raw_lock_send(cli->tree, &io3);
2902 1 : torture_assert(tctx,(req4 != NULL), talloc_asprintf(tctx,
2903 : "Failed to setup timed locks (%s)\n", __location__));
2904 :
2905 : /*
2906 : * f)
2907 : * Unlock (a) lock[0] 100-109
2908 : */
2909 1 : io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
2910 1 : io.lockx.in.timeout = 0;
2911 1 : io.lockx.in.ulock_cnt = 1;
2912 1 : io.lockx.in.lock_cnt = 0;
2913 1 : io.lockx.in.locks = &lock[0];
2914 1 : lock[0].pid = cli->session->pid;
2915 1 : status = smb_raw_lock(cli->tree, &io);
2916 1 : CHECK_STATUS(status, NT_STATUS_OK);
2917 :
2918 : /*
2919 : * g)
2920 : * receive the successful blocked lock request (c)
2921 : * on 110-119 while (b) 100-109/120-129 is still waiting.
2922 : */
2923 1 : status = smbcli_request_simple_recv(req2);
2924 1 : CHECK_STATUS(status, NT_STATUS_OK);
2925 :
2926 : /*
2927 : * h)
2928 : * try to lock lock[0] 100-109 again
2929 : * (read/write)
2930 : */
2931 1 : lock[0].pid = cli->session->pid+5;
2932 1 : io.lockx.in.ulock_cnt = 0;
2933 1 : io.lockx.in.lock_cnt = 1;
2934 1 : status = smb_raw_lock(cli->tree, &io);
2935 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
2936 :
2937 : /*
2938 : * i)
2939 : * try to lock lock[0] 100-109 again with the pid (b)
2940 : * that's still waiting.
2941 : */
2942 1 : lock[0].pid = cli->session->pid+1;
2943 1 : io.lockx.in.ulock_cnt = 0;
2944 1 : io.lockx.in.lock_cnt = 1;
2945 1 : status = smb_raw_lock(cli->tree, &io);
2946 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2947 :
2948 1 : torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
2949 : "req should still wait");
2950 1 : torture_assert(tctx, req4->state <= SMBCLI_REQUEST_RECV,
2951 : "req4 should still wait");
2952 :
2953 : /*
2954 : * j)
2955 : * Unlock (d) lock[0] 110-119
2956 : */
2957 1 : io3.lockx.in.timeout = 0;
2958 1 : io3.lockx.in.ulock_cnt = 1;
2959 1 : io3.lockx.in.lock_cnt = 0;
2960 1 : lock3[0].pid = cli->session->pid+3;
2961 1 : status = smb_raw_lock(cli->tree, &io3);
2962 1 : CHECK_STATUS(status, NT_STATUS_OK);
2963 :
2964 : /*
2965 : * k)
2966 : * receive the successful blocked
2967 : * lock request (e) on 110-119.
2968 : */
2969 1 : status = smbcli_request_simple_recv(req4);
2970 1 : CHECK_STATUS(status, NT_STATUS_OK);
2971 :
2972 : /*
2973 : * l)
2974 : * try to lock lock[0] 100-109 again
2975 : */
2976 1 : lock[0].pid = cli->session->pid+6;
2977 1 : io.lockx.in.ulock_cnt = 0;
2978 1 : io.lockx.in.lock_cnt = 1;
2979 1 : status = smb_raw_lock(cli->tree, &io);
2980 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2981 :
2982 : /*
2983 : * m)
2984 : * try to lock lock[0] 100-109 again with the pid (b)
2985 : * that's still waiting
2986 : */
2987 1 : lock[0].pid = cli->session->pid+1;
2988 1 : io.lockx.in.ulock_cnt = 0;
2989 1 : io.lockx.in.lock_cnt = 1;
2990 1 : status = smb_raw_lock(cli->tree, &io);
2991 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
2992 :
2993 1 : torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
2994 : "req should still wait");
2995 :
2996 : /* Start the clock. */
2997 1 : t = time_mono(NULL);
2998 :
2999 : /*
3000 : * n)
3001 : * Unlock (a) lock[1] 120-129
3002 : */
3003 1 : io.lockx.in.timeout = 0;
3004 1 : io.lockx.in.ulock_cnt = 1;
3005 1 : io.lockx.in.lock_cnt = 0;
3006 1 : io.lockx.in.locks = &lock[1];
3007 1 : lock[1].pid = cli->session->pid;
3008 1 : status = smb_raw_lock(cli->tree, &io);
3009 1 : CHECK_STATUS(status, NT_STATUS_OK);
3010 :
3011 : /*
3012 : * o)
3013 : * receive the successful blocked lock request (b)
3014 : */
3015 1 : status = smbcli_request_simple_recv(req);
3016 1 : CHECK_STATUS(status, NT_STATUS_OK);
3017 :
3018 : /* Fail if this took more than 2 seconds. */
3019 1 : torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
3020 : "Blocking locks were not granted immediately (%s)\n",
3021 : __location__));
3022 1 : done:
3023 1 : smb_raw_exit(cli->session);
3024 1 : smbcli_deltree(cli->tree, BASEDIR);
3025 1 : return ret;
3026 : }
3027 :
3028 : /*
3029 : test multi5 Locking&X operation
3030 : This test is designed to show that
3031 : lock precedence on the server is based
3032 : on the order received, not on the ability
3033 : to grant.
3034 :
3035 : Compared to test_multilock3() (above)
3036 : this test demonstrates that the initial
3037 : lock request that block the following
3038 : exclusive locks can be a shared lock.
3039 :
3040 : For example:
3041 :
3042 : All locks except (a) are LOCKING_ANDX_EXCLUSIVE_LOCK (rw).
3043 :
3044 : (a) lock(ro) 100->109, 120->129 (granted)
3045 : (b) lock 100->109, 120->129 (blocks, timeout=20s)
3046 : (c) lock 100->109 (blocks, timeout=2s)
3047 : (d) lock 110->119 (granted)
3048 : (e) lock 110->119 (blocks, timeout=20s)
3049 : (f) unlock 100->109 (a)
3050 : (g) lock 100->109 (not granted, blocked by (b))
3051 : (h) lock 100->109 (not granted, blocked by itself (b))
3052 : (i) lock (c) will not be granted(conflict, times out)
3053 : as lock (b) will take precedence.
3054 : (j) unlock 110-119 (d)
3055 : (k) lock (e) completes and is not blocked by (a) nor (b)
3056 : (l) lock 100->109 (not granted(conflict), blocked by (b))
3057 : (m) lock 100->109 (not granted(conflict), blocked by itself (b))
3058 : (n) unlock 120-129 (a)
3059 : (o) lock (b) completes
3060 : */
3061 1 : static bool test_multilock5(struct torture_context *tctx,
3062 : struct smbcli_state *cli)
3063 : {
3064 : union smb_lock io;
3065 : struct smb_lock_entry lock[2];
3066 : union smb_lock io3;
3067 : struct smb_lock_entry lock3[1];
3068 : NTSTATUS status;
3069 1 : bool ret = true;
3070 : int fnum;
3071 1 : const char *fname = BASEDIR "\\multilock5_test.txt";
3072 : time_t t;
3073 1 : struct smbcli_request *req = NULL;
3074 1 : struct smbcli_request *req2 = NULL;
3075 1 : struct smbcli_request *req4 = NULL;
3076 :
3077 1 : torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
3078 : "Failed to setup up test directory: " BASEDIR);
3079 :
3080 1 : torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 5\n");
3081 1 : io.generic.level = RAW_LOCK_LOCKX;
3082 :
3083 : /* Create the test file. */
3084 1 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3085 1 : torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
3086 : "Failed to create %s - %s\n",
3087 : fname, smbcli_errstr(cli->tree)));
3088 :
3089 : /*
3090 : * a)
3091 : * Lock regions 100->109, 120->129 as
3092 : * two separate write locks in one request.
3093 : * (read only)
3094 : */
3095 1 : io.lockx.level = RAW_LOCK_LOCKX;
3096 1 : io.lockx.in.file.fnum = fnum;
3097 1 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
3098 1 : io.lockx.in.timeout = 0;
3099 1 : io.lockx.in.ulock_cnt = 0;
3100 1 : io.lockx.in.lock_cnt = 2;
3101 1 : io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
3102 1 : lock[0].pid = cli->session->pid;
3103 1 : lock[0].offset = 100;
3104 1 : lock[0].count = 10;
3105 1 : lock[1].pid = cli->session->pid;
3106 1 : lock[1].offset = 120;
3107 1 : lock[1].count = 10;
3108 1 : io.lockx.in.locks = &lock[0];
3109 1 : status = smb_raw_lock(cli->tree, &io);
3110 1 : CHECK_STATUS(status, NT_STATUS_OK);
3111 :
3112 : /*
3113 : * b)
3114 : * Now request the same locks on a different
3115 : * context as blocking locks.
3116 : * (read write)
3117 : */
3118 1 : io.lockx.in.timeout = 20000;
3119 1 : io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
3120 1 : lock[0].pid = cli->session->pid+1;
3121 1 : lock[1].pid = cli->session->pid+1;
3122 1 : req = smb_raw_lock_send(cli->tree, &io);
3123 1 : torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
3124 : "Failed to setup timed locks (%s)\n", __location__));
3125 :
3126 : /*
3127 : * c)
3128 : * Request the first lock again on a separate context.
3129 : * Wait 2 seconds. This should time out (the previous
3130 : * multi-lock request should take precedence).
3131 : * (read write)
3132 : */
3133 1 : io.lockx.in.timeout = 2000;
3134 1 : lock[0].pid = cli->session->pid+2;
3135 1 : io.lockx.in.lock_cnt = 1;
3136 1 : req2 = smb_raw_lock_send(cli->tree, &io);
3137 1 : torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
3138 : "Failed to setup timed locks (%s)\n", __location__));
3139 :
3140 : /*
3141 : * d)
3142 : * Lock regions 110->119
3143 : */
3144 1 : io3.lockx.level = RAW_LOCK_LOCKX;
3145 1 : io3.lockx.in.file.fnum = fnum;
3146 1 : io3.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
3147 1 : io3.lockx.in.timeout = 0;
3148 1 : io3.lockx.in.ulock_cnt = 0;
3149 1 : io3.lockx.in.lock_cnt = 1;
3150 1 : io3.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
3151 1 : lock3[0].pid = cli->session->pid+3;
3152 1 : lock3[0].offset = 110;
3153 1 : lock3[0].count = 10;
3154 1 : io3.lockx.in.locks = &lock3[0];
3155 1 : status = smb_raw_lock(cli->tree, &io3);
3156 1 : CHECK_STATUS(status, NT_STATUS_OK);
3157 :
3158 : /*
3159 : * e)
3160 : * try 110-119 again
3161 : */
3162 1 : io3.lockx.in.timeout = 20000;
3163 1 : lock3[0].pid = cli->session->pid+4;
3164 1 : req4 = smb_raw_lock_send(cli->tree, &io3);
3165 1 : torture_assert(tctx,(req4 != NULL), talloc_asprintf(tctx,
3166 : "Failed to setup timed locks (%s)\n", __location__));
3167 :
3168 : /*
3169 : * f)
3170 : * Unlock (a) lock[0] 100-109
3171 : *
3172 : * Note we send LOCKING_ANDX_EXCLUSIVE_LOCK
3173 : * while the lock used LOCKING_ANDX_SHARED_LOCK
3174 : * to check if that also works.
3175 : */
3176 1 : io.lockx.in.timeout = 0;
3177 1 : io.lockx.in.ulock_cnt = 1;
3178 1 : io.lockx.in.lock_cnt = 0;
3179 1 : io.lockx.in.locks = &lock[0];
3180 1 : lock[0].pid = cli->session->pid;
3181 1 : status = smb_raw_lock(cli->tree, &io);
3182 1 : CHECK_STATUS(status, NT_STATUS_OK);
3183 :
3184 : /*
3185 : * g)
3186 : * try to lock lock[0] 100-109 again
3187 : */
3188 1 : lock[0].pid = cli->session->pid+5;
3189 1 : io.lockx.in.ulock_cnt = 0;
3190 1 : io.lockx.in.lock_cnt = 1;
3191 1 : status = smb_raw_lock(cli->tree, &io);
3192 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3193 :
3194 : /*
3195 : * h)
3196 : * try to lock lock[0] 100-109 again with the pid (b)
3197 : * that's still waiting.
3198 : * (read write)
3199 : */
3200 1 : lock[0].pid = cli->session->pid+1;
3201 1 : io.lockx.in.ulock_cnt = 0;
3202 1 : io.lockx.in.lock_cnt = 1;
3203 1 : status = smb_raw_lock(cli->tree, &io);
3204 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
3205 :
3206 1 : torture_assert(tctx, req2->state <= SMBCLI_REQUEST_RECV,
3207 : "req2 should still wait");
3208 :
3209 : /*
3210 : * i)
3211 : * Did the second lock complete (should time out) ?
3212 : */
3213 1 : status = smbcli_request_simple_recv(req2);
3214 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
3215 :
3216 1 : torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
3217 : "req should still wait");
3218 1 : torture_assert(tctx, req4->state <= SMBCLI_REQUEST_RECV,
3219 : "req4 should still wait");
3220 :
3221 : /*
3222 : * j)
3223 : * Unlock (d) lock[0] 110-119
3224 : */
3225 1 : io3.lockx.in.timeout = 0;
3226 1 : io3.lockx.in.ulock_cnt = 1;
3227 1 : io3.lockx.in.lock_cnt = 0;
3228 1 : lock3[0].pid = cli->session->pid+3;
3229 1 : status = smb_raw_lock(cli->tree, &io3);
3230 1 : CHECK_STATUS(status, NT_STATUS_OK);
3231 :
3232 : /*
3233 : * k)
3234 : * receive the successful blocked lock requests
3235 : * on 110-119 while the 100-109/120-129 is still waiting.
3236 : */
3237 1 : status = smbcli_request_simple_recv(req4);
3238 1 : CHECK_STATUS(status, NT_STATUS_OK);
3239 :
3240 : /*
3241 : * l)
3242 : * try to lock lock[0] 100-109 again
3243 : */
3244 1 : lock[0].pid = cli->session->pid+6;
3245 1 : io.lockx.in.ulock_cnt = 0;
3246 1 : io.lockx.in.lock_cnt = 1;
3247 1 : status = smb_raw_lock(cli->tree, &io);
3248 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
3249 :
3250 : /*
3251 : * m)
3252 : * try to lock lock[0] 100-109 again with the pid (b)
3253 : * that's still waiting
3254 : */
3255 1 : lock[0].pid = cli->session->pid+1;
3256 1 : io.lockx.in.ulock_cnt = 0;
3257 1 : io.lockx.in.lock_cnt = 1;
3258 1 : status = smb_raw_lock(cli->tree, &io);
3259 1 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
3260 :
3261 1 : torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
3262 : "req should still wait");
3263 :
3264 : /* Start the clock. */
3265 1 : t = time_mono(NULL);
3266 :
3267 : /*
3268 : * n)
3269 : * Unlock (a) lock[1] 120-129
3270 : */
3271 1 : io.lockx.in.timeout = 0;
3272 1 : io.lockx.in.ulock_cnt = 1;
3273 1 : io.lockx.in.lock_cnt = 0;
3274 1 : io.lockx.in.locks = &lock[1];
3275 1 : lock[1].pid = cli->session->pid;
3276 1 : status = smb_raw_lock(cli->tree, &io);
3277 1 : CHECK_STATUS(status, NT_STATUS_OK);
3278 :
3279 : /*
3280 : * o)
3281 : * receive the successful blocked lock request (b)
3282 : */
3283 1 : status = smbcli_request_simple_recv(req);
3284 1 : CHECK_STATUS(status, NT_STATUS_OK);
3285 :
3286 : /* Fail if this took more than 2 seconds. */
3287 1 : torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
3288 : "Blocking locks were not granted immediately (%s)\n",
3289 : __location__));
3290 1 : done:
3291 1 : smb_raw_exit(cli->session);
3292 1 : smbcli_deltree(cli->tree, BASEDIR);
3293 1 : return ret;
3294 : }
3295 :
3296 : /*
3297 : test multi6 Locking&X operation
3298 : This test is designed to show that
3299 : lock precedence on the server is based
3300 : on the order received, not on the ability
3301 : to grant.
3302 :
3303 : Compared to test_multilock4() (above)
3304 : this test demonstrates the behavior if
3305 : only just the first blocking lock
3306 : being a shared lock.
3307 :
3308 : For example:
3309 :
3310 : All locks except (b) are LOCKING_ANDX_EXCLUSIVE_LOCK (rw).
3311 :
3312 : (a) lock 100->109, 120->129 (granted)
3313 : (b) lock(ro) 100->109, 120->129 (blocks, timeout=20s)
3314 : (c) lock 100->109 (blocks, timeout=2s)
3315 : (d) lock 110->119 (granted)
3316 : (e) lock 110->119 (blocks, timeout=20s)
3317 : (f) unlock 100->109 (a)
3318 : (g) lock 100->109 (not granted, blocked by (b))
3319 : (h) lock 100->109 (not granted, blocked by itself (b))
3320 : (i) lock (c) will not be granted(conflict, times out)
3321 : as lock (b) will take precedence.
3322 : (j) unlock 110-119 (d)
3323 : (k) lock (e) completes and is not blocked by (a) nor (b)
3324 : (l) lock 100->109 (not granted(conflict), blocked by (b))
3325 : (m) lock 100->109 (not granted(conflict), blocked by itself (b))
3326 : (n) unlock 120-129 (a)
3327 : (o) lock (b) completes
3328 : */
3329 1 : static bool test_multilock6(struct torture_context *tctx,
3330 : struct smbcli_state *cli)
3331 : {
3332 : union smb_lock io;
3333 : struct smb_lock_entry lock[2];
3334 : union smb_lock io3;
3335 : struct smb_lock_entry lock3[1];
3336 : NTSTATUS status;
3337 1 : bool ret = true;
3338 : int fnum;
3339 1 : const char *fname = BASEDIR "\\multilock6_test.txt";
3340 : time_t t;
3341 1 : struct smbcli_request *req = NULL;
3342 1 : struct smbcli_request *req2 = NULL;
3343 1 : struct smbcli_request *req4 = NULL;
3344 :
3345 1 : torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
3346 : "Failed to setup up test directory: " BASEDIR);
3347 :
3348 1 : torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 6\n");
3349 1 : io.generic.level = RAW_LOCK_LOCKX;
3350 :
3351 : /* Create the test file. */
3352 1 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3353 1 : torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
3354 : "Failed to create %s - %s\n",
3355 : fname, smbcli_errstr(cli->tree)));
3356 :
3357 : /*
3358 : * a)
3359 : * Lock regions 100->109, 120->129 as
3360 : * two separate write locks in one request.
3361 : */
3362 1 : io.lockx.level = RAW_LOCK_LOCKX;
3363 1 : io.lockx.in.file.fnum = fnum;
3364 1 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
3365 1 : io.lockx.in.timeout = 0;
3366 1 : io.lockx.in.ulock_cnt = 0;
3367 1 : io.lockx.in.lock_cnt = 2;
3368 1 : io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
3369 1 : lock[0].pid = cli->session->pid;
3370 1 : lock[0].offset = 100;
3371 1 : lock[0].count = 10;
3372 1 : lock[1].pid = cli->session->pid;
3373 1 : lock[1].offset = 120;
3374 1 : lock[1].count = 10;
3375 1 : io.lockx.in.locks = &lock[0];
3376 1 : status = smb_raw_lock(cli->tree, &io);
3377 1 : CHECK_STATUS(status, NT_STATUS_OK);
3378 :
3379 : /*
3380 : * b)
3381 : * Now request the same locks on a different
3382 : * context as blocking locks.
3383 : * (read only)
3384 : */
3385 1 : io.lockx.in.timeout = 20000;
3386 1 : io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
3387 1 : lock[0].pid = cli->session->pid+1;
3388 1 : lock[1].pid = cli->session->pid+1;
3389 1 : req = smb_raw_lock_send(cli->tree, &io);
3390 1 : torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
3391 : "Failed to setup timed locks (%s)\n", __location__));
3392 :
3393 : /*
3394 : * c)
3395 : * Request the first lock again on a separate context.
3396 : * Wait 2 seconds. This should time out (the previous
3397 : * multi-lock request should take precedence).
3398 : */
3399 1 : io.lockx.in.timeout = 2000;
3400 1 : io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
3401 1 : lock[0].pid = cli->session->pid+2;
3402 1 : io.lockx.in.lock_cnt = 1;
3403 1 : req2 = smb_raw_lock_send(cli->tree, &io);
3404 1 : torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
3405 : "Failed to setup timed locks (%s)\n", __location__));
3406 :
3407 : /*
3408 : * d)
3409 : * Lock regions 110->119
3410 : */
3411 1 : io3.lockx.level = RAW_LOCK_LOCKX;
3412 1 : io3.lockx.in.file.fnum = fnum;
3413 1 : io3.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
3414 1 : io3.lockx.in.timeout = 0;
3415 1 : io3.lockx.in.ulock_cnt = 0;
3416 1 : io3.lockx.in.lock_cnt = 1;
3417 1 : io3.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
3418 1 : lock3[0].pid = cli->session->pid+3;
3419 1 : lock3[0].offset = 110;
3420 1 : lock3[0].count = 10;
3421 1 : io3.lockx.in.locks = &lock3[0];
3422 1 : status = smb_raw_lock(cli->tree, &io3);
3423 1 : CHECK_STATUS(status, NT_STATUS_OK);
3424 :
3425 : /*
3426 : * e)
3427 : * try 110-119 again
3428 : */
3429 1 : io3.lockx.in.timeout = 20000;
3430 1 : lock3[0].pid = cli->session->pid+4;
3431 1 : req4 = smb_raw_lock_send(cli->tree, &io3);
3432 1 : torture_assert(tctx,(req4 != NULL), talloc_asprintf(tctx,
3433 : "Failed to setup timed locks (%s)\n", __location__));
3434 :
3435 : /*
3436 : * f)
3437 : * Unlock (a) lock[0] 100-109
3438 : */
3439 1 : io.lockx.in.timeout = 0;
3440 1 : io.lockx.in.ulock_cnt = 1;
3441 1 : io.lockx.in.lock_cnt = 0;
3442 1 : io.lockx.in.locks = &lock[0];
3443 1 : lock[0].pid = cli->session->pid;
3444 1 : status = smb_raw_lock(cli->tree, &io);
3445 1 : CHECK_STATUS(status, NT_STATUS_OK);
3446 :
3447 : /*
3448 : * g)
3449 : * try to lock lock[0] 100-109 again
3450 : */
3451 1 : lock[0].pid = cli->session->pid+5;
3452 1 : io.lockx.in.ulock_cnt = 0;
3453 1 : io.lockx.in.lock_cnt = 1;
3454 1 : status = smb_raw_lock(cli->tree, &io);
3455 1 : CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
3456 :
3457 : /*
3458 : * h)
3459 : * try to lock lock[0] 100-109 again with the pid (b)
3460 : * that's still waiting
3461 : */
3462 0 : lock[0].pid = cli->session->pid+1;
3463 0 : io.lockx.in.ulock_cnt = 0;
3464 0 : io.lockx.in.lock_cnt = 1;
3465 0 : status = smb_raw_lock(cli->tree, &io);
3466 0 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
3467 :
3468 0 : torture_assert(tctx, req2->state <= SMBCLI_REQUEST_RECV,
3469 : "req2 should still wait");
3470 :
3471 : /*
3472 : * i)
3473 : * Did the second lock (c) complete (should time out) ?
3474 : */
3475 0 : status = smbcli_request_simple_recv(req2);
3476 0 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
3477 :
3478 0 : torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
3479 : "req should still wait");
3480 0 : torture_assert(tctx, req4->state <= SMBCLI_REQUEST_RECV,
3481 : "req4 should still wait");
3482 :
3483 : /*
3484 : * j)
3485 : * Unlock (d) lock[0] 110-119
3486 : */
3487 0 : io3.lockx.in.timeout = 0;
3488 0 : io3.lockx.in.ulock_cnt = 1;
3489 0 : io3.lockx.in.lock_cnt = 0;
3490 0 : lock3[0].pid = cli->session->pid+3;
3491 0 : status = smb_raw_lock(cli->tree, &io3);
3492 0 : CHECK_STATUS(status, NT_STATUS_OK);
3493 :
3494 : /*
3495 : * k)
3496 : * receive the successful blocked lock request (e)
3497 : * on 110-119 while (b) 100-109/120-129 is still waiting.
3498 : */
3499 0 : status = smbcli_request_simple_recv(req4);
3500 0 : CHECK_STATUS(status, NT_STATUS_OK);
3501 :
3502 : /*
3503 : * l)
3504 : * try to lock lock[0] 100-109 again
3505 : */
3506 0 : lock[0].pid = cli->session->pid+6;
3507 0 : io.lockx.in.ulock_cnt = 0;
3508 0 : io.lockx.in.lock_cnt = 1;
3509 0 : status = smb_raw_lock(cli->tree, &io);
3510 0 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
3511 :
3512 : /*
3513 : * m)
3514 : * try to lock lock[0] 100-109 again with the pid (b)
3515 : * that's still waiting
3516 : */
3517 0 : lock[0].pid = cli->session->pid+1;
3518 0 : io.lockx.in.ulock_cnt = 0;
3519 0 : io.lockx.in.lock_cnt = 1;
3520 0 : status = smb_raw_lock(cli->tree, &io);
3521 0 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
3522 :
3523 0 : torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
3524 : "req should still wait");
3525 :
3526 : /* Start the clock. */
3527 0 : t = time_mono(NULL);
3528 :
3529 : /*
3530 : * n)
3531 : * Unlock (a) lock[1] 120-129
3532 : */
3533 0 : io.lockx.in.timeout = 0;
3534 0 : io.lockx.in.ulock_cnt = 1;
3535 0 : io.lockx.in.lock_cnt = 0;
3536 0 : io.lockx.in.locks = &lock[1];
3537 0 : lock[1].pid = cli->session->pid;
3538 0 : status = smb_raw_lock(cli->tree, &io);
3539 0 : CHECK_STATUS(status, NT_STATUS_OK);
3540 :
3541 : /*
3542 : * o)
3543 : * receive the successful blocked lock request (b)
3544 : */
3545 0 : status = smbcli_request_simple_recv(req);
3546 0 : CHECK_STATUS(status, NT_STATUS_OK);
3547 :
3548 : /* Fail if this took more than 2 seconds. */
3549 0 : torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
3550 : "Blocking locks were not granted immediately (%s)\n",
3551 : __location__));
3552 0 : done:
3553 1 : smb_raw_exit(cli->session);
3554 1 : smbcli_deltree(cli->tree, BASEDIR);
3555 1 : return ret;
3556 : }
3557 :
3558 : /*
3559 : basic testing of lock calls
3560 : */
3561 964 : struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx)
3562 : {
3563 964 : struct torture_suite *suite = torture_suite_create(mem_ctx, "lock");
3564 :
3565 964 : torture_suite_add_1smb_test(suite, "lockx", test_lockx);
3566 964 : torture_suite_add_1smb_test(suite, "lock", test_lock);
3567 964 : torture_suite_add_1smb_test(suite, "pidhigh", test_pidhigh);
3568 964 : torture_suite_add_1smb_test(suite, "async", test_async);
3569 964 : torture_suite_add_1smb_test(suite, "errorcode", test_errorcode);
3570 964 : torture_suite_add_1smb_test(suite, "changetype", test_changetype);
3571 :
3572 964 : torture_suite_add_1smb_test(suite, "stacking", test_stacking);
3573 964 : torture_suite_add_1smb_test(suite, "unlock", test_unlock);
3574 964 : torture_suite_add_1smb_test(suite, "multiple_unlock",
3575 : test_multiple_unlock);
3576 964 : torture_suite_add_1smb_test(suite, "zerobytelocks", test_zerobytelocks);
3577 964 : torture_suite_add_1smb_test(suite, "zerobyteread", test_zerobyteread);
3578 964 : torture_suite_add_1smb_test(suite, "multilock", test_multilock);
3579 964 : torture_suite_add_1smb_test(suite, "multilock2", test_multilock2);
3580 964 : torture_suite_add_1smb_test(suite, "multilock3", test_multilock3);
3581 964 : torture_suite_add_1smb_test(suite, "multilock4", test_multilock4);
3582 964 : torture_suite_add_1smb_test(suite, "multilock5", test_multilock5);
3583 964 : torture_suite_add_1smb_test(suite, "multilock6", test_multilock6);
3584 :
3585 964 : return suite;
3586 : }
|