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 0 : static bool test_valid_request(struct torture_context *torture,
83 : struct smb2_tree *tree)
84 : {
85 0 : bool ret = true;
86 : NTSTATUS status;
87 : struct smb2_handle dh;
88 : struct smb2_notify n;
89 : struct smb2_request *req;
90 : uint32_t max_buffer_size;
91 :
92 0 : torture_comment(torture, "TESTING VALIDITY OF CHANGE NOTIFY REQUEST\n");
93 :
94 0 : smb2_transport_credits_ask_num(tree->session->transport, 256);
95 :
96 0 : smb2_util_unlink(tree, FNAME);
97 :
98 0 : status = smb2_util_roothandle(tree, &dh);
99 0 : CHECK_STATUS(status, NT_STATUS_OK);
100 :
101 0 : max_buffer_size =
102 0 : smb2cli_conn_max_trans_size(tree->session->transport->conn);
103 :
104 0 : n.in.recursive = 0x0000;
105 0 : n.in.buffer_size = max_buffer_size;
106 0 : n.in.file.handle = dh;
107 0 : n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
108 0 : n.in.unknown = 0x00000000;
109 0 : req = smb2_notify_send(tree, &n);
110 :
111 0 : while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
112 0 : if (tevent_loop_once(torture->ev) != 0) {
113 0 : break;
114 : }
115 : }
116 :
117 0 : status = torture_setup_simple_file(torture, tree, FNAME);
118 0 : CHECK_STATUS(status, NT_STATUS_OK);
119 :
120 0 : status = smb2_notify_recv(req, torture, &n);
121 0 : CHECK_STATUS(status, NT_STATUS_OK);
122 0 : CHECK_VAL(n.out.num_changes, 1);
123 0 : CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_ADDED);
124 0 : 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 0 : n.in.buffer_size = 0x00000000;
131 0 : req = smb2_notify_send(tree, &n);
132 :
133 0 : while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
134 0 : if (tevent_loop_once(torture->ev) != 0) {
135 0 : break;
136 : }
137 : }
138 :
139 0 : status = torture_setup_simple_file(torture, tree, FNAME);
140 0 : CHECK_STATUS(status, NT_STATUS_OK);
141 :
142 0 : status = smb2_notify_recv(req, torture, &n);
143 0 : 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 0 : n.in.buffer_size = max_buffer_size;
150 0 : req = smb2_notify_send(tree, &n);
151 :
152 0 : while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
153 0 : if (tevent_loop_once(torture->ev) != 0) {
154 0 : break;
155 : }
156 : }
157 :
158 0 : status = torture_setup_simple_file(torture, tree, FNAME);
159 0 : CHECK_STATUS(status, NT_STATUS_OK);
160 :
161 0 : status = smb2_notify_recv(req, torture, &n);
162 0 : CHECK_STATUS(status, NT_STATUS_OK);
163 0 : 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 0 : done:
221 0 : return ret;
222 : }
223 :
224 : /*
225 : basic testing of change notify on directories
226 : */
227 :
228 : #define BASEDIR_DIR BASEDIR "_DIR"
229 :
230 0 : static bool torture_smb2_notify_dir(struct torture_context *torture,
231 : struct smb2_tree *tree1,
232 : struct smb2_tree *tree2)
233 : {
234 0 : bool ret = true;
235 : NTSTATUS status;
236 : union smb_notify notify;
237 : union smb_open io;
238 : union smb_close cl;
239 : int i, count;
240 0 : struct smb2_handle h1 = {{0}};
241 0 : struct smb2_handle h2 = {{0}};
242 : struct smb2_request *req, *req2;
243 0 : const char *fname = BASEDIR_DIR "\\subdir-name";
244 : extern int torture_numops;
245 :
246 0 : torture_comment(torture, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
247 :
248 0 : smb2_deltree(tree1, BASEDIR_DIR);
249 0 : smb2_util_rmdir(tree1, BASEDIR_DIR);
250 : /*
251 : get a handle on the directory
252 : */
253 0 : ZERO_STRUCT(io.smb2);
254 0 : io.generic.level = RAW_OPEN_SMB2;
255 0 : io.smb2.in.create_flags = 0;
256 0 : io.smb2.in.desired_access = SEC_FILE_ALL;
257 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
258 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
259 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
260 : NTCREATEX_SHARE_ACCESS_WRITE;
261 0 : io.smb2.in.alloc_size = 0;
262 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
263 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
264 0 : io.smb2.in.security_flags = 0;
265 0 : io.smb2.in.fname = BASEDIR_DIR;
266 :
267 0 : status = smb2_create(tree1, torture, &(io.smb2));
268 0 : CHECK_STATUS(status, NT_STATUS_OK);
269 0 : h1 = io.smb2.out.file.handle;
270 :
271 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
272 0 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ;
273 0 : status = smb2_create(tree1, torture, &(io.smb2));
274 0 : CHECK_STATUS(status, NT_STATUS_OK);
275 0 : h2 = io.smb2.out.file.handle;
276 :
277 : /* ask for a change notify,
278 : on file or directory name changes */
279 0 : ZERO_STRUCT(notify.smb2);
280 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
281 0 : notify.smb2.in.buffer_size = 1000;
282 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
283 0 : notify.smb2.in.file.handle = h1;
284 0 : notify.smb2.in.recursive = true;
285 :
286 0 : torture_comment(torture, "Testing notify cancel\n");
287 :
288 0 : req = smb2_notify_send(tree1, &(notify.smb2));
289 0 : smb2_cancel(req);
290 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
291 0 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
292 :
293 0 : torture_comment(torture, "Testing notify mkdir\n");
294 :
295 0 : req = smb2_notify_send(tree1, &(notify.smb2));
296 0 : smb2_util_mkdir(tree2, fname);
297 :
298 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
299 0 : CHECK_STATUS(status, NT_STATUS_OK);
300 :
301 0 : CHECK_VAL(notify.smb2.out.num_changes, 1);
302 0 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
303 0 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
304 :
305 0 : torture_comment(torture, "Testing notify rmdir\n");
306 :
307 0 : req = smb2_notify_send(tree1, &(notify.smb2));
308 0 : smb2_util_rmdir(tree2, fname);
309 :
310 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
311 0 : CHECK_STATUS(status, NT_STATUS_OK);
312 0 : CHECK_VAL(notify.smb2.out.num_changes, 1);
313 0 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
314 0 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
315 :
316 0 : torture_comment(torture,
317 : "Testing notify mkdir - rmdir - mkdir - rmdir\n");
318 :
319 0 : smb2_util_mkdir(tree2, fname);
320 0 : smb2_util_rmdir(tree2, fname);
321 0 : smb2_util_mkdir(tree2, fname);
322 0 : smb2_util_rmdir(tree2, fname);
323 0 : smb_msleep(200);
324 0 : req = smb2_notify_send(tree1, &(notify.smb2));
325 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
326 0 : CHECK_STATUS(status, NT_STATUS_OK);
327 0 : CHECK_VAL(notify.smb2.out.num_changes, 4);
328 0 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
329 0 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
330 0 : CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_REMOVED);
331 0 : CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name");
332 0 : CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_ADDED);
333 0 : CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name");
334 0 : CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_REMOVED);
335 0 : CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name");
336 :
337 0 : count = torture_numops;
338 0 : torture_comment(torture,
339 : "Testing buffered notify on create of %d files\n", count);
340 0 : for (i=0;i<count;i++) {
341 : struct smb2_handle h12;
342 0 : char *fname2 = talloc_asprintf(torture,
343 : BASEDIR_DIR "\\test%d.txt",
344 : i);
345 :
346 0 : ZERO_STRUCT(io.smb2);
347 0 : io.generic.level = RAW_OPEN_SMB2;
348 0 : io.smb2.in.create_flags = 0;
349 0 : io.smb2.in.desired_access = SEC_FILE_ALL;
350 0 : io.smb2.in.create_options =
351 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
352 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
353 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
354 : NTCREATEX_SHARE_ACCESS_WRITE;
355 0 : io.smb2.in.alloc_size = 0;
356 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
357 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
358 0 : io.smb2.in.security_flags = 0;
359 0 : io.smb2.in.fname = fname2;
360 :
361 0 : status = smb2_create(tree1, torture, &(io.smb2));
362 0 : 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 0 : h12 = io.smb2.out.file.handle;
369 0 : talloc_free(fname2);
370 0 : 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 0 : notify.smb2.in.file.handle = h2;
376 0 : 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 0 : notify.smb2.in.file.handle = h1;
381 0 : req = smb2_notify_send(tree1, &(notify.smb2));
382 :
383 0 : status = smb2_util_unlink(tree1, BASEDIR_DIR "\\nonexistent.txt");
384 0 : 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 0 : torture_comment(torture,
390 : "Testing notify on unlink for the first file\n");
391 0 : status = smb2_util_unlink(tree2, BASEDIR_DIR "\\test0.txt");
392 0 : CHECK_STATUS(status, NT_STATUS_OK);
393 :
394 : /* receive the reply from the 2nd notify */
395 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
396 0 : CHECK_STATUS(status, NT_STATUS_OK);
397 :
398 0 : CHECK_VAL(notify.smb2.out.num_changes, count);
399 0 : for (i=1;i<count;i++) {
400 0 : CHECK_VAL(notify.smb2.out.changes[i].action,
401 : NOTIFY_ACTION_ADDED);
402 : }
403 0 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
404 :
405 0 : torture_comment(torture, "and now from the 1st notify\n");
406 0 : status = smb2_notify_recv(req2, torture, &(notify.smb2));
407 0 : CHECK_STATUS(status, NT_STATUS_OK);
408 0 : CHECK_VAL(notify.smb2.out.num_changes, 1);
409 0 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
410 0 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
411 :
412 0 : torture_comment(torture,
413 : "(3rd notify) this notify will only see the 1st unlink\n");
414 0 : req = smb2_notify_send(tree1, &(notify.smb2));
415 :
416 0 : status = smb2_util_unlink(tree1, BASEDIR_DIR "\\nonexistent.txt");
417 0 : CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
418 :
419 0 : for (i=1;i<count;i++) {
420 0 : char *fname2 = talloc_asprintf(torture,
421 : BASEDIR_DIR "\\test%d.txt", i);
422 0 : status = smb2_util_unlink(tree2, fname2);
423 0 : CHECK_STATUS(status, NT_STATUS_OK);
424 0 : talloc_free(fname2);
425 : }
426 :
427 : /* receive the 3rd notify */
428 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
429 0 : CHECK_STATUS(status, NT_STATUS_OK);
430 0 : CHECK_VAL(notify.smb2.out.num_changes, 1);
431 0 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
432 0 : 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 0 : notify.smb2.in.file.handle = h1;
437 0 : sleep(3);
438 0 : req = smb2_notify_send(tree1, &(notify.smb2));
439 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
440 0 : CHECK_STATUS(status, NT_STATUS_OK);
441 0 : CHECK_VAL(notify.smb2.out.num_changes, count-1);
442 0 : for (i=0;i<notify.smb2.out.num_changes;i++) {
443 0 : CHECK_VAL(notify.smb2.out.changes[i].action,
444 : NOTIFY_ACTION_REMOVED);
445 : }
446 0 : notify.smb2.in.file.handle = h2;
447 0 : req = smb2_notify_send(tree1, &(notify.smb2));
448 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
449 0 : CHECK_STATUS(status, NT_STATUS_OK);
450 0 : CHECK_VAL(notify.smb2.out.num_changes, count-1);
451 0 : for (i=0;i<notify.smb2.out.num_changes;i++) {
452 0 : CHECK_VAL(notify.smb2.out.changes[i].action,
453 : NOTIFY_ACTION_REMOVED);
454 : }
455 :
456 0 : torture_comment(torture,
457 : "Testing if a close() on the dir handle triggers the notify reply\n");
458 :
459 0 : notify.smb2.in.file.handle = h1;
460 0 : req = smb2_notify_send(tree1, &(notify.smb2));
461 :
462 0 : ZERO_STRUCT(cl.smb2);
463 0 : cl.smb2.level = RAW_CLOSE_SMB2;
464 0 : cl.smb2.in.file.handle = h1;
465 0 : status = smb2_close(tree1, &(cl.smb2));
466 0 : CHECK_STATUS(status, NT_STATUS_OK);
467 :
468 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
469 0 : CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
470 0 : CHECK_VAL(notify.smb2.out.num_changes, 9);
471 :
472 0 : done:
473 0 : smb2_util_close(tree1, h1);
474 0 : smb2_util_close(tree1, h2);
475 0 : smb2_deltree(tree1, BASEDIR_DIR);
476 0 : return ret;
477 : }
478 :
479 0 : static struct smb2_handle custom_smb2_create(struct smb2_tree *tree,
480 : struct torture_context *torture,
481 : struct smb2_create *smb2)
482 : {
483 : struct smb2_handle h1;
484 0 : bool ret = true;
485 : NTSTATUS status;
486 0 : smb2_deltree(tree, smb2->in.fname);
487 0 : status = smb2_create(tree, torture, smb2);
488 0 : CHECK_STATUS(status, NT_STATUS_OK);
489 0 : h1 = smb2->out.file.handle;
490 0 : done:
491 0 : if (!ret) {
492 0 : h1 = (struct smb2_handle) {
493 : .data = { 0 , 0},
494 : };
495 : }
496 0 : return h1;
497 : }
498 :
499 : /*
500 : testing of recursive change notify
501 : */
502 :
503 : #define BASEDIR_REC BASEDIR "_REC"
504 :
505 0 : static bool torture_smb2_notify_recursive(struct torture_context *torture,
506 : struct smb2_tree *tree1,
507 : struct smb2_tree *tree2)
508 : {
509 0 : bool ret = true;
510 : NTSTATUS status;
511 : union smb_notify notify;
512 : union smb_open io, io1;
513 : union smb_setfileinfo sinfo;
514 : struct smb2_handle h1;
515 : struct smb2_request *req1, *req2;
516 :
517 0 : smb2_deltree(tree1, BASEDIR_REC);
518 0 : smb2_util_rmdir(tree1, BASEDIR_REC);
519 :
520 0 : torture_comment(torture, "TESTING CHANGE NOTIFY WITH RECURSION\n");
521 :
522 : /*
523 : get a handle on the directory
524 : */
525 0 : ZERO_STRUCT(io.smb2);
526 0 : io.generic.level = RAW_OPEN_SMB2;
527 0 : io.smb2.in.create_flags = 0;
528 0 : io.smb2.in.desired_access = SEC_FILE_ALL;
529 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
530 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
531 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
532 : NTCREATEX_SHARE_ACCESS_WRITE;
533 0 : io.smb2.in.alloc_size = 0;
534 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
535 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
536 0 : io.smb2.in.security_flags = 0;
537 0 : io.smb2.in.fname = BASEDIR_REC;
538 :
539 0 : status = smb2_create(tree1, torture, &(io.smb2));
540 0 : CHECK_STATUS(status, NT_STATUS_OK);
541 0 : 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 0 : ZERO_STRUCT(notify.smb2);
546 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
547 0 : notify.smb2.in.buffer_size = 1000;
548 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
549 : FILE_NOTIFY_CHANGE_ATTRIBUTES |
550 : FILE_NOTIFY_CHANGE_CREATION;
551 0 : notify.smb2.in.file.handle = h1;
552 :
553 0 : notify.smb2.in.recursive = true;
554 0 : req1 = smb2_notify_send(tree1, &(notify.smb2));
555 0 : smb2_cancel(req1);
556 0 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
557 0 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
558 :
559 0 : notify.smb2.in.recursive = false;
560 0 : req2 = smb2_notify_send(tree1, &(notify.smb2));
561 0 : smb2_cancel(req2);
562 0 : status = smb2_notify_recv(req2, torture, &(notify.smb2));
563 0 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
564 :
565 0 : ZERO_STRUCT(io1.smb2);
566 0 : io1.generic.level = RAW_OPEN_SMB2;
567 0 : io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
568 0 : io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
569 : SEC_RIGHTS_FILE_WRITE|
570 : SEC_RIGHTS_FILE_ALL;
571 0 : io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
572 0 : io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
573 0 : io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
574 : NTCREATEX_SHARE_ACCESS_WRITE |
575 : NTCREATEX_SHARE_ACCESS_DELETE;
576 0 : io1.smb2.in.alloc_size = 0;
577 0 : io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
578 0 : io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
579 0 : io1.smb2.in.security_flags = 0;
580 0 : io1.smb2.in.fname = BASEDIR_REC "\\subdir-name";
581 0 : status = smb2_create(tree2, torture, &(io1.smb2));
582 0 : CHECK_STATUS(status, NT_STATUS_OK);
583 0 : smb2_util_close(tree2, io1.smb2.out.file.handle);
584 :
585 0 : io1.smb2.in.fname = BASEDIR_REC "\\subdir-name\\subname1";
586 0 : status = smb2_create(tree2, torture, &(io1.smb2));
587 0 : CHECK_STATUS(status, NT_STATUS_OK);
588 0 : ZERO_STRUCT(sinfo);
589 0 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
590 0 : sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
591 0 : sinfo.rename_information.in.overwrite = 0;
592 0 : sinfo.rename_information.in.root_fid = 0;
593 0 : sinfo.rename_information.in.new_name =
594 : BASEDIR_REC "\\subdir-name\\subname1-r";
595 0 : status = smb2_setinfo_file(tree2, &sinfo);
596 0 : CHECK_STATUS(status, NT_STATUS_OK);
597 :
598 0 : io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
599 0 : io1.smb2.in.fname = BASEDIR_REC "\\subdir-name\\subname2";
600 0 : status = smb2_create(tree2, torture, &(io1.smb2));
601 0 : CHECK_STATUS(status, NT_STATUS_OK);
602 0 : ZERO_STRUCT(sinfo);
603 0 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
604 0 : sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
605 0 : sinfo.rename_information.in.overwrite = true;
606 0 : sinfo.rename_information.in.root_fid = 0;
607 0 : sinfo.rename_information.in.new_name = BASEDIR_REC "\\subname2-r";
608 0 : status = smb2_setinfo_file(tree2, &sinfo);
609 0 : CHECK_STATUS(status, NT_STATUS_OK);
610 :
611 0 : io1.smb2.in.fname = BASEDIR_REC "\\subname2-r";
612 0 : io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
613 0 : status = smb2_create(tree2, torture, &(io1.smb2));
614 0 : CHECK_STATUS(status, NT_STATUS_OK);
615 0 : ZERO_STRUCT(sinfo);
616 0 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
617 0 : sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
618 0 : sinfo.rename_information.in.overwrite = true;
619 0 : sinfo.rename_information.in.root_fid = 0;
620 0 : sinfo.rename_information.in.new_name = BASEDIR_REC "\\subname3-r";
621 0 : status = smb2_setinfo_file(tree2, &sinfo);
622 0 : CHECK_STATUS(status, NT_STATUS_OK);
623 :
624 0 : notify.smb2.in.completion_filter = 0;
625 0 : notify.smb2.in.recursive = true;
626 0 : smb_msleep(200);
627 0 : req1 = smb2_notify_send(tree1, &(notify.smb2));
628 :
629 0 : status = smb2_util_rmdir(tree2,
630 : BASEDIR_REC "\\subdir-name\\subname1-r");
631 0 : CHECK_STATUS(status, NT_STATUS_OK);
632 0 : status = smb2_util_rmdir(tree2,
633 : BASEDIR_REC "\\subdir-name");
634 0 : CHECK_STATUS(status, NT_STATUS_OK);
635 0 : status = smb2_util_unlink(tree2, BASEDIR_REC "\\subname3-r");
636 0 : CHECK_STATUS(status, NT_STATUS_OK);
637 :
638 0 : notify.smb2.in.recursive = false;
639 0 : req2 = smb2_notify_send(tree1, &(notify.smb2));
640 :
641 0 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
642 0 : CHECK_STATUS(status, NT_STATUS_OK);
643 :
644 0 : 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 0 : smb2_deltree(tree1, BASEDIR_REC);
666 0 : return ret;
667 : }
668 :
669 : /*
670 : testing of change notify mask change
671 : */
672 :
673 : #define BASEDIR_MC BASEDIR "_MC"
674 :
675 0 : static bool torture_smb2_notify_mask_change(struct torture_context *torture,
676 : struct smb2_tree *tree1,
677 : struct smb2_tree *tree2)
678 : {
679 0 : bool ret = true;
680 : NTSTATUS status;
681 : union smb_notify notify;
682 : union smb_open io, io1;
683 : struct smb2_handle h1;
684 : struct smb2_request *req1, *req2;
685 : union smb_setfileinfo sinfo;
686 :
687 0 : smb2_deltree(tree1, BASEDIR_MC);
688 0 : smb2_util_rmdir(tree1, BASEDIR_MC);
689 :
690 0 : torture_comment(torture, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
691 :
692 : /*
693 : get a handle on the directory
694 : */
695 0 : ZERO_STRUCT(io.smb2);
696 0 : io.generic.level = RAW_OPEN_SMB2;
697 0 : io.smb2.in.create_flags = 0;
698 0 : io.smb2.in.desired_access = SEC_FILE_ALL;
699 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
700 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
701 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
702 : NTCREATEX_SHARE_ACCESS_WRITE;
703 0 : io.smb2.in.alloc_size = 0;
704 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
705 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
706 0 : io.smb2.in.security_flags = 0;
707 0 : io.smb2.in.fname = BASEDIR_MC;
708 :
709 0 : status = smb2_create(tree1, torture, &(io.smb2));
710 0 : CHECK_STATUS(status, NT_STATUS_OK);
711 0 : 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 0 : ZERO_STRUCT(notify.smb2);
716 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
717 0 : notify.smb2.in.buffer_size = 1000;
718 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
719 0 : notify.smb2.in.file.handle = h1;
720 :
721 0 : notify.smb2.in.recursive = true;
722 0 : req1 = smb2_notify_send(tree1, &(notify.smb2));
723 :
724 0 : smb2_cancel(req1);
725 0 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
726 0 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
727 :
728 :
729 0 : notify.smb2.in.recursive = false;
730 0 : req2 = smb2_notify_send(tree1, &(notify.smb2));
731 :
732 0 : smb2_cancel(req2);
733 0 : status = smb2_notify_recv(req2, torture, &(notify.smb2));
734 0 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
735 :
736 0 : notify.smb2.in.recursive = true;
737 0 : req1 = smb2_notify_send(tree1, &(notify.smb2));
738 :
739 : /* Set to hidden then back again. */
740 0 : ZERO_STRUCT(io1.smb2);
741 0 : io1.generic.level = RAW_OPEN_SMB2;
742 0 : io1.smb2.in.create_flags = 0;
743 0 : io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
744 : SEC_RIGHTS_FILE_WRITE|
745 : SEC_RIGHTS_FILE_ALL;
746 0 : io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
747 0 : io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
748 : NTCREATEX_SHARE_ACCESS_WRITE |
749 : NTCREATEX_SHARE_ACCESS_DELETE;
750 0 : io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
751 0 : io1.smb2.in.security_flags = 0;
752 0 : io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
753 0 : io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
754 0 : io1.smb2.in.fname = BASEDIR_MC "\\tname1";
755 :
756 0 : smb2_util_close(tree1,
757 : custom_smb2_create(tree1, torture, &(io1.smb2)));
758 0 : status = smb2_util_setatr(tree1, BASEDIR_MC "\\tname1",
759 : FILE_ATTRIBUTE_HIDDEN);
760 0 : CHECK_STATUS(status, NT_STATUS_OK);
761 0 : smb2_util_unlink(tree1, BASEDIR_MC "\\tname1");
762 :
763 0 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
764 0 : CHECK_STATUS(status, NT_STATUS_OK);
765 :
766 0 : CHECK_VAL(notify.smb2.out.num_changes, 1);
767 0 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
768 0 : 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 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
775 : FILE_NOTIFY_CHANGE_ATTRIBUTES |
776 : FILE_NOTIFY_CHANGE_CREATION;
777 0 : notify.smb2.in.recursive = true;
778 0 : req1 = smb2_notify_send(tree1, &(notify.smb2));
779 :
780 0 : notify.smb2.in.recursive = false;
781 0 : req2 = smb2_notify_send(tree1, &(notify.smb2));
782 :
783 0 : io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
784 0 : io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
785 0 : io1.smb2.in.fname = BASEDIR_MC "\\subdir-name";
786 0 : status = smb2_create(tree2, torture, &(io1.smb2));
787 0 : CHECK_STATUS(status, NT_STATUS_OK);
788 0 : smb2_util_close(tree2, io1.smb2.out.file.handle);
789 :
790 0 : ZERO_STRUCT(sinfo);
791 0 : io1.smb2.in.fname = BASEDIR_MC "\\subdir-name\\subname1";
792 0 : io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
793 0 : io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
794 0 : status = smb2_create(tree2, torture, &(io1.smb2));
795 0 : CHECK_STATUS(status, NT_STATUS_OK);
796 0 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
797 0 : sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
798 0 : sinfo.rename_information.in.overwrite = true;
799 0 : sinfo.rename_information.in.root_fid = 0;
800 0 : sinfo.rename_information.in.new_name =
801 : BASEDIR_MC "\\subdir-name\\subname1-r";
802 0 : status = smb2_setinfo_file(tree2, &sinfo);
803 0 : CHECK_STATUS(status, NT_STATUS_OK);
804 :
805 0 : io1.smb2.in.fname = BASEDIR_MC "\\subdir-name\\subname2";
806 0 : io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
807 0 : io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
808 0 : status = smb2_create(tree2, torture, &(io1.smb2));
809 0 : CHECK_STATUS(status, NT_STATUS_OK);
810 0 : sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
811 0 : sinfo.rename_information.in.new_name = BASEDIR_MC "\\subname2-r";
812 0 : status = smb2_setinfo_file(tree2, &sinfo);
813 0 : CHECK_STATUS(status, NT_STATUS_OK);
814 0 : smb2_util_close(tree2, io1.smb2.out.file.handle);
815 :
816 0 : io1.smb2.in.fname = BASEDIR_MC "\\subname2-r";
817 0 : io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
818 0 : status = smb2_create(tree2, torture, &(io1.smb2));
819 0 : CHECK_STATUS(status, NT_STATUS_OK);
820 0 : sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
821 0 : sinfo.rename_information.in.new_name = BASEDIR_MC "\\subname3-r";
822 0 : status = smb2_setinfo_file(tree2, &sinfo);
823 0 : CHECK_STATUS(status, NT_STATUS_OK);
824 0 : smb2_util_close(tree2, io1.smb2.out.file.handle);
825 :
826 0 : status = smb2_util_rmdir(tree2, BASEDIR_MC "\\subdir-name\\subname1-r");
827 0 : CHECK_STATUS(status, NT_STATUS_OK);
828 0 : status = smb2_util_rmdir(tree2, BASEDIR_MC "\\subdir-name");
829 0 : CHECK_STATUS(status, NT_STATUS_OK);
830 0 : status = smb2_util_unlink(tree2, BASEDIR_MC "\\subname3-r");
831 0 : CHECK_STATUS(status, NT_STATUS_OK);
832 :
833 0 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
834 0 : CHECK_STATUS(status, NT_STATUS_OK);
835 :
836 0 : CHECK_VAL(notify.smb2.out.num_changes, 1);
837 0 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
838 0 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname2-r");
839 :
840 0 : status = smb2_notify_recv(req2, torture, &(notify.smb2));
841 0 : CHECK_STATUS(status, NT_STATUS_OK);
842 :
843 0 : CHECK_VAL(notify.smb2.out.num_changes, 1);
844 0 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
845 0 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname3-r");
846 :
847 0 : if (!ret) {
848 0 : goto done;
849 : }
850 :
851 0 : done:
852 0 : smb2_deltree(tree1, BASEDIR_MC);
853 0 : return ret;
854 : }
855 :
856 : /*
857 : testing of mask bits for change notify
858 : */
859 :
860 : #define BASEDIR_MSK BASEDIR "_MSK"
861 :
862 0 : static bool torture_smb2_notify_mask(struct torture_context *torture,
863 : struct smb2_tree *tree1,
864 : struct smb2_tree *tree2)
865 : {
866 0 : bool ret = true;
867 : NTSTATUS status;
868 : union smb_notify notify;
869 : union smb_open io, io1;
870 : struct smb2_handle h1, h2;
871 : int i;
872 0 : char c = 1;
873 : union smb_setfileinfo sinfo;
874 :
875 0 : smb2_deltree(tree1, BASEDIR_MSK);
876 0 : smb2_util_rmdir(tree1, BASEDIR_MSK);
877 :
878 0 : torture_comment(torture, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
879 :
880 :
881 0 : ZERO_STRUCT(h1);
882 0 : ZERO_STRUCT(h2);
883 : /*
884 : get a handle on the directory
885 : */
886 0 : ZERO_STRUCT(io.smb2);
887 0 : io.generic.level = RAW_OPEN_SMB2;
888 0 : io.smb2.in.create_flags = 0;
889 0 : io.smb2.in.desired_access = SEC_FILE_ALL;
890 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
891 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
892 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
893 : NTCREATEX_SHARE_ACCESS_WRITE;
894 0 : io.smb2.in.alloc_size = 0;
895 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
896 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
897 0 : io.smb2.in.security_flags = 0;
898 0 : io.smb2.in.fname = BASEDIR_MSK;
899 :
900 0 : ZERO_STRUCT(notify.smb2);
901 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
902 0 : notify.smb2.in.buffer_size = 1000;
903 0 : 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 0 : torture_comment(torture, "Testing mkdir\n");
972 0 : 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 : FILE_NOTIFY_CHANGE_DIR_NAME, 1);
977 :
978 0 : torture_comment(torture, "Testing create file\n");
979 0 : ZERO_STRUCT(io1.smb2);
980 0 : io1.generic.level = RAW_OPEN_SMB2;
981 0 : io1.smb2.in.create_flags = 0;
982 0 : io1.smb2.in.desired_access = SEC_FILE_ALL;
983 0 : io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
984 0 : io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
985 : NTCREATEX_SHARE_ACCESS_WRITE;
986 0 : io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
987 0 : io1.smb2.in.security_flags = 0;
988 0 : io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
989 0 : io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
990 0 : io1.smb2.in.fname = BASEDIR_MSK "\\tname1";
991 :
992 0 : 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 : FILE_NOTIFY_CHANGE_FILE_NAME, 1);
998 :
999 0 : torture_comment(torture, "Testing unlink\n");
1000 0 : 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 : FILE_NOTIFY_CHANGE_FILE_NAME, 1);
1007 :
1008 0 : torture_comment(torture, "Testing rmdir\n");
1009 0 : 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 : FILE_NOTIFY_CHANGE_DIR_NAME, 1);
1015 :
1016 0 : torture_comment(torture, "Testing rename file\n");
1017 0 : ZERO_STRUCT(sinfo);
1018 0 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1019 0 : sinfo.rename_information.in.file.handle = h1;
1020 0 : sinfo.rename_information.in.overwrite = true;
1021 0 : sinfo.rename_information.in.root_fid = 0;
1022 0 : sinfo.rename_information.in.new_name = BASEDIR_MSK "\\tname2";
1023 0 : 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 : FILE_NOTIFY_CHANGE_FILE_NAME, 2);
1030 :
1031 0 : torture_comment(torture, "Testing rename dir\n");
1032 0 : ZERO_STRUCT(sinfo);
1033 0 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1034 0 : sinfo.rename_information.in.file.handle = h1;
1035 0 : sinfo.rename_information.in.overwrite = true;
1036 0 : sinfo.rename_information.in.root_fid = 0;
1037 0 : sinfo.rename_information.in.new_name = BASEDIR_MSK "\\tname2";
1038 0 : 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 : FILE_NOTIFY_CHANGE_DIR_NAME, 2);
1044 :
1045 0 : torture_comment(torture, "Testing set path attribute\n");
1046 0 : 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 : FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
1054 :
1055 0 : torture_comment(torture, "Testing set path write time\n");
1056 0 : ZERO_STRUCT(sinfo);
1057 0 : sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1058 0 : sinfo.generic.in.file.handle = h1;
1059 0 : sinfo.basic_info.in.write_time = 1000;
1060 0 : 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 : FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
1067 :
1068 0 : if (torture_setting_bool(torture, "samba3", false)) {
1069 0 : 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 : FILE_NOTIFY_CHANGE_CREATION, 1);
1087 : }
1088 :
1089 0 : ZERO_STRUCT(sinfo);
1090 0 : sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1091 0 : sinfo.generic.in.file.handle = h1;
1092 0 : sinfo.basic_info.in.access_time = 0;
1093 0 : torture_comment(torture, "Testing set file access time\n");
1094 0 : 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 : FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
1104 :
1105 0 : ZERO_STRUCT(sinfo);
1106 0 : sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1107 0 : sinfo.generic.in.file.handle = h1;
1108 0 : sinfo.basic_info.in.change_time = 0;
1109 0 : torture_comment(torture, "Testing set file change time\n");
1110 0 : 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, 1);
1120 :
1121 :
1122 0 : torture_comment(torture, "Testing write\n");
1123 0 : 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, 1);
1133 :
1134 0 : done:
1135 0 : smb2_deltree(tree1, BASEDIR_MSK);
1136 0 : return ret;
1137 : }
1138 :
1139 : #define BASEDIR_FL BASEDIR "_FL"
1140 : /*
1141 : basic testing of change notify on files
1142 : */
1143 0 : static bool torture_smb2_notify_file(struct torture_context *torture,
1144 : struct smb2_tree *tree)
1145 : {
1146 : NTSTATUS status;
1147 0 : bool ret = true;
1148 : union smb_open io;
1149 : union smb_close cl;
1150 : union smb_notify notify;
1151 : struct smb2_request *req;
1152 : struct smb2_handle h1;
1153 0 : const char *fname = BASEDIR_FL "\\file.txt";
1154 :
1155 0 : smb2_deltree(tree, BASEDIR_FL);
1156 0 : smb2_util_rmdir(tree, BASEDIR_FL);
1157 :
1158 0 : torture_comment(torture, "TESTING CHANGE NOTIFY ON FILES\n");
1159 0 : status = torture_smb2_testdir(tree, BASEDIR_FL, &h1);
1160 0 : CHECK_STATUS(status, NT_STATUS_OK);
1161 :
1162 0 : ZERO_STRUCT(io.smb2);
1163 0 : io.generic.level = RAW_OPEN_SMB2;
1164 0 : io.smb2.in.create_flags = 0;
1165 0 : io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
1166 0 : io.smb2.in.create_options = 0;
1167 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1168 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1169 : NTCREATEX_SHARE_ACCESS_WRITE;
1170 0 : io.smb2.in.alloc_size = 0;
1171 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1172 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1173 0 : io.smb2.in.security_flags = 0;
1174 0 : io.smb2.in.fname = fname;
1175 0 : status = smb2_create(tree, torture, &(io.smb2));
1176 0 : CHECK_STATUS(status, NT_STATUS_OK);
1177 0 : h1 = io.smb2.out.file.handle;
1178 :
1179 : /* ask for a change notify,
1180 : on file or directory name changes */
1181 0 : ZERO_STRUCT(notify.smb2);
1182 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
1183 0 : notify.smb2.in.file.handle = h1;
1184 0 : notify.smb2.in.buffer_size = 1000;
1185 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
1186 0 : notify.smb2.in.recursive = false;
1187 :
1188 0 : torture_comment(torture,
1189 : "Testing if notifies on file handles are invalid (should be)\n");
1190 :
1191 0 : req = smb2_notify_send(tree, &(notify.smb2));
1192 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1193 0 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1194 :
1195 0 : ZERO_STRUCT(cl.smb2);
1196 0 : cl.close.level = RAW_CLOSE_SMB2;
1197 0 : cl.close.in.file.handle = h1;
1198 0 : status = smb2_close(tree, &(cl.smb2));
1199 0 : CHECK_STATUS(status, NT_STATUS_OK);
1200 :
1201 0 : status = smb2_util_unlink(tree, fname);
1202 0 : CHECK_STATUS(status, NT_STATUS_OK);
1203 :
1204 0 : done:
1205 0 : smb2_deltree(tree, BASEDIR_FL);
1206 0 : return ret;
1207 : }
1208 : /*
1209 : basic testing of change notifies followed by a tdis
1210 : */
1211 :
1212 : #define BASEDIR_TD BASEDIR "_TD"
1213 :
1214 0 : static bool torture_smb2_notify_tree_disconnect(
1215 : struct torture_context *torture,
1216 : struct smb2_tree *tree)
1217 : {
1218 0 : bool ret = true;
1219 : NTSTATUS status;
1220 : union smb_notify notify;
1221 : union smb_open io;
1222 : struct smb2_handle h1;
1223 : struct smb2_request *req;
1224 :
1225 0 : smb2_deltree(tree, BASEDIR_TD);
1226 0 : smb2_util_rmdir(tree, BASEDIR_TD);
1227 :
1228 0 : torture_comment(torture, "TESTING CHANGE NOTIFY+CANCEL FOLLOWED BY "
1229 : "TREE-DISCONNECT\n");
1230 :
1231 : /*
1232 : get a handle on the directory
1233 : */
1234 0 : ZERO_STRUCT(io.smb2);
1235 0 : io.generic.level = RAW_OPEN_SMB2;
1236 0 : io.smb2.in.create_flags = 0;
1237 0 : io.smb2.in.desired_access = SEC_FILE_ALL;
1238 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1239 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1240 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1241 : NTCREATEX_SHARE_ACCESS_WRITE;
1242 0 : io.smb2.in.alloc_size = 0;
1243 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1244 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1245 0 : io.smb2.in.security_flags = 0;
1246 0 : io.smb2.in.fname = BASEDIR_TD;
1247 :
1248 0 : status = smb2_create(tree, torture, &(io.smb2));
1249 0 : CHECK_STATUS(status, NT_STATUS_OK);
1250 0 : h1 = io.smb2.out.file.handle;
1251 :
1252 : /* ask for a change notify,
1253 : on file or directory name changes */
1254 0 : ZERO_STRUCT(notify.smb2);
1255 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
1256 0 : notify.smb2.in.buffer_size = 1000;
1257 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1258 0 : notify.smb2.in.file.handle = h1;
1259 0 : notify.smb2.in.recursive = true;
1260 :
1261 0 : req = smb2_notify_send(tree, &(notify.smb2));
1262 0 : smb2_cancel(req);
1263 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1264 :
1265 0 : status = smb2_tdis(tree);
1266 0 : CHECK_STATUS(status, NT_STATUS_OK);
1267 :
1268 0 : req = smb2_notify_send(tree, &(notify.smb2));
1269 :
1270 0 : smb2_notify_recv(req, torture, &(notify.smb2));
1271 0 : CHECK_STATUS(status, NT_STATUS_OK);
1272 0 : CHECK_VAL(notify.smb2.out.num_changes, 0);
1273 :
1274 0 : done:
1275 0 : smb2_deltree(tree, BASEDIR_TD);
1276 0 : 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 0 : static bool torture_smb2_notify_tree_disconnect_1(
1286 : struct torture_context *torture,
1287 : struct smb2_tree *tree)
1288 : {
1289 0 : bool ret = true;
1290 : NTSTATUS status;
1291 : union smb_notify notify;
1292 : union smb_open io;
1293 : struct smb2_handle h1;
1294 : struct smb2_request *req;
1295 :
1296 0 : smb2_deltree(tree, BASEDIR_NTDIS);
1297 0 : smb2_util_rmdir(tree, BASEDIR_NTDIS);
1298 :
1299 0 : torture_comment(torture, "TESTING CHANGE NOTIFY ASYNC FOLLOWED BY "
1300 : "TREE-DISCONNECT\n");
1301 :
1302 : /*
1303 : get a handle on the directory
1304 : */
1305 0 : ZERO_STRUCT(io.smb2);
1306 0 : io.generic.level = RAW_OPEN_SMB2;
1307 0 : io.smb2.in.create_flags = 0;
1308 0 : io.smb2.in.desired_access = SEC_FILE_ALL;
1309 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1310 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1311 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1312 : NTCREATEX_SHARE_ACCESS_WRITE;
1313 0 : io.smb2.in.alloc_size = 0;
1314 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1315 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1316 0 : io.smb2.in.security_flags = 0;
1317 0 : io.smb2.in.fname = BASEDIR_NTDIS;
1318 :
1319 0 : status = smb2_create(tree, torture, &(io.smb2));
1320 0 : CHECK_STATUS(status, NT_STATUS_OK);
1321 0 : h1 = io.smb2.out.file.handle;
1322 :
1323 : /* ask for a change notify,
1324 : on file or directory name changes */
1325 0 : ZERO_STRUCT(notify.smb2);
1326 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
1327 0 : notify.smb2.in.buffer_size = 1000;
1328 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1329 0 : notify.smb2.in.file.handle = h1;
1330 0 : notify.smb2.in.recursive = true;
1331 :
1332 0 : req = smb2_notify_send(tree, &(notify.smb2));
1333 0 : WAIT_FOR_ASYNC_RESPONSE(req);
1334 :
1335 0 : status = smb2_tdis(tree);
1336 0 : CHECK_STATUS(status, NT_STATUS_OK);
1337 :
1338 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1339 0 : CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
1340 0 : CHECK_VAL(notify.smb2.out.num_changes, 0);
1341 :
1342 0 : done:
1343 0 : smb2_deltree(tree, BASEDIR_NTDIS);
1344 0 : 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 0 : static bool torture_smb2_notify_close(struct torture_context *torture,
1354 : struct smb2_tree *tree1)
1355 : {
1356 0 : bool ret = true;
1357 : NTSTATUS status;
1358 : union smb_notify notify;
1359 : union smb_open io;
1360 : struct smb2_handle h1;
1361 : struct smb2_request *req;
1362 :
1363 0 : smb2_deltree(tree1, BASEDIR_CNC);
1364 0 : smb2_util_rmdir(tree1, BASEDIR_CNC);
1365 :
1366 0 : torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1367 :
1368 : /*
1369 : get a handle on the directory
1370 : */
1371 0 : ZERO_STRUCT(io.smb2);
1372 0 : io.generic.level = RAW_OPEN_SMB2;
1373 0 : io.smb2.in.create_flags = 0;
1374 0 : io.smb2.in.desired_access = SEC_FILE_ALL;
1375 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1376 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1377 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1378 : NTCREATEX_SHARE_ACCESS_WRITE;
1379 0 : io.smb2.in.alloc_size = 0;
1380 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1381 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1382 0 : io.smb2.in.security_flags = 0;
1383 0 : io.smb2.in.fname = BASEDIR_CNC;
1384 :
1385 0 : status = smb2_create(tree1, torture, &(io.smb2));
1386 0 : CHECK_STATUS(status, NT_STATUS_OK);
1387 :
1388 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1389 0 : status = smb2_create(tree1, torture, &(io.smb2));
1390 0 : CHECK_STATUS(status, NT_STATUS_OK);
1391 0 : h1 = io.smb2.out.file.handle;
1392 :
1393 : /* ask for a change notify,
1394 : on file or directory name changes */
1395 0 : ZERO_STRUCT(notify.smb2);
1396 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
1397 0 : notify.smb2.in.buffer_size = 1000;
1398 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1399 0 : notify.smb2.in.file.handle = h1;
1400 0 : notify.smb2.in.recursive = true;
1401 :
1402 0 : req = smb2_notify_send(tree1, &(notify.smb2));
1403 :
1404 0 : WAIT_FOR_ASYNC_RESPONSE(req);
1405 :
1406 0 : status = smb2_util_close(tree1, h1);
1407 0 : CHECK_STATUS(status, NT_STATUS_OK);
1408 :
1409 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1410 0 : CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
1411 0 : CHECK_VAL(notify.smb2.out.num_changes, 0);
1412 :
1413 0 : done:
1414 0 : smb2_deltree(tree1, BASEDIR_CNC);
1415 0 : return ret;
1416 : }
1417 :
1418 : /*
1419 : basic testing of change notifies followed by a ulogoff
1420 : */
1421 :
1422 : #define BASEDIR_NUL BASEDIR "_NUL"
1423 0 : static bool torture_smb2_notify_ulogoff(struct torture_context *torture,
1424 : struct smb2_tree *tree1)
1425 : {
1426 0 : bool ret = true;
1427 : NTSTATUS status;
1428 : union smb_notify notify;
1429 : union smb_open io;
1430 : struct smb2_handle h1;
1431 : struct smb2_request *req;
1432 :
1433 0 : smb2_deltree(tree1, BASEDIR_NUL);
1434 0 : smb2_util_rmdir(tree1, BASEDIR_NUL);
1435 :
1436 0 : torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1437 :
1438 : /*
1439 : get a handle on the directory
1440 : */
1441 0 : ZERO_STRUCT(io.smb2);
1442 0 : io.generic.level = RAW_OPEN_SMB2;
1443 0 : io.smb2.in.create_flags = 0;
1444 0 : io.smb2.in.desired_access = SEC_FILE_ALL;
1445 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1446 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1447 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1448 : NTCREATEX_SHARE_ACCESS_WRITE;
1449 0 : io.smb2.in.alloc_size = 0;
1450 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1451 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1452 0 : io.smb2.in.security_flags = 0;
1453 0 : io.smb2.in.fname = BASEDIR_NUL;
1454 :
1455 0 : status = smb2_create(tree1, torture, &(io.smb2));
1456 0 : CHECK_STATUS(status, NT_STATUS_OK);
1457 :
1458 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1459 0 : status = smb2_create(tree1, torture, &(io.smb2));
1460 0 : CHECK_STATUS(status, NT_STATUS_OK);
1461 0 : h1 = io.smb2.out.file.handle;
1462 :
1463 : /* ask for a change notify,
1464 : on file or directory name changes */
1465 0 : ZERO_STRUCT(notify.smb2);
1466 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
1467 0 : notify.smb2.in.buffer_size = 1000;
1468 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1469 0 : notify.smb2.in.file.handle = h1;
1470 0 : notify.smb2.in.recursive = true;
1471 :
1472 0 : req = smb2_notify_send(tree1, &(notify.smb2));
1473 :
1474 0 : WAIT_FOR_ASYNC_RESPONSE(req);
1475 :
1476 0 : status = smb2_logoff(tree1->session);
1477 0 : CHECK_STATUS(status, NT_STATUS_OK);
1478 :
1479 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1480 0 : CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
1481 0 : CHECK_VAL(notify.smb2.out.num_changes, 0);
1482 :
1483 0 : done:
1484 0 : smb2_deltree(tree1, BASEDIR_NUL);
1485 0 : 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 0 : static bool torture_smb2_notify_session_reconnect(struct torture_context *torture,
1495 : struct smb2_tree *tree1)
1496 : {
1497 0 : bool ret = true;
1498 : NTSTATUS status;
1499 : union smb_notify notify;
1500 : union smb_open io;
1501 : struct smb2_handle h1;
1502 : struct smb2_request *req;
1503 0 : uint64_t previous_session_id = 0;
1504 0 : struct smb2_session *session2 = NULL;
1505 :
1506 0 : smb2_deltree(tree1, BASEDIR_NSR);
1507 0 : smb2_util_rmdir(tree1, BASEDIR_NSR);
1508 :
1509 0 : torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY SESSION RECONNECT\n");
1510 :
1511 : /*
1512 : get a handle on the directory
1513 : */
1514 0 : ZERO_STRUCT(io.smb2);
1515 0 : io.generic.level = RAW_OPEN_SMB2;
1516 0 : io.smb2.in.create_flags = 0;
1517 0 : io.smb2.in.desired_access = SEC_FILE_ALL;
1518 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1519 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1520 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1521 : NTCREATEX_SHARE_ACCESS_WRITE;
1522 0 : io.smb2.in.alloc_size = 0;
1523 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1524 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1525 0 : io.smb2.in.security_flags = 0;
1526 0 : io.smb2.in.fname = BASEDIR_NSR;
1527 :
1528 0 : status = smb2_create(tree1, torture, &(io.smb2));
1529 0 : CHECK_STATUS(status, NT_STATUS_OK);
1530 :
1531 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1532 0 : status = smb2_create(tree1, torture, &(io.smb2));
1533 0 : CHECK_STATUS(status, NT_STATUS_OK);
1534 0 : h1 = io.smb2.out.file.handle;
1535 :
1536 : /* ask for a change notify,
1537 : on file or directory name changes */
1538 0 : ZERO_STRUCT(notify.smb2);
1539 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
1540 0 : notify.smb2.in.buffer_size = 1000;
1541 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1542 0 : notify.smb2.in.file.handle = h1;
1543 0 : notify.smb2.in.recursive = true;
1544 :
1545 0 : req = smb2_notify_send(tree1, &(notify.smb2));
1546 :
1547 0 : WAIT_FOR_ASYNC_RESPONSE(req);
1548 :
1549 0 : previous_session_id = smb2cli_session_current_id(tree1->session->smbXcli);
1550 0 : 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 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1557 0 : CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
1558 0 : CHECK_VAL(notify.smb2.out.num_changes, 0);
1559 :
1560 0 : status = smb2_logoff(tree1->session);
1561 0 : CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
1562 :
1563 0 : status = smb2_logoff(session2);
1564 0 : CHECK_STATUS(status, NT_STATUS_OK);
1565 0 : done:
1566 0 : smb2_deltree(tree1, BASEDIR_NSR);
1567 0 : 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 0 : static bool torture_smb2_notify_invalid_reauth(struct torture_context *torture,
1577 : struct smb2_tree *tree1,
1578 : struct smb2_tree *tree2)
1579 : {
1580 0 : bool ret = true;
1581 : NTSTATUS status;
1582 : union smb_notify notify;
1583 : union smb_open io;
1584 : struct smb2_handle h1;
1585 : struct smb2_request *req;
1586 : struct cli_credentials *invalid_creds;
1587 :
1588 0 : smb2_deltree(tree2, BASEDIR_IR);
1589 0 : smb2_util_rmdir(tree2, BASEDIR_IR);
1590 :
1591 0 : torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY invalid REAUTH\n");
1592 :
1593 : /*
1594 : get a handle on the directory
1595 : */
1596 0 : ZERO_STRUCT(io.smb2);
1597 0 : io.generic.level = RAW_OPEN_SMB2;
1598 0 : io.smb2.in.create_flags = 0;
1599 0 : io.smb2.in.desired_access = SEC_FILE_ALL;
1600 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1601 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1602 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1603 : NTCREATEX_SHARE_ACCESS_WRITE;
1604 0 : io.smb2.in.alloc_size = 0;
1605 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1606 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1607 0 : io.smb2.in.security_flags = 0;
1608 0 : io.smb2.in.fname = BASEDIR_IR;
1609 :
1610 0 : status = smb2_create(tree1, torture, &(io.smb2));
1611 0 : CHECK_STATUS(status, NT_STATUS_OK);
1612 :
1613 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1614 0 : status = smb2_create(tree1, torture, &(io.smb2));
1615 0 : CHECK_STATUS(status, NT_STATUS_OK);
1616 0 : h1 = io.smb2.out.file.handle;
1617 :
1618 : /* ask for a change notify,
1619 : on file or directory name changes */
1620 0 : ZERO_STRUCT(notify.smb2);
1621 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
1622 0 : notify.smb2.in.buffer_size = 1000;
1623 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1624 0 : notify.smb2.in.file.handle = h1;
1625 0 : notify.smb2.in.recursive = true;
1626 :
1627 0 : req = smb2_notify_send(tree1, &(notify.smb2));
1628 :
1629 0 : WAIT_FOR_ASYNC_RESPONSE(req);
1630 :
1631 0 : invalid_creds = cli_credentials_init(torture);
1632 0 : torture_assert(torture, (invalid_creds != NULL), "talloc error");
1633 0 : cli_credentials_set_username(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1634 0 : cli_credentials_set_domain(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1635 0 : cli_credentials_set_password(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1636 0 : cli_credentials_set_realm(invalid_creds, NULL, CRED_SPECIFIED);
1637 0 : cli_credentials_set_workstation(invalid_creds, "", CRED_UNINITIALISED);
1638 :
1639 0 : status = smb2_session_setup_spnego(tree1->session,
1640 : invalid_creds,
1641 : 0 /* previous_session_id */);
1642 0 : CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE);
1643 :
1644 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1645 0 : CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
1646 0 : CHECK_VAL(notify.smb2.out.num_changes, 0);
1647 :
1648 : /*
1649 : * Demonstrate that the session is no longer valid.
1650 : */
1651 0 : status = smb2_create(tree1, torture, &(io.smb2));
1652 0 : CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
1653 0 : done:
1654 0 : smb2_deltree(tree2, BASEDIR_IR);
1655 0 : return ret;
1656 : }
1657 :
1658 0 : static void tcp_dis_handler(struct smb2_transport *t, void *p)
1659 : {
1660 0 : struct smb2_tree *tree = (struct smb2_tree *)p;
1661 0 : smb2_transport_dead(tree->session->transport,
1662 0 : NT_STATUS_LOCAL_DISCONNECT);
1663 0 : t = NULL;
1664 0 : tree = NULL;
1665 0 : }
1666 :
1667 : /*
1668 : basic testing of change notifies followed by tcp disconnect
1669 : */
1670 :
1671 : #define BASEDIR_NTCPD BASEDIR "_NTCPD"
1672 :
1673 0 : static bool torture_smb2_notify_tcp_disconnect(
1674 : struct torture_context *torture,
1675 : struct smb2_tree *tree)
1676 : {
1677 0 : bool ret = true;
1678 : NTSTATUS status;
1679 : union smb_notify notify;
1680 : union smb_open io;
1681 : struct smb2_handle h1;
1682 : struct smb2_request *req;
1683 :
1684 0 : smb2_deltree(tree, BASEDIR_NTCPD);
1685 0 : smb2_util_rmdir(tree, BASEDIR_NTCPD);
1686 :
1687 0 : torture_comment(torture,
1688 : "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1689 :
1690 : /*
1691 : get a handle on the directory
1692 : */
1693 0 : ZERO_STRUCT(io.smb2);
1694 0 : io.generic.level = RAW_OPEN_SMB2;
1695 0 : io.smb2.in.create_flags = 0;
1696 0 : io.smb2.in.desired_access = SEC_FILE_ALL;
1697 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1698 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1699 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1700 : NTCREATEX_SHARE_ACCESS_WRITE;
1701 0 : io.smb2.in.alloc_size = 0;
1702 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1703 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1704 0 : io.smb2.in.security_flags = 0;
1705 0 : io.smb2.in.fname = BASEDIR_NTCPD;
1706 :
1707 0 : status = smb2_create(tree, torture, &(io.smb2));
1708 0 : CHECK_STATUS(status, NT_STATUS_OK);
1709 0 : h1 = io.smb2.out.file.handle;
1710 :
1711 : /* ask for a change notify,
1712 : on file or directory name changes */
1713 0 : ZERO_STRUCT(notify.smb2);
1714 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
1715 0 : notify.smb2.in.buffer_size = 1000;
1716 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1717 0 : notify.smb2.in.file.handle = h1;
1718 0 : notify.smb2.in.recursive = true;
1719 :
1720 0 : req = smb2_notify_send(tree, &(notify.smb2));
1721 0 : smb2_cancel(req);
1722 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1723 0 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
1724 :
1725 0 : notify.smb2.in.recursive = true;
1726 0 : req = smb2_notify_send(tree, &(notify.smb2));
1727 0 : smb2_transport_idle_handler(tree->session->transport,
1728 : tcp_dis_handler, 250000, tree);
1729 0 : tree = NULL;
1730 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
1731 0 : CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
1732 :
1733 0 : done:
1734 0 : 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 0 : static bool torture_smb2_notify_double(struct torture_context *torture,
1744 : struct smb2_tree *tree1,
1745 : struct smb2_tree *tree2)
1746 : {
1747 0 : bool ret = true;
1748 : NTSTATUS status;
1749 : union smb_notify notify;
1750 : union smb_open io;
1751 : struct smb2_handle h1;
1752 : struct smb2_request *req1, *req2;
1753 :
1754 0 : smb2_deltree(tree1, BASEDIR_NDOH);
1755 0 : smb2_util_rmdir(tree1, BASEDIR_NDOH);
1756 :
1757 0 : torture_comment(torture,
1758 : "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1759 :
1760 : /*
1761 : get a handle on the directory
1762 : */
1763 0 : ZERO_STRUCT(io.smb2);
1764 0 : io.generic.level = RAW_OPEN_SMB2;
1765 0 : io.smb2.in.create_flags = 0;
1766 0 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ|
1767 : SEC_RIGHTS_FILE_WRITE|
1768 : SEC_RIGHTS_FILE_ALL;
1769 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1770 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1771 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1772 : NTCREATEX_SHARE_ACCESS_WRITE;
1773 0 : io.smb2.in.alloc_size = 0;
1774 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1775 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1776 0 : io.smb2.in.security_flags = 0;
1777 0 : io.smb2.in.fname = BASEDIR_NDOH;
1778 :
1779 0 : status = smb2_create(tree1, torture, &(io.smb2));
1780 0 : CHECK_STATUS(status, NT_STATUS_OK);
1781 0 : h1 = io.smb2.out.file.handle;
1782 :
1783 : /* ask for a change notify,
1784 : on file or directory name changes */
1785 0 : ZERO_STRUCT(notify.smb2);
1786 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
1787 0 : notify.smb2.in.buffer_size = 1000;
1788 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1789 0 : notify.smb2.in.file.handle = h1;
1790 0 : notify.smb2.in.recursive = true;
1791 :
1792 0 : req1 = smb2_notify_send(tree1, &(notify.smb2));
1793 0 : smb2_cancel(req1);
1794 0 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
1795 0 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
1796 :
1797 0 : req2 = smb2_notify_send(tree1, &(notify.smb2));
1798 0 : smb2_cancel(req2);
1799 0 : status = smb2_notify_recv(req2, torture, &(notify.smb2));
1800 0 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
1801 :
1802 0 : smb2_util_mkdir(tree2, BASEDIR_NDOH "\\subdir-name");
1803 0 : req1 = smb2_notify_send(tree1, &(notify.smb2));
1804 0 : req2 = smb2_notify_send(tree1, &(notify.smb2));
1805 :
1806 0 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
1807 0 : CHECK_STATUS(status, NT_STATUS_OK);
1808 0 : CHECK_VAL(notify.smb2.out.num_changes, 1);
1809 0 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1810 :
1811 0 : smb2_util_mkdir(tree2, BASEDIR_NDOH "\\subdir-name2");
1812 :
1813 0 : status = smb2_notify_recv(req2, torture, &(notify.smb2));
1814 0 : CHECK_STATUS(status, NT_STATUS_OK);
1815 0 : CHECK_VAL(notify.smb2.out.num_changes, 1);
1816 0 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name2");
1817 :
1818 0 : done:
1819 0 : smb2_deltree(tree1, BASEDIR_NDOH);
1820 0 : 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 0 : static bool torture_smb2_notify_tree(struct torture_context *torture,
1831 : struct smb2_tree *tree)
1832 : {
1833 0 : bool ret = true;
1834 : union smb_notify notify;
1835 : union smb_open io;
1836 : struct smb2_request *req;
1837 : struct timeval tv;
1838 : struct {
1839 : const char *path;
1840 : bool recursive;
1841 : uint32_t filter;
1842 : int expected;
1843 : struct smb2_handle h1;
1844 : int counted;
1845 0 : } 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 : int i;
1968 : NTSTATUS status;
1969 0 : bool all_done = false;
1970 :
1971 0 : smb2_deltree(tree, BASEDIR_TREE);
1972 0 : smb2_util_rmdir(tree, BASEDIR_TREE);
1973 :
1974 0 : torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1975 :
1976 0 : ZERO_STRUCT(io.smb2);
1977 0 : io.generic.level = RAW_OPEN_SMB2;
1978 0 : io.smb2.in.create_flags = 0;
1979 0 : io.smb2.in.desired_access = SEC_FILE_ALL;
1980 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1981 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1982 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1983 : NTCREATEX_SHARE_ACCESS_WRITE;
1984 0 : io.smb2.in.alloc_size = 0;
1985 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1986 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1987 0 : io.smb2.in.security_flags = 0;
1988 0 : io.smb2.in.fname = BASEDIR_TREE;
1989 0 : status = smb2_create(tree, torture, &(io.smb2));
1990 0 : CHECK_STATUS(status, NT_STATUS_OK);
1991 :
1992 0 : ZERO_STRUCT(notify.smb2);
1993 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
1994 0 : notify.smb2.in.buffer_size = 20000;
1995 :
1996 : /*
1997 : setup the directory tree, and the notify buffer on each directory
1998 : */
1999 0 : for (i=0;i<ARRAY_SIZE(dirs);i++) {
2000 0 : io.smb2.in.fname = dirs[i].path;
2001 0 : status = smb2_create(tree, torture, &(io.smb2));
2002 0 : CHECK_STATUS(status, NT_STATUS_OK);
2003 0 : dirs[i].h1 = io.smb2.out.file.handle;
2004 :
2005 0 : notify.smb2.in.completion_filter = dirs[i].filter;
2006 0 : notify.smb2.in.file.handle = dirs[i].h1;
2007 0 : notify.smb2.in.recursive = dirs[i].recursive;
2008 0 : req = smb2_notify_send(tree, &(notify.smb2));
2009 0 : smb2_cancel(req);
2010 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2011 0 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
2012 : }
2013 :
2014 : /* trigger 2 events in each dir */
2015 0 : for (i=0;i<ARRAY_SIZE(dirs);i++) {
2016 0 : char *path = talloc_asprintf(torture, "%s\\test.dir",
2017 : dirs[i].path);
2018 0 : smb2_util_mkdir(tree, path);
2019 0 : smb2_util_rmdir(tree, path);
2020 0 : talloc_free(path);
2021 : }
2022 :
2023 : /* give a bit of time for the events to propagate */
2024 0 : tv = timeval_current();
2025 :
2026 : do {
2027 : /* count events that have happened in each dir */
2028 0 : for (i=0;i<ARRAY_SIZE(dirs);i++) {
2029 0 : notify.smb2.in.completion_filter = dirs[i].filter;
2030 0 : notify.smb2.in.file.handle = dirs[i].h1;
2031 0 : notify.smb2.in.recursive = dirs[i].recursive;
2032 0 : req = smb2_notify_send(tree, &(notify.smb2));
2033 0 : smb2_cancel(req);
2034 0 : notify.smb2.out.num_changes = 0;
2035 0 : status = smb2_notify_recv(req, torture,
2036 : &(notify.smb2));
2037 0 : dirs[i].counted += notify.smb2.out.num_changes;
2038 : }
2039 :
2040 0 : all_done = true;
2041 :
2042 0 : for (i=0;i<ARRAY_SIZE(dirs);i++) {
2043 0 : if (dirs[i].counted != dirs[i].expected) {
2044 0 : all_done = false;
2045 : }
2046 : }
2047 0 : } while (!all_done && timeval_elapsed(&tv) < 20);
2048 :
2049 0 : torture_comment(torture, "took %.4f seconds to propagate all events\n",
2050 : timeval_elapsed(&tv));
2051 :
2052 0 : for (i=0;i<ARRAY_SIZE(dirs);i++) {
2053 0 : 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 0 : for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
2066 0 : smb2_util_close(tree, dirs[i].h1);
2067 0 : smb2_util_rmdir(tree, dirs[i].path);
2068 : }
2069 :
2070 0 : done:
2071 0 : smb2_deltree(tree, BASEDIR_TREE);
2072 0 : smb2_util_rmdir(tree, BASEDIR_TREE);
2073 0 : 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 0 : static bool torture_smb2_notify_overflow(struct torture_context *torture,
2084 : struct smb2_tree *tree)
2085 : {
2086 0 : bool ret = true;
2087 : NTSTATUS status;
2088 : union smb_notify notify;
2089 : union smb_open io;
2090 : struct smb2_handle h1, h2;
2091 0 : int count = 100;
2092 : struct smb2_request *req1;
2093 : int i;
2094 :
2095 0 : smb2_deltree(tree, BASEDIR_OVF);
2096 0 : smb2_util_rmdir(tree, BASEDIR_OVF);
2097 :
2098 0 : torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
2099 :
2100 : /* get a handle on the directory */
2101 0 : ZERO_STRUCT(io.smb2);
2102 0 : io.generic.level = RAW_OPEN_SMB2;
2103 0 : io.smb2.in.create_flags = 0;
2104 0 : io.smb2.in.desired_access = SEC_FILE_ALL;
2105 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2106 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2107 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2108 : NTCREATEX_SHARE_ACCESS_WRITE;
2109 0 : io.smb2.in.alloc_size = 0;
2110 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2111 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2112 0 : io.smb2.in.security_flags = 0;
2113 0 : io.smb2.in.fname = BASEDIR_OVF;
2114 :
2115 0 : status = smb2_create(tree, torture, &(io.smb2));
2116 0 : CHECK_STATUS(status, NT_STATUS_OK);
2117 0 : h1 = io.smb2.out.file.handle;
2118 :
2119 : /* ask for a change notify, on name changes. */
2120 0 : ZERO_STRUCT(notify.smb2);
2121 0 : notify.smb2.level = RAW_NOTIFY_NTTRANS;
2122 0 : notify.smb2.in.buffer_size = 1000;
2123 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2124 0 : notify.smb2.in.file.handle = h1;
2125 :
2126 0 : notify.smb2.in.recursive = true;
2127 0 : req1 = smb2_notify_send(tree, &(notify.smb2));
2128 :
2129 : /* cancel initial requests so the buffer is setup */
2130 0 : smb2_cancel(req1);
2131 0 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
2132 0 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
2133 :
2134 : /* open a lot of files, filling up the server side notify buffer */
2135 0 : torture_comment(torture,
2136 : "Testing overflowed buffer notify on create of %d files\n",
2137 : count);
2138 :
2139 0 : for (i=0;i<count;i++) {
2140 0 : char *fname = talloc_asprintf(torture,
2141 : BASEDIR_OVF "\\test%d.txt", i);
2142 : union smb_open io1;
2143 0 : ZERO_STRUCT(io1.smb2);
2144 0 : io1.generic.level = RAW_OPEN_SMB2;
2145 0 : io1.smb2.in.create_flags = 0;
2146 0 : io1.smb2.in.desired_access = SEC_FILE_ALL;
2147 0 : io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2148 0 : io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2149 0 : io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2150 : NTCREATEX_SHARE_ACCESS_WRITE;
2151 0 : io1.smb2.in.alloc_size = 0;
2152 0 : io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2153 0 : io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2154 0 : io1.smb2.in.security_flags = 0;
2155 0 : io1.smb2.in.fname = fname;
2156 :
2157 0 : h2 = custom_smb2_create(tree, torture, &(io1.smb2));
2158 0 : talloc_free(fname);
2159 0 : smb2_util_close(tree, h2);
2160 : }
2161 :
2162 0 : req1 = smb2_notify_send(tree, &(notify.smb2));
2163 0 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
2164 0 : CHECK_STATUS(status, NT_STATUS_NOTIFY_ENUM_DIR);
2165 0 : CHECK_VAL(notify.smb2.out.num_changes, 0);
2166 :
2167 0 : done:
2168 0 : smb2_deltree(tree, BASEDIR_OVF);
2169 0 : 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 0 : static bool torture_smb2_notify_basedir(struct torture_context *torture,
2180 : struct smb2_tree *tree1,
2181 : struct smb2_tree *tree2)
2182 : {
2183 0 : bool ret = true;
2184 : NTSTATUS status;
2185 : union smb_notify notify;
2186 : union smb_open io;
2187 : struct smb2_handle h1;
2188 : struct smb2_request *req1;
2189 :
2190 0 : smb2_deltree(tree1, BASEDIR_BAS);
2191 0 : smb2_util_rmdir(tree1, BASEDIR_BAS);
2192 :
2193 0 : torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
2194 :
2195 : /* get a handle on the directory */
2196 0 : ZERO_STRUCT(io.smb2);
2197 0 : io.generic.level = RAW_OPEN_SMB2;
2198 0 : io.smb2.in.create_flags = 0;
2199 0 : io.smb2.in.desired_access = SEC_FILE_ALL;
2200 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2201 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2202 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2203 : NTCREATEX_SHARE_ACCESS_WRITE;
2204 0 : io.smb2.in.alloc_size = 0;
2205 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2206 0 : io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
2207 0 : io.smb2.in.security_flags = 0;
2208 0 : io.smb2.in.fname = BASEDIR_BAS;
2209 :
2210 0 : status = smb2_create(tree1, torture, &(io.smb2));
2211 0 : CHECK_STATUS(status, NT_STATUS_OK);
2212 0 : h1 = io.smb2.out.file.handle;
2213 :
2214 : /* create a test file that will also be modified */
2215 0 : io.smb2.in.fname = BASEDIR_BAS "\\tname1";
2216 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
2217 0 : status = smb2_create(tree2, torture, &(io.smb2));
2218 0 : CHECK_STATUS(status,NT_STATUS_OK);
2219 0 : smb2_util_close(tree2, io.smb2.out.file.handle);
2220 :
2221 : /* ask for a change notify, on attribute changes. */
2222 0 : ZERO_STRUCT(notify.smb2);
2223 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
2224 0 : notify.smb2.in.buffer_size = 1000;
2225 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
2226 0 : notify.smb2.in.file.handle = h1;
2227 0 : notify.smb2.in.recursive = true;
2228 :
2229 0 : req1 = smb2_notify_send(tree1, &(notify.smb2));
2230 :
2231 : /* set attribute on the base dir */
2232 0 : smb2_util_setatr(tree2, BASEDIR_BAS, FILE_ATTRIBUTE_HIDDEN);
2233 :
2234 : /* set attribute on a file to assure we receive a notification */
2235 0 : smb2_util_setatr(tree2, BASEDIR_BAS "\\tname1", FILE_ATTRIBUTE_HIDDEN);
2236 0 : smb_msleep(200);
2237 :
2238 : /* check how many responses were given, expect only 1 for the file */
2239 0 : status = smb2_notify_recv(req1, torture, &(notify.smb2));
2240 0 : CHECK_STATUS(status, NT_STATUS_OK);
2241 0 : CHECK_VAL(notify.smb2.out.num_changes, 1);
2242 0 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
2243 0 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
2244 :
2245 0 : done:
2246 0 : smb2_deltree(tree1, BASEDIR_BAS);
2247 0 : return ret;
2248 : }
2249 :
2250 : /*
2251 : very simple change notify test
2252 : */
2253 :
2254 : #define BASEDIR_TCON BASEDIR "_TCON"
2255 :
2256 0 : static bool torture_smb2_notify_tcon(struct torture_context *torture,
2257 : struct smb2_tree *tree)
2258 : {
2259 0 : bool ret = true;
2260 : NTSTATUS status;
2261 : union smb_notify notify;
2262 : union smb_open io;
2263 0 : struct smb2_handle h1 = {{0}};
2264 0 : struct smb2_request *req = NULL;
2265 0 : struct smb2_tree *tree1 = NULL;
2266 0 : const char *fname = BASEDIR_TCON "\\subdir-name";
2267 :
2268 0 : smb2_deltree(tree, BASEDIR_TCON);
2269 0 : smb2_util_rmdir(tree, BASEDIR_TCON);
2270 :
2271 0 : torture_comment(torture, "TESTING SIMPLE CHANGE NOTIFY\n");
2272 :
2273 : /*
2274 : get a handle on the directory
2275 : */
2276 :
2277 0 : ZERO_STRUCT(io.smb2);
2278 0 : io.generic.level = RAW_OPEN_SMB2;
2279 0 : io.smb2.in.create_flags = 0;
2280 0 : io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2281 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2282 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL |
2283 : FILE_ATTRIBUTE_DIRECTORY;
2284 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2285 : NTCREATEX_SHARE_ACCESS_WRITE;
2286 0 : io.smb2.in.alloc_size = 0;
2287 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2288 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2289 0 : io.smb2.in.security_flags = 0;
2290 0 : io.smb2.in.fname = BASEDIR_TCON;
2291 :
2292 0 : status = smb2_create(tree, torture, &(io.smb2));
2293 0 : CHECK_STATUS(status, NT_STATUS_OK);
2294 0 : h1 = io.smb2.out.file.handle;
2295 :
2296 : /* ask for a change notify,
2297 : on file or directory name changes */
2298 0 : ZERO_STRUCT(notify.smb2);
2299 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
2300 0 : notify.smb2.in.buffer_size = 1000;
2301 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2302 0 : notify.smb2.in.file.handle = h1;
2303 0 : notify.smb2.in.recursive = true;
2304 :
2305 0 : torture_comment(torture, "Testing notify mkdir\n");
2306 0 : req = smb2_notify_send(tree, &(notify.smb2));
2307 0 : smb2_cancel(req);
2308 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2309 0 : CHECK_STATUS(status, NT_STATUS_CANCELLED);
2310 :
2311 0 : notify.smb2.in.recursive = true;
2312 0 : req = smb2_notify_send(tree, &(notify.smb2));
2313 0 : status = smb2_util_mkdir(tree, fname);
2314 0 : CHECK_STATUS(status, NT_STATUS_OK);
2315 :
2316 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2317 0 : CHECK_STATUS(status, NT_STATUS_OK);
2318 :
2319 0 : CHECK_VAL(notify.smb2.out.num_changes, 1);
2320 0 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2321 0 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2322 :
2323 0 : torture_comment(torture, "Testing notify rmdir\n");
2324 0 : req = smb2_notify_send(tree, &(notify.smb2));
2325 0 : status = smb2_util_rmdir(tree, fname);
2326 0 : CHECK_STATUS(status, NT_STATUS_OK);
2327 :
2328 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2329 0 : CHECK_STATUS(status, NT_STATUS_OK);
2330 0 : CHECK_VAL(notify.smb2.out.num_changes, 1);
2331 0 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2332 0 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2333 :
2334 0 : torture_comment(torture, "SIMPLE CHANGE NOTIFY OK\n");
2335 :
2336 0 : torture_comment(torture, "TESTING WITH SECONDARY TCON\n");
2337 0 : 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 0 : torture_comment(torture, "tid1=%d tid2=%d\n",
2344 : smb2cli_tcon_current_id(tree->smbXcli),
2345 0 : smb2cli_tcon_current_id(tree1->smbXcli));
2346 :
2347 0 : torture_comment(torture, "Testing notify mkdir\n");
2348 0 : req = smb2_notify_send(tree, &(notify.smb2));
2349 0 : smb2_util_mkdir(tree1, fname);
2350 :
2351 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2352 0 : CHECK_STATUS(status, NT_STATUS_OK);
2353 :
2354 0 : CHECK_VAL(notify.smb2.out.num_changes, 1);
2355 0 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2356 0 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2357 :
2358 0 : torture_comment(torture, "Testing notify rmdir\n");
2359 0 : req = smb2_notify_send(tree, &(notify.smb2));
2360 0 : smb2_util_rmdir(tree, fname);
2361 :
2362 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2363 0 : CHECK_STATUS(status, NT_STATUS_OK);
2364 0 : CHECK_VAL(notify.smb2.out.num_changes, 1);
2365 0 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2366 0 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2367 :
2368 0 : torture_comment(torture, "CHANGE NOTIFY WITH TCON OK\n");
2369 :
2370 0 : torture_comment(torture, "Disconnecting secondary tree\n");
2371 0 : status = smb2_tdis(tree1);
2372 0 : CHECK_STATUS(status, NT_STATUS_OK);
2373 0 : talloc_free(tree1);
2374 :
2375 0 : torture_comment(torture, "Testing notify mkdir\n");
2376 0 : req = smb2_notify_send(tree, &(notify.smb2));
2377 0 : smb2_util_mkdir(tree, fname);
2378 :
2379 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2380 0 : CHECK_STATUS(status, NT_STATUS_OK);
2381 :
2382 0 : CHECK_VAL(notify.smb2.out.num_changes, 1);
2383 0 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2384 0 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2385 :
2386 0 : torture_comment(torture, "Testing notify rmdir\n");
2387 0 : req = smb2_notify_send(tree, &(notify.smb2));
2388 0 : smb2_util_rmdir(tree, fname);
2389 :
2390 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2391 0 : CHECK_STATUS(status, NT_STATUS_OK);
2392 0 : CHECK_VAL(notify.smb2.out.num_changes, 1);
2393 0 : CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2394 0 : CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2395 :
2396 0 : torture_comment(torture, "CHANGE NOTIFY WITH TDIS OK\n");
2397 0 : done:
2398 0 : smb2_util_close(tree, h1);
2399 0 : smb2_deltree(tree, BASEDIR_TCON);
2400 :
2401 0 : return ret;
2402 : }
2403 :
2404 : #define BASEDIR_RMD BASEDIR "_RMD"
2405 :
2406 0 : 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 0 : bool ret = true;
2412 : NTSTATUS status;
2413 0 : union smb_notify notify = {};
2414 0 : union smb_setfileinfo sfinfo = {};
2415 0 : union smb_open io = {};
2416 0 : struct smb2_handle h = {};
2417 : struct smb2_request *req;
2418 :
2419 0 : torture_comment(torture, "TESTING NOTIFY CANCEL FOR DELETED DIR\n");
2420 :
2421 0 : smb2_deltree(tree1, BASEDIR_RMD);
2422 0 : smb2_util_rmdir(tree1, BASEDIR_RMD);
2423 :
2424 0 : ZERO_STRUCT(io.smb2);
2425 0 : io.generic.level = RAW_OPEN_SMB2;
2426 0 : io.smb2.in.create_flags = 0;
2427 0 : io.smb2.in.desired_access = SEC_FILE_ALL;
2428 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2429 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2430 0 : io.smb2.in.share_access =
2431 : NTCREATEX_SHARE_ACCESS_READ |
2432 : NTCREATEX_SHARE_ACCESS_WRITE |
2433 : NTCREATEX_SHARE_ACCESS_DELETE ;
2434 0 : io.smb2.in.alloc_size = 0;
2435 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2436 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2437 0 : io.smb2.in.security_flags = 0;
2438 0 : io.smb2.in.fname = BASEDIR_RMD;
2439 :
2440 0 : status = smb2_create(tree1, torture, &(io.smb2));
2441 0 : CHECK_STATUS(status, NT_STATUS_OK);
2442 0 : h = io.smb2.out.file.handle;
2443 :
2444 0 : ZERO_STRUCT(notify.smb2);
2445 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
2446 0 : notify.smb2.in.buffer_size = 1000;
2447 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2448 0 : notify.smb2.in.file.handle = h;
2449 0 : notify.smb2.in.recursive = false;
2450 :
2451 0 : io.smb2.in.desired_access |= SEC_STD_DELETE;
2452 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
2453 0 : req = smb2_notify_send(tree1, &(notify.smb2));
2454 :
2455 0 : if (initial_delete_on_close) {
2456 0 : status = smb2_util_rmdir(tree2, BASEDIR_RMD);
2457 0 : CHECK_STATUS(status, NT_STATUS_OK);
2458 : } else {
2459 0 : status = smb2_create(tree2, torture, &(io.smb2));
2460 0 : CHECK_STATUS(status, NT_STATUS_OK);
2461 :
2462 0 : sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
2463 0 : sfinfo.generic.in.file.handle = io.smb2.out.file.handle;
2464 0 : sfinfo.disposition_info.in.delete_on_close = 1;
2465 0 : status = smb2_setinfo_file(tree2, &sfinfo);
2466 0 : CHECK_STATUS(status, NT_STATUS_OK);
2467 :
2468 0 : smb2_util_close(tree2, io.smb2.out.file.handle);
2469 : }
2470 :
2471 0 : status = smb2_notify_recv(req, torture, &(notify.smb2));
2472 0 : CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
2473 :
2474 0 : done:
2475 :
2476 0 : smb2_util_close(tree1, h);
2477 0 : smb2_deltree(tree1, BASEDIR_RMD);
2478 :
2479 0 : return ret;
2480 : }
2481 :
2482 0 : static bool torture_smb2_notify_rmdir1(struct torture_context *torture,
2483 : struct smb2_tree *tree)
2484 : {
2485 0 : return torture_smb2_notify_rmdir(torture, tree, tree, false);
2486 : }
2487 :
2488 0 : static bool torture_smb2_notify_rmdir2(struct torture_context *torture,
2489 : struct smb2_tree *tree)
2490 : {
2491 0 : return torture_smb2_notify_rmdir(torture, tree, tree, true);
2492 : }
2493 :
2494 0 : static bool torture_smb2_notify_rmdir3(struct torture_context *torture,
2495 : struct smb2_tree *tree1,
2496 : struct smb2_tree *tree2)
2497 : {
2498 0 : return torture_smb2_notify_rmdir(torture, tree1, tree2, false);
2499 : }
2500 :
2501 0 : static bool torture_smb2_notify_rmdir4(struct torture_context *torture,
2502 : struct smb2_tree *tree1,
2503 : struct smb2_tree *tree2)
2504 : {
2505 0 : 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 0 : static bool torture_smb2_inotify_rename(struct torture_context *torture,
2522 : struct smb2_tree *tree1,
2523 : struct smb2_tree *tree2)
2524 : {
2525 : NTSTATUS status;
2526 : struct smb2_notify notify;
2527 0 : struct notify_changes change1 = {0};
2528 0 : struct notify_changes change2 = {0};
2529 : struct smb2_create create;
2530 : union smb_setfileinfo sinfo;
2531 0 : struct smb2_handle h1 = {{0}};
2532 0 : struct smb2_handle h2 = {{0}};
2533 : struct smb2_request *req;
2534 0 : struct tevent_timer *te = NULL;
2535 0 : bool ok = false;
2536 :
2537 0 : smb2_deltree(tree1, BASEDIR_INR);
2538 :
2539 0 : torture_comment(torture, "Testing change notify of a rename with inotify\n");
2540 :
2541 0 : status = torture_smb2_testdir(tree1, BASEDIR_INR, &h1);
2542 0 : torture_assert_ntstatus_ok_goto(torture, status, ok, done, "torture_smb2_testdir failed");
2543 :
2544 0 : ZERO_STRUCT(create);
2545 0 : create.in.desired_access = SEC_RIGHTS_FILE_READ |
2546 : SEC_RIGHTS_FILE_WRITE|
2547 : SEC_RIGHTS_FILE_ALL;
2548 0 : create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2549 0 : create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2550 0 : create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2551 : NTCREATEX_SHARE_ACCESS_WRITE |
2552 : NTCREATEX_SHARE_ACCESS_DELETE;
2553 0 : create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2554 0 : create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2555 0 : create.in.fname = BASEDIR_INR "\\subdir-name";
2556 :
2557 0 : status = smb2_create(tree2, torture, &create);
2558 0 : torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_create failed\n");
2559 0 : h2 = create.out.file.handle;
2560 :
2561 0 : ZERO_STRUCT(notify);
2562 0 : notify.level = RAW_NOTIFY_SMB2;
2563 0 : notify.in.buffer_size = 4096;
2564 0 : notify.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2565 0 : notify.in.file.handle = h1;
2566 0 : notify.in.recursive = true;
2567 0 : req = smb2_notify_send(tree1, ¬ify);
2568 0 : torture_assert_not_null_goto(torture, req, ok, done, "smb2_notify_send failed\n");
2569 :
2570 0 : while (!NT_STATUS_EQUAL(req->status, NT_STATUS_PENDING)) {
2571 0 : if (tevent_loop_once(torture->ev) != 0) {
2572 0 : goto done;
2573 : }
2574 : }
2575 :
2576 0 : ZERO_STRUCT(sinfo);
2577 0 : sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
2578 0 : sinfo.rename_information.in.file.handle = h2;
2579 0 : sinfo.rename_information.in.new_name = BASEDIR_INR "\\subdir-name-r";
2580 :
2581 0 : status = smb2_setinfo_file(tree2, &sinfo);
2582 0 : torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_setinfo_file failed\n");
2583 :
2584 0 : smb2_util_close(tree2, h2);
2585 :
2586 0 : te = tevent_add_timer(torture->ev,
2587 : tree1,
2588 : tevent_timeval_current_ofs(1, 0),
2589 : notify_timeout,
2590 : req);
2591 0 : torture_assert_not_null_goto(torture, te, ok, done, "tevent_add_timer failed\n");
2592 :
2593 0 : status = smb2_notify_recv(req, torture, ¬ify);
2594 0 : torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_notify_recv failed\n");
2595 :
2596 0 : torture_assert_goto(torture, notify.out.num_changes == 1 || notify.out.num_changes == 2,
2597 : ok, done, "bad notify\n");
2598 :
2599 0 : change1 = notify.out.changes[0];
2600 0 : if (notify.out.num_changes == 2) {
2601 0 : 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 0 : 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 0 : torture_assert_str_equal_goto(torture, change1.name.s, "subdir-name",
2632 : ok, done, "bad change notification\n");
2633 :
2634 0 : 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 0 : torture_assert_str_equal_goto(torture, change2.name.s, "subdir-name-r",
2640 : ok, done, "bad change notification\n");
2641 :
2642 0 : ok = true;
2643 0 : done:
2644 0 : if (!smb2_util_handle_empty(h1)) {
2645 0 : smb2_util_close(tree1, h1);
2646 : }
2647 0 : if (!smb2_util_handle_empty(h2)) {
2648 0 : smb2_util_close(tree2, h2);
2649 : }
2650 :
2651 0 : smb2_deltree(tree1, BASEDIR_INR);
2652 0 : 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 0 : static bool torture_smb2_notify_handle_permissions(
2662 : struct torture_context *torture,
2663 : struct smb2_tree *tree)
2664 : {
2665 0 : bool ret = true;
2666 : NTSTATUS status;
2667 : union smb_notify notify;
2668 : union smb_open io;
2669 0 : struct smb2_handle h1 = {{0}};
2670 : struct smb2_request *req;
2671 :
2672 0 : smb2_deltree(tree, BASEDIR_HPERM);
2673 0 : smb2_util_rmdir(tree, BASEDIR_HPERM);
2674 :
2675 0 : 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 0 : ZERO_STRUCT(io.smb2);
2683 0 : io.generic.level = RAW_OPEN_SMB2;
2684 0 : io.smb2.in.create_flags = 0;
2685 0 : io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
2686 0 : io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2687 0 : io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2688 0 : io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2689 : NTCREATEX_SHARE_ACCESS_WRITE;
2690 0 : io.smb2.in.alloc_size = 0;
2691 0 : io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2692 0 : io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2693 0 : io.smb2.in.security_flags = 0;
2694 0 : io.smb2.in.fname = BASEDIR_HPERM;
2695 :
2696 0 : status = smb2_create(tree, torture, &io.smb2);
2697 0 : CHECK_STATUS(status, NT_STATUS_OK);
2698 0 : h1 = io.smb2.out.file.handle;
2699 :
2700 : /* ask for a change notify,
2701 : on file or directory name changes */
2702 0 : ZERO_STRUCT(notify.smb2);
2703 0 : notify.smb2.level = RAW_NOTIFY_SMB2;
2704 0 : notify.smb2.in.buffer_size = 1000;
2705 0 : notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2706 0 : notify.smb2.in.file.handle = h1;
2707 0 : notify.smb2.in.recursive = true;
2708 :
2709 0 : req = smb2_notify_send(tree, ¬ify.smb2);
2710 0 : 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 0 : smb2_cancel(req);
2720 0 : status = smb2_notify_recv(req, torture, ¬ify.smb2);
2721 : /* Handle h1 doesn't have permissions for ChangeNotify. */
2722 0 : CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
2723 :
2724 0 : done:
2725 0 : if (!smb2_util_handle_empty(h1)) {
2726 0 : smb2_util_close(tree, h1);
2727 : }
2728 0 : smb2_deltree(tree, BASEDIR_HPERM);
2729 0 : return ret;
2730 : }
2731 :
2732 : /*
2733 : basic testing of SMB2 change notify
2734 : */
2735 964 : struct torture_suite *torture_smb2_notify_init(TALLOC_CTX *ctx)
2736 : {
2737 964 : struct torture_suite *suite = torture_suite_create(ctx, "notify");
2738 :
2739 964 : torture_suite_add_1smb2_test(suite, "valid-req", test_valid_request);
2740 964 : torture_suite_add_1smb2_test(suite, "tcon", torture_smb2_notify_tcon);
2741 964 : torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir);
2742 964 : torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask);
2743 964 : torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
2744 964 : torture_suite_add_1smb2_test(suite, "tdis1", torture_smb2_notify_tree_disconnect_1);
2745 964 : torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
2746 964 : torture_suite_add_1smb2_test(suite, "close", torture_smb2_notify_close);
2747 964 : torture_suite_add_1smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
2748 964 : torture_suite_add_1smb2_test(suite, "session-reconnect", torture_smb2_notify_session_reconnect);
2749 964 : torture_suite_add_2smb2_test(suite, "invalid-reauth", torture_smb2_notify_invalid_reauth);
2750 964 : torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
2751 964 : torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
2752 964 : torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
2753 964 : torture_suite_add_1smb2_test(suite, "file", torture_smb2_notify_file);
2754 964 : torture_suite_add_1smb2_test(suite, "tcp", torture_smb2_notify_tcp_disconnect);
2755 964 : torture_suite_add_2smb2_test(suite, "rec", torture_smb2_notify_recursive);
2756 964 : torture_suite_add_1smb2_test(suite, "overflow", torture_smb2_notify_overflow);
2757 964 : torture_suite_add_1smb2_test(suite, "rmdir1",
2758 : torture_smb2_notify_rmdir1);
2759 964 : torture_suite_add_1smb2_test(suite, "rmdir2",
2760 : torture_smb2_notify_rmdir2);
2761 964 : torture_suite_add_2smb2_test(suite, "rmdir3",
2762 : torture_smb2_notify_rmdir3);
2763 964 : torture_suite_add_2smb2_test(suite, "rmdir4",
2764 : torture_smb2_notify_rmdir4);
2765 964 : torture_suite_add_1smb2_test(suite,
2766 : "handle-permissions",
2767 : torture_smb2_notify_handle_permissions);
2768 :
2769 964 : suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");
2770 :
2771 964 : return suite;
2772 : }
2773 :
2774 : /*
2775 : basic testing of SMB2 change notify
2776 : */
2777 964 : struct torture_suite *torture_smb2_notify_inotify_init(TALLOC_CTX *ctx)
2778 : {
2779 964 : struct torture_suite *suite = torture_suite_create(ctx, "notify-inotify");
2780 :
2781 964 : suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests that use inotify");
2782 :
2783 964 : torture_suite_add_2smb2_test(suite, "inotify-rename", torture_smb2_inotify_rename);
2784 :
2785 964 : return suite;
2786 : }
|