2 Unix SMB/CIFS implementation.
3 basic raw test suite for oplocks
4 Copyright (C) Andrew Tridgell 2003
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.
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.
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.
22 #include "librpc/gen_ndr/ndr_security.h"
24 #define CHECK_VAL(v, correct) do { \
25 if ((v) != (correct)) { \
26 printf("(%d) wrong value for %s got 0x%x - should be 0x%x\n", \
27 __LINE__, #v, (int)v, (int)correct); \
31 #define CHECK_STATUS(status, correct) do { \
32 if (!NT_STATUS_EQUAL(status, correct)) { \
33 printf("(%d) Incorrect status %s - should be %s\n", \
34 __LINE__, nt_errstr(status), nt_errstr(correct)); \
47 a handler function for oplock break requests
49 static BOOL oplock_handler_ack(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private)
51 struct smbcli_tree *tree = private;
52 break_info.fnum = fnum;
53 break_info.level = level;
56 printf("Acking in oplock handler\n");
58 return smbcli_oplock_ack(tree, fnum, level);
62 a handler function for oplock break requests - close the file
64 static BOOL oplock_handler_close(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private)
68 struct smbcli_tree *tree = private;
70 break_info.fnum = fnum;
71 break_info.level = level;
74 io.close.level = RAW_CLOSE_CLOSE;
75 io.close.in.fnum = fnum;
76 io.close.in.write_time = 0;
77 status = smb_raw_close(tree, &io);
79 printf("Closing in oplock handler\n");
81 if (!NT_STATUS_IS_OK(status)) {
82 printf("close failed in oplock_handler_close\n");
91 static BOOL test_oplock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
93 const char *fname = "\\test_oplock.dat";
97 struct smb_unlink unl;
99 uint16_t fnum=0, fnum2=0;
102 smbcli_unlink(cli->tree, fname);
104 smbcli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
109 io.generic.level = RAW_OPEN_NTCREATEX;
110 io.ntcreatex.in.root_fid = 0;
111 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
112 io.ntcreatex.in.alloc_size = 0;
113 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
114 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
115 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
116 io.ntcreatex.in.create_options = 0;
117 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
118 io.ntcreatex.in.security_flags = 0;
119 io.ntcreatex.in.fname = fname;
121 printf("open a file with a normal oplock\n");
122 ZERO_STRUCT(break_info);
123 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
125 status = smb_raw_open(cli->tree, mem_ctx, &io);
126 CHECK_STATUS(status, NT_STATUS_OK);
127 fnum = io.ntcreatex.out.fnum;
128 CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
130 printf("unlink it - should be no break\n");
131 unl.in.pattern = fname;
133 status = smb_raw_unlink(cli->tree, &unl);
134 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
135 CHECK_VAL(break_info.count, 0);
137 smbcli_close(cli->tree, fnum);
140 with a batch oplock we get a break
142 printf("open with batch oplock\n");
143 ZERO_STRUCT(break_info);
144 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
145 NTCREATEX_FLAGS_REQUEST_OPLOCK |
146 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
147 status = smb_raw_open(cli->tree, mem_ctx, &io);
148 CHECK_STATUS(status, NT_STATUS_OK);
149 fnum = io.ntcreatex.out.fnum;
150 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
152 printf("unlink should generate a break\n");
153 unl.in.pattern = fname;
155 status = smb_raw_unlink(cli->tree, &unl);
156 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
158 CHECK_VAL(break_info.fnum, fnum);
159 CHECK_VAL(break_info.level, 1);
160 CHECK_VAL(break_info.count, 1);
163 smbcli_close(cli->tree, fnum);
165 printf("if we close on break then the unlink can succeed\n");
166 ZERO_STRUCT(break_info);
167 smbcli_oplock_handler(cli->transport, oplock_handler_close, cli->tree);
168 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
169 NTCREATEX_FLAGS_REQUEST_OPLOCK |
170 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
171 status = smb_raw_open(cli->tree, mem_ctx, &io);
172 CHECK_STATUS(status, NT_STATUS_OK);
173 fnum = io.ntcreatex.out.fnum;
174 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
176 unl.in.pattern = fname;
178 ZERO_STRUCT(break_info);
179 status = smb_raw_unlink(cli->tree, &unl);
180 CHECK_STATUS(status, NT_STATUS_OK);
182 CHECK_VAL(break_info.fnum, fnum);
183 CHECK_VAL(break_info.level, 1);
184 CHECK_VAL(break_info.count, 1);
186 printf("a self read should not cause a break\n");
187 ZERO_STRUCT(break_info);
188 smbcli_close(cli->tree, fnum);
189 smbcli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
191 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
192 NTCREATEX_FLAGS_REQUEST_OPLOCK |
193 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
194 status = smb_raw_open(cli->tree, mem_ctx, &io);
195 CHECK_STATUS(status, NT_STATUS_OK);
196 fnum = io.ntcreatex.out.fnum;
197 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
199 rd.read.level = RAW_READ_READ;
200 rd.read.in.fnum = fnum;
201 rd.read.in.count = 1;
202 rd.read.in.offset = 0;
203 rd.read.in.remaining = 0;
204 status = smb_raw_read(cli->tree, &rd);
205 CHECK_STATUS(status, NT_STATUS_OK);
206 CHECK_VAL(break_info.count, 0);
209 printf("a 2nd open should give a break\n");
210 ZERO_STRUCT(break_info);
211 smbcli_close(cli->tree, fnum);
212 smbcli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
214 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
215 NTCREATEX_FLAGS_REQUEST_OPLOCK |
216 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
217 status = smb_raw_open(cli->tree, mem_ctx, &io);
218 CHECK_STATUS(status, NT_STATUS_OK);
219 fnum = io.ntcreatex.out.fnum;
220 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
222 ZERO_STRUCT(break_info);
224 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
225 status = smb_raw_open(cli->tree, mem_ctx, &io);
226 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
228 CHECK_VAL(break_info.count, 1);
229 CHECK_VAL(break_info.fnum, fnum);
230 CHECK_VAL(break_info.level, 1);
232 printf("a 2nd open should get an oplock when we close instead of ack\n");
233 ZERO_STRUCT(break_info);
234 smbcli_close(cli->tree, fnum);
235 smbcli_oplock_handler(cli->transport, oplock_handler_close, cli->tree);
237 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
238 NTCREATEX_FLAGS_REQUEST_OPLOCK |
239 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
240 status = smb_raw_open(cli->tree, mem_ctx, &io);
241 CHECK_STATUS(status, NT_STATUS_OK);
242 fnum2 = io.ntcreatex.out.fnum;
243 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
245 ZERO_STRUCT(break_info);
247 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
248 NTCREATEX_FLAGS_REQUEST_OPLOCK |
249 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
250 status = smb_raw_open(cli->tree, mem_ctx, &io);
251 CHECK_STATUS(status, NT_STATUS_OK);
252 fnum = io.ntcreatex.out.fnum;
253 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
255 CHECK_VAL(break_info.count, 1);
256 CHECK_VAL(break_info.fnum, fnum2);
257 CHECK_VAL(break_info.level, 1);
259 smbcli_close(cli->tree, fnum);
261 printf("open with batch oplock\n");
262 ZERO_STRUCT(break_info);
263 smbcli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
265 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
266 NTCREATEX_FLAGS_REQUEST_OPLOCK |
267 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
268 status = smb_raw_open(cli->tree, mem_ctx, &io);
269 CHECK_STATUS(status, NT_STATUS_OK);
270 fnum = io.ntcreatex.out.fnum;
271 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
273 ZERO_STRUCT(break_info);
274 printf("second open with attributes only shouldn't cause oplock break\n");
276 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
277 NTCREATEX_FLAGS_REQUEST_OPLOCK |
278 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
279 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
280 status = smb_raw_open(cli->tree, mem_ctx, &io);
281 CHECK_STATUS(status, NT_STATUS_OK);
282 fnum2 = io.ntcreatex.out.fnum;
283 CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
284 CHECK_VAL(break_info.count, 0);
285 CHECK_VAL(break_info.fnum, 0);
286 CHECK_VAL(break_info.level, 0);
288 smbcli_close(cli->tree, fnum);
289 smbcli_close(cli->tree, fnum2);
290 smbcli_unlink(cli->tree, fname);
292 printf("open with attributes only can create file\n");
293 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
294 NTCREATEX_FLAGS_REQUEST_OPLOCK |
295 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
296 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
297 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
298 status = smb_raw_open(cli->tree, mem_ctx, &io);
299 CHECK_STATUS(status, NT_STATUS_OK);
300 fnum = io.ntcreatex.out.fnum;
301 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
303 printf("Subsequent normal open should break oplock on attribute only open to level II\n");
305 ZERO_STRUCT(break_info);
306 smbcli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
308 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
309 NTCREATEX_FLAGS_REQUEST_OPLOCK |
310 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
311 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
312 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
313 status = smb_raw_open(cli->tree, mem_ctx, &io);
314 CHECK_STATUS(status, NT_STATUS_OK);
315 fnum2 = io.ntcreatex.out.fnum;
316 CHECK_VAL(break_info.count, 1);
317 CHECK_VAL(break_info.fnum, fnum);
318 CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
321 smbcli_close(cli->tree, fnum);
322 smbcli_close(cli->tree, fnum2);
323 smbcli_unlink(cli->tree, fname);
329 basic testing of oplocks
331 BOOL torture_raw_oplock(void)
333 struct smbcli_state *cli1;
337 if (!torture_open_connection(&cli1)) {
341 mem_ctx = talloc_init("torture_raw_oplock");
343 if (!test_oplock(cli1, mem_ctx)) {
347 torture_close_connection(cli1);
348 talloc_free(mem_ctx);