1 /*
2    Unix SMB/CIFS implementation.
3    basic raw test suite for oplocks
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 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 
21 #include "includes.h"
22 #include "torture/torture.h"
23 #include "librpc/gen_ndr/security.h"
24 #include "libcli/raw/libcliraw.h"
25 #include "libcli/libcli.h"
26 #include "torture/util.h"
27 #include "lib/events/events.h"
28 
29 #define CHECK_VAL(v, correct) do { \
30 	if ((v) != (correct)) { \
31 		printf("(%d) wrong value for %s  got 0x%x - should be 0x%x\n", \
32 		       __LINE__, #v, (int)v, (int)correct); \
33 		ret = False; \
34 	}} while (0)
35 
36 #define CHECK_STATUS(status, correct) do { \
37 	if (!NT_STATUS_EQUAL(status, correct)) { \
38 		printf("(%d) Incorrect status %s - should be %s\n", \
39 		       __LINE__, nt_errstr(status), nt_errstr(correct)); \
40 		ret = False; \
41 		goto done; \
42 	}} while (0)
43 
44 
45 static struct {
46 	int fnum;
47 	uint8_t level;
48 	int count;
49 	int failures;
50 } break_info;
51 
52 #define BASEDIR "\\test_notify"
53 
54 /*
55   a handler function for oplock break requests. Ack it as a break to level II if possible
56 */
oplock_handler_ack_to_levelII(struct smbcli_transport * transport,uint16_t tid,uint16_t fnum,uint8_t level,void * private)57 static BOOL oplock_handler_ack_to_levelII(struct smbcli_transport *transport, uint16_t tid,
58 			       uint16_t fnum, uint8_t level, void *private)
59 {
60 	struct smbcli_tree *tree = private;
61 	break_info.fnum = fnum;
62 	break_info.level = level;
63 	break_info.count++;
64 
65 	printf("Acking to level II in oplock handler\n");
66 
67 	return smbcli_oplock_ack(tree, fnum, level);
68 }
69 
70 /*
71   a handler function for oplock break requests. Ack it as a break to none
72 */
oplock_handler_ack_to_none(struct smbcli_transport * transport,uint16_t tid,uint16_t fnum,uint8_t level,void * private)73 static BOOL oplock_handler_ack_to_none(struct smbcli_transport *transport, uint16_t tid,
74 				    uint16_t fnum, uint8_t level,
75 				    void *private)
76 {
77 	struct smbcli_tree *tree = private;
78 	break_info.fnum = fnum;
79 	break_info.level = level;
80 	break_info.count++;
81 
82 	printf("Acking to none in oplock handler\n");
83 
84 	return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE);
85 }
86 
oplock_handler_close_recv(struct smbcli_request * req)87 static void oplock_handler_close_recv(struct smbcli_request *req)
88 {
89 	NTSTATUS status;
90 	status = smbcli_request_simple_recv(req);
91 	if (!NT_STATUS_IS_OK(status)) {
92 		printf("close failed in oplock_handler_close\n");
93 		break_info.failures++;
94 	}
95 }
96 
97 /*
98   a handler function for oplock break requests - close the file
99 */
oplock_handler_close(struct smbcli_transport * transport,uint16_t tid,uint16_t fnum,uint8_t level,void * private)100 static BOOL oplock_handler_close(struct smbcli_transport *transport, uint16_t tid,
101 				 uint16_t fnum, uint8_t level, void *private)
102 {
103 	union smb_close io;
104 	struct smbcli_tree *tree = private;
105 	struct smbcli_request *req;
106 
107 	break_info.fnum = fnum;
108 	break_info.level = level;
109 	break_info.count++;
110 
111 	io.close.level = RAW_CLOSE_CLOSE;
112 	io.close.in.file.fnum = fnum;
113 	io.close.in.write_time = 0;
114 	req = smb_raw_close_send(tree, &io);
115 	if (req == NULL) {
116 		printf("failed to send close in oplock_handler_close\n");
117 		return False;
118 	}
119 
120 	req->async.fn = oplock_handler_close_recv;
121 	req->async.private = NULL;
122 
123 	return True;
124 }
125 
126 /*
127   test oplock ops
128 */
test_oplock(struct smbcli_state * cli1,struct smbcli_state * cli2,TALLOC_CTX * mem_ctx)129 static BOOL test_oplock(struct smbcli_state *cli1, struct smbcli_state *cli2, TALLOC_CTX *mem_ctx)
130 {
131 	const char *fname = BASEDIR "\\test_oplock.dat";
132 	NTSTATUS status;
133 	BOOL ret = True;
134 	union smb_open io;
135 	union smb_unlink unl;
136 	union smb_read rd;
137 	union smb_setfileinfo sfi;
138 	uint16_t fnum=0, fnum2=0;
139 	char c = 0;
140 
141 	/* cleanup */
142 	smbcli_unlink(cli1->tree, fname);
143 
144 	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
145 
146 	/*
147 	  base ntcreatex parms
148 	*/
149 	io.generic.level = RAW_OPEN_NTCREATEX;
150 	io.ntcreatex.in.root_fid = 0;
151 	io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
152 	io.ntcreatex.in.alloc_size = 0;
153 	io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
154 	io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
155 	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
156 	io.ntcreatex.in.create_options = 0;
157 	io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
158 	io.ntcreatex.in.security_flags = 0;
159 	io.ntcreatex.in.fname = fname;
160 
161 	printf("open a file with a normal oplock\n");
162 	ZERO_STRUCT(break_info);
163 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
164 
165 	status = smb_raw_open(cli1->tree, mem_ctx, &io);
166 	CHECK_STATUS(status, NT_STATUS_OK);
167 	fnum = io.ntcreatex.out.file.fnum;
168 	CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
169 
170 	printf("a 2nd open should not cause a break\n");
171 	status = smb_raw_open(cli2->tree, mem_ctx, &io);
172 	CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
173 	CHECK_VAL(break_info.count, 0);
174 	CHECK_VAL(break_info.failures, 0);
175 
176 	printf("unlink it - should also be no break\n");
177 	unl.unlink.in.pattern = fname;
178 	unl.unlink.in.attrib = 0;
179 	status = smb_raw_unlink(cli2->tree, &unl);
180 	CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
181 	CHECK_VAL(break_info.count, 0);
182 	CHECK_VAL(break_info.failures, 0);
183 
184 	smbcli_close(cli1->tree, fnum);
185 
186 	/*
187 	  with a batch oplock we get a break
188 	*/
189 	printf("open with batch oplock\n");
190 	ZERO_STRUCT(break_info);
191 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
192 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
193 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
194 	status = smb_raw_open(cli1->tree, mem_ctx, &io);
195 	CHECK_STATUS(status, NT_STATUS_OK);
196 	fnum = io.ntcreatex.out.file.fnum;
197 	CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
198 
199 	printf("unlink should generate a break\n");
200 	unl.unlink.in.pattern = fname;
201 	unl.unlink.in.attrib = 0;
202 	status = smb_raw_unlink(cli2->tree, &unl);
203 	CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
204 
205 	CHECK_VAL(break_info.count, 1);
206 	CHECK_VAL(break_info.fnum, fnum);
207 	CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
208 	CHECK_VAL(break_info.failures, 0);
209 
210 	printf("2nd unlink should not generate a break\n");
211 	ZERO_STRUCT(break_info);
212 	status = smb_raw_unlink(cli2->tree, &unl);
213 	CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
214 
215 	CHECK_VAL(break_info.count, 0);
216 
217 	printf("writing should generate a self break to none\n");
218 	smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
219 	msleep(100);
220 	smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
221 
222 	CHECK_VAL(break_info.count, 1);
223 	CHECK_VAL(break_info.fnum, fnum);
224 	CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
225 	CHECK_VAL(break_info.failures, 0);
226 
227 	smbcli_close(cli1->tree, fnum);
228 
229 
230 	printf("open with batch oplock\n");
231 	ZERO_STRUCT(break_info);
232 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
233 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
234 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
235 	status = smb_raw_open(cli1->tree, mem_ctx, &io);
236 	CHECK_STATUS(status, NT_STATUS_OK);
237 	fnum = io.ntcreatex.out.file.fnum;
238 	CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
239 
240 	printf("unlink should generate a break, which we ack as break to none\n");
241 	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_none, cli1->tree);
242 	unl.unlink.in.pattern = fname;
243 	unl.unlink.in.attrib = 0;
244 	status = smb_raw_unlink(cli2->tree, &unl);
245 	CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
246 
247 	CHECK_VAL(break_info.count, 1);
248 	CHECK_VAL(break_info.fnum, fnum);
249 	CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
250 	CHECK_VAL(break_info.failures, 0);
251 
252 	printf("2nd unlink should not generate a break\n");
253 	ZERO_STRUCT(break_info);
254 	status = smb_raw_unlink(cli2->tree, &unl);
255 	CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
256 
257 	CHECK_VAL(break_info.count, 0);
258 
259 	printf("writing should not generate a break\n");
260 	smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
261 	msleep(100);
262 	smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
263 
264 	CHECK_VAL(break_info.count, 0);
265 
266 	smbcli_close(cli1->tree, fnum);
267 
268 	printf("if we close on break then the unlink can succeed\n");
269 	ZERO_STRUCT(break_info);
270 	smbcli_oplock_handler(cli1->transport, oplock_handler_close, cli1->tree);
271 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
272 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
273 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
274 	status = smb_raw_open(cli1->tree, mem_ctx, &io);
275 	CHECK_STATUS(status, NT_STATUS_OK);
276 	fnum = io.ntcreatex.out.file.fnum;
277 	CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
278 
279 	unl.unlink.in.pattern = fname;
280 	unl.unlink.in.attrib = 0;
281 	ZERO_STRUCT(break_info);
282 	status = smb_raw_unlink(cli2->tree, &unl);
283 	CHECK_STATUS(status, NT_STATUS_OK);
284 
285 	CHECK_VAL(break_info.count, 1);
286 	CHECK_VAL(break_info.fnum, fnum);
287 	CHECK_VAL(break_info.level, 1);
288 	CHECK_VAL(break_info.failures, 0);
289 
290 	printf("a self read should not cause a break\n");
291 	ZERO_STRUCT(break_info);
292 	smbcli_close(cli1->tree, fnum);
293 	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
294 
295 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
296 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
297 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
298 	status = smb_raw_open(cli1->tree, mem_ctx, &io);
299 	CHECK_STATUS(status, NT_STATUS_OK);
300 	fnum = io.ntcreatex.out.file.fnum;
301 	CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
302 
303 	rd.read.level = RAW_READ_READ;
304 	rd.read.in.file.fnum = fnum;
305 	rd.read.in.count = 1;
306 	rd.read.in.offset = 0;
307 	rd.read.in.remaining = 0;
308 	status = smb_raw_read(cli1->tree, &rd);
309 	CHECK_STATUS(status, NT_STATUS_OK);
310 	CHECK_VAL(break_info.count, 0);
311 	CHECK_VAL(break_info.failures, 0);
312 
313 	printf("a 2nd open should give a break\n");
314 	ZERO_STRUCT(break_info);
315 	smbcli_close(cli1->tree, fnum);
316 	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
317 
318 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
319 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
320 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
321 	status = smb_raw_open(cli1->tree, mem_ctx, &io);
322 	CHECK_STATUS(status, NT_STATUS_OK);
323 	fnum = io.ntcreatex.out.file.fnum;
324 	CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
325 
326 	ZERO_STRUCT(break_info);
327 
328 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
329 	status = smb_raw_open(cli2->tree, mem_ctx, &io);
330 	CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
331 
332 	CHECK_VAL(break_info.count, 1);
333 	CHECK_VAL(break_info.fnum, fnum);
334 	CHECK_VAL(break_info.level, 1);
335 	CHECK_VAL(break_info.failures, 0);
336 
337 
338 	printf("a 2nd open should give a break to level II if the first open allowed shared read\n");
339 	ZERO_STRUCT(break_info);
340 	smbcli_close(cli1->tree, fnum);
341 	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
342 	smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
343 
344 	io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE;
345 	io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
346 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
347 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
348 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
349 	status = smb_raw_open(cli1->tree, mem_ctx, &io);
350 	CHECK_STATUS(status, NT_STATUS_OK);
351 	fnum = io.ntcreatex.out.file.fnum;
352 	CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
353 
354 	ZERO_STRUCT(break_info);
355 
356 	status = smb_raw_open(cli2->tree, mem_ctx, &io);
357 	CHECK_STATUS(status, NT_STATUS_OK);
358 	fnum2 = io.ntcreatex.out.file.fnum;
359 	CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
360 
361 	CHECK_VAL(break_info.count, 1);
362 	CHECK_VAL(break_info.fnum, fnum);
363 	CHECK_VAL(break_info.level, 1);
364 	CHECK_VAL(break_info.failures, 0);
365 	ZERO_STRUCT(break_info);
366 
367 	printf("write should trigger a break to none on both\n");
368 	smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
369 	msleep(100);
370 	smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
371 
372 	CHECK_VAL(break_info.count, 2);
373 	CHECK_VAL(break_info.level, 0);
374 	CHECK_VAL(break_info.failures, 0);
375 
376 	smbcli_close(cli1->tree, fnum);
377 	smbcli_close(cli2->tree, fnum2);
378 
379 	printf("a 2nd open should get an oplock when we close instead of ack\n");
380 	ZERO_STRUCT(break_info);
381 	smbcli_oplock_handler(cli1->transport, oplock_handler_close, cli1->tree);
382 
383 	io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
384 	io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
385 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
386 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
387 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
388 	status = smb_raw_open(cli1->tree, mem_ctx, &io);
389 	CHECK_STATUS(status, NT_STATUS_OK);
390 	fnum2 = io.ntcreatex.out.file.fnum;
391 	CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
392 
393 	ZERO_STRUCT(break_info);
394 
395 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
396 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
397 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
398 	status = smb_raw_open(cli2->tree, mem_ctx, &io);
399 	CHECK_STATUS(status, NT_STATUS_OK);
400 	fnum = io.ntcreatex.out.file.fnum;
401 	CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
402 
403 	CHECK_VAL(break_info.count, 1);
404 	CHECK_VAL(break_info.fnum, fnum2);
405 	CHECK_VAL(break_info.level, 1);
406 	CHECK_VAL(break_info.failures, 0);
407 
408 	smbcli_close(cli2->tree, fnum);
409 
410 	printf("open with batch oplock\n");
411 	ZERO_STRUCT(break_info);
412 	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
413 
414 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
415 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
416 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
417 	status = smb_raw_open(cli1->tree, mem_ctx, &io);
418 	CHECK_STATUS(status, NT_STATUS_OK);
419 	fnum = io.ntcreatex.out.file.fnum;
420 	CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
421 
422 	ZERO_STRUCT(break_info);
423 	printf("second open with attributes only shouldn't cause oplock break\n");
424 
425 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
426 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
427 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
428 	io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
429 	status = smb_raw_open(cli2->tree, mem_ctx, &io);
430 	CHECK_STATUS(status, NT_STATUS_OK);
431 	fnum2 = io.ntcreatex.out.file.fnum;
432 	CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
433 	CHECK_VAL(break_info.count, 0);
434 	CHECK_VAL(break_info.failures, 0);
435 
436 	smbcli_close(cli1->tree, fnum);
437 	smbcli_close(cli2->tree, fnum2);
438 	smbcli_unlink(cli1->tree, fname);
439 
440 	printf("open with attributes only can create file\n");
441 
442 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
443 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
444 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
445 	io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
446 	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
447 	status = smb_raw_open(cli1->tree, mem_ctx, &io);
448 	CHECK_STATUS(status, NT_STATUS_OK);
449 	fnum = io.ntcreatex.out.file.fnum;
450 	CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
451 
452 	printf("Subsequent normal open should break oplock on attribute only open to level II\n");
453 
454 	ZERO_STRUCT(break_info);
455 	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
456 
457 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
458 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
459 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
460 	io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
461 	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
462 	status = smb_raw_open(cli2->tree, mem_ctx, &io);
463 	CHECK_STATUS(status, NT_STATUS_OK);
464 	fnum2 = io.ntcreatex.out.file.fnum;
465 	CHECK_VAL(break_info.count, 1);
466 	CHECK_VAL(break_info.fnum, fnum);
467 	CHECK_VAL(break_info.failures, 0);
468 	CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
469 	CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
470 	smbcli_close(cli2->tree, fnum2);
471 
472 	printf("third oplocked open should grant level2 without break\n");
473 	ZERO_STRUCT(break_info);
474 	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
475 	smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
476 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
477 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
478 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
479 	io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
480 	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
481 	status = smb_raw_open(cli2->tree, mem_ctx, &io);
482 	CHECK_STATUS(status, NT_STATUS_OK);
483 	fnum2 = io.ntcreatex.out.file.fnum;
484 	CHECK_VAL(break_info.count, 0);
485 	CHECK_VAL(break_info.failures, 0);
486 	CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
487 
488 	ZERO_STRUCT(break_info);
489 
490 	printf("write should trigger a break to none on both\n");
491 	smbcli_write(cli2->tree, fnum2, 0, &c, 0, 1);
492 
493 	/* Now the oplock break request comes in. But right now we can't
494 	 * answer it. Do another write */
495 
496 	msleep(100);
497 	smbcli_write(cli2->tree, fnum2, 0, &c, 1, 1);
498 
499 	CHECK_VAL(break_info.count, 2);
500 	CHECK_VAL(break_info.level, 0);
501 	CHECK_VAL(break_info.failures, 0);
502 
503 	smbcli_close(cli1->tree, fnum);
504 	smbcli_close(cli2->tree, fnum2);
505 
506 	ZERO_STRUCT(break_info);
507 	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
508 
509 	printf("Open with oplock after a on-oplock open should grant level2\n");
510 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
511 	io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
512 	io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
513 		NTCREATEX_SHARE_ACCESS_WRITE|
514 		NTCREATEX_SHARE_ACCESS_DELETE;
515 	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
516 	status = smb_raw_open(cli1->tree, mem_ctx, &io);
517 	CHECK_STATUS(status, NT_STATUS_OK);
518 	fnum = io.ntcreatex.out.file.fnum;
519 	CHECK_VAL(break_info.count, 0);
520 	CHECK_VAL(break_info.failures, 0);
521 	CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
522 
523 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
524 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
525 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
526 	io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
527 	io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
528 		NTCREATEX_SHARE_ACCESS_WRITE|
529 		NTCREATEX_SHARE_ACCESS_DELETE;
530 	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
531 	status = smb_raw_open(cli2->tree, mem_ctx, &io);
532 	CHECK_STATUS(status, NT_STATUS_OK);
533 	fnum2 = io.ntcreatex.out.file.fnum;
534 	CHECK_VAL(break_info.count, 0);
535 	CHECK_VAL(break_info.failures, 0);
536 	CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
537 
538 	printf("write should trigger a break to none\n");
539 	{
540 		union smb_write wr;
541 		wr.write.level = RAW_WRITE_WRITE;
542 		wr.write.in.file.fnum = fnum;
543 		wr.write.in.count = 1;
544 		wr.write.in.offset = 0;
545 		wr.write.in.remaining = 0;
546 		wr.write.in.data = (const uint8_t *)"x";
547 		status = smb_raw_write(cli1->tree, &wr);
548 		CHECK_STATUS(status, NT_STATUS_OK);
549 	}
550 
551 	/* Now the oplock break request comes in. But right now we can't
552 	 * answer it. Do another write */
553 
554 	msleep(100);
555 
556 	{
557 		union smb_write wr;
558 		wr.write.level = RAW_WRITE_WRITE;
559 		wr.write.in.file.fnum = fnum;
560 		wr.write.in.count = 1;
561 		wr.write.in.offset = 0;
562 		wr.write.in.remaining = 0;
563 		wr.write.in.data = (const uint8_t *)"x";
564 		status = smb_raw_write(cli1->tree, &wr);
565 		CHECK_STATUS(status, NT_STATUS_OK);
566 	}
567 
568 	CHECK_VAL(break_info.count, 1);
569 	CHECK_VAL(break_info.fnum, fnum2);
570 	CHECK_VAL(break_info.level, 0);
571 	CHECK_VAL(break_info.failures, 0);
572 
573 	smbcli_close(cli1->tree, fnum);
574 	smbcli_close(cli2->tree, fnum2);
575 	smbcli_unlink(cli1->tree, fname);
576 
577 	/* Test if a set-eof on pathname breaks an exclusive oplock. */
578 	printf("Test if setpathinfo set EOF breaks oplocks.\n");
579 
580 	ZERO_STRUCT(break_info);
581 	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
582 
583 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
584 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
585 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
586 	io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
587 	io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
588 		NTCREATEX_SHARE_ACCESS_WRITE|
589 		NTCREATEX_SHARE_ACCESS_DELETE;
590 	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
591 	status = smb_raw_open(cli1->tree, mem_ctx, &io);
592 	CHECK_STATUS(status, NT_STATUS_OK);
593 	fnum = io.ntcreatex.out.file.fnum;
594 	CHECK_VAL(break_info.count, 0);
595 	CHECK_VAL(break_info.failures, 0);
596 	CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
597 
598 	ZERO_STRUCT(sfi);
599 	sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
600 	sfi.generic.in.file.path = fname;
601 	sfi.end_of_file_info.in.size = 100;
602 
603         status = smb_raw_setpathinfo(cli2->tree, &sfi);
604 
605 	CHECK_STATUS(status, NT_STATUS_OK);
606 	CHECK_VAL(break_info.count, 1);
607 	CHECK_VAL(break_info.failures, 0);
608 	CHECK_VAL(break_info.level, 0);
609 
610 	smbcli_close(cli1->tree, fnum);
611 	smbcli_unlink(cli1->tree, fname);
612 
613 	/* Test if a set-allocation size on pathname breaks an exclusive oplock. */
614 	printf("Test if setpathinfo allocation size breaks oplocks.\n");
615 
616 	ZERO_STRUCT(break_info);
617 	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
618 
619 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
620 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
621 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
622 	io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
623 	io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
624 		NTCREATEX_SHARE_ACCESS_WRITE|
625 		NTCREATEX_SHARE_ACCESS_DELETE;
626 	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
627 	status = smb_raw_open(cli1->tree, mem_ctx, &io);
628 	CHECK_STATUS(status, NT_STATUS_OK);
629 	fnum = io.ntcreatex.out.file.fnum;
630 	CHECK_VAL(break_info.count, 0);
631 	CHECK_VAL(break_info.failures, 0);
632 	CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
633 
634 	ZERO_STRUCT(sfi);
635 	sfi.generic.level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
636 	sfi.generic.in.file.path = fname;
637 	sfi.allocation_info.in.alloc_size = 65536 * 8;
638 
639         status = smb_raw_setpathinfo(cli2->tree, &sfi);
640 
641 	CHECK_STATUS(status, NT_STATUS_OK);
642 	CHECK_VAL(break_info.count, 1);
643 	CHECK_VAL(break_info.failures, 0);
644 	CHECK_VAL(break_info.level, 0);
645 
646 	smbcli_close(cli1->tree, fnum);
647 	smbcli_close(cli2->tree, fnum2);
648 	smbcli_unlink(cli1->tree, fname);
649 
650 	printf("open with batch oplock\n");
651 	ZERO_STRUCT(break_info);
652 	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
653 
654 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
655 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
656 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
657 	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
658 	status = smb_raw_open(cli1->tree, mem_ctx, &io);
659 	CHECK_STATUS(status, NT_STATUS_OK);
660 	fnum = io.ntcreatex.out.file.fnum;
661 	CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
662 
663 	ZERO_STRUCT(break_info);
664 
665 	printf("second open with attributes only and NTCREATEX_DISP_OVERWRITE dispostion causes oplock break\n");
666 
667 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
668 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
669 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
670 	io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
671 	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
672 	status = smb_raw_open(cli2->tree, mem_ctx, &io);
673 	CHECK_STATUS(status, NT_STATUS_OK);
674 	fnum2 = io.ntcreatex.out.file.fnum;
675 	CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
676 	CHECK_VAL(break_info.count, 1);
677 	CHECK_VAL(break_info.failures, 0);
678 
679 	smbcli_close(cli1->tree, fnum);
680 	smbcli_close(cli2->tree, fnum2);
681 	smbcli_unlink(cli1->tree, fname);
682 
683 	printf("open with batch oplock\n");
684 	ZERO_STRUCT(break_info);
685 	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
686 
687 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
688 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
689 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
690 	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
691 	status = smb_raw_open(cli1->tree, mem_ctx, &io);
692 	CHECK_STATUS(status, NT_STATUS_OK);
693 	fnum = io.ntcreatex.out.file.fnum;
694 	CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
695 
696 	ZERO_STRUCT(break_info);
697 
698 	printf("second open with attributes only and NTCREATEX_DISP_SUPERSEDE dispostion causes oplock break\n");
699 
700 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
701 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
702 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
703 	io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
704 	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
705 	status = smb_raw_open(cli2->tree, mem_ctx, &io);
706 	CHECK_STATUS(status, NT_STATUS_OK);
707 	fnum2 = io.ntcreatex.out.file.fnum;
708 	CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
709 	CHECK_VAL(break_info.count, 1);
710 	CHECK_VAL(break_info.failures, 0);
711 
712 	smbcli_close(cli1->tree, fnum);
713 	smbcli_close(cli2->tree, fnum2);
714 	smbcli_unlink(cli1->tree, fname);
715 
716 
717 done:
718 	smbcli_close(cli1->tree, fnum);
719 	smbcli_close(cli2->tree, fnum2);
720 	smbcli_unlink(cli1->tree, fname);
721 	return ret;
722 }
723 
724 
725 /*
726    basic testing of oplocks
727 */
torture_raw_oplock(struct torture_context * torture)728 BOOL torture_raw_oplock(struct torture_context *torture)
729 {
730 	struct smbcli_state *cli1, *cli2;
731 	BOOL ret = True;
732 	TALLOC_CTX *mem_ctx;
733 
734 	if (!torture_open_connection(&cli1, 0)) {
735 		return False;
736 	}
737 
738 	if (!torture_open_connection_ev(
739 		    &cli2, 1, cli1->transport->socket->event.ctx)) {
740 		return False;
741 	}
742 
743 	if (!torture_setup_dir(cli1, BASEDIR)) {
744 		return False;
745 	}
746 
747 	mem_ctx = talloc_init("torture_raw_oplock");
748 
749 	if (!test_oplock(cli1, cli2, mem_ctx)) {
750 		ret = False;
751 	}
752 
753 	smb_raw_exit(cli1->session);
754 	smbcli_deltree(cli1->tree, BASEDIR);
755 	torture_close_connection(cli1);
756 	torture_close_connection(cli2);
757 	talloc_free(mem_ctx);
758 	return ret;
759 }
760 
761 
762 /*
763    stress testing of oplocks
764 */
torture_bench_oplock(struct torture_context * torture)765 BOOL torture_bench_oplock(struct torture_context *torture)
766 {
767 	struct smbcli_state **cli;
768 	BOOL ret = True;
769 	TALLOC_CTX *mem_ctx = talloc_new(torture);
770 	int torture_nprocs = lp_parm_int(-1, "torture", "nprocs", 4);
771 	int i, count=0;
772 	int timelimit = torture_setting_int(torture, "timelimit", 10);
773 	union smb_open io;
774 	struct timeval tv;
775 	struct event_context *ev = event_context_find(mem_ctx);
776 
777 	cli = talloc_array(mem_ctx, struct smbcli_state *, torture_nprocs);
778 
779 	printf("Opening %d connections\n", torture_nprocs);
780 	for (i=0;i<torture_nprocs;i++) {
781 		if (!torture_open_connection_ev(&cli[i], i, ev)) {
782 			return False;
783 		}
784 		talloc_steal(mem_ctx, cli[i]);
785 		smbcli_oplock_handler(cli[i]->transport, oplock_handler_close,
786 				      cli[i]->tree);
787 	}
788 
789 	if (!torture_setup_dir(cli[0], BASEDIR)) {
790 		ret = False;
791 		goto done;
792 	}
793 
794 	io.ntcreatex.level = RAW_OPEN_NTCREATEX;
795 	io.ntcreatex.in.root_fid = 0;
796 	io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
797 	io.ntcreatex.in.alloc_size = 0;
798 	io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
799 	io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
800 	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
801 	io.ntcreatex.in.create_options = 0;
802 	io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
803 	io.ntcreatex.in.security_flags = 0;
804 	io.ntcreatex.in.fname = BASEDIR "\\test.dat";
805 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
806 		NTCREATEX_FLAGS_REQUEST_OPLOCK |
807 		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
808 
809 	tv = timeval_current();
810 
811 	/*
812 	  we open the same file with SHARE_ACCESS_NONE from all the
813 	  connections in a round robin fashion. Each open causes an
814 	  oplock break on the previous connection, which is answered
815 	  by the oplock_handler_close() to close the file.
816 
817 	  This measures how fast we can pass on oplocks, and stresses
818 	  the oplock handling code
819 	*/
820 	printf("Running for %d seconds\n", timelimit);
821 	while (timeval_elapsed(&tv) < timelimit) {
822 		for (i=0;i<torture_nprocs;i++) {
823 			NTSTATUS status;
824 
825 			status = smb_raw_open(cli[i]->tree, mem_ctx, &io);
826 			CHECK_STATUS(status, NT_STATUS_OK);
827 			count++;
828 		}
829 		printf("%.2f ops/second\r", count/timeval_elapsed(&tv));
830 	}
831 
832 	printf("%.2f ops/second\n", count/timeval_elapsed(&tv));
833 
834 	smb_raw_exit(cli[torture_nprocs-1]->session);
835 
836 done:
837 	smb_raw_exit(cli[0]->session);
838 	smbcli_deltree(cli[0]->tree, BASEDIR);
839 	talloc_free(mem_ctx);
840 	return ret;
841 }
842