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