Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : SMB2 notify test suite
5 :
6 : Copyright (C) Stefan Metzmacher 2006
7 : Copyright (C) Andrew Tridgell 2009
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "includes.h"
24 : #include "libcli/smb2/smb2.h"
25 : #include "libcli/smb2/smb2_calls.h"
26 : #include "../libcli/smb/smbXcli_base.h"
27 :
28 : #include "torture/torture.h"
29 : #include "torture/smb2/proto.h"
30 : #include "librpc/gen_ndr/ndr_security.h"
31 : #include "libcli/security/security.h"
32 : #include "torture/util.h"
33 :
34 : #include "system/filesys.h"
35 : #include "auth/credentials/credentials.h"
36 : #include "lib/cmdline/cmdline.h"
37 : #include "librpc/gen_ndr/security.h"
38 :
39 : #include "lib/events/events.h"
40 :
41 : #include "libcli/raw/libcliraw.h"
42 : #include "libcli/raw/raw_proto.h"
43 : #include "libcli/libcli.h"
44 :
45 : #define CHECK_STATUS(status, correct) do { \
46 : if (!NT_STATUS_EQUAL(status, correct)) { \
47 : torture_result(torture, TORTURE_FAIL, \
48 : "(%s) Incorrect status %s - should be %s\n", \
49 : __location__, nt_errstr(status), nt_errstr(correct)); \
50 : ret = false; \
51 : goto done; \
52 : }} while (0)
53 :
54 : #define CHECK_VAL(v, correct) do { \
55 : if ((v) != (correct)) { \
56 : torture_result(torture, TORTURE_FAIL, \
57 : "(%s) wrong value for %s 0x%x should be 0x%x\n", \
58 : __location__, #v, (int)v, (int)correct); \
59 : ret = false; \
60 : goto done; \
61 : }} while (0)
62 :
63 : #define CHECK_WIRE_STR(field, value) do { \
64 : if (!field.s || strcmp(field.s, value)) { \
65 : torture_result(torture, TORTURE_FAIL, \
66 : "(%s) %s [%s] != %s\n", __location__, #field, \
67 : field.s, value); \
68 : ret = false; \
69 : goto done; \
70 : }} while (0)
71 :
72 : #define WAIT_FOR_ASYNC_RESPONSE(req) \
73 : while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \
74 : if (tevent_loop_once(torture->ev) != 0) { \
75 : break; \
76 : } \
77 : }
78 :
79 : #define BASEDIR "test_notify"
80 : #define FNAME "smb2-notify01.dat"
81 :
82 2 : static bool test_valid_request(struct torture_context *torture,
83 : struct smb2_tree *tree)
84 : {
85 2 : bool ret = true;
86 0 : NTSTATUS status;
87 0 : struct smb2_handle dh;
88 0 : struct smb2_notify n;
89 0 : struct smb2_request *req;
90 0 : uint32_t max_buffer_size;
91 :
92 2 : torture_comment(torture, "TESTING VALIDITY OF CHANGE NOTIFY REQUEST\n");
93 :
94 2 : smb2_transport_credits_ask_num(tree->session->transport, 256);
95 :
96 2 : smb2_util_unlink(tree, FNAME);
97 :
98 2 : status = smb2_util_roothandle(tree, &dh);
99 2 : CHECK_STATUS(status, NT_STATUS_OK);
100 :
101 0 : max_buffer_size =
102 2 : smb2cli_conn_max_trans_size(tree->session->transport->conn);
103 :
104 2 : n.in.recursive = 0x0000;
105 2 : n.in.buffer_size = max_buffer_size;
106 2 : n.in.file.handle = dh;
107 2 : n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
108 2 : n.in.unknown = 0x00000000;
109 2 : req = smb2_notify_send(tree, &n);
110 :
111 10 : while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
112 8 : if (tevent_loop_once(torture->ev) != 0) {
113 0 : break;
114 : }
115 : }
116 :
117 2 : status = torture_setup_simple_file(torture, tree, FNAME);
118 2 : CHECK_STATUS(status, NT_STATUS_OK);
119 :
120 2 : status = smb2_notify_recv(req, torture, &n);
121 2 : CHECK_STATUS(status, NT_STATUS_OK);
122 2 : CHECK_VAL(n.out.num_changes, 1);
123 2 : CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_ADDED);
124 2 : CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
125 :
126 : /*
127 : * if the change response doesn't fit in the buffer
128 : * NOTIFY_ENUM_DIR is returned.
129 : */
130 2 : n.in.buffer_size = 0x00000000;
131 2 : req = smb2_notify_send(tree, &n);
132 :
133 10 : while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
134 8 : if (tevent_loop_once(torture->ev) != 0) {
135 0 : break;
136 : }
137 : }
138 :
139 2 : status = torture_setup_simple_file(torture, tree, FNAME);
140 2 : CHECK_STATUS(status, NT_STATUS_OK);
141 :
142 2 : status = smb2_notify_recv(req, torture, &n);
143 2 : CHECK_STATUS(status, NT_STATUS_NOTIFY_ENUM_DIR);
144 :
145 : /*
146 : * if the change response fits in the buffer we get
147 : * NT_STATUS_OK again
148 : */
149 2 : n.in.buffer_size = max_buffer_size;
150 2 : req = smb2_notify_send(tree, &n);
151 :
152 10 : while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
153 8 : if (tevent_loop_once(torture->ev) != 0) {
154 0 : break;
155 : }
156 : }
157 :
158 2 : status = torture_setup_simple_file(torture, tree, FNAME);
159 2 : CHECK_STATUS(status, NT_STATUS_OK);
160 :
161 2 : status = smb2_notify_recv(req, torture, &n);
162 2 : CHECK_STATUS(status, NT_STATUS_OK);
163 2 : CHECK_VAL(n.out.num_changes, 3);
164 0 : CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_REMOVED);
165 0 : CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
166 0 : CHECK_VAL(n.out.changes[1].action, NOTIFY_ACTION_ADDED);
167 0 : CHECK_WIRE_STR(n.out.changes[1].name, FNAME);
168 0 : CHECK_VAL(n.out.changes[2].action, NOTIFY_ACTION_MODIFIED);
169 0 : CHECK_WIRE_STR(n.out.changes[2].name, FNAME);
170 :
171 : /* if the first notify returns NOTIFY_ENUM_DIR, all do */
172 0 : status = smb2_util_close(tree, dh);
173 0 : CHECK_STATUS(status, NT_STATUS_OK);
174 0 : status = smb2_util_roothandle(tree, &dh);
175 0 : CHECK_STATUS(status, NT_STATUS_OK);
176 :
177 0 : n.in.recursive = 0x0000;
178 0 : n.in.buffer_size = 0x00000001;
179 0 : n.in.file.handle = dh;
180 0 : n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
181 0 : n.in.unknown = 0x00000000;
182 0 : req = smb2_notify_send(tree, &n);
183 :
184 0 : while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
185 0 : if (tevent_loop_once(torture->ev) != 0) {
186 0 : break;
187 : }
188 : }
189 :
190 0 : status = torture_setup_simple_file(torture, tree, FNAME);
191 0 : CHECK_STATUS(status, NT_STATUS_OK);
192 :
193 0 : status = smb2_notify_recv(req, torture, &n);
194 0 : CHECK_STATUS(status, NT_STATUS_NOTIFY_ENUM_DIR);
195 :
196 0 : n.in.buffer_size = max_buffer_size;
197 0 : req = smb2_notify_send(tree, &n);
198 0 : while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
199 0 : if (tevent_loop_once(torture->ev) != 0) {
200 0 : break;
201 : }
202 : }
203 :
204 0 : status = torture_setup_simple_file(torture, tree, FNAME);
205 0 : CHECK_STATUS(status, NT_STATUS_OK);
206 :
207 0 : status = smb2_notify_recv(req, torture, &n);
208 0 : CHECK_STATUS(status, NT_STATUS_NOTIFY_ENUM_DIR);
209 :
210 : /* if the buffer size is too large, we get invalid parameter */
211 0 : n.in.recursive = 0x0000;
212 0 : n.in.buffer_size = max_buffer_size + 1;
213 0 : n.in.file.handle = dh;
214 0 : n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
215 0 : n.in.unknown = 0x00000000;
216 0 : req = smb2_notify_send(tree, &n);
217 0 : status = smb2_notify_recv(req, torture, &n);
218 0 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
219 :
220 2 : done:
221 2 : return ret;
222 : }
223 :
224 : /*
225 : basic testing of change notify on directories
226 : */
227 :
228 : #define BASEDIR_DIR BASEDIR "_DIR"
229 :
230 2 : static bool torture_smb2_notify_dir(struct torture_context *torture,
231 : struct smb2_tree *tree1,
232 : struct smb2_tree *tree2)
233 : {
234 2 : bool ret = true;
235 0 : NTSTATUS status;
236 0 : union smb_notify notify;
237 0 : union smb_open io;
238 0 : union smb_close cl;
239 0 : int i, count;
240 2 : struct smb2_handle h1 = {{0}};
241 2 : struct smb2_handle h2 = {{0}};
242 0 : struct smb2_request *req, *req2;
243 2 : const char *fname = BASEDIR_DIR "\\subdir-name";
244 0 : extern int torture_numops;
245 :
246 2 : torture_comment(torture, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
247 :
248 2 : smb2_deltree(tree1, BASEDIR_DIR);
249 2 : smb2_util_rmdir(tree1, BASEDIR_DIR);
250 : /*
251 : get a handle on the directory
252 : */
253 2 : ZERO_STRUCT(io.smb2);
254 2 : io.generic.level = RAW_OPEN_SMB2;
255 2 : io.smb2.in.create_flags = 0;
256 2 : io.smb2.in.desired_access = SEC_FILE_ALL;
257 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
258 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
259 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
260 : NTCREATEX_SHARE_ACCESS_WRITE;
261 2 : io.smb2.in.alloc_size = 0;
262 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
263 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
264 2 : io.smb2.in.security_flags = 0;
265 2 : io.smb2.in.fname = BASEDIR_DIR;
266 :
267 2 : status = smb2_create(tree1, torture, &(io.smb2));
268 2 : CHECK_STATUS(status, NT_STATUS_OK);
269 2 : h1 = io.smb2.out.file.handle;
270 :
271 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
272 2 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ;
273 2 : status = smb2_create(tree1, torture, &(io.smb2));
274 2 : CHECK_STATUS(status, NT_STATUS_OK);
275 2 : h2 = io.smb2.out.file.handle;
276 :
277 : /* ask for a change notify,
278 : on file or directory name changes */
279 2 : ZERO_STRUCT(notify.smb2);
280 2 : notify.smb2.level = RAW_NOTIFY_SMB2;
281 2 : notify.smb2.in.buffer_size = 1000;
282 2 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
283 2 : notify.smb2.in.file.handle = h1;
284 2 : notify.smb2.in.recursive = true;
285 :
286 2 : torture_comment(torture, "Testing notify cancel\n");
287 :
288 2 : req = smb2_notify_send(tree1, &(notify.smb2));
289 2 : smb2_cancel(req);
290 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
291 2 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
292 :
293 2 : torture_comment(torture, "Testing notify mkdir\n");
294 :
295 2 : req = smb2_notify_send(tree1, &(notify.smb2));
296 2 : smb2_util_mkdir(tree2, fname);
297 :
298 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
299 2 : CHECK_STATUS(status, NT_STATUS_OK);
300 :
301 2 : CHECK_VAL(notify.smb2.out.num_changes, 1);
302 2 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
303 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
304 :
305 2 : torture_comment(torture, "Testing notify rmdir\n");
306 :
307 2 : req = smb2_notify_send(tree1, &(notify.smb2));
308 2 : smb2_util_rmdir(tree2, fname);
309 :
310 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
311 2 : CHECK_STATUS(status, NT_STATUS_OK);
312 2 : CHECK_VAL(notify.smb2.out.num_changes, 1);
313 2 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
314 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
315 :
316 2 : torture_comment(torture,
317 : "Testing notify mkdir - rmdir - mkdir - rmdir\n");
318 :
319 2 : smb2_util_mkdir(tree2, fname);
320 2 : smb2_util_rmdir(tree2, fname);
321 2 : smb2_util_mkdir(tree2, fname);
322 2 : smb2_util_rmdir(tree2, fname);
323 2 : smb_msleep(200);
324 2 : req = smb2_notify_send(tree1, &(notify.smb2));
325 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
326 2 : CHECK_STATUS(status, NT_STATUS_OK);
327 2 : CHECK_VAL(notify.smb2.out.num_changes, 4);
328 2 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
329 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
330 2 : CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_REMOVED);
331 2 : CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name");
332 2 : CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_ADDED);
333 2 : CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name");
334 2 : CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_REMOVED);
335 2 : CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name");
336 :
337 2 : count = torture_numops;
338 2 : torture_comment(torture,
339 : "Testing buffered notify on create of %d files\n", count);
340 22 : for (i=0;i<count;i++) {
341 0 : struct smb2_handle h12;
342 20 : char *fname2 = talloc_asprintf(torture,
343 : BASEDIR_DIR "\\test%d.txt",
344 : i);
345 :
346 20 : ZERO_STRUCT(io.smb2);
347 20 : io.generic.level = RAW_OPEN_SMB2;
348 20 : io.smb2.in.create_flags = 0;
349 20 : io.smb2.in.desired_access = SEC_FILE_ALL;
350 20 : io.smb2.in.create_options =
351 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
352 20 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
353 20 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
354 : NTCREATEX_SHARE_ACCESS_WRITE;
355 20 : io.smb2.in.alloc_size = 0;
356 20 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
357 20 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
358 20 : io.smb2.in.security_flags = 0;
359 20 : io.smb2.in.fname = fname2;
360 :
361 20 : status = smb2_create(tree1, torture, &(io.smb2));
362 20 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
363 0 : torture_comment(torture, "Failed to create %s \n",
364 : fname);
365 0 : ret = false;
366 0 : goto done;
367 : }
368 20 : h12 = io.smb2.out.file.handle;
369 20 : talloc_free(fname2);
370 20 : smb2_util_close(tree1, h12);
371 : }
372 :
373 : /* (1st notify) setup a new notify on a different directory handle.
374 : This new notify won't see the events above. */
375 2 : notify.smb2.in.file.handle = h2;
376 2 : req2 = smb2_notify_send(tree1, &(notify.smb2));
377 :
378 : /* (2nd notify) whereas this notify will see the above buffered events,
379 : and it directly returns the buffered events */
380 2 : notify.smb2.in.file.handle = h1;
381 2 : req = smb2_notify_send(tree1, &(notify.smb2));
382 :
383 2 : status = smb2_util_unlink(tree1, BASEDIR_DIR "\\nonexistent.txt");
384 2 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
385 :
386 : /* (1st unlink) as the 2nd notify directly returns,
387 : this unlink is only seen by the 1st notify and
388 : the 3rd notify (later) */
389 2 : torture_comment(torture,
390 : "Testing notify on unlink for the first file\n");
391 2 : status = smb2_util_unlink(tree2, BASEDIR_DIR "\\test0.txt");
392 2 : CHECK_STATUS(status, NT_STATUS_OK);
393 :
394 : /* receive the reply from the 2nd notify */
395 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
396 2 : CHECK_STATUS(status, NT_STATUS_OK);
397 :
398 2 : CHECK_VAL(notify.smb2.out.num_changes, count);
399 20 : for (i=1;i<count;i++) {
400 18 : CHECK_VAL(notify.smb2.out.changes[i].action,
401 : NOTIFY_ACTION_ADDED);
402 : }
403 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
404 :
405 2 : torture_comment(torture, "and now from the 1st notify\n");
406 2 : status = smb2_notify_recv(req2, torture, &(notify.smb2));
407 2 : CHECK_STATUS(status, NT_STATUS_OK);
408 2 : CHECK_VAL(notify.smb2.out.num_changes, 1);
409 2 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
410 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
411 :
412 2 : torture_comment(torture,
413 : "(3rd notify) this notify will only see the 1st unlink\n");
414 2 : req = smb2_notify_send(tree1, &(notify.smb2));
415 :
416 2 : status = smb2_util_unlink(tree1, BASEDIR_DIR "\\nonexistent.txt");
417 2 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
418 :
419 20 : for (i=1;i<count;i++) {
420 18 : char *fname2 = talloc_asprintf(torture,
421 : BASEDIR_DIR "\\test%d.txt", i);
422 18 : status = smb2_util_unlink(tree2, fname2);
423 18 : CHECK_STATUS(status, NT_STATUS_OK);
424 18 : talloc_free(fname2);
425 : }
426 :
427 : /* receive the 3rd notify */
428 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
429 2 : CHECK_STATUS(status, NT_STATUS_OK);
430 2 : CHECK_VAL(notify.smb2.out.num_changes, 1);
431 2 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
432 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
433 :
434 : /* and we now see the rest of the unlink calls on both
435 : * directory handles */
436 2 : notify.smb2.in.file.handle = h1;
437 2 : sleep(3);
438 2 : req = smb2_notify_send(tree1, &(notify.smb2));
439 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
440 2 : CHECK_STATUS(status, NT_STATUS_OK);
441 2 : CHECK_VAL(notify.smb2.out.num_changes, count-1);
442 20 : for (i=0;i<notify.smb2.out.num_changes;i++) {
443 18 : CHECK_VAL(notify.smb2.out.changes[i].action,
444 : NOTIFY_ACTION_REMOVED);
445 : }
446 2 : notify.smb2.in.file.handle = h2;
447 2 : req = smb2_notify_send(tree1, &(notify.smb2));
448 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
449 2 : CHECK_STATUS(status, NT_STATUS_OK);
450 2 : CHECK_VAL(notify.smb2.out.num_changes, count-1);
451 20 : for (i=0;i<notify.smb2.out.num_changes;i++) {
452 18 : CHECK_VAL(notify.smb2.out.changes[i].action,
453 : NOTIFY_ACTION_REMOVED);
454 : }
455 :
456 2 : torture_comment(torture,
457 : "Testing if a close() on the dir handle triggers the notify reply\n");
458 :
459 2 : notify.smb2.in.file.handle = h1;
460 2 : req = smb2_notify_send(tree1, &(notify.smb2));
461 :
462 2 : ZERO_STRUCT(cl.smb2);
463 2 : cl.smb2.level = RAW_CLOSE_SMB2;
464 2 : cl.smb2.in.file.handle = h1;
465 2 : status = smb2_close(tree1, &(cl.smb2));
466 2 : CHECK_STATUS(status, NT_STATUS_OK);
467 :
468 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
469 2 : CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
470 2 : CHECK_VAL(notify.smb2.out.num_changes, 9);
471 :
472 2 : done:
473 2 : smb2_util_close(tree1, h1);
474 2 : smb2_util_close(tree1, h2);
475 2 : smb2_deltree(tree1, BASEDIR_DIR);
476 2 : return ret;
477 : }
478 :
479 522 : static struct smb2_handle custom_smb2_create(struct smb2_tree *tree,
480 : struct torture_context *torture,
481 : struct smb2_create *smb2)
482 : {
483 0 : struct smb2_handle h1;
484 522 : bool ret = true;
485 0 : NTSTATUS status;
486 522 : smb2_deltree(tree, smb2->in.fname);
487 522 : status = smb2_create(tree, torture, smb2);
488 522 : CHECK_STATUS(status, NT_STATUS_OK);
489 522 : h1 = smb2->out.file.handle;
490 522 : done:
491 522 : if (!ret) {
492 0 : h1 = (struct smb2_handle) {
493 : .data = { 0 , 0},
494 : };
495 : }
496 522 : return h1;
497 : }
498 :
499 : /*
500 : testing of recursive change notify
501 : */
502 :
503 : #define BASEDIR_REC BASEDIR "_REC"
504 :
505 2 : static bool torture_smb2_notify_recursive(struct torture_context *torture,
506 : struct smb2_tree *tree1,
507 : struct smb2_tree *tree2)
508 : {
509 2 : bool ret = true;
510 0 : NTSTATUS status;
511 0 : union smb_notify notify;
512 0 : union smb_open io, io1;
513 0 : union smb_setfileinfo sinfo;
514 0 : struct smb2_handle h1;
515 0 : struct smb2_request *req1, *req2;
516 :
517 2 : smb2_deltree(tree1, BASEDIR_REC);
518 2 : smb2_util_rmdir(tree1, BASEDIR_REC);
519 :
520 2 : torture_comment(torture, "TESTING CHANGE NOTIFY WITH RECURSION\n");
521 :
522 : /*
523 : get a handle on the directory
524 : */
525 2 : ZERO_STRUCT(io.smb2);
526 2 : io.generic.level = RAW_OPEN_SMB2;
527 2 : io.smb2.in.create_flags = 0;
528 2 : io.smb2.in.desired_access = SEC_FILE_ALL;
529 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
530 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
531 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
532 : NTCREATEX_SHARE_ACCESS_WRITE;
533 2 : io.smb2.in.alloc_size = 0;
534 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
535 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
536 2 : io.smb2.in.security_flags = 0;
537 2 : io.smb2.in.fname = BASEDIR_REC;
538 :
539 2 : status = smb2_create(tree1, torture, &(io.smb2));
540 2 : CHECK_STATUS(status, NT_STATUS_OK);
541 2 : h1 = io.smb2.out.file.handle;
542 :
543 : /* ask for a change notify, on file or directory name
544 : changes. Setup both with and without recursion */
545 2 : ZERO_STRUCT(notify.smb2);
546 2 : notify.smb2.level = RAW_NOTIFY_SMB2;
547 2 : notify.smb2.in.buffer_size = 1000;
548 2 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
549 : FILE_NOTIFY_CHANGE_ATTRIBUTES |
550 : FILE_NOTIFY_CHANGE_CREATION;
551 2 : notify.smb2.in.file.handle = h1;
552 :
553 2 : notify.smb2.in.recursive = true;
554 2 : req1 = smb2_notify_send(tree1, &(notify.smb2));
555 2 : smb2_cancel(req1);
556 2 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
557 2 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
558 :
559 2 : notify.smb2.in.recursive = false;
560 2 : req2 = smb2_notify_send(tree1, &(notify.smb2));
561 2 : smb2_cancel(req2);
562 2 : status = smb2_notify_recv(req2, torture, &(notify.smb2));
563 2 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
564 :
565 2 : ZERO_STRUCT(io1.smb2);
566 2 : io1.generic.level = RAW_OPEN_SMB2;
567 2 : io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
568 2 : io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
569 : SEC_RIGHTS_FILE_WRITE|
570 : SEC_RIGHTS_FILE_ALL;
571 2 : io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
572 2 : io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
573 2 : io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
574 : NTCREATEX_SHARE_ACCESS_WRITE |
575 : NTCREATEX_SHARE_ACCESS_DELETE;
576 2 : io1.smb2.in.alloc_size = 0;
577 2 : io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
578 2 : io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
579 2 : io1.smb2.in.security_flags = 0;
580 2 : io1.smb2.in.fname = BASEDIR_REC "\\subdir-name";
581 2 : status = smb2_create(tree2, torture, &(io1.smb2));
582 2 : CHECK_STATUS(status, NT_STATUS_OK);
583 2 : smb2_util_close(tree2, io1.smb2.out.file.handle);
584 :
585 2 : io1.smb2.in.fname = BASEDIR_REC "\\subdir-name\\subname1";
586 2 : status = smb2_create(tree2, torture, &(io1.smb2));
587 2 : CHECK_STATUS(status, NT_STATUS_OK);
588 2 : ZERO_STRUCT(sinfo);
589 2 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
590 2 : sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
591 2 : sinfo.rename_information.in.overwrite = 0;
592 2 : sinfo.rename_information.in.root_fid = 0;
593 2 : sinfo.rename_information.in.new_name =
594 : BASEDIR_REC "\\subdir-name\\subname1-r";
595 2 : status = smb2_setinfo_file(tree2, &sinfo);
596 2 : CHECK_STATUS(status, NT_STATUS_OK);
597 :
598 2 : io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
599 2 : io1.smb2.in.fname = BASEDIR_REC "\\subdir-name\\subname2";
600 2 : status = smb2_create(tree2, torture, &(io1.smb2));
601 2 : CHECK_STATUS(status, NT_STATUS_OK);
602 2 : ZERO_STRUCT(sinfo);
603 2 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
604 2 : sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
605 2 : sinfo.rename_information.in.overwrite = true;
606 2 : sinfo.rename_information.in.root_fid = 0;
607 2 : sinfo.rename_information.in.new_name = BASEDIR_REC "\\subname2-r";
608 2 : status = smb2_setinfo_file(tree2, &sinfo);
609 2 : CHECK_STATUS(status, NT_STATUS_OK);
610 :
611 2 : io1.smb2.in.fname = BASEDIR_REC "\\subname2-r";
612 2 : io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
613 2 : status = smb2_create(tree2, torture, &(io1.smb2));
614 2 : CHECK_STATUS(status, NT_STATUS_OK);
615 2 : ZERO_STRUCT(sinfo);
616 2 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
617 2 : sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
618 2 : sinfo.rename_information.in.overwrite = true;
619 2 : sinfo.rename_information.in.root_fid = 0;
620 2 : sinfo.rename_information.in.new_name = BASEDIR_REC "\\subname3-r";
621 2 : status = smb2_setinfo_file(tree2, &sinfo);
622 2 : CHECK_STATUS(status, NT_STATUS_OK);
623 :
624 2 : notify.smb2.in.completion_filter = 0;
625 2 : notify.smb2.in.recursive = true;
626 2 : smb_msleep(200);
627 2 : req1 = smb2_notify_send(tree1, &(notify.smb2));
628 :
629 2 : status = smb2_util_rmdir(tree2,
630 : BASEDIR_REC "\\subdir-name\\subname1-r");
631 2 : CHECK_STATUS(status, NT_STATUS_OK);
632 2 : status = smb2_util_rmdir(tree2,
633 : BASEDIR_REC "\\subdir-name");
634 2 : CHECK_STATUS(status, NT_STATUS_OK);
635 2 : status = smb2_util_unlink(tree2, BASEDIR_REC "\\subname3-r");
636 2 : CHECK_STATUS(status, NT_STATUS_OK);
637 :
638 2 : notify.smb2.in.recursive = false;
639 2 : req2 = smb2_notify_send(tree1, &(notify.smb2));
640 :
641 2 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
642 2 : CHECK_STATUS(status, NT_STATUS_OK);
643 :
644 2 : CHECK_VAL(notify.smb2.out.num_changes, 9);
645 0 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
646 0 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
647 0 : CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_ADDED);
648 0 : CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name\\subname1");
649 0 : CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_OLD_NAME);
650 0 : CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name\\subname1");
651 0 : CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_NEW_NAME);
652 0 : CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name\\subname1-r");
653 0 : CHECK_VAL(notify.smb2.out.changes[4].action, NOTIFY_ACTION_ADDED);
654 0 : CHECK_WIRE_STR(notify.smb2.out.changes[4].name, "subdir-name\\subname2");
655 0 : CHECK_VAL(notify.smb2.out.changes[5].action, NOTIFY_ACTION_REMOVED);
656 0 : CHECK_WIRE_STR(notify.smb2.out.changes[5].name, "subdir-name\\subname2");
657 0 : CHECK_VAL(notify.smb2.out.changes[6].action, NOTIFY_ACTION_ADDED);
658 0 : CHECK_WIRE_STR(notify.smb2.out.changes[6].name, "subname2-r");
659 0 : CHECK_VAL(notify.smb2.out.changes[7].action, NOTIFY_ACTION_OLD_NAME);
660 0 : CHECK_WIRE_STR(notify.smb2.out.changes[7].name, "subname2-r");
661 0 : CHECK_VAL(notify.smb2.out.changes[8].action, NOTIFY_ACTION_NEW_NAME);
662 0 : CHECK_WIRE_STR(notify.smb2.out.changes[8].name, "subname3-r");
663 :
664 0 : done:
665 2 : smb2_deltree(tree1, BASEDIR_REC);
666 2 : return ret;
667 : }
668 :
669 : /*
670 : testing of change notify mask change
671 : */
672 :
673 : #define BASEDIR_MC BASEDIR "_MC"
674 :
675 2 : static bool torture_smb2_notify_mask_change(struct torture_context *torture,
676 : struct smb2_tree *tree1,
677 : struct smb2_tree *tree2)
678 : {
679 2 : bool ret = true;
680 0 : NTSTATUS status;
681 0 : union smb_notify notify;
682 0 : union smb_open io, io1;
683 0 : struct smb2_handle h1;
684 0 : struct smb2_request *req1, *req2;
685 0 : union smb_setfileinfo sinfo;
686 :
687 2 : smb2_deltree(tree1, BASEDIR_MC);
688 2 : smb2_util_rmdir(tree1, BASEDIR_MC);
689 :
690 2 : torture_comment(torture, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
691 :
692 : /*
693 : get a handle on the directory
694 : */
695 2 : ZERO_STRUCT(io.smb2);
696 2 : io.generic.level = RAW_OPEN_SMB2;
697 2 : io.smb2.in.create_flags = 0;
698 2 : io.smb2.in.desired_access = SEC_FILE_ALL;
699 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
700 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
701 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
702 : NTCREATEX_SHARE_ACCESS_WRITE;
703 2 : io.smb2.in.alloc_size = 0;
704 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
705 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
706 2 : io.smb2.in.security_flags = 0;
707 2 : io.smb2.in.fname = BASEDIR_MC;
708 :
709 2 : status = smb2_create(tree1, torture, &(io.smb2));
710 2 : CHECK_STATUS(status, NT_STATUS_OK);
711 2 : h1 = io.smb2.out.file.handle;
712 :
713 : /* ask for a change notify, on file or directory name
714 : changes. Setup both with and without recursion */
715 2 : ZERO_STRUCT(notify.smb2);
716 2 : notify.smb2.level = RAW_NOTIFY_SMB2;
717 2 : notify.smb2.in.buffer_size = 1000;
718 2 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
719 2 : notify.smb2.in.file.handle = h1;
720 :
721 2 : notify.smb2.in.recursive = true;
722 2 : req1 = smb2_notify_send(tree1, &(notify.smb2));
723 :
724 2 : smb2_cancel(req1);
725 2 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
726 2 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
727 :
728 :
729 2 : notify.smb2.in.recursive = false;
730 2 : req2 = smb2_notify_send(tree1, &(notify.smb2));
731 :
732 2 : smb2_cancel(req2);
733 2 : status = smb2_notify_recv(req2, torture, &(notify.smb2));
734 2 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
735 :
736 2 : notify.smb2.in.recursive = true;
737 2 : req1 = smb2_notify_send(tree1, &(notify.smb2));
738 :
739 : /* Set to hidden then back again. */
740 2 : ZERO_STRUCT(io1.smb2);
741 2 : io1.generic.level = RAW_OPEN_SMB2;
742 2 : io1.smb2.in.create_flags = 0;
743 2 : io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
744 : SEC_RIGHTS_FILE_WRITE|
745 : SEC_RIGHTS_FILE_ALL;
746 2 : io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
747 2 : io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
748 : NTCREATEX_SHARE_ACCESS_WRITE |
749 : NTCREATEX_SHARE_ACCESS_DELETE;
750 2 : io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
751 2 : io1.smb2.in.security_flags = 0;
752 2 : io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
753 2 : io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
754 2 : io1.smb2.in.fname = BASEDIR_MC "\\tname1";
755 :
756 2 : smb2_util_close(tree1,
757 : custom_smb2_create(tree1, torture, &(io1.smb2)));
758 2 : status = smb2_util_setatr(tree1, BASEDIR_MC "\\tname1",
759 : FILE_ATTRIBUTE_HIDDEN);
760 2 : CHECK_STATUS(status, NT_STATUS_OK);
761 2 : smb2_util_unlink(tree1, BASEDIR_MC "\\tname1");
762 :
763 2 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
764 2 : CHECK_STATUS(status, NT_STATUS_OK);
765 :
766 2 : CHECK_VAL(notify.smb2.out.num_changes, 1);
767 2 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
768 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
769 :
770 : /* Now try and change the mask to include other events.
771 : * This should not work - once the mask is set on a directory
772 : * h1 it seems to be fixed until the fnum is closed. */
773 :
774 2 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
775 : FILE_NOTIFY_CHANGE_ATTRIBUTES |
776 : FILE_NOTIFY_CHANGE_CREATION;
777 2 : notify.smb2.in.recursive = true;
778 2 : req1 = smb2_notify_send(tree1, &(notify.smb2));
779 :
780 2 : notify.smb2.in.recursive = false;
781 2 : req2 = smb2_notify_send(tree1, &(notify.smb2));
782 :
783 2 : io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
784 2 : io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
785 2 : io1.smb2.in.fname = BASEDIR_MC "\\subdir-name";
786 2 : status = smb2_create(tree2, torture, &(io1.smb2));
787 2 : CHECK_STATUS(status, NT_STATUS_OK);
788 2 : smb2_util_close(tree2, io1.smb2.out.file.handle);
789 :
790 2 : ZERO_STRUCT(sinfo);
791 2 : io1.smb2.in.fname = BASEDIR_MC "\\subdir-name\\subname1";
792 2 : io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
793 2 : io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
794 2 : status = smb2_create(tree2, torture, &(io1.smb2));
795 2 : CHECK_STATUS(status, NT_STATUS_OK);
796 2 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
797 2 : sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
798 2 : sinfo.rename_information.in.overwrite = true;
799 2 : sinfo.rename_information.in.root_fid = 0;
800 2 : sinfo.rename_information.in.new_name =
801 : BASEDIR_MC "\\subdir-name\\subname1-r";
802 2 : status = smb2_setinfo_file(tree2, &sinfo);
803 2 : CHECK_STATUS(status, NT_STATUS_OK);
804 :
805 2 : io1.smb2.in.fname = BASEDIR_MC "\\subdir-name\\subname2";
806 2 : io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
807 2 : io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
808 2 : status = smb2_create(tree2, torture, &(io1.smb2));
809 2 : CHECK_STATUS(status, NT_STATUS_OK);
810 2 : sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
811 2 : sinfo.rename_information.in.new_name = BASEDIR_MC "\\subname2-r";
812 2 : status = smb2_setinfo_file(tree2, &sinfo);
813 2 : CHECK_STATUS(status, NT_STATUS_OK);
814 2 : smb2_util_close(tree2, io1.smb2.out.file.handle);
815 :
816 2 : io1.smb2.in.fname = BASEDIR_MC "\\subname2-r";
817 2 : io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
818 2 : status = smb2_create(tree2, torture, &(io1.smb2));
819 2 : CHECK_STATUS(status, NT_STATUS_OK);
820 2 : sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
821 2 : sinfo.rename_information.in.new_name = BASEDIR_MC "\\subname3-r";
822 2 : status = smb2_setinfo_file(tree2, &sinfo);
823 2 : CHECK_STATUS(status, NT_STATUS_OK);
824 2 : smb2_util_close(tree2, io1.smb2.out.file.handle);
825 :
826 2 : status = smb2_util_rmdir(tree2, BASEDIR_MC "\\subdir-name\\subname1-r");
827 2 : CHECK_STATUS(status, NT_STATUS_OK);
828 2 : status = smb2_util_rmdir(tree2, BASEDIR_MC "\\subdir-name");
829 2 : CHECK_STATUS(status, NT_STATUS_OK);
830 2 : status = smb2_util_unlink(tree2, BASEDIR_MC "\\subname3-r");
831 2 : CHECK_STATUS(status, NT_STATUS_OK);
832 :
833 2 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
834 2 : CHECK_STATUS(status, NT_STATUS_OK);
835 :
836 2 : CHECK_VAL(notify.smb2.out.num_changes, 1);
837 2 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
838 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname2-r");
839 :
840 2 : status = smb2_notify_recv(req2, torture, &(notify.smb2));
841 2 : CHECK_STATUS(status, NT_STATUS_OK);
842 :
843 2 : CHECK_VAL(notify.smb2.out.num_changes, 1);
844 2 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
845 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname3-r");
846 :
847 2 : if (!ret) {
848 0 : goto done;
849 : }
850 :
851 2 : done:
852 2 : smb2_deltree(tree1, BASEDIR_MC);
853 2 : return ret;
854 : }
855 :
856 : /*
857 : testing of mask bits for change notify
858 : */
859 :
860 : #define BASEDIR_MSK BASEDIR "_MSK"
861 :
862 2 : static bool torture_smb2_notify_mask(struct torture_context *torture,
863 : struct smb2_tree *tree1,
864 : struct smb2_tree *tree2)
865 : {
866 2 : bool ret = true;
867 0 : NTSTATUS status;
868 0 : union smb_notify notify;
869 0 : union smb_open io, io1;
870 0 : struct smb2_handle h1, h2;
871 0 : int i;
872 2 : char c = 1;
873 0 : union smb_setfileinfo sinfo;
874 :
875 2 : smb2_deltree(tree1, BASEDIR_MSK);
876 2 : smb2_util_rmdir(tree1, BASEDIR_MSK);
877 :
878 2 : torture_comment(torture, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
879 :
880 :
881 2 : ZERO_STRUCT(h1);
882 2 : ZERO_STRUCT(h2);
883 : /*
884 : get a handle on the directory
885 : */
886 2 : ZERO_STRUCT(io.smb2);
887 2 : io.generic.level = RAW_OPEN_SMB2;
888 2 : io.smb2.in.create_flags = 0;
889 2 : io.smb2.in.desired_access = SEC_FILE_ALL;
890 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
891 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
892 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
893 : NTCREATEX_SHARE_ACCESS_WRITE;
894 2 : io.smb2.in.alloc_size = 0;
895 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
896 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
897 2 : io.smb2.in.security_flags = 0;
898 2 : io.smb2.in.fname = BASEDIR_MSK;
899 :
900 2 : ZERO_STRUCT(notify.smb2);
901 2 : notify.smb2.level = RAW_NOTIFY_SMB2;
902 2 : notify.smb2.in.buffer_size = 1000;
903 2 : notify.smb2.in.recursive = true;
904 :
905 : #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
906 : expected, nchanges) \
907 : do { \
908 : do { for (i=0;i<32;i++) { \
909 : struct smb2_request *req; \
910 : status = smb2_create(tree1, torture, &(io.smb2)); \
911 : CHECK_STATUS(status, NT_STATUS_OK); \
912 : h1 = io.smb2.out.file.handle; \
913 : setup \
914 : notify.smb2.in.file.handle = h1; \
915 : notify.smb2.in.completion_filter = ((uint32_t)1<<i); \
916 : /* cancel initial requests so the buffer is setup */ \
917 : req = smb2_notify_send(tree1, &(notify.smb2)); \
918 : smb2_cancel(req); \
919 : status = smb2_notify_recv(req, torture, &(notify.smb2)); \
920 : CHECK_STATUS(status, NT_STATUS_CANCELLED); \
921 : /* send the change notify request */ \
922 : req = smb2_notify_send(tree1, &(notify.smb2)); \
923 : op \
924 : smb_msleep(200); smb2_cancel(req); \
925 : status = smb2_notify_recv(req, torture, &(notify.smb2)); \
926 : cleanup \
927 : smb2_util_close(tree1, h1); \
928 : if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
929 : CHECK_STATUS(status, NT_STATUS_OK); \
930 : /* special case to cope with file rename behaviour */ \
931 : if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
932 : notify.smb2.out.changes[0].action == \
933 : NOTIFY_ACTION_MODIFIED && \
934 : ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
935 : Action == NOTIFY_ACTION_OLD_NAME) { \
936 : torture_comment(torture, \
937 : "(rename file special handling OK)\n"); \
938 : } else if (nchanges != notify.smb2.out.num_changes) { \
939 : torture_result(torture, TORTURE_FAIL, \
940 : "ERROR: nchanges=%d expected=%d "\
941 : "action=%d filter=0x%08x\n", \
942 : notify.smb2.out.num_changes, \
943 : nchanges, \
944 : notify.smb2.out.changes[0].action, \
945 : notify.smb2.in.completion_filter); \
946 : ret = false; \
947 : } else if (notify.smb2.out.changes[0].action != Action) { \
948 : torture_result(torture, TORTURE_FAIL, \
949 : "ERROR: nchanges=%d action=%d " \
950 : "expectedAction=%d filter=0x%08x\n", \
951 : notify.smb2.out.num_changes, \
952 : notify.smb2.out.changes[0].action, \
953 : Action, \
954 : notify.smb2.in.completion_filter); \
955 : ret = false; \
956 : } else if (strcmp(notify.smb2.out.changes[0].name.s, \
957 : "tname1") != 0) { \
958 : torture_result(torture, TORTURE_FAIL, \
959 : "ERROR: nchanges=%d action=%d " \
960 : "filter=0x%08x name=%s\n", \
961 : notify.smb2.out.num_changes, \
962 : notify.smb2.out.changes[0].action, \
963 : notify.smb2.in.completion_filter, \
964 : notify.smb2.out.changes[0].name.s); \
965 : ret = false; \
966 : } \
967 : } \
968 : } while (0); \
969 : } while (0);
970 :
971 2 : torture_comment(torture, "Testing mkdir\n");
972 66 : NOTIFY_MASK_TEST("Testing mkdir",;,
973 : smb2_util_mkdir(tree2, BASEDIR_MSK "\\tname1");,
974 : smb2_util_rmdir(tree2, BASEDIR_MSK "\\tname1");,
975 : NOTIFY_ACTION_ADDED,
976 0 : FILE_NOTIFY_CHANGE_DIR_NAME, 1);
977 :
978 2 : torture_comment(torture, "Testing create file\n");
979 2 : ZERO_STRUCT(io1.smb2);
980 2 : io1.generic.level = RAW_OPEN_SMB2;
981 2 : io1.smb2.in.create_flags = 0;
982 2 : io1.smb2.in.desired_access = SEC_FILE_ALL;
983 2 : io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
984 2 : io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
985 : NTCREATEX_SHARE_ACCESS_WRITE;
986 2 : io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
987 2 : io1.smb2.in.security_flags = 0;
988 2 : io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
989 2 : io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
990 2 : io1.smb2.in.fname = BASEDIR_MSK "\\tname1";
991 :
992 66 : NOTIFY_MASK_TEST("Testing create file",;,
993 : smb2_util_close(tree2, custom_smb2_create(tree2,
994 : torture, &(io1.smb2)));,
995 : smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
996 : NOTIFY_ACTION_ADDED,
997 0 : FILE_NOTIFY_CHANGE_FILE_NAME, 1);
998 :
999 2 : torture_comment(torture, "Testing unlink\n");
1000 66 : NOTIFY_MASK_TEST("Testing unlink",
1001 : smb2_util_close(tree2, custom_smb2_create(tree2,
1002 : torture, &(io1.smb2)));,
1003 : smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
1004 : ;,
1005 : NOTIFY_ACTION_REMOVED,
1006 0 : FILE_NOTIFY_CHANGE_FILE_NAME, 1);
1007 :
1008 2 : torture_comment(torture, "Testing rmdir\n");
1009 66 : NOTIFY_MASK_TEST("Testing rmdir",
1010 : smb2_util_mkdir(tree2, BASEDIR_MSK "\\tname1");,
1011 : smb2_util_rmdir(tree2, BASEDIR_MSK "\\tname1");,
1012 : ;,
1013 : NOTIFY_ACTION_REMOVED,
1014 0 : FILE_NOTIFY_CHANGE_DIR_NAME, 1);
1015 :
1016 2 : torture_comment(torture, "Testing rename file\n");
1017 2 : ZERO_STRUCT(sinfo);
1018 2 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1019 2 : sinfo.rename_information.in.file.handle = h1;
1020 2 : sinfo.rename_information.in.overwrite = true;
1021 2 : sinfo.rename_information.in.root_fid = 0;
1022 2 : sinfo.rename_information.in.new_name = BASEDIR_MSK "\\tname2";
1023 66 : NOTIFY_MASK_TEST("Testing rename file",
1024 : smb2_util_close(tree2, custom_smb2_create(tree2,
1025 : torture, &(io1.smb2)));,
1026 : smb2_setinfo_file(tree2, &sinfo);,
1027 : smb2_util_unlink(tree2, BASEDIR_MSK "\\tname2");,
1028 : NOTIFY_ACTION_OLD_NAME,
1029 0 : FILE_NOTIFY_CHANGE_FILE_NAME, 2);
1030 :
1031 2 : torture_comment(torture, "Testing rename dir\n");
1032 2 : ZERO_STRUCT(sinfo);
1033 2 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1034 2 : sinfo.rename_information.in.file.handle = h1;
1035 2 : sinfo.rename_information.in.overwrite = true;
1036 2 : sinfo.rename_information.in.root_fid = 0;
1037 2 : sinfo.rename_information.in.new_name = BASEDIR_MSK "\\tname2";
1038 66 : NOTIFY_MASK_TEST("Testing rename dir",
1039 : smb2_util_mkdir(tree2, BASEDIR_MSK "\\tname1");,
1040 : smb2_setinfo_file(tree2, &sinfo);,
1041 : smb2_util_rmdir(tree2, BASEDIR_MSK "\\tname2");,
1042 : NOTIFY_ACTION_OLD_NAME,
1043 0 : FILE_NOTIFY_CHANGE_DIR_NAME, 2);
1044 :
1045 2 : torture_comment(torture, "Testing set path attribute\n");
1046 66 : NOTIFY_MASK_TEST("Testing set path attribute",
1047 : smb2_util_close(tree2, custom_smb2_create(tree2,
1048 : torture, &(io.smb2)));,
1049 : smb2_util_setatr(tree2, BASEDIR_MSK "\\tname1",
1050 : FILE_ATTRIBUTE_HIDDEN);,
1051 : smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
1052 : NOTIFY_ACTION_MODIFIED,
1053 0 : FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
1054 :
1055 2 : torture_comment(torture, "Testing set path write time\n");
1056 2 : ZERO_STRUCT(sinfo);
1057 2 : sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1058 2 : sinfo.generic.in.file.handle = h1;
1059 2 : sinfo.basic_info.in.write_time = 1000;
1060 66 : NOTIFY_MASK_TEST("Testing set path write time",
1061 : smb2_util_close(tree2, custom_smb2_create(tree2,
1062 : torture, &(io1.smb2)));,
1063 : smb2_setinfo_file(tree2, &sinfo);,
1064 : smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
1065 : NOTIFY_ACTION_MODIFIED,
1066 0 : FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
1067 :
1068 2 : if (torture_setting_bool(torture, "samba3", false)) {
1069 2 : torture_comment(torture,
1070 : "Samba3 does not yet support create times "
1071 : "everywhere\n");
1072 : }
1073 : else {
1074 0 : ZERO_STRUCT(sinfo);
1075 0 : sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1076 0 : sinfo.generic.in.file.handle = h1;
1077 0 : sinfo.basic_info.in.create_time = 0;
1078 0 : torture_comment(torture, "Testing set file create time\n");
1079 0 : NOTIFY_MASK_TEST("Testing set file create time",
1080 : smb2_create_complex_file(torture, tree2,
1081 : BASEDIR_MSK "\\tname1", &h2);,
1082 : smb2_setinfo_file(tree2, &sinfo);,
1083 : (smb2_util_close(tree2, h2),
1084 : smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
1085 : NOTIFY_ACTION_MODIFIED,
1086 0 : FILE_NOTIFY_CHANGE_CREATION, 1);
1087 : }
1088 :
1089 2 : ZERO_STRUCT(sinfo);
1090 2 : sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1091 2 : sinfo.generic.in.file.handle = h1;
1092 2 : sinfo.basic_info.in.access_time = 0;
1093 2 : torture_comment(torture, "Testing set file access time\n");
1094 66 : NOTIFY_MASK_TEST("Testing set file access time",
1095 : smb2_create_complex_file(torture,
1096 : tree2,
1097 : BASEDIR_MSK "\\tname1",
1098 : &h2);,
1099 : smb2_setinfo_file(tree2, &sinfo);,
1100 : (smb2_util_close(tree2, h2),
1101 : smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
1102 : NOTIFY_ACTION_MODIFIED,
1103 0 : FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
1104 :
1105 2 : ZERO_STRUCT(sinfo);
1106 2 : sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1107 2 : sinfo.generic.in.file.handle = h1;
1108 2 : sinfo.basic_info.in.change_time = 0;
1109 2 : torture_comment(torture, "Testing set file change time\n");
1110 66 : NOTIFY_MASK_TEST("Testing set file change time",
1111 : smb2_create_complex_file(torture,
1112 : tree2,
1113 : BASEDIR_MSK "\\tname1",
1114 : &h2);,
1115 : smb2_setinfo_file(tree2, &sinfo);,
1116 : (smb2_util_close(tree2, h2),
1117 : smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
1118 : NOTIFY_ACTION_MODIFIED,
1119 0 : 0, 1);
1120 :
1121 :
1122 2 : torture_comment(torture, "Testing write\n");
1123 66 : NOTIFY_MASK_TEST("Testing write",
1124 : smb2_create_complex_file(torture,
1125 : tree2,
1126 : BASEDIR_MSK "\\tname1",
1127 : &h2);,
1128 : smb2_util_write(tree2, h2, &c, 10000, 1);,
1129 : (smb2_util_close(tree2, h2),
1130 : smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
1131 : NOTIFY_ACTION_MODIFIED,
1132 0 : 0, 1);
1133 :
1134 2 : done:
1135 2 : smb2_deltree(tree1, BASEDIR_MSK);
1136 2 : return ret;
1137 : }
1138 :
1139 : #define BASEDIR_FL BASEDIR "_FL"
1140 : /*
1141 : basic testing of change notify on files
1142 : */
1143 2 : static bool torture_smb2_notify_file(struct torture_context *torture,
1144 : struct smb2_tree *tree)
1145 : {
1146 0 : NTSTATUS status;
1147 2 : bool ret = true;
1148 0 : union smb_open io;
1149 0 : union smb_close cl;
1150 0 : union smb_notify notify;
1151 0 : struct smb2_request *req;
1152 0 : struct smb2_handle h1;
1153 2 : const char *fname = BASEDIR_FL "\\file.txt";
1154 :
1155 2 : smb2_deltree(tree, BASEDIR_FL);
1156 2 : smb2_util_rmdir(tree, BASEDIR_FL);
1157 :
1158 2 : torture_comment(torture, "TESTING CHANGE NOTIFY ON FILES\n");
1159 2 : status = torture_smb2_testdir(tree, BASEDIR_FL, &h1);
1160 2 : CHECK_STATUS(status, NT_STATUS_OK);
1161 :
1162 2 : ZERO_STRUCT(io.smb2);
1163 2 : io.generic.level = RAW_OPEN_SMB2;
1164 2 : io.smb2.in.create_flags = 0;
1165 2 : io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
1166 2 : io.smb2.in.create_options = 0;
1167 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1168 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1169 : NTCREATEX_SHARE_ACCESS_WRITE;
1170 2 : io.smb2.in.alloc_size = 0;
1171 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1172 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1173 2 : io.smb2.in.security_flags = 0;
1174 2 : io.smb2.in.fname = fname;
1175 2 : status = smb2_create(tree, torture, &(io.smb2));
1176 2 : CHECK_STATUS(status, NT_STATUS_OK);
1177 2 : h1 = io.smb2.out.file.handle;
1178 :
1179 : /* ask for a change notify,
1180 : on file or directory name changes */
1181 2 : ZERO_STRUCT(notify.smb2);
1182 2 : notify.smb2.level = RAW_NOTIFY_SMB2;
1183 2 : notify.smb2.in.file.handle = h1;
1184 2 : notify.smb2.in.buffer_size = 1000;
1185 2 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
1186 2 : notify.smb2.in.recursive = false;
1187 :
1188 2 : torture_comment(torture,
1189 : "Testing if notifies on file handles are invalid (should be)\n");
1190 :
1191 2 : req = smb2_notify_send(tree, &(notify.smb2));
1192 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1193 2 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1194 :
1195 2 : ZERO_STRUCT(cl.smb2);
1196 2 : cl.close.level = RAW_CLOSE_SMB2;
1197 2 : cl.close.in.file.handle = h1;
1198 2 : status = smb2_close(tree, &(cl.smb2));
1199 2 : CHECK_STATUS(status, NT_STATUS_OK);
1200 :
1201 2 : status = smb2_util_unlink(tree, fname);
1202 2 : CHECK_STATUS(status, NT_STATUS_OK);
1203 :
1204 2 : done:
1205 2 : smb2_deltree(tree, BASEDIR_FL);
1206 2 : return ret;
1207 : }
1208 : /*
1209 : basic testing of change notifies followed by a tdis
1210 : */
1211 :
1212 : #define BASEDIR_TD BASEDIR "_TD"
1213 :
1214 2 : static bool torture_smb2_notify_tree_disconnect(
1215 : struct torture_context *torture,
1216 : struct smb2_tree *tree)
1217 : {
1218 2 : bool ret = true;
1219 0 : NTSTATUS status;
1220 0 : union smb_notify notify;
1221 0 : union smb_open io;
1222 0 : struct smb2_handle h1;
1223 0 : struct smb2_request *req;
1224 :
1225 2 : smb2_deltree(tree, BASEDIR_TD);
1226 2 : smb2_util_rmdir(tree, BASEDIR_TD);
1227 :
1228 2 : torture_comment(torture, "TESTING CHANGE NOTIFY+CANCEL FOLLOWED BY "
1229 : "TREE-DISCONNECT\n");
1230 :
1231 : /*
1232 : get a handle on the directory
1233 : */
1234 2 : ZERO_STRUCT(io.smb2);
1235 2 : io.generic.level = RAW_OPEN_SMB2;
1236 2 : io.smb2.in.create_flags = 0;
1237 2 : io.smb2.in.desired_access = SEC_FILE_ALL;
1238 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1239 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1240 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1241 : NTCREATEX_SHARE_ACCESS_WRITE;
1242 2 : io.smb2.in.alloc_size = 0;
1243 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1244 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1245 2 : io.smb2.in.security_flags = 0;
1246 2 : io.smb2.in.fname = BASEDIR_TD;
1247 :
1248 2 : status = smb2_create(tree, torture, &(io.smb2));
1249 2 : CHECK_STATUS(status, NT_STATUS_OK);
1250 2 : h1 = io.smb2.out.file.handle;
1251 :
1252 : /* ask for a change notify,
1253 : on file or directory name changes */
1254 2 : ZERO_STRUCT(notify.smb2);
1255 2 : notify.smb2.level = RAW_NOTIFY_SMB2;
1256 2 : notify.smb2.in.buffer_size = 1000;
1257 2 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1258 2 : notify.smb2.in.file.handle = h1;
1259 2 : notify.smb2.in.recursive = true;
1260 :
1261 2 : req = smb2_notify_send(tree, &(notify.smb2));
1262 2 : smb2_cancel(req);
1263 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1264 :
1265 2 : status = smb2_tdis(tree);
1266 2 : CHECK_STATUS(status, NT_STATUS_OK);
1267 :
1268 2 : req = smb2_notify_send(tree, &(notify.smb2));
1269 :
1270 2 : smb2_notify_recv(req, torture, &(notify.smb2));
1271 2 : CHECK_STATUS(status, NT_STATUS_OK);
1272 2 : CHECK_VAL(notify.smb2.out.num_changes, 0);
1273 :
1274 2 : done:
1275 2 : smb2_deltree(tree, BASEDIR_TD);
1276 2 : return ret;
1277 : }
1278 :
1279 : /*
1280 : testing of change notifies followed by a tdis - no cancel
1281 : */
1282 :
1283 : #define BASEDIR_NTDIS BASEDIR "_NTDIS"
1284 :
1285 2 : static bool torture_smb2_notify_tree_disconnect_1(
1286 : struct torture_context *torture,
1287 : struct smb2_tree *tree)
1288 : {
1289 2 : bool ret = true;
1290 0 : NTSTATUS status;
1291 0 : union smb_notify notify;
1292 0 : union smb_open io;
1293 0 : struct smb2_handle h1;
1294 0 : struct smb2_request *req;
1295 :
1296 2 : smb2_deltree(tree, BASEDIR_NTDIS);
1297 2 : smb2_util_rmdir(tree, BASEDIR_NTDIS);
1298 :
1299 2 : torture_comment(torture, "TESTING CHANGE NOTIFY ASYNC FOLLOWED BY "
1300 : "TREE-DISCONNECT\n");
1301 :
1302 : /*
1303 : get a handle on the directory
1304 : */
1305 2 : ZERO_STRUCT(io.smb2);
1306 2 : io.generic.level = RAW_OPEN_SMB2;
1307 2 : io.smb2.in.create_flags = 0;
1308 2 : io.smb2.in.desired_access = SEC_FILE_ALL;
1309 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1310 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1311 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1312 : NTCREATEX_SHARE_ACCESS_WRITE;
1313 2 : io.smb2.in.alloc_size = 0;
1314 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1315 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1316 2 : io.smb2.in.security_flags = 0;
1317 2 : io.smb2.in.fname = BASEDIR_NTDIS;
1318 :
1319 2 : status = smb2_create(tree, torture, &(io.smb2));
1320 2 : CHECK_STATUS(status, NT_STATUS_OK);
1321 2 : h1 = io.smb2.out.file.handle;
1322 :
1323 : /* ask for a change notify,
1324 : on file or directory name changes */
1325 2 : ZERO_STRUCT(notify.smb2);
1326 2 : notify.smb2.level = RAW_NOTIFY_SMB2;
1327 2 : notify.smb2.in.buffer_size = 1000;
1328 2 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1329 2 : notify.smb2.in.file.handle = h1;
1330 2 : notify.smb2.in.recursive = true;
1331 :
1332 2 : req = smb2_notify_send(tree, &(notify.smb2));
1333 10 : WAIT_FOR_ASYNC_RESPONSE(req);
1334 :
1335 2 : status = smb2_tdis(tree);
1336 2 : CHECK_STATUS(status, NT_STATUS_OK);
1337 :
1338 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1339 2 : CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
1340 2 : CHECK_VAL(notify.smb2.out.num_changes, 0);
1341 :
1342 2 : done:
1343 2 : smb2_deltree(tree, BASEDIR_NTDIS);
1344 2 : return ret;
1345 : }
1346 :
1347 : /*
1348 : basic testing of change notifies followed by a close
1349 : */
1350 :
1351 : #define BASEDIR_CNC BASEDIR "_CNC"
1352 :
1353 2 : static bool torture_smb2_notify_close(struct torture_context *torture,
1354 : struct smb2_tree *tree1)
1355 : {
1356 2 : bool ret = true;
1357 0 : NTSTATUS status;
1358 0 : union smb_notify notify;
1359 0 : union smb_open io;
1360 0 : struct smb2_handle h1;
1361 0 : struct smb2_request *req;
1362 :
1363 2 : smb2_deltree(tree1, BASEDIR_CNC);
1364 2 : smb2_util_rmdir(tree1, BASEDIR_CNC);
1365 :
1366 2 : torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1367 :
1368 : /*
1369 : get a handle on the directory
1370 : */
1371 2 : ZERO_STRUCT(io.smb2);
1372 2 : io.generic.level = RAW_OPEN_SMB2;
1373 2 : io.smb2.in.create_flags = 0;
1374 2 : io.smb2.in.desired_access = SEC_FILE_ALL;
1375 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1376 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1377 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1378 : NTCREATEX_SHARE_ACCESS_WRITE;
1379 2 : io.smb2.in.alloc_size = 0;
1380 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1381 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1382 2 : io.smb2.in.security_flags = 0;
1383 2 : io.smb2.in.fname = BASEDIR_CNC;
1384 :
1385 2 : status = smb2_create(tree1, torture, &(io.smb2));
1386 2 : CHECK_STATUS(status, NT_STATUS_OK);
1387 :
1388 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1389 2 : status = smb2_create(tree1, torture, &(io.smb2));
1390 2 : CHECK_STATUS(status, NT_STATUS_OK);
1391 2 : h1 = io.smb2.out.file.handle;
1392 :
1393 : /* ask for a change notify,
1394 : on file or directory name changes */
1395 2 : ZERO_STRUCT(notify.smb2);
1396 2 : notify.smb2.level = RAW_NOTIFY_SMB2;
1397 2 : notify.smb2.in.buffer_size = 1000;
1398 2 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1399 2 : notify.smb2.in.file.handle = h1;
1400 2 : notify.smb2.in.recursive = true;
1401 :
1402 2 : req = smb2_notify_send(tree1, &(notify.smb2));
1403 :
1404 10 : WAIT_FOR_ASYNC_RESPONSE(req);
1405 :
1406 2 : status = smb2_util_close(tree1, h1);
1407 2 : CHECK_STATUS(status, NT_STATUS_OK);
1408 :
1409 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1410 2 : CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
1411 2 : CHECK_VAL(notify.smb2.out.num_changes, 0);
1412 :
1413 2 : done:
1414 2 : smb2_deltree(tree1, BASEDIR_CNC);
1415 2 : return ret;
1416 : }
1417 :
1418 : /*
1419 : basic testing of change notifies followed by a ulogoff
1420 : */
1421 :
1422 : #define BASEDIR_NUL BASEDIR "_NUL"
1423 2 : static bool torture_smb2_notify_ulogoff(struct torture_context *torture,
1424 : struct smb2_tree *tree1)
1425 : {
1426 2 : bool ret = true;
1427 0 : NTSTATUS status;
1428 0 : union smb_notify notify;
1429 0 : union smb_open io;
1430 0 : struct smb2_handle h1;
1431 0 : struct smb2_request *req;
1432 :
1433 2 : smb2_deltree(tree1, BASEDIR_NUL);
1434 2 : smb2_util_rmdir(tree1, BASEDIR_NUL);
1435 :
1436 2 : torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1437 :
1438 : /*
1439 : get a handle on the directory
1440 : */
1441 2 : ZERO_STRUCT(io.smb2);
1442 2 : io.generic.level = RAW_OPEN_SMB2;
1443 2 : io.smb2.in.create_flags = 0;
1444 2 : io.smb2.in.desired_access = SEC_FILE_ALL;
1445 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1446 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1447 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1448 : NTCREATEX_SHARE_ACCESS_WRITE;
1449 2 : io.smb2.in.alloc_size = 0;
1450 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1451 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1452 2 : io.smb2.in.security_flags = 0;
1453 2 : io.smb2.in.fname = BASEDIR_NUL;
1454 :
1455 2 : status = smb2_create(tree1, torture, &(io.smb2));
1456 2 : CHECK_STATUS(status, NT_STATUS_OK);
1457 :
1458 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1459 2 : status = smb2_create(tree1, torture, &(io.smb2));
1460 2 : CHECK_STATUS(status, NT_STATUS_OK);
1461 2 : h1 = io.smb2.out.file.handle;
1462 :
1463 : /* ask for a change notify,
1464 : on file or directory name changes */
1465 2 : ZERO_STRUCT(notify.smb2);
1466 2 : notify.smb2.level = RAW_NOTIFY_SMB2;
1467 2 : notify.smb2.in.buffer_size = 1000;
1468 2 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1469 2 : notify.smb2.in.file.handle = h1;
1470 2 : notify.smb2.in.recursive = true;
1471 :
1472 2 : req = smb2_notify_send(tree1, &(notify.smb2));
1473 :
1474 10 : WAIT_FOR_ASYNC_RESPONSE(req);
1475 :
1476 2 : status = smb2_logoff(tree1->session);
1477 2 : CHECK_STATUS(status, NT_STATUS_OK);
1478 :
1479 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1480 2 : CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
1481 2 : CHECK_VAL(notify.smb2.out.num_changes, 0);
1482 :
1483 2 : done:
1484 2 : smb2_deltree(tree1, BASEDIR_NUL);
1485 2 : return ret;
1486 : }
1487 :
1488 : /*
1489 : basic testing of change notifies followed by a session reconnect
1490 : */
1491 :
1492 : #define BASEDIR_NSR BASEDIR "_NSR"
1493 :
1494 2 : static bool torture_smb2_notify_session_reconnect(struct torture_context *torture,
1495 : struct smb2_tree *tree1)
1496 : {
1497 2 : bool ret = true;
1498 0 : NTSTATUS status;
1499 0 : union smb_notify notify;
1500 0 : union smb_open io;
1501 0 : struct smb2_handle h1;
1502 0 : struct smb2_request *req;
1503 2 : uint64_t previous_session_id = 0;
1504 2 : struct smb2_session *session2 = NULL;
1505 :
1506 2 : smb2_deltree(tree1, BASEDIR_NSR);
1507 2 : smb2_util_rmdir(tree1, BASEDIR_NSR);
1508 :
1509 2 : torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY SESSION RECONNECT\n");
1510 :
1511 : /*
1512 : get a handle on the directory
1513 : */
1514 2 : ZERO_STRUCT(io.smb2);
1515 2 : io.generic.level = RAW_OPEN_SMB2;
1516 2 : io.smb2.in.create_flags = 0;
1517 2 : io.smb2.in.desired_access = SEC_FILE_ALL;
1518 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1519 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1520 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1521 : NTCREATEX_SHARE_ACCESS_WRITE;
1522 2 : io.smb2.in.alloc_size = 0;
1523 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1524 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1525 2 : io.smb2.in.security_flags = 0;
1526 2 : io.smb2.in.fname = BASEDIR_NSR;
1527 :
1528 2 : status = smb2_create(tree1, torture, &(io.smb2));
1529 2 : CHECK_STATUS(status, NT_STATUS_OK);
1530 :
1531 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1532 2 : status = smb2_create(tree1, torture, &(io.smb2));
1533 2 : CHECK_STATUS(status, NT_STATUS_OK);
1534 2 : h1 = io.smb2.out.file.handle;
1535 :
1536 : /* ask for a change notify,
1537 : on file or directory name changes */
1538 2 : ZERO_STRUCT(notify.smb2);
1539 2 : notify.smb2.level = RAW_NOTIFY_SMB2;
1540 2 : notify.smb2.in.buffer_size = 1000;
1541 2 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1542 2 : notify.smb2.in.file.handle = h1;
1543 2 : notify.smb2.in.recursive = true;
1544 :
1545 2 : req = smb2_notify_send(tree1, &(notify.smb2));
1546 :
1547 10 : WAIT_FOR_ASYNC_RESPONSE(req);
1548 :
1549 2 : previous_session_id = smb2cli_session_current_id(tree1->session->smbXcli);
1550 2 : torture_assert(torture, torture_smb2_session_setup(torture,
1551 : tree1->session->transport,
1552 : previous_session_id,
1553 : torture, &session2),
1554 : "session setup with previous_session_id failed");
1555 :
1556 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1557 2 : CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
1558 2 : CHECK_VAL(notify.smb2.out.num_changes, 0);
1559 :
1560 2 : status = smb2_logoff(tree1->session);
1561 2 : CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
1562 :
1563 2 : status = smb2_logoff(session2);
1564 2 : CHECK_STATUS(status, NT_STATUS_OK);
1565 2 : done:
1566 2 : smb2_deltree(tree1, BASEDIR_NSR);
1567 2 : return ret;
1568 : }
1569 :
1570 : /*
1571 : basic testing of change notifies followed by an invalid reauth
1572 : */
1573 :
1574 : #define BASEDIR_IR BASEDIR "_IR"
1575 :
1576 2 : static bool torture_smb2_notify_invalid_reauth(struct torture_context *torture,
1577 : struct smb2_tree *tree1,
1578 : struct smb2_tree *tree2)
1579 : {
1580 2 : bool ret = true;
1581 0 : NTSTATUS status;
1582 0 : union smb_notify notify;
1583 0 : union smb_open io;
1584 0 : struct smb2_handle h1;
1585 0 : struct smb2_request *req;
1586 0 : struct cli_credentials *invalid_creds;
1587 :
1588 2 : smb2_deltree(tree2, BASEDIR_IR);
1589 2 : smb2_util_rmdir(tree2, BASEDIR_IR);
1590 :
1591 2 : torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY invalid REAUTH\n");
1592 :
1593 : /*
1594 : get a handle on the directory
1595 : */
1596 2 : ZERO_STRUCT(io.smb2);
1597 2 : io.generic.level = RAW_OPEN_SMB2;
1598 2 : io.smb2.in.create_flags = 0;
1599 2 : io.smb2.in.desired_access = SEC_FILE_ALL;
1600 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1601 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1602 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1603 : NTCREATEX_SHARE_ACCESS_WRITE;
1604 2 : io.smb2.in.alloc_size = 0;
1605 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1606 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1607 2 : io.smb2.in.security_flags = 0;
1608 2 : io.smb2.in.fname = BASEDIR_IR;
1609 :
1610 2 : status = smb2_create(tree1, torture, &(io.smb2));
1611 2 : CHECK_STATUS(status, NT_STATUS_OK);
1612 :
1613 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1614 2 : status = smb2_create(tree1, torture, &(io.smb2));
1615 2 : CHECK_STATUS(status, NT_STATUS_OK);
1616 2 : h1 = io.smb2.out.file.handle;
1617 :
1618 : /* ask for a change notify,
1619 : on file or directory name changes */
1620 2 : ZERO_STRUCT(notify.smb2);
1621 2 : notify.smb2.level = RAW_NOTIFY_SMB2;
1622 2 : notify.smb2.in.buffer_size = 1000;
1623 2 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1624 2 : notify.smb2.in.file.handle = h1;
1625 2 : notify.smb2.in.recursive = true;
1626 :
1627 2 : req = smb2_notify_send(tree1, &(notify.smb2));
1628 :
1629 10 : WAIT_FOR_ASYNC_RESPONSE(req);
1630 :
1631 2 : invalid_creds = cli_credentials_init(torture);
1632 2 : torture_assert(torture, (invalid_creds != NULL), "talloc error");
1633 2 : cli_credentials_set_username(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1634 2 : cli_credentials_set_domain(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1635 2 : cli_credentials_set_password(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1636 2 : cli_credentials_set_realm(invalid_creds, NULL, CRED_SPECIFIED);
1637 2 : cli_credentials_set_workstation(invalid_creds, "", CRED_UNINITIALISED);
1638 :
1639 2 : status = smb2_session_setup_spnego(tree1->session,
1640 : invalid_creds,
1641 : 0 /* previous_session_id */);
1642 2 : CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE);
1643 :
1644 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1645 2 : CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
1646 2 : CHECK_VAL(notify.smb2.out.num_changes, 0);
1647 :
1648 : /*
1649 : * Demonstrate that the session is no longer valid.
1650 : */
1651 2 : status = smb2_create(tree1, torture, &(io.smb2));
1652 2 : CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
1653 2 : done:
1654 2 : smb2_deltree(tree2, BASEDIR_IR);
1655 2 : return ret;
1656 : }
1657 :
1658 2 : static void tcp_dis_handler(struct smb2_transport *t, void *p)
1659 : {
1660 2 : struct smb2_tree *tree = (struct smb2_tree *)p;
1661 2 : smb2_transport_dead(tree->session->transport,
1662 2 : NT_STATUS_LOCAL_DISCONNECT);
1663 2 : t = NULL;
1664 2 : tree = NULL;
1665 2 : }
1666 :
1667 : /*
1668 : basic testing of change notifies followed by tcp disconnect
1669 : */
1670 :
1671 : #define BASEDIR_NTCPD BASEDIR "_NTCPD"
1672 :
1673 2 : static bool torture_smb2_notify_tcp_disconnect(
1674 : struct torture_context *torture,
1675 : struct smb2_tree *tree)
1676 : {
1677 2 : bool ret = true;
1678 0 : NTSTATUS status;
1679 0 : union smb_notify notify;
1680 0 : union smb_open io;
1681 0 : struct smb2_handle h1;
1682 0 : struct smb2_request *req;
1683 :
1684 2 : smb2_deltree(tree, BASEDIR_NTCPD);
1685 2 : smb2_util_rmdir(tree, BASEDIR_NTCPD);
1686 :
1687 2 : torture_comment(torture,
1688 : "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1689 :
1690 : /*
1691 : get a handle on the directory
1692 : */
1693 2 : ZERO_STRUCT(io.smb2);
1694 2 : io.generic.level = RAW_OPEN_SMB2;
1695 2 : io.smb2.in.create_flags = 0;
1696 2 : io.smb2.in.desired_access = SEC_FILE_ALL;
1697 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1698 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1699 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1700 : NTCREATEX_SHARE_ACCESS_WRITE;
1701 2 : io.smb2.in.alloc_size = 0;
1702 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1703 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1704 2 : io.smb2.in.security_flags = 0;
1705 2 : io.smb2.in.fname = BASEDIR_NTCPD;
1706 :
1707 2 : status = smb2_create(tree, torture, &(io.smb2));
1708 2 : CHECK_STATUS(status, NT_STATUS_OK);
1709 2 : h1 = io.smb2.out.file.handle;
1710 :
1711 : /* ask for a change notify,
1712 : on file or directory name changes */
1713 2 : ZERO_STRUCT(notify.smb2);
1714 2 : notify.smb2.level = RAW_NOTIFY_SMB2;
1715 2 : notify.smb2.in.buffer_size = 1000;
1716 2 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1717 2 : notify.smb2.in.file.handle = h1;
1718 2 : notify.smb2.in.recursive = true;
1719 :
1720 2 : req = smb2_notify_send(tree, &(notify.smb2));
1721 2 : smb2_cancel(req);
1722 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1723 2 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
1724 :
1725 2 : notify.smb2.in.recursive = true;
1726 2 : req = smb2_notify_send(tree, &(notify.smb2));
1727 2 : smb2_transport_idle_handler(tree->session->transport,
1728 : tcp_dis_handler, 250000, tree);
1729 2 : tree = NULL;
1730 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1731 2 : CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
1732 :
1733 2 : done:
1734 2 : return ret;
1735 : }
1736 :
1737 : /*
1738 : test setting up two change notify requests on one handle
1739 : */
1740 :
1741 : #define BASEDIR_NDOH BASEDIR "_NDOH"
1742 :
1743 2 : static bool torture_smb2_notify_double(struct torture_context *torture,
1744 : struct smb2_tree *tree1,
1745 : struct smb2_tree *tree2)
1746 : {
1747 2 : bool ret = true;
1748 0 : NTSTATUS status;
1749 0 : union smb_notify notify;
1750 0 : union smb_open io;
1751 0 : struct smb2_handle h1;
1752 0 : struct smb2_request *req1, *req2;
1753 :
1754 2 : smb2_deltree(tree1, BASEDIR_NDOH);
1755 2 : smb2_util_rmdir(tree1, BASEDIR_NDOH);
1756 :
1757 2 : torture_comment(torture,
1758 : "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1759 :
1760 : /*
1761 : get a handle on the directory
1762 : */
1763 2 : ZERO_STRUCT(io.smb2);
1764 2 : io.generic.level = RAW_OPEN_SMB2;
1765 2 : io.smb2.in.create_flags = 0;
1766 2 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ|
1767 : SEC_RIGHTS_FILE_WRITE|
1768 : SEC_RIGHTS_FILE_ALL;
1769 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1770 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1771 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1772 : NTCREATEX_SHARE_ACCESS_WRITE;
1773 2 : io.smb2.in.alloc_size = 0;
1774 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1775 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1776 2 : io.smb2.in.security_flags = 0;
1777 2 : io.smb2.in.fname = BASEDIR_NDOH;
1778 :
1779 2 : status = smb2_create(tree1, torture, &(io.smb2));
1780 2 : CHECK_STATUS(status, NT_STATUS_OK);
1781 2 : h1 = io.smb2.out.file.handle;
1782 :
1783 : /* ask for a change notify,
1784 : on file or directory name changes */
1785 2 : ZERO_STRUCT(notify.smb2);
1786 2 : notify.smb2.level = RAW_NOTIFY_SMB2;
1787 2 : notify.smb2.in.buffer_size = 1000;
1788 2 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1789 2 : notify.smb2.in.file.handle = h1;
1790 2 : notify.smb2.in.recursive = true;
1791 :
1792 2 : req1 = smb2_notify_send(tree1, &(notify.smb2));
1793 2 : smb2_cancel(req1);
1794 2 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
1795 2 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
1796 :
1797 2 : req2 = smb2_notify_send(tree1, &(notify.smb2));
1798 2 : smb2_cancel(req2);
1799 2 : status = smb2_notify_recv(req2, torture, &(notify.smb2));
1800 2 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
1801 :
1802 2 : smb2_util_mkdir(tree2, BASEDIR_NDOH "\\subdir-name");
1803 2 : req1 = smb2_notify_send(tree1, &(notify.smb2));
1804 2 : req2 = smb2_notify_send(tree1, &(notify.smb2));
1805 :
1806 2 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
1807 2 : CHECK_STATUS(status, NT_STATUS_OK);
1808 2 : CHECK_VAL(notify.smb2.out.num_changes, 1);
1809 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1810 :
1811 2 : smb2_util_mkdir(tree2, BASEDIR_NDOH "\\subdir-name2");
1812 :
1813 2 : status = smb2_notify_recv(req2, torture, &(notify.smb2));
1814 2 : CHECK_STATUS(status, NT_STATUS_OK);
1815 2 : CHECK_VAL(notify.smb2.out.num_changes, 1);
1816 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name2");
1817 :
1818 2 : done:
1819 2 : smb2_deltree(tree1, BASEDIR_NDOH);
1820 2 : return ret;
1821 : }
1822 :
1823 :
1824 : /*
1825 : test multiple change notifies at different depths and with/without recursion
1826 : */
1827 :
1828 : #define BASEDIR_TREE BASEDIR "_TREE"
1829 :
1830 2 : static bool torture_smb2_notify_tree(struct torture_context *torture,
1831 : struct smb2_tree *tree)
1832 : {
1833 2 : bool ret = true;
1834 0 : union smb_notify notify;
1835 0 : union smb_open io;
1836 0 : struct smb2_request *req;
1837 0 : struct timeval tv;
1838 0 : struct {
1839 : const char *path;
1840 : bool recursive;
1841 : uint32_t filter;
1842 : int expected;
1843 : struct smb2_handle h1;
1844 : int counted;
1845 2 : } dirs[] = {
1846 : {
1847 : .path = BASEDIR_TREE "\\abc",
1848 : .recursive = true,
1849 : .filter = FILE_NOTIFY_CHANGE_NAME,
1850 : .expected = 30,
1851 : },
1852 : {
1853 : .path = BASEDIR_TREE "\\zqy",
1854 : .recursive = true,
1855 : .filter = FILE_NOTIFY_CHANGE_NAME,
1856 : .expected = 8,
1857 : },
1858 : {
1859 : .path = BASEDIR_TREE "\\atsy",
1860 : .recursive = true,
1861 : .filter = FILE_NOTIFY_CHANGE_NAME,
1862 : .expected = 4,
1863 : },
1864 : {
1865 : .path = BASEDIR_TREE "\\abc\\foo",
1866 : .recursive = true,
1867 : .filter = FILE_NOTIFY_CHANGE_NAME,
1868 : .expected = 2,
1869 : },
1870 : {
1871 : .path = BASEDIR_TREE "\\abc\\blah",
1872 : .recursive = true,
1873 : .filter = FILE_NOTIFY_CHANGE_NAME,
1874 : .expected = 13,
1875 : },
1876 : {
1877 : .path = BASEDIR_TREE "\\abc\\blah",
1878 : .recursive = false,
1879 : .filter = FILE_NOTIFY_CHANGE_NAME,
1880 : .expected = 7,
1881 : },
1882 : {
1883 : .path = BASEDIR_TREE "\\abc\\blah\\a",
1884 : .recursive = true,
1885 : .filter = FILE_NOTIFY_CHANGE_NAME,
1886 : .expected = 2,
1887 : },
1888 : {
1889 : .path = BASEDIR_TREE "\\abc\\blah\\b",
1890 : .recursive = true,
1891 : .filter = FILE_NOTIFY_CHANGE_NAME,
1892 : .expected = 2,
1893 : },
1894 : {
1895 : .path = BASEDIR_TREE "\\abc\\blah\\c",
1896 : .recursive = true,
1897 : .filter = FILE_NOTIFY_CHANGE_NAME,
1898 : .expected = 2,
1899 : },
1900 : {
1901 : .path = BASEDIR_TREE "\\abc\\fooblah",
1902 : .recursive = true,
1903 : .filter = FILE_NOTIFY_CHANGE_NAME,
1904 : .expected = 2,
1905 : },
1906 : {
1907 : .path = BASEDIR_TREE "\\zqy\\xx",
1908 : .recursive = true,
1909 : .filter = FILE_NOTIFY_CHANGE_NAME,
1910 : .expected = 2,
1911 : },
1912 : {
1913 : .path = BASEDIR_TREE "\\zqy\\yyy",
1914 : .recursive = true,
1915 : .filter = FILE_NOTIFY_CHANGE_NAME,
1916 : .expected = 2,
1917 : },
1918 : {
1919 : .path = BASEDIR_TREE "\\zqy\\..",
1920 : .recursive = true,
1921 : .filter = FILE_NOTIFY_CHANGE_NAME,
1922 : .expected = 40,
1923 : },
1924 : {
1925 : .path = BASEDIR_TREE,
1926 : .recursive = true,
1927 : .filter = FILE_NOTIFY_CHANGE_NAME,
1928 : .expected = 40,
1929 : },
1930 : {
1931 : .path = BASEDIR_TREE,
1932 : .recursive = false,
1933 : .filter = FILE_NOTIFY_CHANGE_NAME,
1934 : .expected = 6,
1935 : },
1936 : {
1937 : .path = BASEDIR_TREE "\\atsy",
1938 : .recursive = false,
1939 : .filter = FILE_NOTIFY_CHANGE_NAME,
1940 : .expected = 4,
1941 : },
1942 : {
1943 : .path = BASEDIR_TREE "\\abc",
1944 : .recursive = true,
1945 : .filter = FILE_NOTIFY_CHANGE_NAME,
1946 : .expected = 24,
1947 : },
1948 : {
1949 : .path = BASEDIR_TREE "\\abc",
1950 : .recursive = false,
1951 : .filter = FILE_NOTIFY_CHANGE_FILE_NAME,
1952 : .expected = 0,
1953 : },
1954 : {
1955 : .path = BASEDIR_TREE "\\abc",
1956 : .recursive = true,
1957 : .filter = FILE_NOTIFY_CHANGE_FILE_NAME,
1958 : .expected = 0,
1959 : },
1960 : {
1961 : .path = BASEDIR_TREE "\\abc",
1962 : .recursive = true,
1963 : .filter = FILE_NOTIFY_CHANGE_NAME,
1964 : .expected = 24,
1965 : },
1966 : };
1967 0 : int i;
1968 0 : NTSTATUS status;
1969 2 : bool all_done = false;
1970 :
1971 2 : smb2_deltree(tree, BASEDIR_TREE);
1972 2 : smb2_util_rmdir(tree, BASEDIR_TREE);
1973 :
1974 2 : torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1975 :
1976 2 : ZERO_STRUCT(io.smb2);
1977 2 : io.generic.level = RAW_OPEN_SMB2;
1978 2 : io.smb2.in.create_flags = 0;
1979 2 : io.smb2.in.desired_access = SEC_FILE_ALL;
1980 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1981 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1982 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1983 : NTCREATEX_SHARE_ACCESS_WRITE;
1984 2 : io.smb2.in.alloc_size = 0;
1985 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1986 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1987 2 : io.smb2.in.security_flags = 0;
1988 2 : io.smb2.in.fname = BASEDIR_TREE;
1989 2 : status = smb2_create(tree, torture, &(io.smb2));
1990 2 : CHECK_STATUS(status, NT_STATUS_OK);
1991 :
1992 2 : ZERO_STRUCT(notify.smb2);
1993 2 : notify.smb2.level = RAW_NOTIFY_SMB2;
1994 2 : notify.smb2.in.buffer_size = 20000;
1995 :
1996 : /*
1997 : setup the directory tree, and the notify buffer on each directory
1998 : */
1999 42 : for (i=0;i<ARRAY_SIZE(dirs);i++) {
2000 40 : io.smb2.in.fname = dirs[i].path;
2001 40 : status = smb2_create(tree, torture, &(io.smb2));
2002 40 : CHECK_STATUS(status, NT_STATUS_OK);
2003 40 : dirs[i].h1 = io.smb2.out.file.handle;
2004 :
2005 40 : notify.smb2.in.completion_filter = dirs[i].filter;
2006 40 : notify.smb2.in.file.handle = dirs[i].h1;
2007 40 : notify.smb2.in.recursive = dirs[i].recursive;
2008 40 : req = smb2_notify_send(tree, &(notify.smb2));
2009 40 : smb2_cancel(req);
2010 40 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2011 40 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
2012 : }
2013 :
2014 : /* trigger 2 events in each dir */
2015 42 : for (i=0;i<ARRAY_SIZE(dirs);i++) {
2016 40 : char *path = talloc_asprintf(torture, "%s\\test.dir",
2017 : dirs[i].path);
2018 40 : smb2_util_mkdir(tree, path);
2019 40 : smb2_util_rmdir(tree, path);
2020 40 : talloc_free(path);
2021 : }
2022 :
2023 : /* give a bit of time for the events to propagate */
2024 2 : tv = timeval_current();
2025 :
2026 0 : do {
2027 : /* count events that have happened in each dir */
2028 42 : for (i=0;i<ARRAY_SIZE(dirs);i++) {
2029 40 : notify.smb2.in.completion_filter = dirs[i].filter;
2030 40 : notify.smb2.in.file.handle = dirs[i].h1;
2031 40 : notify.smb2.in.recursive = dirs[i].recursive;
2032 40 : req = smb2_notify_send(tree, &(notify.smb2));
2033 40 : smb2_cancel(req);
2034 40 : notify.smb2.out.num_changes = 0;
2035 40 : status = smb2_notify_recv(req, torture,
2036 : &(notify.smb2));
2037 40 : dirs[i].counted += notify.smb2.out.num_changes;
2038 : }
2039 :
2040 2 : all_done = true;
2041 :
2042 42 : for (i=0;i<ARRAY_SIZE(dirs);i++) {
2043 40 : if (dirs[i].counted != dirs[i].expected) {
2044 0 : all_done = false;
2045 : }
2046 : }
2047 2 : } while (!all_done && timeval_elapsed(&tv) < 20);
2048 :
2049 2 : torture_comment(torture, "took %.4f seconds to propagate all events\n",
2050 : timeval_elapsed(&tv));
2051 :
2052 42 : for (i=0;i<ARRAY_SIZE(dirs);i++) {
2053 40 : if (dirs[i].counted != dirs[i].expected) {
2054 0 : torture_comment(torture,
2055 : "ERROR: i=%d expected %d got %d for '%s'\n",
2056 : i, dirs[i].expected, dirs[i].counted,
2057 : dirs[i].path);
2058 0 : ret = false;
2059 : }
2060 : }
2061 :
2062 : /*
2063 : run from the back, closing and deleting
2064 : */
2065 42 : for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
2066 40 : smb2_util_close(tree, dirs[i].h1);
2067 40 : smb2_util_rmdir(tree, dirs[i].path);
2068 : }
2069 :
2070 2 : done:
2071 2 : smb2_deltree(tree, BASEDIR_TREE);
2072 2 : smb2_util_rmdir(tree, BASEDIR_TREE);
2073 2 : return ret;
2074 : }
2075 :
2076 : /*
2077 : Test response when cached server events exceed single NT NOTFIY response
2078 : packet size.
2079 : */
2080 :
2081 : #define BASEDIR_OVF BASEDIR "_OVF"
2082 :
2083 2 : static bool torture_smb2_notify_overflow(struct torture_context *torture,
2084 : struct smb2_tree *tree)
2085 : {
2086 2 : bool ret = true;
2087 0 : NTSTATUS status;
2088 0 : union smb_notify notify;
2089 0 : union smb_open io;
2090 0 : struct smb2_handle h1, h2;
2091 2 : int count = 100;
2092 0 : struct smb2_request *req1;
2093 0 : int i;
2094 :
2095 2 : smb2_deltree(tree, BASEDIR_OVF);
2096 2 : smb2_util_rmdir(tree, BASEDIR_OVF);
2097 :
2098 2 : torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
2099 :
2100 : /* get a handle on the directory */
2101 2 : ZERO_STRUCT(io.smb2);
2102 2 : io.generic.level = RAW_OPEN_SMB2;
2103 2 : io.smb2.in.create_flags = 0;
2104 2 : io.smb2.in.desired_access = SEC_FILE_ALL;
2105 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2106 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2107 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2108 : NTCREATEX_SHARE_ACCESS_WRITE;
2109 2 : io.smb2.in.alloc_size = 0;
2110 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2111 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2112 2 : io.smb2.in.security_flags = 0;
2113 2 : io.smb2.in.fname = BASEDIR_OVF;
2114 :
2115 2 : status = smb2_create(tree, torture, &(io.smb2));
2116 2 : CHECK_STATUS(status, NT_STATUS_OK);
2117 2 : h1 = io.smb2.out.file.handle;
2118 :
2119 : /* ask for a change notify, on name changes. */
2120 2 : ZERO_STRUCT(notify.smb2);
2121 2 : notify.smb2.level = RAW_NOTIFY_NTTRANS;
2122 2 : notify.smb2.in.buffer_size = 1000;
2123 2 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2124 2 : notify.smb2.in.file.handle = h1;
2125 :
2126 2 : notify.smb2.in.recursive = true;
2127 2 : req1 = smb2_notify_send(tree, &(notify.smb2));
2128 :
2129 : /* cancel initial requests so the buffer is setup */
2130 2 : smb2_cancel(req1);
2131 2 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
2132 2 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
2133 :
2134 : /* open a lot of files, filling up the server side notify buffer */
2135 2 : torture_comment(torture,
2136 : "Testing overflowed buffer notify on create of %d files\n",
2137 : count);
2138 :
2139 202 : for (i=0;i<count;i++) {
2140 200 : char *fname = talloc_asprintf(torture,
2141 : BASEDIR_OVF "\\test%d.txt", i);
2142 0 : union smb_open io1;
2143 200 : ZERO_STRUCT(io1.smb2);
2144 200 : io1.generic.level = RAW_OPEN_SMB2;
2145 200 : io1.smb2.in.create_flags = 0;
2146 200 : io1.smb2.in.desired_access = SEC_FILE_ALL;
2147 200 : io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2148 200 : io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2149 200 : io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2150 : NTCREATEX_SHARE_ACCESS_WRITE;
2151 200 : io1.smb2.in.alloc_size = 0;
2152 200 : io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2153 200 : io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2154 200 : io1.smb2.in.security_flags = 0;
2155 200 : io1.smb2.in.fname = fname;
2156 :
2157 200 : h2 = custom_smb2_create(tree, torture, &(io1.smb2));
2158 200 : talloc_free(fname);
2159 200 : smb2_util_close(tree, h2);
2160 : }
2161 :
2162 2 : req1 = smb2_notify_send(tree, &(notify.smb2));
2163 2 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
2164 2 : CHECK_STATUS(status, NT_STATUS_NOTIFY_ENUM_DIR);
2165 2 : CHECK_VAL(notify.smb2.out.num_changes, 0);
2166 :
2167 2 : done:
2168 2 : smb2_deltree(tree, BASEDIR_OVF);
2169 2 : return ret;
2170 : }
2171 :
2172 : /*
2173 : Test if notifications are returned for changes to the base directory.
2174 : They shouldn't be.
2175 : */
2176 :
2177 : #define BASEDIR_BAS BASEDIR "_BAS"
2178 :
2179 2 : static bool torture_smb2_notify_basedir(struct torture_context *torture,
2180 : struct smb2_tree *tree1,
2181 : struct smb2_tree *tree2)
2182 : {
2183 2 : bool ret = true;
2184 0 : NTSTATUS status;
2185 0 : union smb_notify notify;
2186 0 : union smb_open io;
2187 0 : struct smb2_handle h1;
2188 0 : struct smb2_request *req1;
2189 :
2190 2 : smb2_deltree(tree1, BASEDIR_BAS);
2191 2 : smb2_util_rmdir(tree1, BASEDIR_BAS);
2192 :
2193 2 : torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
2194 :
2195 : /* get a handle on the directory */
2196 2 : ZERO_STRUCT(io.smb2);
2197 2 : io.generic.level = RAW_OPEN_SMB2;
2198 2 : io.smb2.in.create_flags = 0;
2199 2 : io.smb2.in.desired_access = SEC_FILE_ALL;
2200 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2201 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2202 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2203 : NTCREATEX_SHARE_ACCESS_WRITE;
2204 2 : io.smb2.in.alloc_size = 0;
2205 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2206 2 : io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
2207 2 : io.smb2.in.security_flags = 0;
2208 2 : io.smb2.in.fname = BASEDIR_BAS;
2209 :
2210 2 : status = smb2_create(tree1, torture, &(io.smb2));
2211 2 : CHECK_STATUS(status, NT_STATUS_OK);
2212 2 : h1 = io.smb2.out.file.handle;
2213 :
2214 : /* create a test file that will also be modified */
2215 2 : io.smb2.in.fname = BASEDIR_BAS "\\tname1";
2216 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
2217 2 : status = smb2_create(tree2, torture, &(io.smb2));
2218 2 : CHECK_STATUS(status,NT_STATUS_OK);
2219 2 : smb2_util_close(tree2, io.smb2.out.file.handle);
2220 :
2221 : /* ask for a change notify, on attribute changes. */
2222 2 : ZERO_STRUCT(notify.smb2);
2223 2 : notify.smb2.level = RAW_NOTIFY_SMB2;
2224 2 : notify.smb2.in.buffer_size = 1000;
2225 2 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
2226 2 : notify.smb2.in.file.handle = h1;
2227 2 : notify.smb2.in.recursive = true;
2228 :
2229 2 : req1 = smb2_notify_send(tree1, &(notify.smb2));
2230 :
2231 : /* set attribute on the base dir */
2232 2 : smb2_util_setatr(tree2, BASEDIR_BAS, FILE_ATTRIBUTE_HIDDEN);
2233 :
2234 : /* set attribute on a file to assure we receive a notification */
2235 2 : smb2_util_setatr(tree2, BASEDIR_BAS "\\tname1", FILE_ATTRIBUTE_HIDDEN);
2236 2 : smb_msleep(200);
2237 :
2238 : /* check how many responses were given, expect only 1 for the file */
2239 2 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
2240 2 : CHECK_STATUS(status, NT_STATUS_OK);
2241 2 : CHECK_VAL(notify.smb2.out.num_changes, 1);
2242 2 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
2243 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
2244 :
2245 2 : done:
2246 2 : smb2_deltree(tree1, BASEDIR_BAS);
2247 2 : return ret;
2248 : }
2249 :
2250 : /*
2251 : very simple change notify test
2252 : */
2253 :
2254 : #define BASEDIR_TCON BASEDIR "_TCON"
2255 :
2256 2 : static bool torture_smb2_notify_tcon(struct torture_context *torture,
2257 : struct smb2_tree *tree)
2258 : {
2259 2 : bool ret = true;
2260 0 : NTSTATUS status;
2261 0 : union smb_notify notify;
2262 0 : union smb_open io;
2263 2 : struct smb2_handle h1 = {{0}};
2264 2 : struct smb2_request *req = NULL;
2265 2 : struct smb2_tree *tree1 = NULL;
2266 2 : const char *fname = BASEDIR_TCON "\\subdir-name";
2267 :
2268 2 : smb2_deltree(tree, BASEDIR_TCON);
2269 2 : smb2_util_rmdir(tree, BASEDIR_TCON);
2270 :
2271 2 : torture_comment(torture, "TESTING SIMPLE CHANGE NOTIFY\n");
2272 :
2273 : /*
2274 : get a handle on the directory
2275 : */
2276 :
2277 2 : ZERO_STRUCT(io.smb2);
2278 2 : io.generic.level = RAW_OPEN_SMB2;
2279 2 : io.smb2.in.create_flags = 0;
2280 2 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2281 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2282 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL |
2283 : FILE_ATTRIBUTE_DIRECTORY;
2284 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2285 : NTCREATEX_SHARE_ACCESS_WRITE;
2286 2 : io.smb2.in.alloc_size = 0;
2287 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2288 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2289 2 : io.smb2.in.security_flags = 0;
2290 2 : io.smb2.in.fname = BASEDIR_TCON;
2291 :
2292 2 : status = smb2_create(tree, torture, &(io.smb2));
2293 2 : CHECK_STATUS(status, NT_STATUS_OK);
2294 2 : h1 = io.smb2.out.file.handle;
2295 :
2296 : /* ask for a change notify,
2297 : on file or directory name changes */
2298 2 : ZERO_STRUCT(notify.smb2);
2299 2 : notify.smb2.level = RAW_NOTIFY_SMB2;
2300 2 : notify.smb2.in.buffer_size = 1000;
2301 2 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2302 2 : notify.smb2.in.file.handle = h1;
2303 2 : notify.smb2.in.recursive = true;
2304 :
2305 2 : torture_comment(torture, "Testing notify mkdir\n");
2306 2 : req = smb2_notify_send(tree, &(notify.smb2));
2307 2 : smb2_cancel(req);
2308 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2309 2 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
2310 :
2311 2 : notify.smb2.in.recursive = true;
2312 2 : req = smb2_notify_send(tree, &(notify.smb2));
2313 2 : status = smb2_util_mkdir(tree, fname);
2314 2 : CHECK_STATUS(status, NT_STATUS_OK);
2315 :
2316 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2317 2 : CHECK_STATUS(status, NT_STATUS_OK);
2318 :
2319 2 : CHECK_VAL(notify.smb2.out.num_changes, 1);
2320 2 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2321 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2322 :
2323 2 : torture_comment(torture, "Testing notify rmdir\n");
2324 2 : req = smb2_notify_send(tree, &(notify.smb2));
2325 2 : status = smb2_util_rmdir(tree, fname);
2326 2 : CHECK_STATUS(status, NT_STATUS_OK);
2327 :
2328 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2329 2 : CHECK_STATUS(status, NT_STATUS_OK);
2330 2 : CHECK_VAL(notify.smb2.out.num_changes, 1);
2331 2 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2332 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2333 :
2334 2 : torture_comment(torture, "SIMPLE CHANGE NOTIFY OK\n");
2335 :
2336 2 : torture_comment(torture, "TESTING WITH SECONDARY TCON\n");
2337 2 : if (!torture_smb2_tree_connect(torture, tree->session, tree, &tree1)) {
2338 0 : torture_warning(torture, "couldn't reconnect to share, bailing\n");
2339 0 : ret = false;
2340 0 : goto done;
2341 : }
2342 :
2343 2 : torture_comment(torture, "tid1=%d tid2=%d\n",
2344 : smb2cli_tcon_current_id(tree->smbXcli),
2345 2 : smb2cli_tcon_current_id(tree1->smbXcli));
2346 :
2347 2 : torture_comment(torture, "Testing notify mkdir\n");
2348 2 : req = smb2_notify_send(tree, &(notify.smb2));
2349 2 : smb2_util_mkdir(tree1, fname);
2350 :
2351 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2352 2 : CHECK_STATUS(status, NT_STATUS_OK);
2353 :
2354 2 : CHECK_VAL(notify.smb2.out.num_changes, 1);
2355 2 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2356 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2357 :
2358 2 : torture_comment(torture, "Testing notify rmdir\n");
2359 2 : req = smb2_notify_send(tree, &(notify.smb2));
2360 2 : smb2_util_rmdir(tree, fname);
2361 :
2362 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2363 2 : CHECK_STATUS(status, NT_STATUS_OK);
2364 2 : CHECK_VAL(notify.smb2.out.num_changes, 1);
2365 2 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2366 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2367 :
2368 2 : torture_comment(torture, "CHANGE NOTIFY WITH TCON OK\n");
2369 :
2370 2 : torture_comment(torture, "Disconnecting secondary tree\n");
2371 2 : status = smb2_tdis(tree1);
2372 2 : CHECK_STATUS(status, NT_STATUS_OK);
2373 2 : talloc_free(tree1);
2374 :
2375 2 : torture_comment(torture, "Testing notify mkdir\n");
2376 2 : req = smb2_notify_send(tree, &(notify.smb2));
2377 2 : smb2_util_mkdir(tree, fname);
2378 :
2379 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2380 2 : CHECK_STATUS(status, NT_STATUS_OK);
2381 :
2382 2 : CHECK_VAL(notify.smb2.out.num_changes, 1);
2383 2 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2384 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2385 :
2386 2 : torture_comment(torture, "Testing notify rmdir\n");
2387 2 : req = smb2_notify_send(tree, &(notify.smb2));
2388 2 : smb2_util_rmdir(tree, fname);
2389 :
2390 2 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2391 2 : CHECK_STATUS(status, NT_STATUS_OK);
2392 2 : CHECK_VAL(notify.smb2.out.num_changes, 1);
2393 2 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2394 2 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2395 :
2396 2 : torture_comment(torture, "CHANGE NOTIFY WITH TDIS OK\n");
2397 2 : done:
2398 2 : smb2_util_close(tree, h1);
2399 2 : smb2_deltree(tree, BASEDIR_TCON);
2400 :
2401 2 : return ret;
2402 : }
2403 :
2404 : #define BASEDIR_RMD BASEDIR "_RMD"
2405 :
2406 8 : static bool torture_smb2_notify_rmdir(struct torture_context *torture,
2407 : struct smb2_tree *tree1,
2408 : struct smb2_tree *tree2,
2409 : bool initial_delete_on_close)
2410 : {
2411 8 : bool ret = true;
2412 0 : NTSTATUS status;
2413 8 : union smb_notify notify = {};
2414 8 : union smb_setfileinfo sfinfo = {};
2415 8 : union smb_open io = {};
2416 8 : struct smb2_handle h = {};
2417 0 : struct smb2_request *req;
2418 :
2419 8 : torture_comment(torture, "TESTING NOTIFY CANCEL FOR DELETED DIR\n");
2420 :
2421 8 : smb2_deltree(tree1, BASEDIR_RMD);
2422 8 : smb2_util_rmdir(tree1, BASEDIR_RMD);
2423 :
2424 8 : ZERO_STRUCT(io.smb2);
2425 8 : io.generic.level = RAW_OPEN_SMB2;
2426 8 : io.smb2.in.create_flags = 0;
2427 8 : io.smb2.in.desired_access = SEC_FILE_ALL;
2428 8 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2429 8 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2430 8 : io.smb2.in.share_access =
2431 : NTCREATEX_SHARE_ACCESS_READ |
2432 : NTCREATEX_SHARE_ACCESS_WRITE |
2433 : NTCREATEX_SHARE_ACCESS_DELETE ;
2434 8 : io.smb2.in.alloc_size = 0;
2435 8 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2436 8 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2437 8 : io.smb2.in.security_flags = 0;
2438 8 : io.smb2.in.fname = BASEDIR_RMD;
2439 :
2440 8 : status = smb2_create(tree1, torture, &(io.smb2));
2441 8 : CHECK_STATUS(status, NT_STATUS_OK);
2442 8 : h = io.smb2.out.file.handle;
2443 :
2444 8 : ZERO_STRUCT(notify.smb2);
2445 8 : notify.smb2.level = RAW_NOTIFY_SMB2;
2446 8 : notify.smb2.in.buffer_size = 1000;
2447 8 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2448 8 : notify.smb2.in.file.handle = h;
2449 8 : notify.smb2.in.recursive = false;
2450 :
2451 8 : io.smb2.in.desired_access |= SEC_STD_DELETE;
2452 8 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
2453 8 : req = smb2_notify_send(tree1, &(notify.smb2));
2454 :
2455 8 : if (initial_delete_on_close) {
2456 4 : status = smb2_util_rmdir(tree2, BASEDIR_RMD);
2457 4 : CHECK_STATUS(status, NT_STATUS_OK);
2458 : } else {
2459 4 : status = smb2_create(tree2, torture, &(io.smb2));
2460 4 : CHECK_STATUS(status, NT_STATUS_OK);
2461 :
2462 4 : sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
2463 4 : sfinfo.generic.in.file.handle = io.smb2.out.file.handle;
2464 4 : sfinfo.disposition_info.in.delete_on_close = 1;
2465 4 : status = smb2_setinfo_file(tree2, &sfinfo);
2466 4 : CHECK_STATUS(status, NT_STATUS_OK);
2467 :
2468 4 : smb2_util_close(tree2, io.smb2.out.file.handle);
2469 : }
2470 :
2471 8 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2472 8 : CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
2473 :
2474 8 : done:
2475 :
2476 8 : smb2_util_close(tree1, h);
2477 8 : smb2_deltree(tree1, BASEDIR_RMD);
2478 :
2479 8 : return ret;
2480 : }
2481 :
2482 2 : static bool torture_smb2_notify_rmdir1(struct torture_context *torture,
2483 : struct smb2_tree *tree)
2484 : {
2485 2 : return torture_smb2_notify_rmdir(torture, tree, tree, false);
2486 : }
2487 :
2488 2 : static bool torture_smb2_notify_rmdir2(struct torture_context *torture,
2489 : struct smb2_tree *tree)
2490 : {
2491 2 : return torture_smb2_notify_rmdir(torture, tree, tree, true);
2492 : }
2493 :
2494 2 : static bool torture_smb2_notify_rmdir3(struct torture_context *torture,
2495 : struct smb2_tree *tree1,
2496 : struct smb2_tree *tree2)
2497 : {
2498 2 : return torture_smb2_notify_rmdir(torture, tree1, tree2, false);
2499 : }
2500 :
2501 2 : static bool torture_smb2_notify_rmdir4(struct torture_context *torture,
2502 : struct smb2_tree *tree1,
2503 : struct smb2_tree *tree2)
2504 : {
2505 2 : return torture_smb2_notify_rmdir(torture, tree1, tree2, true);
2506 : }
2507 :
2508 0 : static void notify_timeout(struct tevent_context *ev,
2509 : struct tevent_timer *te,
2510 : struct timeval current_time,
2511 : void *private_data)
2512 : {
2513 0 : struct smb2_request *req = talloc_get_type_abort(
2514 : private_data, struct smb2_request);
2515 :
2516 0 : smb2_cancel(req);
2517 0 : }
2518 :
2519 : #define BASEDIR_INR BASEDIR "_INR"
2520 :
2521 2 : static bool torture_smb2_inotify_rename(struct torture_context *torture,
2522 : struct smb2_tree *tree1,
2523 : struct smb2_tree *tree2)
2524 : {
2525 0 : NTSTATUS status;
2526 0 : struct smb2_notify notify;
2527 2 : struct notify_changes change1 = {0};
2528 2 : struct notify_changes change2 = {0};
2529 0 : struct smb2_create create;
2530 0 : union smb_setfileinfo sinfo;
2531 2 : struct smb2_handle h1 = {{0}};
2532 2 : struct smb2_handle h2 = {{0}};
2533 0 : struct smb2_request *req;
2534 2 : struct tevent_timer *te = NULL;
2535 2 : bool ok = false;
2536 :
2537 2 : smb2_deltree(tree1, BASEDIR_INR);
2538 :
2539 2 : torture_comment(torture, "Testing change notify of a rename with inotify\n");
2540 :
2541 2 : status = torture_smb2_testdir(tree1, BASEDIR_INR, &h1);
2542 2 : torture_assert_ntstatus_ok_goto(torture, status, ok, done, "torture_smb2_testdir failed");
2543 :
2544 2 : ZERO_STRUCT(create);
2545 2 : create.in.desired_access = SEC_RIGHTS_FILE_READ |
2546 : SEC_RIGHTS_FILE_WRITE|
2547 : SEC_RIGHTS_FILE_ALL;
2548 2 : create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2549 2 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2550 2 : create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2551 : NTCREATEX_SHARE_ACCESS_WRITE |
2552 : NTCREATEX_SHARE_ACCESS_DELETE;
2553 2 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2554 2 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2555 2 : create.in.fname = BASEDIR_INR "\\subdir-name";
2556 :
2557 2 : status = smb2_create(tree2, torture, &create);
2558 2 : torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_create failed\n");
2559 2 : h2 = create.out.file.handle;
2560 :
2561 2 : ZERO_STRUCT(notify);
2562 2 : notify.level = RAW_NOTIFY_SMB2;
2563 2 : notify.in.buffer_size = 4096;
2564 2 : notify.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2565 2 : notify.in.file.handle = h1;
2566 2 : notify.in.recursive = true;
2567 2 : req = smb2_notify_send(tree1, ¬ify);
2568 2 : torture_assert_not_null_goto(torture, req, ok, done, "smb2_notify_send failed\n");
2569 :
2570 10 : while (!NT_STATUS_EQUAL(req->status, NT_STATUS_PENDING)) {
2571 8 : if (tevent_loop_once(torture->ev) != 0) {
2572 0 : goto done;
2573 : }
2574 : }
2575 :
2576 2 : ZERO_STRUCT(sinfo);
2577 2 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
2578 2 : sinfo.rename_information.in.file.handle = h2;
2579 2 : sinfo.rename_information.in.new_name = BASEDIR_INR "\\subdir-name-r";
2580 :
2581 2 : status = smb2_setinfo_file(tree2, &sinfo);
2582 2 : torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_setinfo_file failed\n");
2583 :
2584 2 : smb2_util_close(tree2, h2);
2585 :
2586 2 : te = tevent_add_timer(torture->ev,
2587 : tree1,
2588 : tevent_timeval_current_ofs(1, 0),
2589 : notify_timeout,
2590 : req);
2591 2 : torture_assert_not_null_goto(torture, te, ok, done, "tevent_add_timer failed\n");
2592 :
2593 2 : status = smb2_notify_recv(req, torture, ¬ify);
2594 2 : torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_notify_recv failed\n");
2595 :
2596 2 : torture_assert_goto(torture, notify.out.num_changes == 1 || notify.out.num_changes == 2,
2597 : ok, done, "bad notify\n");
2598 :
2599 2 : change1 = notify.out.changes[0];
2600 2 : if (notify.out.num_changes == 2) {
2601 2 : change2 = notify.out.changes[1];
2602 : } else {
2603 : /*
2604 : * We may only get one event at a time, so check for the
2605 : * matching second event for the oldname/newname or
2606 : * removed/added pair.
2607 : */
2608 0 : ZERO_STRUCT(notify);
2609 0 : notify.level = RAW_NOTIFY_SMB2;
2610 0 : notify.in.buffer_size = 4096;
2611 0 : notify.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2612 0 : notify.in.file.handle = h1;
2613 0 : notify.in.recursive = true;
2614 0 : req = smb2_notify_send(tree1, ¬ify);
2615 0 : torture_assert_not_null_goto(torture, req, ok, done, "smb2_notify_send failed\n");
2616 :
2617 0 : status = smb2_notify_recv(req, torture, ¬ify);
2618 0 : torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_notify_recv failed\n");
2619 :
2620 0 : torture_assert_goto(torture, notify.out.num_changes == 1, ok, done,
2621 : "bad notify\n");
2622 :
2623 0 : change2 = notify.out.changes[0];
2624 : }
2625 :
2626 2 : if ((change1.action != NOTIFY_ACTION_OLD_NAME) &&
2627 0 : (change1.action != NOTIFY_ACTION_REMOVED))
2628 : {
2629 0 : torture_fail_goto(torture, done, "bad change notification\n");
2630 : }
2631 2 : torture_assert_str_equal_goto(torture, change1.name.s, "subdir-name",
2632 : ok, done, "bad change notification\n");
2633 :
2634 2 : if ((change2.action != NOTIFY_ACTION_NEW_NAME) &&
2635 0 : (change2.action != NOTIFY_ACTION_ADDED))
2636 : {
2637 0 : torture_fail_goto(torture, done, "bad change notification\n");
2638 : }
2639 2 : torture_assert_str_equal_goto(torture, change2.name.s, "subdir-name-r",
2640 : ok, done, "bad change notification\n");
2641 :
2642 2 : ok = true;
2643 2 : done:
2644 2 : if (!smb2_util_handle_empty(h1)) {
2645 2 : smb2_util_close(tree1, h1);
2646 : }
2647 2 : if (!smb2_util_handle_empty(h2)) {
2648 2 : smb2_util_close(tree2, h2);
2649 : }
2650 :
2651 2 : smb2_deltree(tree1, BASEDIR_INR);
2652 2 : return ok;
2653 : }
2654 :
2655 : /*
2656 : Test asking for a change notify on a handle without permissions.
2657 : */
2658 :
2659 : #define BASEDIR_HPERM BASEDIR "_HPERM"
2660 :
2661 2 : static bool torture_smb2_notify_handle_permissions(
2662 : struct torture_context *torture,
2663 : struct smb2_tree *tree)
2664 : {
2665 2 : bool ret = true;
2666 0 : NTSTATUS status;
2667 0 : union smb_notify notify;
2668 0 : union smb_open io;
2669 2 : struct smb2_handle h1 = {{0}};
2670 0 : struct smb2_request *req;
2671 :
2672 2 : smb2_deltree(tree, BASEDIR_HPERM);
2673 2 : smb2_util_rmdir(tree, BASEDIR_HPERM);
2674 :
2675 2 : torture_comment(torture,
2676 : "TESTING CHANGE NOTIFY "
2677 : "ON A HANDLE WITHOUT PERMISSIONS\n");
2678 :
2679 : /*
2680 : get a handle on the directory
2681 : */
2682 2 : ZERO_STRUCT(io.smb2);
2683 2 : io.generic.level = RAW_OPEN_SMB2;
2684 2 : io.smb2.in.create_flags = 0;
2685 2 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
2686 2 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2687 2 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2688 2 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2689 : NTCREATEX_SHARE_ACCESS_WRITE;
2690 2 : io.smb2.in.alloc_size = 0;
2691 2 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2692 2 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2693 2 : io.smb2.in.security_flags = 0;
2694 2 : io.smb2.in.fname = BASEDIR_HPERM;
2695 :
2696 2 : status = smb2_create(tree, torture, &io.smb2);
2697 2 : CHECK_STATUS(status, NT_STATUS_OK);
2698 2 : h1 = io.smb2.out.file.handle;
2699 :
2700 : /* ask for a change notify,
2701 : on file or directory name changes */
2702 2 : ZERO_STRUCT(notify.smb2);
2703 2 : notify.smb2.level = RAW_NOTIFY_SMB2;
2704 2 : notify.smb2.in.buffer_size = 1000;
2705 2 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2706 2 : notify.smb2.in.file.handle = h1;
2707 2 : notify.smb2.in.recursive = true;
2708 :
2709 2 : req = smb2_notify_send(tree, ¬ify.smb2);
2710 2 : torture_assert_goto(torture,
2711 : req != NULL,
2712 : ret,
2713 : done,
2714 : "smb2_notify_send failed\n");
2715 :
2716 : /*
2717 : * Cancel it, we don't really want to wait.
2718 : */
2719 2 : smb2_cancel(req);
2720 2 : status = smb2_notify_recv(req, torture, ¬ify.smb2);
2721 : /* Handle h1 doesn't have permissions for ChangeNotify. */
2722 2 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
2723 :
2724 2 : done:
2725 2 : if (!smb2_util_handle_empty(h1)) {
2726 2 : smb2_util_close(tree, h1);
2727 : }
2728 2 : smb2_deltree(tree, BASEDIR_HPERM);
2729 2 : return ret;
2730 : }
2731 :
2732 : /*
2733 : basic testing of SMB2 change notify
2734 : */
2735 2354 : struct torture_suite *torture_smb2_notify_init(TALLOC_CTX *ctx)
2736 : {
2737 2354 : struct torture_suite *suite = torture_suite_create(ctx, "notify");
2738 :
2739 2354 : torture_suite_add_1smb2_test(suite, "valid-req", test_valid_request);
2740 2354 : torture_suite_add_1smb2_test(suite, "tcon", torture_smb2_notify_tcon);
2741 2354 : torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir);
2742 2354 : torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask);
2743 2354 : torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
2744 2354 : torture_suite_add_1smb2_test(suite, "tdis1", torture_smb2_notify_tree_disconnect_1);
2745 2354 : torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
2746 2354 : torture_suite_add_1smb2_test(suite, "close", torture_smb2_notify_close);
2747 2354 : torture_suite_add_1smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
2748 2354 : torture_suite_add_1smb2_test(suite, "session-reconnect", torture_smb2_notify_session_reconnect);
2749 2354 : torture_suite_add_2smb2_test(suite, "invalid-reauth", torture_smb2_notify_invalid_reauth);
2750 2354 : torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
2751 2354 : torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
2752 2354 : torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
2753 2354 : torture_suite_add_1smb2_test(suite, "file", torture_smb2_notify_file);
2754 2354 : torture_suite_add_1smb2_test(suite, "tcp", torture_smb2_notify_tcp_disconnect);
2755 2354 : torture_suite_add_2smb2_test(suite, "rec", torture_smb2_notify_recursive);
2756 2354 : torture_suite_add_1smb2_test(suite, "overflow", torture_smb2_notify_overflow);
2757 2354 : torture_suite_add_1smb2_test(suite, "rmdir1",
2758 : torture_smb2_notify_rmdir1);
2759 2354 : torture_suite_add_1smb2_test(suite, "rmdir2",
2760 : torture_smb2_notify_rmdir2);
2761 2354 : torture_suite_add_2smb2_test(suite, "rmdir3",
2762 : torture_smb2_notify_rmdir3);
2763 2354 : torture_suite_add_2smb2_test(suite, "rmdir4",
2764 : torture_smb2_notify_rmdir4);
2765 2354 : torture_suite_add_1smb2_test(suite,
2766 : "handle-permissions",
2767 : torture_smb2_notify_handle_permissions);
2768 :
2769 2354 : suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");
2770 :
2771 2354 : return suite;
2772 : }
2773 :
2774 : /*
2775 : basic testing of SMB2 change notify
2776 : */
2777 2354 : struct torture_suite *torture_smb2_notify_inotify_init(TALLOC_CTX *ctx)
2778 : {
2779 2354 : struct torture_suite *suite = torture_suite_create(ctx, "notify-inotify");
2780 :
2781 2354 : suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests that use inotify");
2782 :
2783 2354 : torture_suite_add_2smb2_test(suite, "inotify-rename", torture_smb2_inotify_rename);
2784 :
2785 2354 : return suite;
2786 : }
|