torture: Fix uninitialized variables
[Samba.git] / source4 / torture / smb2 / notify.c
blob90f5ad9a6337ffe691020eb7e90c827c7caa726c
1 /*
2 Unix SMB/CIFS implementation.
4 SMB2 notify test suite
6 Copyright (C) Stefan Metzmacher 2006
7 Copyright (C) Andrew Tridgell 2009
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.
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.
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/>.
23 #include "includes.h"
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "../libcli/smb/smbXcli_base.h"
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"
34 #include "system/filesys.h"
35 #include "auth/credentials/credentials.h"
36 #include "lib/cmdline/popt_common.h"
37 #include "librpc/gen_ndr/security.h"
39 #include "lib/events/events.h"
41 #include "libcli/raw/libcliraw.h"
42 #include "libcli/raw/raw_proto.h"
43 #include "libcli/libcli.h"
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)
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)
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)
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 } \
79 #define BASEDIR "test_notify"
80 #define FNAME "smb2-notify01.dat"
82 static bool test_valid_request(struct torture_context *torture,
83 struct smb2_tree *tree)
85 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;
92 torture_comment(torture, "TESTING VALIDITY OF CHANGE NOTIFY REQUEST\n");
94 smb2_util_unlink(tree, FNAME);
96 status = smb2_util_roothandle(tree, &dh);
97 CHECK_STATUS(status, NT_STATUS_OK);
99 /* 0x00080000 is the default max buffer size for Windows servers
100 * pre-Win7 */
101 max_buffer_size = torture_setting_ulong(torture, "cn_max_buffer_size",
102 0x00080000);
104 n.in.recursive = 0x0000;
105 n.in.buffer_size = max_buffer_size;
106 n.in.file.handle = dh;
107 n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
108 n.in.unknown = 0x00000000;
109 req = smb2_notify_send(tree, &n);
111 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
112 if (tevent_loop_once(torture->ev) != 0) {
113 break;
117 status = torture_setup_complex_file(torture, tree, FNAME);
118 CHECK_STATUS(status, NT_STATUS_OK);
120 status = smb2_notify_recv(req, torture, &n);
121 CHECK_STATUS(status, NT_STATUS_OK);
122 CHECK_VAL(n.out.num_changes, 1);
123 CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_ADDED);
124 CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
127 * if the change response doesn't fit in the buffer
128 * NOTIFY_ENUM_DIR is returned.
130 n.in.buffer_size = 0x00000000;
131 req = smb2_notify_send(tree, &n);
133 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
134 if (tevent_loop_once(torture->ev) != 0) {
135 break;
139 status = torture_setup_complex_file(torture, tree, FNAME);
140 CHECK_STATUS(status, NT_STATUS_OK);
142 status = smb2_notify_recv(req, torture, &n);
143 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
146 * if the change response fits in the buffer we get
147 * NT_STATUS_OK again
149 n.in.buffer_size = max_buffer_size;
150 req = smb2_notify_send(tree, &n);
152 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
153 if (tevent_loop_once(torture->ev) != 0) {
154 break;
158 status = torture_setup_complex_file(torture, tree, FNAME);
159 CHECK_STATUS(status, NT_STATUS_OK);
161 status = smb2_notify_recv(req, torture, &n);
162 CHECK_STATUS(status, NT_STATUS_OK);
163 CHECK_VAL(n.out.num_changes, 3);
164 CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_REMOVED);
165 CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
166 CHECK_VAL(n.out.changes[1].action, NOTIFY_ACTION_ADDED);
167 CHECK_WIRE_STR(n.out.changes[1].name, FNAME);
168 CHECK_VAL(n.out.changes[2].action, NOTIFY_ACTION_MODIFIED);
169 CHECK_WIRE_STR(n.out.changes[2].name, FNAME);
171 /* if the first notify returns NOTIFY_ENUM_DIR, all do */
172 status = smb2_util_close(tree, dh);
173 CHECK_STATUS(status, NT_STATUS_OK);
174 status = smb2_util_roothandle(tree, &dh);
175 CHECK_STATUS(status, NT_STATUS_OK);
177 n.in.recursive = 0x0000;
178 n.in.buffer_size = 0x00000001;
179 n.in.file.handle = dh;
180 n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
181 n.in.unknown = 0x00000000;
182 req = smb2_notify_send(tree, &n);
184 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
185 if (tevent_loop_once(torture->ev) != 0) {
186 break;
190 status = torture_setup_complex_file(torture, tree, FNAME);
191 CHECK_STATUS(status, NT_STATUS_OK);
193 status = smb2_notify_recv(req, torture, &n);
194 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
196 n.in.buffer_size = max_buffer_size;
197 req = smb2_notify_send(tree, &n);
198 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
199 if (tevent_loop_once(torture->ev) != 0) {
200 break;
204 status = torture_setup_complex_file(torture, tree, FNAME);
205 CHECK_STATUS(status, NT_STATUS_OK);
207 status = smb2_notify_recv(req, torture, &n);
208 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
210 /* if the buffer size is too large, we get invalid parameter */
211 n.in.recursive = 0x0000;
212 n.in.buffer_size = max_buffer_size + 1;
213 n.in.file.handle = dh;
214 n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
215 n.in.unknown = 0x00000000;
216 req = smb2_notify_send(tree, &n);
217 status = smb2_notify_recv(req, torture, &n);
218 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
220 done:
221 return ret;
225 basic testing of change notify on directories
227 static bool torture_smb2_notify_dir(struct torture_context *torture,
228 struct smb2_tree *tree1,
229 struct smb2_tree *tree2)
231 bool ret = true;
232 NTSTATUS status;
233 union smb_notify notify;
234 union smb_open io;
235 union smb_close cl;
236 int i, count;
237 struct smb2_handle h1 = {{0}};
238 struct smb2_handle h2 = {{0}};
239 struct smb2_request *req, *req2;
240 const char *fname = BASEDIR "\\subdir-name";
241 extern int torture_numops;
243 torture_comment(torture, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
245 smb2_deltree(tree1, BASEDIR);
246 smb2_util_rmdir(tree1, BASEDIR);
248 get a handle on the directory
250 ZERO_STRUCT(io.smb2);
251 io.generic.level = RAW_OPEN_SMB2;
252 io.smb2.in.create_flags = 0;
253 io.smb2.in.desired_access = SEC_FILE_ALL;
254 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
255 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
256 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
257 NTCREATEX_SHARE_ACCESS_WRITE;
258 io.smb2.in.alloc_size = 0;
259 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
260 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
261 io.smb2.in.security_flags = 0;
262 io.smb2.in.fname = BASEDIR;
264 status = smb2_create(tree1, torture, &(io.smb2));
265 CHECK_STATUS(status, NT_STATUS_OK);
266 h1 = io.smb2.out.file.handle;
268 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
269 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ;
270 status = smb2_create(tree1, torture, &(io.smb2));
271 CHECK_STATUS(status, NT_STATUS_OK);
272 h2 = io.smb2.out.file.handle;
274 /* ask for a change notify,
275 on file or directory name changes */
276 ZERO_STRUCT(notify.smb2);
277 notify.smb2.level = RAW_NOTIFY_SMB2;
278 notify.smb2.in.buffer_size = 1000;
279 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
280 notify.smb2.in.file.handle = h1;
281 notify.smb2.in.recursive = true;
283 torture_comment(torture, "Testing notify cancel\n");
285 req = smb2_notify_send(tree1, &(notify.smb2));
286 smb2_cancel(req);
287 status = smb2_notify_recv(req, torture, &(notify.smb2));
288 CHECK_STATUS(status, NT_STATUS_CANCELLED);
290 torture_comment(torture, "Testing notify mkdir\n");
292 req = smb2_notify_send(tree1, &(notify.smb2));
293 smb2_util_mkdir(tree2, fname);
295 status = smb2_notify_recv(req, torture, &(notify.smb2));
296 CHECK_STATUS(status, NT_STATUS_OK);
298 CHECK_VAL(notify.smb2.out.num_changes, 1);
299 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
300 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
302 torture_comment(torture, "Testing notify rmdir\n");
304 req = smb2_notify_send(tree1, &(notify.smb2));
305 smb2_util_rmdir(tree2, fname);
307 status = smb2_notify_recv(req, torture, &(notify.smb2));
308 CHECK_STATUS(status, NT_STATUS_OK);
309 CHECK_VAL(notify.smb2.out.num_changes, 1);
310 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
311 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
313 torture_comment(torture,
314 "Testing notify mkdir - rmdir - mkdir - rmdir\n");
316 smb2_util_mkdir(tree2, fname);
317 smb2_util_rmdir(tree2, fname);
318 smb2_util_mkdir(tree2, fname);
319 smb2_util_rmdir(tree2, fname);
320 smb_msleep(200);
321 req = smb2_notify_send(tree1, &(notify.smb2));
322 status = smb2_notify_recv(req, torture, &(notify.smb2));
323 CHECK_STATUS(status, NT_STATUS_OK);
324 CHECK_VAL(notify.smb2.out.num_changes, 4);
325 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
326 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
327 CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_REMOVED);
328 CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name");
329 CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_ADDED);
330 CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name");
331 CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_REMOVED);
332 CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name");
334 count = torture_numops;
335 torture_comment(torture,
336 "Testing buffered notify on create of %d files\n", count);
337 for (i=0;i<count;i++) {
338 struct smb2_handle h12;
339 char *fname2 = talloc_asprintf(torture, BASEDIR "\\test%d.txt",
342 ZERO_STRUCT(io.smb2);
343 io.generic.level = RAW_OPEN_SMB2;
344 io.smb2.in.create_flags = 0;
345 io.smb2.in.desired_access = SEC_FILE_ALL;
346 io.smb2.in.create_options =
347 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
348 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
349 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
350 NTCREATEX_SHARE_ACCESS_WRITE;
351 io.smb2.in.alloc_size = 0;
352 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
353 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
354 io.smb2.in.security_flags = 0;
355 io.smb2.in.fname = fname2;
357 status = smb2_create(tree1, torture, &(io.smb2));
358 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
359 torture_comment(torture, "Failed to create %s \n",
360 fname);
361 ret = false;
362 goto done;
364 h12 = io.smb2.out.file.handle;
365 talloc_free(fname2);
366 smb2_util_close(tree1, h12);
369 /* (1st notify) setup a new notify on a different directory handle.
370 This new notify won't see the events above. */
371 notify.smb2.in.file.handle = h2;
372 req2 = smb2_notify_send(tree1, &(notify.smb2));
374 /* (2nd notify) whereas this notify will see the above buffered events,
375 and it directly returns the buffered events */
376 notify.smb2.in.file.handle = h1;
377 req = smb2_notify_send(tree1, &(notify.smb2));
379 status = smb2_util_unlink(tree1, BASEDIR "\\nonexistent.txt");
380 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
382 /* (1st unlink) as the 2nd notify directly returns,
383 this unlink is only seen by the 1st notify and
384 the 3rd notify (later) */
385 torture_comment(torture,
386 "Testing notify on unlink for the first file\n");
387 status = smb2_util_unlink(tree2, BASEDIR "\\test0.txt");
388 CHECK_STATUS(status, NT_STATUS_OK);
390 /* receive the reply from the 2nd notify */
391 status = smb2_notify_recv(req, torture, &(notify.smb2));
392 CHECK_STATUS(status, NT_STATUS_OK);
394 CHECK_VAL(notify.smb2.out.num_changes, count);
395 for (i=1;i<count;i++) {
396 CHECK_VAL(notify.smb2.out.changes[i].action,
397 NOTIFY_ACTION_ADDED);
399 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
401 torture_comment(torture, "and now from the 1st notify\n");
402 status = smb2_notify_recv(req2, torture, &(notify.smb2));
403 CHECK_STATUS(status, NT_STATUS_OK);
404 CHECK_VAL(notify.smb2.out.num_changes, 1);
405 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
406 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
408 torture_comment(torture,
409 "(3rd notify) this notify will only see the 1st unlink\n");
410 req = smb2_notify_send(tree1, &(notify.smb2));
412 status = smb2_util_unlink(tree1, BASEDIR "\\nonexistent.txt");
413 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
415 for (i=1;i<count;i++) {
416 char *fname2 = talloc_asprintf(torture,
417 BASEDIR "\\test%d.txt", i);
418 status = smb2_util_unlink(tree2, fname2);
419 CHECK_STATUS(status, NT_STATUS_OK);
420 talloc_free(fname2);
423 /* receive the 3rd notify */
424 status = smb2_notify_recv(req, torture, &(notify.smb2));
425 CHECK_STATUS(status, NT_STATUS_OK);
426 CHECK_VAL(notify.smb2.out.num_changes, 1);
427 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
428 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
430 /* and we now see the rest of the unlink calls on both
431 * directory handles */
432 notify.smb2.in.file.handle = h1;
433 sleep(3);
434 req = smb2_notify_send(tree1, &(notify.smb2));
435 status = smb2_notify_recv(req, torture, &(notify.smb2));
436 CHECK_STATUS(status, NT_STATUS_OK);
437 CHECK_VAL(notify.smb2.out.num_changes, count-1);
438 for (i=0;i<notify.smb2.out.num_changes;i++) {
439 CHECK_VAL(notify.smb2.out.changes[i].action,
440 NOTIFY_ACTION_REMOVED);
442 notify.smb2.in.file.handle = h2;
443 req = smb2_notify_send(tree1, &(notify.smb2));
444 status = smb2_notify_recv(req, torture, &(notify.smb2));
445 CHECK_STATUS(status, NT_STATUS_OK);
446 CHECK_VAL(notify.smb2.out.num_changes, count-1);
447 for (i=0;i<notify.smb2.out.num_changes;i++) {
448 CHECK_VAL(notify.smb2.out.changes[i].action,
449 NOTIFY_ACTION_REMOVED);
452 torture_comment(torture,
453 "Testing if a close() on the dir handle triggers the notify reply\n");
455 notify.smb2.in.file.handle = h1;
456 req = smb2_notify_send(tree1, &(notify.smb2));
458 ZERO_STRUCT(cl.smb2);
459 cl.smb2.level = RAW_CLOSE_SMB2;
460 cl.smb2.in.file.handle = h1;
461 status = smb2_close(tree1, &(cl.smb2));
462 CHECK_STATUS(status, NT_STATUS_OK);
464 status = smb2_notify_recv(req, torture, &(notify.smb2));
465 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
466 CHECK_VAL(notify.smb2.out.num_changes, 9);
468 done:
469 smb2_util_close(tree1, h1);
470 smb2_util_close(tree1, h2);
471 smb2_deltree(tree1, BASEDIR);
472 return ret;
475 static struct smb2_handle custom_smb2_create(struct smb2_tree *tree,
476 struct torture_context *torture,
477 struct smb2_create *smb2)
479 struct smb2_handle h1;
480 bool ret = true;
481 NTSTATUS status;
482 smb2_deltree(tree, smb2->in.fname);
483 status = smb2_create(tree, torture, smb2);
484 CHECK_STATUS(status, NT_STATUS_OK);
485 h1 = smb2->out.file.handle;
486 done:
487 if (!ret) {
488 h1 = (struct smb2_handle) {
489 .data = { 0 , 0},
492 return h1;
496 testing of recursive change notify
499 static bool torture_smb2_notify_recursive(struct torture_context *torture,
500 struct smb2_tree *tree1,
501 struct smb2_tree *tree2)
503 bool ret = true;
504 NTSTATUS status;
505 union smb_notify notify;
506 union smb_open io, io1;
507 union smb_setfileinfo sinfo;
508 struct smb2_handle h1;
509 struct smb2_request *req1, *req2;
511 smb2_deltree(tree1, BASEDIR);
512 smb2_util_rmdir(tree1, BASEDIR);
514 torture_comment(torture, "TESTING CHANGE NOTIFY WITH RECURSION\n");
517 get a handle on the directory
519 ZERO_STRUCT(io.smb2);
520 io.generic.level = RAW_OPEN_SMB2;
521 io.smb2.in.create_flags = 0;
522 io.smb2.in.desired_access = SEC_FILE_ALL;
523 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
524 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
525 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
526 NTCREATEX_SHARE_ACCESS_WRITE;
527 io.smb2.in.alloc_size = 0;
528 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
529 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
530 io.smb2.in.security_flags = 0;
531 io.smb2.in.fname = BASEDIR;
533 status = smb2_create(tree1, torture, &(io.smb2));
534 CHECK_STATUS(status, NT_STATUS_OK);
535 h1 = io.smb2.out.file.handle;
537 /* ask for a change notify, on file or directory name
538 changes. Setup both with and without recursion */
539 ZERO_STRUCT(notify.smb2);
540 notify.smb2.level = RAW_NOTIFY_SMB2;
541 notify.smb2.in.buffer_size = 1000;
542 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
543 FILE_NOTIFY_CHANGE_ATTRIBUTES |
544 FILE_NOTIFY_CHANGE_CREATION;
545 notify.smb2.in.file.handle = h1;
547 notify.smb2.in.recursive = true;
548 req1 = smb2_notify_send(tree1, &(notify.smb2));
549 smb2_cancel(req1);
550 status = smb2_notify_recv(req1, torture, &(notify.smb2));
551 CHECK_STATUS(status, NT_STATUS_CANCELLED);
553 notify.smb2.in.recursive = false;
554 req2 = smb2_notify_send(tree1, &(notify.smb2));
555 smb2_cancel(req2);
556 status = smb2_notify_recv(req2, torture, &(notify.smb2));
557 CHECK_STATUS(status, NT_STATUS_CANCELLED);
559 ZERO_STRUCT(io1.smb2);
560 io1.generic.level = RAW_OPEN_SMB2;
561 io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
562 io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
563 SEC_RIGHTS_FILE_WRITE|
564 SEC_RIGHTS_FILE_ALL;
565 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
566 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
567 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
568 NTCREATEX_SHARE_ACCESS_WRITE |
569 NTCREATEX_SHARE_ACCESS_DELETE;
570 io1.smb2.in.alloc_size = 0;
571 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
572 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
573 io1.smb2.in.security_flags = 0;
574 io1.smb2.in.fname = BASEDIR "\\subdir-name";
575 status = smb2_create(tree2, torture, &(io1.smb2));
576 CHECK_STATUS(status, NT_STATUS_OK);
577 smb2_util_close(tree2, io1.smb2.out.file.handle);
579 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname1";
580 status = smb2_create(tree2, torture, &(io1.smb2));
581 CHECK_STATUS(status, NT_STATUS_OK);
582 ZERO_STRUCT(sinfo);
583 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
584 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
585 sinfo.rename_information.in.overwrite = 0;
586 sinfo.rename_information.in.root_fid = 0;
587 sinfo.rename_information.in.new_name =
588 BASEDIR "\\subdir-name\\subname1-r";
589 status = smb2_setinfo_file(tree2, &sinfo);
590 CHECK_STATUS(status, NT_STATUS_OK);
592 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
593 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname2";
594 status = smb2_create(tree2, torture, &(io1.smb2));
595 CHECK_STATUS(status, NT_STATUS_OK);
596 ZERO_STRUCT(sinfo);
597 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
598 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
599 sinfo.rename_information.in.overwrite = true;
600 sinfo.rename_information.in.root_fid = 0;
601 sinfo.rename_information.in.new_name = BASEDIR "\\subname2-r";
602 status = smb2_setinfo_file(tree2, &sinfo);
603 CHECK_STATUS(status, NT_STATUS_OK);
605 io1.smb2.in.fname = BASEDIR "\\subname2-r";
606 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
607 status = smb2_create(tree2, torture, &(io1.smb2));
608 CHECK_STATUS(status, NT_STATUS_OK);
609 ZERO_STRUCT(sinfo);
610 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
611 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
612 sinfo.rename_information.in.overwrite = true;
613 sinfo.rename_information.in.root_fid = 0;
614 sinfo.rename_information.in.new_name = BASEDIR "\\subname3-r";
615 status = smb2_setinfo_file(tree2, &sinfo);
616 CHECK_STATUS(status, NT_STATUS_OK);
618 notify.smb2.in.completion_filter = 0;
619 notify.smb2.in.recursive = true;
620 smb_msleep(200);
621 req1 = smb2_notify_send(tree1, &(notify.smb2));
623 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name\\subname1-r");
624 CHECK_STATUS(status, NT_STATUS_OK);
625 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name");
626 CHECK_STATUS(status, NT_STATUS_OK);
627 status = smb2_util_unlink(tree2, BASEDIR "\\subname3-r");
628 CHECK_STATUS(status, NT_STATUS_OK);
630 notify.smb2.in.recursive = false;
631 req2 = smb2_notify_send(tree1, &(notify.smb2));
633 status = smb2_notify_recv(req1, torture, &(notify.smb2));
634 CHECK_STATUS(status, NT_STATUS_OK);
636 CHECK_VAL(notify.smb2.out.num_changes, 9);
637 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
638 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
639 CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_ADDED);
640 CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name\\subname1");
641 CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_OLD_NAME);
642 CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name\\subname1");
643 CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_NEW_NAME);
644 CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name\\subname1-r");
645 CHECK_VAL(notify.smb2.out.changes[4].action, NOTIFY_ACTION_ADDED);
646 CHECK_WIRE_STR(notify.smb2.out.changes[4].name, "subdir-name\\subname2");
647 CHECK_VAL(notify.smb2.out.changes[5].action, NOTIFY_ACTION_REMOVED);
648 CHECK_WIRE_STR(notify.smb2.out.changes[5].name, "subdir-name\\subname2");
649 CHECK_VAL(notify.smb2.out.changes[6].action, NOTIFY_ACTION_ADDED);
650 CHECK_WIRE_STR(notify.smb2.out.changes[6].name, "subname2-r");
651 CHECK_VAL(notify.smb2.out.changes[7].action, NOTIFY_ACTION_OLD_NAME);
652 CHECK_WIRE_STR(notify.smb2.out.changes[7].name, "subname2-r");
653 CHECK_VAL(notify.smb2.out.changes[8].action, NOTIFY_ACTION_NEW_NAME);
654 CHECK_WIRE_STR(notify.smb2.out.changes[8].name, "subname3-r");
656 done:
657 smb2_deltree(tree1, BASEDIR);
658 return ret;
662 testing of change notify mask change
665 static bool torture_smb2_notify_mask_change(struct torture_context *torture,
666 struct smb2_tree *tree1,
667 struct smb2_tree *tree2)
669 bool ret = true;
670 NTSTATUS status;
671 union smb_notify notify;
672 union smb_open io, io1;
673 struct smb2_handle h1;
674 struct smb2_request *req1, *req2;
675 union smb_setfileinfo sinfo;
677 smb2_deltree(tree1, BASEDIR);
678 smb2_util_rmdir(tree1, BASEDIR);
680 torture_comment(torture, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
683 get a handle on the directory
685 ZERO_STRUCT(io.smb2);
686 io.generic.level = RAW_OPEN_SMB2;
687 io.smb2.in.create_flags = 0;
688 io.smb2.in.desired_access = SEC_FILE_ALL;
689 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
690 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
691 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
692 NTCREATEX_SHARE_ACCESS_WRITE;
693 io.smb2.in.alloc_size = 0;
694 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
695 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
696 io.smb2.in.security_flags = 0;
697 io.smb2.in.fname = BASEDIR;
699 status = smb2_create(tree1, torture, &(io.smb2));
700 CHECK_STATUS(status, NT_STATUS_OK);
701 h1 = io.smb2.out.file.handle;
703 /* ask for a change notify, on file or directory name
704 changes. Setup both with and without recursion */
705 ZERO_STRUCT(notify.smb2);
706 notify.smb2.level = RAW_NOTIFY_SMB2;
707 notify.smb2.in.buffer_size = 1000;
708 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
709 notify.smb2.in.file.handle = h1;
711 notify.smb2.in.recursive = true;
712 req1 = smb2_notify_send(tree1, &(notify.smb2));
714 smb2_cancel(req1);
715 status = smb2_notify_recv(req1, torture, &(notify.smb2));
716 CHECK_STATUS(status, NT_STATUS_CANCELLED);
719 notify.smb2.in.recursive = false;
720 req2 = smb2_notify_send(tree1, &(notify.smb2));
722 smb2_cancel(req2);
723 status = smb2_notify_recv(req2, torture, &(notify.smb2));
724 CHECK_STATUS(status, NT_STATUS_CANCELLED);
726 notify.smb2.in.recursive = true;
727 req1 = smb2_notify_send(tree1, &(notify.smb2));
729 /* Set to hidden then back again. */
730 ZERO_STRUCT(io1.smb2);
731 io1.generic.level = RAW_OPEN_SMB2;
732 io1.smb2.in.create_flags = 0;
733 io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
734 SEC_RIGHTS_FILE_WRITE|
735 SEC_RIGHTS_FILE_ALL;
736 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
737 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
738 NTCREATEX_SHARE_ACCESS_WRITE |
739 NTCREATEX_SHARE_ACCESS_DELETE;
740 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
741 io1.smb2.in.security_flags = 0;
742 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
743 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
744 io1.smb2.in.fname = BASEDIR "\\tname1";
746 smb2_util_close(tree1,
747 custom_smb2_create(tree1, torture, &(io1.smb2)));
748 status = smb2_util_setatr(tree1, BASEDIR "\\tname1",
749 FILE_ATTRIBUTE_HIDDEN);
750 CHECK_STATUS(status, NT_STATUS_OK);
751 smb2_util_unlink(tree1, BASEDIR "\\tname1");
753 status = smb2_notify_recv(req1, torture, &(notify.smb2));
754 CHECK_STATUS(status, NT_STATUS_OK);
756 CHECK_VAL(notify.smb2.out.num_changes, 1);
757 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
758 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
760 /* Now try and change the mask to include other events.
761 * This should not work - once the mask is set on a directory
762 * h1 it seems to be fixed until the fnum is closed. */
764 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
765 FILE_NOTIFY_CHANGE_ATTRIBUTES |
766 FILE_NOTIFY_CHANGE_CREATION;
767 notify.smb2.in.recursive = true;
768 req1 = smb2_notify_send(tree1, &(notify.smb2));
770 notify.smb2.in.recursive = false;
771 req2 = smb2_notify_send(tree1, &(notify.smb2));
773 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
774 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
775 io1.smb2.in.fname = BASEDIR "\\subdir-name";
776 status = smb2_create(tree2, torture, &(io1.smb2));
777 CHECK_STATUS(status, NT_STATUS_OK);
778 smb2_util_close(tree2, io1.smb2.out.file.handle);
780 ZERO_STRUCT(sinfo);
781 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname1";
782 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
783 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
784 status = smb2_create(tree2, torture, &(io1.smb2));
785 CHECK_STATUS(status, NT_STATUS_OK);
786 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
787 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
788 sinfo.rename_information.in.overwrite = true;
789 sinfo.rename_information.in.root_fid = 0;
790 sinfo.rename_information.in.new_name =
791 BASEDIR "\\subdir-name\\subname1-r";
792 status = smb2_setinfo_file(tree2, &sinfo);
793 CHECK_STATUS(status, NT_STATUS_OK);
795 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname2";
796 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
797 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
798 status = smb2_create(tree2, torture, &(io1.smb2));
799 CHECK_STATUS(status, NT_STATUS_OK);
800 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
801 sinfo.rename_information.in.new_name = BASEDIR "\\subname2-r";
802 status = smb2_setinfo_file(tree2, &sinfo);
803 CHECK_STATUS(status, NT_STATUS_OK);
804 smb2_util_close(tree2, io1.smb2.out.file.handle);
806 io1.smb2.in.fname = BASEDIR "\\subname2-r";
807 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
808 status = smb2_create(tree2, torture, &(io1.smb2));
809 CHECK_STATUS(status, NT_STATUS_OK);
810 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
811 sinfo.rename_information.in.new_name = BASEDIR "\\subname3-r";
812 status = smb2_setinfo_file(tree2, &sinfo);
813 CHECK_STATUS(status, NT_STATUS_OK);
814 smb2_util_close(tree2, io1.smb2.out.file.handle);
816 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name\\subname1-r");
817 CHECK_STATUS(status, NT_STATUS_OK);
818 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name");
819 CHECK_STATUS(status, NT_STATUS_OK);
820 status = smb2_util_unlink(tree2, BASEDIR "\\subname3-r");
821 CHECK_STATUS(status, NT_STATUS_OK);
823 status = smb2_notify_recv(req1, torture, &(notify.smb2));
824 CHECK_STATUS(status, NT_STATUS_OK);
826 CHECK_VAL(notify.smb2.out.num_changes, 1);
827 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
828 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname2-r");
830 status = smb2_notify_recv(req2, torture, &(notify.smb2));
831 CHECK_STATUS(status, NT_STATUS_OK);
833 CHECK_VAL(notify.smb2.out.num_changes, 1);
834 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
835 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname3-r");
837 if (!ret) {
838 goto done;
841 done:
842 smb2_deltree(tree1, BASEDIR);
843 return ret;
847 testing of mask bits for change notify
850 static bool torture_smb2_notify_mask(struct torture_context *torture,
851 struct smb2_tree *tree1,
852 struct smb2_tree *tree2)
854 bool ret = true;
855 NTSTATUS status;
856 union smb_notify notify;
857 union smb_open io, io1;
858 struct smb2_handle h1, h2;
859 uint32_t mask;
860 int i;
861 char c = 1;
862 union smb_setfileinfo sinfo;
864 smb2_deltree(tree1, BASEDIR);
865 smb2_util_rmdir(tree1, BASEDIR);
867 torture_comment(torture, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
870 ZERO_STRUCT(h1);
871 ZERO_STRUCT(h2);
873 get a handle on the directory
875 ZERO_STRUCT(io.smb2);
876 io.generic.level = RAW_OPEN_SMB2;
877 io.smb2.in.create_flags = 0;
878 io.smb2.in.desired_access = SEC_FILE_ALL;
879 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
880 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
881 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
882 NTCREATEX_SHARE_ACCESS_WRITE;
883 io.smb2.in.alloc_size = 0;
884 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
885 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
886 io.smb2.in.security_flags = 0;
887 io.smb2.in.fname = BASEDIR;
889 ZERO_STRUCT(notify.smb2);
890 notify.smb2.level = RAW_NOTIFY_SMB2;
891 notify.smb2.in.buffer_size = 1000;
892 notify.smb2.in.recursive = true;
894 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
895 expected, nchanges) \
896 do { \
897 do { for (mask=i=0;i<32;i++) { \
898 struct smb2_request *req; \
899 status = smb2_create(tree1, torture, &(io.smb2)); \
900 CHECK_STATUS(status, NT_STATUS_OK); \
901 h1 = io.smb2.out.file.handle; \
902 setup \
903 notify.smb2.in.file.handle = h1; \
904 notify.smb2.in.completion_filter = (1<<i); \
905 /* cancel initial requests so the buffer is setup */ \
906 req = smb2_notify_send(tree1, &(notify.smb2)); \
907 smb2_cancel(req); \
908 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
909 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
910 /* send the change notify request */ \
911 req = smb2_notify_send(tree1, &(notify.smb2)); \
912 op \
913 smb_msleep(200); smb2_cancel(req); \
914 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
915 cleanup \
916 smb2_util_close(tree1, h1); \
917 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
918 CHECK_STATUS(status, NT_STATUS_OK); \
919 /* special case to cope with file rename behaviour */ \
920 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
921 notify.smb2.out.changes[0].action == \
922 NOTIFY_ACTION_MODIFIED && \
923 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
924 Action == NOTIFY_ACTION_OLD_NAME) { \
925 torture_comment(torture, \
926 "(rename file special handling OK)\n"); \
927 } else if (nchanges != notify.smb2.out.num_changes) { \
928 torture_result(torture, TORTURE_FAIL, \
929 "ERROR: nchanges=%d expected=%d "\
930 "action=%d filter=0x%08x\n", \
931 notify.smb2.out.num_changes, \
932 nchanges, \
933 notify.smb2.out.changes[0].action, \
934 notify.smb2.in.completion_filter); \
935 ret = false; \
936 } else if (notify.smb2.out.changes[0].action != Action) { \
937 torture_result(torture, TORTURE_FAIL, \
938 "ERROR: nchanges=%d action=%d " \
939 "expectedAction=%d filter=0x%08x\n", \
940 notify.smb2.out.num_changes, \
941 notify.smb2.out.changes[0].action, \
942 Action, \
943 notify.smb2.in.completion_filter); \
944 ret = false; \
945 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
946 "tname1") != 0) { \
947 torture_result(torture, TORTURE_FAIL, \
948 "ERROR: nchanges=%d action=%d " \
949 "filter=0x%08x name=%s\n", \
950 notify.smb2.out.num_changes, \
951 notify.smb2.out.changes[0].action, \
952 notify.smb2.in.completion_filter, \
953 notify.smb2.out.changes[0].name.s); \
954 ret = false; \
956 mask |= (1<<i); \
958 } while (0); \
959 } while (0);
961 torture_comment(torture, "Testing mkdir\n");
962 NOTIFY_MASK_TEST("Testing mkdir",;,
963 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
964 smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
965 NOTIFY_ACTION_ADDED,
966 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
968 torture_comment(torture, "Testing create file\n");
969 ZERO_STRUCT(io1.smb2);
970 io1.generic.level = RAW_OPEN_SMB2;
971 io1.smb2.in.create_flags = 0;
972 io1.smb2.in.desired_access = SEC_FILE_ALL;
973 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
974 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
975 NTCREATEX_SHARE_ACCESS_WRITE;
976 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
977 io1.smb2.in.security_flags = 0;
978 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
979 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
980 io1.smb2.in.fname = BASEDIR "\\tname1";
982 NOTIFY_MASK_TEST("Testing create file",;,
983 smb2_util_close(tree2, custom_smb2_create(tree2,
984 torture, &(io1.smb2)));,
985 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
986 NOTIFY_ACTION_ADDED,
987 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
989 torture_comment(torture, "Testing unlink\n");
990 NOTIFY_MASK_TEST("Testing unlink",
991 smb2_util_close(tree2, custom_smb2_create(tree2,
992 torture, &(io1.smb2)));,
993 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
995 NOTIFY_ACTION_REMOVED,
996 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
998 torture_comment(torture, "Testing rmdir\n");
999 NOTIFY_MASK_TEST("Testing rmdir",
1000 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
1001 smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
1003 NOTIFY_ACTION_REMOVED,
1004 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
1006 torture_comment(torture, "Testing rename file\n");
1007 ZERO_STRUCT(sinfo);
1008 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1009 sinfo.rename_information.in.file.handle = h1;
1010 sinfo.rename_information.in.overwrite = true;
1011 sinfo.rename_information.in.root_fid = 0;
1012 sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
1013 NOTIFY_MASK_TEST("Testing rename file",
1014 smb2_util_close(tree2, custom_smb2_create(tree2,
1015 torture, &(io1.smb2)));,
1016 smb2_setinfo_file(tree2, &sinfo);,
1017 smb2_util_unlink(tree2, BASEDIR "\\tname2");,
1018 NOTIFY_ACTION_OLD_NAME,
1019 FILE_NOTIFY_CHANGE_FILE_NAME, 2);
1021 torture_comment(torture, "Testing rename dir\n");
1022 ZERO_STRUCT(sinfo);
1023 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1024 sinfo.rename_information.in.file.handle = h1;
1025 sinfo.rename_information.in.overwrite = true;
1026 sinfo.rename_information.in.root_fid = 0;
1027 sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
1028 NOTIFY_MASK_TEST("Testing rename dir",
1029 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
1030 smb2_setinfo_file(tree2, &sinfo);,
1031 smb2_util_rmdir(tree2, BASEDIR "\\tname2");,
1032 NOTIFY_ACTION_OLD_NAME,
1033 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
1035 torture_comment(torture, "Testing set path attribute\n");
1036 NOTIFY_MASK_TEST("Testing set path attribute",
1037 smb2_util_close(tree2, custom_smb2_create(tree2,
1038 torture, &(io.smb2)));,
1039 smb2_util_setatr(tree2, BASEDIR "\\tname1",
1040 FILE_ATTRIBUTE_HIDDEN);,
1041 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1042 NOTIFY_ACTION_MODIFIED,
1043 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
1045 torture_comment(torture, "Testing set path write time\n");
1046 ZERO_STRUCT(sinfo);
1047 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1048 sinfo.generic.in.file.handle = h1;
1049 sinfo.basic_info.in.write_time = 1000;
1050 NOTIFY_MASK_TEST("Testing set path write time",
1051 smb2_util_close(tree2, custom_smb2_create(tree2,
1052 torture, &(io1.smb2)));,
1053 smb2_setinfo_file(tree2, &sinfo);,
1054 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1055 NOTIFY_ACTION_MODIFIED,
1056 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
1058 if (torture_setting_bool(torture, "samba3", false)) {
1059 torture_comment(torture,
1060 "Samba3 does not yet support create times "
1061 "everywhere\n");
1063 else {
1064 ZERO_STRUCT(sinfo);
1065 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1066 sinfo.generic.in.file.handle = h1;
1067 sinfo.basic_info.in.create_time = 0;
1068 torture_comment(torture, "Testing set file create time\n");
1069 NOTIFY_MASK_TEST("Testing set file create time",
1070 smb2_create_complex_file(torture, tree2,
1071 BASEDIR "\\tname1", &h2);,
1072 smb2_setinfo_file(tree2, &sinfo);,
1073 (smb2_util_close(tree2, h2),
1074 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1075 NOTIFY_ACTION_MODIFIED,
1076 FILE_NOTIFY_CHANGE_CREATION, 1);
1079 ZERO_STRUCT(sinfo);
1080 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1081 sinfo.generic.in.file.handle = h1;
1082 sinfo.basic_info.in.access_time = 0;
1083 torture_comment(torture, "Testing set file access time\n");
1084 NOTIFY_MASK_TEST("Testing set file access time",
1085 smb2_create_complex_file(torture, tree2, BASEDIR "\\tname1", &h2);,
1086 smb2_setinfo_file(tree2, &sinfo);,
1087 (smb2_util_close(tree2, h2),
1088 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1089 NOTIFY_ACTION_MODIFIED,
1090 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
1092 ZERO_STRUCT(sinfo);
1093 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1094 sinfo.generic.in.file.handle = h1;
1095 sinfo.basic_info.in.change_time = 0;
1096 torture_comment(torture, "Testing set file change time\n");
1097 NOTIFY_MASK_TEST("Testing set file change time",
1098 smb2_create_complex_file(torture, tree2, BASEDIR "\\tname1", &h2);,
1099 smb2_setinfo_file(tree2, &sinfo);,
1100 (smb2_util_close(tree2, h2),
1101 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1102 NOTIFY_ACTION_MODIFIED,
1103 0, 1);
1106 torture_comment(torture, "Testing write\n");
1107 NOTIFY_MASK_TEST("Testing write",
1108 smb2_create_complex_file(torture, tree2, BASEDIR "\\tname1", &h2);,
1109 smb2_util_write(tree2, h2, &c, 10000, 1);,
1110 (smb2_util_close(tree2, h2),
1111 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1112 NOTIFY_ACTION_MODIFIED,
1113 0, 1);
1115 done:
1116 smb2_deltree(tree1, BASEDIR);
1117 return ret;
1121 basic testing of change notify on files
1123 static bool torture_smb2_notify_file(struct torture_context *torture,
1124 struct smb2_tree *tree)
1126 NTSTATUS status;
1127 bool ret = true;
1128 union smb_open io;
1129 union smb_close cl;
1130 union smb_notify notify;
1131 struct smb2_request *req;
1132 struct smb2_handle h1;
1133 const char *fname = BASEDIR "\\file.txt";
1135 smb2_deltree(tree, BASEDIR);
1136 smb2_util_rmdir(tree, BASEDIR);
1138 torture_comment(torture, "TESTING CHANGE NOTIFY ON FILES\n");
1139 status = torture_smb2_testdir(tree, BASEDIR, &h1);
1140 CHECK_STATUS(status, NT_STATUS_OK);
1142 ZERO_STRUCT(io.smb2);
1143 io.generic.level = RAW_OPEN_SMB2;
1144 io.smb2.in.create_flags = 0;
1145 io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
1146 io.smb2.in.create_options = 0;
1147 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1148 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1149 NTCREATEX_SHARE_ACCESS_WRITE;
1150 io.smb2.in.alloc_size = 0;
1151 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1152 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1153 io.smb2.in.security_flags = 0;
1154 io.smb2.in.fname = fname;
1155 status = smb2_create(tree, torture, &(io.smb2));
1156 CHECK_STATUS(status, NT_STATUS_OK);
1157 h1 = io.smb2.out.file.handle;
1159 /* ask for a change notify,
1160 on file or directory name changes */
1161 ZERO_STRUCT(notify.smb2);
1162 notify.smb2.level = RAW_NOTIFY_SMB2;
1163 notify.smb2.in.file.handle = h1;
1164 notify.smb2.in.buffer_size = 1000;
1165 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
1166 notify.smb2.in.recursive = false;
1168 torture_comment(torture,
1169 "Testing if notifies on file handles are invalid (should be)\n");
1171 req = smb2_notify_send(tree, &(notify.smb2));
1172 status = smb2_notify_recv(req, torture, &(notify.smb2));
1173 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1175 ZERO_STRUCT(cl.smb2);
1176 cl.close.level = RAW_CLOSE_SMB2;
1177 cl.close.in.file.handle = h1;
1178 status = smb2_close(tree, &(cl.smb2));
1179 CHECK_STATUS(status, NT_STATUS_OK);
1181 status = smb2_util_unlink(tree, fname);
1182 CHECK_STATUS(status, NT_STATUS_OK);
1184 done:
1185 smb2_deltree(tree, BASEDIR);
1186 return ret;
1189 basic testing of change notifies followed by a tdis
1192 static bool torture_smb2_notify_tree_disconnect(
1193 struct torture_context *torture,
1194 struct smb2_tree *tree)
1196 bool ret = true;
1197 NTSTATUS status;
1198 union smb_notify notify;
1199 union smb_open io;
1200 struct smb2_handle h1;
1201 struct smb2_request *req;
1203 smb2_deltree(tree, BASEDIR);
1204 smb2_util_rmdir(tree, BASEDIR);
1206 torture_comment(torture, "TESTING CHANGE NOTIFY+CANCEL FOLLOWED BY "
1207 "TREE-DISCONNECT\n");
1210 get a handle on the directory
1212 ZERO_STRUCT(io.smb2);
1213 io.generic.level = RAW_OPEN_SMB2;
1214 io.smb2.in.create_flags = 0;
1215 io.smb2.in.desired_access = SEC_FILE_ALL;
1216 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1217 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1218 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1219 NTCREATEX_SHARE_ACCESS_WRITE;
1220 io.smb2.in.alloc_size = 0;
1221 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1222 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1223 io.smb2.in.security_flags = 0;
1224 io.smb2.in.fname = BASEDIR;
1226 status = smb2_create(tree, torture, &(io.smb2));
1227 CHECK_STATUS(status, NT_STATUS_OK);
1228 h1 = io.smb2.out.file.handle;
1230 /* ask for a change notify,
1231 on file or directory name changes */
1232 ZERO_STRUCT(notify.smb2);
1233 notify.smb2.level = RAW_NOTIFY_SMB2;
1234 notify.smb2.in.buffer_size = 1000;
1235 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1236 notify.smb2.in.file.handle = h1;
1237 notify.smb2.in.recursive = true;
1239 req = smb2_notify_send(tree, &(notify.smb2));
1240 smb2_cancel(req);
1241 status = smb2_notify_recv(req, torture, &(notify.smb2));
1243 status = smb2_tdis(tree);
1244 CHECK_STATUS(status, NT_STATUS_OK);
1246 req = smb2_notify_send(tree, &(notify.smb2));
1248 smb2_notify_recv(req, torture, &(notify.smb2));
1249 CHECK_STATUS(status, NT_STATUS_OK);
1250 CHECK_VAL(notify.smb2.out.num_changes, 0);
1252 done:
1253 smb2_deltree(tree, BASEDIR);
1254 return ret;
1258 testing of change notifies followed by a tdis - no cancel
1261 static bool torture_smb2_notify_tree_disconnect_1(
1262 struct torture_context *torture,
1263 struct smb2_tree *tree)
1265 bool ret = true;
1266 NTSTATUS status;
1267 union smb_notify notify;
1268 union smb_open io;
1269 struct smb2_handle h1;
1270 struct smb2_request *req;
1272 smb2_deltree(tree, BASEDIR);
1273 smb2_util_rmdir(tree, BASEDIR);
1275 torture_comment(torture, "TESTING CHANGE NOTIFY ASYNC FOLLOWED BY "
1276 "TREE-DISCONNECT\n");
1279 get a handle on the directory
1281 ZERO_STRUCT(io.smb2);
1282 io.generic.level = RAW_OPEN_SMB2;
1283 io.smb2.in.create_flags = 0;
1284 io.smb2.in.desired_access = SEC_FILE_ALL;
1285 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1286 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1287 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1288 NTCREATEX_SHARE_ACCESS_WRITE;
1289 io.smb2.in.alloc_size = 0;
1290 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1291 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1292 io.smb2.in.security_flags = 0;
1293 io.smb2.in.fname = BASEDIR;
1295 status = smb2_create(tree, torture, &(io.smb2));
1296 CHECK_STATUS(status, NT_STATUS_OK);
1297 h1 = io.smb2.out.file.handle;
1299 /* ask for a change notify,
1300 on file or directory name changes */
1301 ZERO_STRUCT(notify.smb2);
1302 notify.smb2.level = RAW_NOTIFY_SMB2;
1303 notify.smb2.in.buffer_size = 1000;
1304 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1305 notify.smb2.in.file.handle = h1;
1306 notify.smb2.in.recursive = true;
1308 req = smb2_notify_send(tree, &(notify.smb2));
1309 WAIT_FOR_ASYNC_RESPONSE(req);
1311 status = smb2_tdis(tree);
1312 CHECK_STATUS(status, NT_STATUS_OK);
1314 status = smb2_notify_recv(req, torture, &(notify.smb2));
1315 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1316 CHECK_VAL(notify.smb2.out.num_changes, 0);
1318 done:
1319 smb2_deltree(tree, BASEDIR);
1320 return ret;
1324 basic testing of change notifies followed by a close
1327 static bool torture_smb2_notify_close(struct torture_context *torture,
1328 struct smb2_tree *tree1)
1330 bool ret = true;
1331 NTSTATUS status;
1332 union smb_notify notify;
1333 union smb_open io;
1334 struct smb2_handle h1;
1335 struct smb2_request *req;
1337 smb2_deltree(tree1, BASEDIR);
1338 smb2_util_rmdir(tree1, BASEDIR);
1340 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1343 get a handle on the directory
1345 ZERO_STRUCT(io.smb2);
1346 io.generic.level = RAW_OPEN_SMB2;
1347 io.smb2.in.create_flags = 0;
1348 io.smb2.in.desired_access = SEC_FILE_ALL;
1349 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1350 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1351 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1352 NTCREATEX_SHARE_ACCESS_WRITE;
1353 io.smb2.in.alloc_size = 0;
1354 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1355 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1356 io.smb2.in.security_flags = 0;
1357 io.smb2.in.fname = BASEDIR;
1359 status = smb2_create(tree1, torture, &(io.smb2));
1360 CHECK_STATUS(status, NT_STATUS_OK);
1362 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1363 status = smb2_create(tree1, torture, &(io.smb2));
1364 CHECK_STATUS(status, NT_STATUS_OK);
1365 h1 = io.smb2.out.file.handle;
1367 /* ask for a change notify,
1368 on file or directory name changes */
1369 ZERO_STRUCT(notify.smb2);
1370 notify.smb2.level = RAW_NOTIFY_SMB2;
1371 notify.smb2.in.buffer_size = 1000;
1372 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1373 notify.smb2.in.file.handle = h1;
1374 notify.smb2.in.recursive = true;
1376 req = smb2_notify_send(tree1, &(notify.smb2));
1378 WAIT_FOR_ASYNC_RESPONSE(req);
1380 status = smb2_util_close(tree1, h1);
1381 CHECK_STATUS(status, NT_STATUS_OK);
1383 status = smb2_notify_recv(req, torture, &(notify.smb2));
1384 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1385 CHECK_VAL(notify.smb2.out.num_changes, 0);
1387 done:
1388 smb2_deltree(tree1, BASEDIR);
1389 return ret;
1393 basic testing of change notifies followed by a ulogoff
1396 static bool torture_smb2_notify_ulogoff(struct torture_context *torture,
1397 struct smb2_tree *tree1)
1399 bool ret = true;
1400 NTSTATUS status;
1401 union smb_notify notify;
1402 union smb_open io;
1403 struct smb2_handle h1;
1404 struct smb2_request *req;
1406 smb2_deltree(tree1, BASEDIR);
1407 smb2_util_rmdir(tree1, BASEDIR);
1409 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1412 get a handle on the directory
1414 ZERO_STRUCT(io.smb2);
1415 io.generic.level = RAW_OPEN_SMB2;
1416 io.smb2.in.create_flags = 0;
1417 io.smb2.in.desired_access = SEC_FILE_ALL;
1418 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1419 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1420 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1421 NTCREATEX_SHARE_ACCESS_WRITE;
1422 io.smb2.in.alloc_size = 0;
1423 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1424 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1425 io.smb2.in.security_flags = 0;
1426 io.smb2.in.fname = BASEDIR;
1428 status = smb2_create(tree1, torture, &(io.smb2));
1429 CHECK_STATUS(status, NT_STATUS_OK);
1431 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1432 status = smb2_create(tree1, torture, &(io.smb2));
1433 CHECK_STATUS(status, NT_STATUS_OK);
1434 h1 = io.smb2.out.file.handle;
1436 /* ask for a change notify,
1437 on file or directory name changes */
1438 ZERO_STRUCT(notify.smb2);
1439 notify.smb2.level = RAW_NOTIFY_SMB2;
1440 notify.smb2.in.buffer_size = 1000;
1441 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1442 notify.smb2.in.file.handle = h1;
1443 notify.smb2.in.recursive = true;
1445 req = smb2_notify_send(tree1, &(notify.smb2));
1447 WAIT_FOR_ASYNC_RESPONSE(req);
1449 status = smb2_logoff(tree1->session);
1450 CHECK_STATUS(status, NT_STATUS_OK);
1452 status = smb2_notify_recv(req, torture, &(notify.smb2));
1453 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1454 CHECK_VAL(notify.smb2.out.num_changes, 0);
1456 done:
1457 smb2_deltree(tree1, BASEDIR);
1458 return ret;
1462 basic testing of change notifies followed by a session reconnect
1465 static bool torture_smb2_notify_session_reconnect(struct torture_context *torture,
1466 struct smb2_tree *tree1)
1468 bool ret = true;
1469 NTSTATUS status;
1470 union smb_notify notify;
1471 union smb_open io;
1472 struct smb2_handle h1;
1473 struct smb2_request *req;
1474 uint64_t previous_session_id = 0;
1475 struct smb2_session *session2 = NULL;
1477 smb2_deltree(tree1, BASEDIR);
1478 smb2_util_rmdir(tree1, BASEDIR);
1480 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY SESSION RECONNECT\n");
1483 get a handle on the directory
1485 ZERO_STRUCT(io.smb2);
1486 io.generic.level = RAW_OPEN_SMB2;
1487 io.smb2.in.create_flags = 0;
1488 io.smb2.in.desired_access = SEC_FILE_ALL;
1489 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1490 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1491 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1492 NTCREATEX_SHARE_ACCESS_WRITE;
1493 io.smb2.in.alloc_size = 0;
1494 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1495 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1496 io.smb2.in.security_flags = 0;
1497 io.smb2.in.fname = BASEDIR;
1499 status = smb2_create(tree1, torture, &(io.smb2));
1500 CHECK_STATUS(status, NT_STATUS_OK);
1502 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1503 status = smb2_create(tree1, torture, &(io.smb2));
1504 CHECK_STATUS(status, NT_STATUS_OK);
1505 h1 = io.smb2.out.file.handle;
1507 /* ask for a change notify,
1508 on file or directory name changes */
1509 ZERO_STRUCT(notify.smb2);
1510 notify.smb2.level = RAW_NOTIFY_SMB2;
1511 notify.smb2.in.buffer_size = 1000;
1512 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1513 notify.smb2.in.file.handle = h1;
1514 notify.smb2.in.recursive = true;
1516 req = smb2_notify_send(tree1, &(notify.smb2));
1518 WAIT_FOR_ASYNC_RESPONSE(req);
1520 previous_session_id = smb2cli_session_current_id(tree1->session->smbXcli);
1521 torture_assert(torture, torture_smb2_session_setup(torture,
1522 tree1->session->transport,
1523 previous_session_id,
1524 torture, &session2),
1525 "session setup with previous_session_id failed");
1527 status = smb2_notify_recv(req, torture, &(notify.smb2));
1528 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1529 CHECK_VAL(notify.smb2.out.num_changes, 0);
1531 status = smb2_logoff(tree1->session);
1532 CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
1534 status = smb2_logoff(session2);
1535 CHECK_STATUS(status, NT_STATUS_OK);
1536 done:
1537 smb2_deltree(tree1, BASEDIR);
1538 return ret;
1542 basic testing of change notifies followed by an invalid reauth
1545 static bool torture_smb2_notify_invalid_reauth(struct torture_context *torture,
1546 struct smb2_tree *tree1,
1547 struct smb2_tree *tree2)
1549 bool ret = true;
1550 NTSTATUS status;
1551 union smb_notify notify;
1552 union smb_open io;
1553 struct smb2_handle h1;
1554 struct smb2_request *req;
1555 struct cli_credentials *invalid_creds;
1557 smb2_deltree(tree2, BASEDIR);
1558 smb2_util_rmdir(tree2, BASEDIR);
1560 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY invalid REAUTH\n");
1563 get a handle on the directory
1565 ZERO_STRUCT(io.smb2);
1566 io.generic.level = RAW_OPEN_SMB2;
1567 io.smb2.in.create_flags = 0;
1568 io.smb2.in.desired_access = SEC_FILE_ALL;
1569 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1570 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1571 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1572 NTCREATEX_SHARE_ACCESS_WRITE;
1573 io.smb2.in.alloc_size = 0;
1574 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1575 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1576 io.smb2.in.security_flags = 0;
1577 io.smb2.in.fname = BASEDIR;
1579 status = smb2_create(tree1, torture, &(io.smb2));
1580 CHECK_STATUS(status, NT_STATUS_OK);
1582 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1583 status = smb2_create(tree1, torture, &(io.smb2));
1584 CHECK_STATUS(status, NT_STATUS_OK);
1585 h1 = io.smb2.out.file.handle;
1587 /* ask for a change notify,
1588 on file or directory name changes */
1589 ZERO_STRUCT(notify.smb2);
1590 notify.smb2.level = RAW_NOTIFY_SMB2;
1591 notify.smb2.in.buffer_size = 1000;
1592 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1593 notify.smb2.in.file.handle = h1;
1594 notify.smb2.in.recursive = true;
1596 req = smb2_notify_send(tree1, &(notify.smb2));
1598 WAIT_FOR_ASYNC_RESPONSE(req);
1600 invalid_creds = cli_credentials_init(torture);
1601 torture_assert(torture, (invalid_creds != NULL), "talloc error");
1602 cli_credentials_set_username(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1603 cli_credentials_set_domain(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1604 cli_credentials_set_password(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1605 cli_credentials_set_realm(invalid_creds, NULL, CRED_SPECIFIED);
1606 cli_credentials_set_workstation(invalid_creds, "", CRED_UNINITIALISED);
1608 status = smb2_session_setup_spnego(tree1->session,
1609 invalid_creds,
1610 0 /* previous_session_id */);
1611 CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE);
1613 status = smb2_notify_recv(req, torture, &(notify.smb2));
1614 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1615 CHECK_VAL(notify.smb2.out.num_changes, 0);
1617 done:
1618 smb2_deltree(tree2, BASEDIR);
1619 return ret;
1622 static void tcp_dis_handler(struct smb2_transport *t, void *p)
1624 struct smb2_tree *tree = (struct smb2_tree *)p;
1625 smb2_transport_dead(tree->session->transport,
1626 NT_STATUS_LOCAL_DISCONNECT);
1627 t = NULL;
1628 tree = NULL;
1632 basic testing of change notifies followed by tcp disconnect
1635 static bool torture_smb2_notify_tcp_disconnect(
1636 struct torture_context *torture,
1637 struct smb2_tree *tree)
1639 bool ret = true;
1640 NTSTATUS status;
1641 union smb_notify notify;
1642 union smb_open io;
1643 struct smb2_handle h1;
1644 struct smb2_request *req;
1646 smb2_deltree(tree, BASEDIR);
1647 smb2_util_rmdir(tree, BASEDIR);
1649 torture_comment(torture,
1650 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1653 get a handle on the directory
1655 ZERO_STRUCT(io.smb2);
1656 io.generic.level = RAW_OPEN_SMB2;
1657 io.smb2.in.create_flags = 0;
1658 io.smb2.in.desired_access = SEC_FILE_ALL;
1659 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1660 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1661 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1662 NTCREATEX_SHARE_ACCESS_WRITE;
1663 io.smb2.in.alloc_size = 0;
1664 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1665 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1666 io.smb2.in.security_flags = 0;
1667 io.smb2.in.fname = BASEDIR;
1669 status = smb2_create(tree, torture, &(io.smb2));
1670 CHECK_STATUS(status, NT_STATUS_OK);
1671 h1 = io.smb2.out.file.handle;
1673 /* ask for a change notify,
1674 on file or directory name changes */
1675 ZERO_STRUCT(notify.smb2);
1676 notify.smb2.level = RAW_NOTIFY_SMB2;
1677 notify.smb2.in.buffer_size = 1000;
1678 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1679 notify.smb2.in.file.handle = h1;
1680 notify.smb2.in.recursive = true;
1682 req = smb2_notify_send(tree, &(notify.smb2));
1683 smb2_cancel(req);
1684 status = smb2_notify_recv(req, torture, &(notify.smb2));
1685 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1687 notify.smb2.in.recursive = true;
1688 req = smb2_notify_send(tree, &(notify.smb2));
1689 smb2_transport_idle_handler(tree->session->transport,
1690 tcp_dis_handler, 250, tree);
1691 tree = NULL;
1692 status = smb2_notify_recv(req, torture, &(notify.smb2));
1693 CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
1695 done:
1696 return ret;
1700 test setting up two change notify requests on one handle
1703 static bool torture_smb2_notify_double(struct torture_context *torture,
1704 struct smb2_tree *tree1,
1705 struct smb2_tree *tree2)
1707 bool ret = true;
1708 NTSTATUS status;
1709 union smb_notify notify;
1710 union smb_open io;
1711 struct smb2_handle h1;
1712 struct smb2_request *req1, *req2;
1714 smb2_deltree(tree1, BASEDIR);
1715 smb2_util_rmdir(tree1, BASEDIR);
1717 torture_comment(torture,
1718 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1721 get a handle on the directory
1723 ZERO_STRUCT(io.smb2);
1724 io.generic.level = RAW_OPEN_SMB2;
1725 io.smb2.in.create_flags = 0;
1726 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ|
1727 SEC_RIGHTS_FILE_WRITE|
1728 SEC_RIGHTS_FILE_ALL;
1729 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1730 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1731 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1732 NTCREATEX_SHARE_ACCESS_WRITE;
1733 io.smb2.in.alloc_size = 0;
1734 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1735 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1736 io.smb2.in.security_flags = 0;
1737 io.smb2.in.fname = BASEDIR;
1739 status = smb2_create(tree1, torture, &(io.smb2));
1740 CHECK_STATUS(status, NT_STATUS_OK);
1741 h1 = io.smb2.out.file.handle;
1743 /* ask for a change notify,
1744 on file or directory name changes */
1745 ZERO_STRUCT(notify.smb2);
1746 notify.smb2.level = RAW_NOTIFY_SMB2;
1747 notify.smb2.in.buffer_size = 1000;
1748 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1749 notify.smb2.in.file.handle = h1;
1750 notify.smb2.in.recursive = true;
1752 req1 = smb2_notify_send(tree1, &(notify.smb2));
1753 smb2_cancel(req1);
1754 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1755 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1757 req2 = smb2_notify_send(tree1, &(notify.smb2));
1758 smb2_cancel(req2);
1759 status = smb2_notify_recv(req2, torture, &(notify.smb2));
1760 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1762 smb2_util_mkdir(tree2, BASEDIR "\\subdir-name");
1763 req1 = smb2_notify_send(tree1, &(notify.smb2));
1764 req2 = smb2_notify_send(tree1, &(notify.smb2));
1766 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1767 CHECK_STATUS(status, NT_STATUS_OK);
1768 CHECK_VAL(notify.smb2.out.num_changes, 1);
1769 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1771 smb2_util_mkdir(tree2, BASEDIR "\\subdir-name2");
1773 status = smb2_notify_recv(req2, torture, &(notify.smb2));
1774 CHECK_STATUS(status, NT_STATUS_OK);
1775 CHECK_VAL(notify.smb2.out.num_changes, 1);
1776 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name2");
1778 done:
1779 smb2_deltree(tree1, BASEDIR);
1780 return ret;
1785 test multiple change notifies at different depths and with/without recursion
1788 static bool torture_smb2_notify_tree(struct torture_context *torture,
1789 struct smb2_tree *tree)
1791 bool ret = true;
1792 union smb_notify notify;
1793 union smb_open io;
1794 struct smb2_request *req;
1795 struct timeval tv;
1796 struct {
1797 const char *path;
1798 bool recursive;
1799 uint32_t filter;
1800 int expected;
1801 struct smb2_handle h1;
1802 int counted;
1803 } dirs[] = {
1804 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 30 },
1805 {BASEDIR "\\zqy", true, FILE_NOTIFY_CHANGE_NAME, 8 },
1806 {BASEDIR "\\atsy", true, FILE_NOTIFY_CHANGE_NAME, 4 },
1807 {BASEDIR "\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1808 {BASEDIR "\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME, 13 },
1809 {BASEDIR "\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME, 7 },
1810 {BASEDIR "\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1811 {BASEDIR "\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1812 {BASEDIR "\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1813 {BASEDIR "\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1814 {BASEDIR "\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1815 {BASEDIR "\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1816 {BASEDIR "\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME, 40 },
1817 {BASEDIR, true, FILE_NOTIFY_CHANGE_NAME, 40 },
1818 {BASEDIR, false,FILE_NOTIFY_CHANGE_NAME, 6 },
1819 {BASEDIR "\\atsy", false,FILE_NOTIFY_CHANGE_NAME, 4 },
1820 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1821 {BASEDIR "\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1822 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1823 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1825 int i;
1826 NTSTATUS status;
1827 bool all_done = false;
1829 smb2_deltree(tree, BASEDIR);
1830 smb2_util_rmdir(tree, BASEDIR);
1832 torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1834 ZERO_STRUCT(io.smb2);
1835 io.generic.level = RAW_OPEN_SMB2;
1836 io.smb2.in.create_flags = 0;
1837 io.smb2.in.desired_access = SEC_FILE_ALL;
1838 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1839 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1840 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1841 NTCREATEX_SHARE_ACCESS_WRITE;
1842 io.smb2.in.alloc_size = 0;
1843 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1844 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1845 io.smb2.in.security_flags = 0;
1846 io.smb2.in.fname = BASEDIR;
1847 status = smb2_create(tree, torture, &(io.smb2));
1848 CHECK_STATUS(status, NT_STATUS_OK);
1850 ZERO_STRUCT(notify.smb2);
1851 notify.smb2.level = RAW_NOTIFY_SMB2;
1852 notify.smb2.in.buffer_size = 20000;
1855 setup the directory tree, and the notify buffer on each directory
1857 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1858 io.smb2.in.fname = dirs[i].path;
1859 status = smb2_create(tree, torture, &(io.smb2));
1860 CHECK_STATUS(status, NT_STATUS_OK);
1861 dirs[i].h1 = io.smb2.out.file.handle;
1863 notify.smb2.in.completion_filter = dirs[i].filter;
1864 notify.smb2.in.file.handle = dirs[i].h1;
1865 notify.smb2.in.recursive = dirs[i].recursive;
1866 req = smb2_notify_send(tree, &(notify.smb2));
1867 smb2_cancel(req);
1868 status = smb2_notify_recv(req, torture, &(notify.smb2));
1869 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1872 /* trigger 2 events in each dir */
1873 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1874 char *path = talloc_asprintf(torture, "%s\\test.dir",
1875 dirs[i].path);
1876 smb2_util_mkdir(tree, path);
1877 smb2_util_rmdir(tree, path);
1878 talloc_free(path);
1881 /* give a bit of time for the events to propogate */
1882 tv = timeval_current();
1884 do {
1885 /* count events that have happened in each dir */
1886 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1887 notify.smb2.in.completion_filter = dirs[i].filter;
1888 notify.smb2.in.file.handle = dirs[i].h1;
1889 notify.smb2.in.recursive = dirs[i].recursive;
1890 req = smb2_notify_send(tree, &(notify.smb2));
1891 smb2_cancel(req);
1892 notify.smb2.out.num_changes = 0;
1893 status = smb2_notify_recv(req, torture,
1894 &(notify.smb2));
1895 dirs[i].counted += notify.smb2.out.num_changes;
1898 all_done = true;
1900 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1901 if (dirs[i].counted != dirs[i].expected) {
1902 all_done = false;
1905 } while (!all_done && timeval_elapsed(&tv) < 20);
1907 torture_comment(torture, "took %.4f seconds to propogate all events\n",
1908 timeval_elapsed(&tv));
1910 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1911 if (dirs[i].counted != dirs[i].expected) {
1912 torture_comment(torture,
1913 "ERROR: i=%d expected %d got %d for '%s'\n",
1914 i, dirs[i].expected, dirs[i].counted,
1915 dirs[i].path);
1916 ret = false;
1921 run from the back, closing and deleting
1923 for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1924 smb2_util_close(tree, dirs[i].h1);
1925 smb2_util_rmdir(tree, dirs[i].path);
1928 done:
1929 smb2_deltree(tree, BASEDIR);
1930 smb2_util_rmdir(tree, BASEDIR);
1931 return ret;
1935 Test response when cached server events exceed single NT NOTFIY response
1936 packet size.
1939 static bool torture_smb2_notify_overflow(struct torture_context *torture,
1940 struct smb2_tree *tree)
1942 bool ret = true;
1943 NTSTATUS status;
1944 union smb_notify notify;
1945 union smb_open io;
1946 struct smb2_handle h1, h2;
1947 int count = 100;
1948 struct smb2_request *req1;
1949 int i;
1951 smb2_deltree(tree, BASEDIR);
1952 smb2_util_rmdir(tree, BASEDIR);
1954 torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1956 /* get a handle on the directory */
1957 ZERO_STRUCT(io.smb2);
1958 io.generic.level = RAW_OPEN_SMB2;
1959 io.smb2.in.create_flags = 0;
1960 io.smb2.in.desired_access = SEC_FILE_ALL;
1961 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1962 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1963 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1964 NTCREATEX_SHARE_ACCESS_WRITE;
1965 io.smb2.in.alloc_size = 0;
1966 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1967 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1968 io.smb2.in.security_flags = 0;
1969 io.smb2.in.fname = BASEDIR;
1971 status = smb2_create(tree, torture, &(io.smb2));
1972 CHECK_STATUS(status, NT_STATUS_OK);
1973 h1 = io.smb2.out.file.handle;
1975 /* ask for a change notify, on name changes. */
1976 ZERO_STRUCT(notify.smb2);
1977 notify.smb2.level = RAW_NOTIFY_NTTRANS;
1978 notify.smb2.in.buffer_size = 1000;
1979 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1980 notify.smb2.in.file.handle = h1;
1982 notify.smb2.in.recursive = true;
1983 req1 = smb2_notify_send(tree, &(notify.smb2));
1985 /* cancel initial requests so the buffer is setup */
1986 smb2_cancel(req1);
1987 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1988 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1990 /* open a lot of files, filling up the server side notify buffer */
1991 torture_comment(torture,
1992 "Testing overflowed buffer notify on create of %d files\n",
1993 count);
1995 for (i=0;i<count;i++) {
1996 char *fname = talloc_asprintf(torture,
1997 BASEDIR "\\test%d.txt", i);
1998 union smb_open io1;
1999 ZERO_STRUCT(io1.smb2);
2000 io1.generic.level = RAW_OPEN_SMB2;
2001 io1.smb2.in.create_flags = 0;
2002 io1.smb2.in.desired_access = SEC_FILE_ALL;
2003 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2004 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2005 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2006 NTCREATEX_SHARE_ACCESS_WRITE;
2007 io1.smb2.in.alloc_size = 0;
2008 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2009 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2010 io1.smb2.in.security_flags = 0;
2011 io1.smb2.in.fname = fname;
2013 h2 = custom_smb2_create(tree, torture, &(io1.smb2));
2014 talloc_free(fname);
2015 smb2_util_close(tree, h2);
2018 req1 = smb2_notify_send(tree, &(notify.smb2));
2019 status = smb2_notify_recv(req1, torture, &(notify.smb2));
2020 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
2021 CHECK_VAL(notify.smb2.out.num_changes, 0);
2023 done:
2024 smb2_deltree(tree, BASEDIR);
2025 return ret;
2029 Test if notifications are returned for changes to the base directory.
2030 They shouldn't be.
2033 static bool torture_smb2_notify_basedir(struct torture_context *torture,
2034 struct smb2_tree *tree1,
2035 struct smb2_tree *tree2)
2037 bool ret = true;
2038 NTSTATUS status;
2039 union smb_notify notify;
2040 union smb_open io;
2041 struct smb2_handle h1;
2042 struct smb2_request *req1;
2044 smb2_deltree(tree1, BASEDIR);
2045 smb2_util_rmdir(tree1, BASEDIR);
2047 torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
2049 /* get a handle on the directory */
2050 ZERO_STRUCT(io.smb2);
2051 io.generic.level = RAW_OPEN_SMB2;
2052 io.smb2.in.create_flags = 0;
2053 io.smb2.in.desired_access = SEC_FILE_ALL;
2054 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2055 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2056 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2057 NTCREATEX_SHARE_ACCESS_WRITE;
2058 io.smb2.in.alloc_size = 0;
2059 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2060 io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
2061 io.smb2.in.security_flags = 0;
2062 io.smb2.in.fname = BASEDIR;
2064 status = smb2_create(tree1, torture, &(io.smb2));
2065 CHECK_STATUS(status, NT_STATUS_OK);
2066 h1 = io.smb2.out.file.handle;
2068 /* create a test file that will also be modified */
2069 io.smb2.in.fname = BASEDIR "\\tname1";
2070 io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
2071 status = smb2_create(tree2, torture, &(io.smb2));
2072 CHECK_STATUS(status,NT_STATUS_OK);
2073 smb2_util_close(tree2, io.smb2.out.file.handle);
2075 /* ask for a change notify, on attribute changes. */
2076 ZERO_STRUCT(notify.smb2);
2077 notify.smb2.level = RAW_NOTIFY_SMB2;
2078 notify.smb2.in.buffer_size = 1000;
2079 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
2080 notify.smb2.in.file.handle = h1;
2081 notify.smb2.in.recursive = true;
2083 req1 = smb2_notify_send(tree1, &(notify.smb2));
2085 /* set attribute on the base dir */
2086 smb2_util_setatr(tree2, BASEDIR, FILE_ATTRIBUTE_HIDDEN);
2088 /* set attribute on a file to assure we receive a notification */
2089 smb2_util_setatr(tree2, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN);
2090 smb_msleep(200);
2092 /* check how many responses were given, expect only 1 for the file */
2093 status = smb2_notify_recv(req1, torture, &(notify.smb2));
2094 CHECK_STATUS(status, NT_STATUS_OK);
2095 CHECK_VAL(notify.smb2.out.num_changes, 1);
2096 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
2097 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
2099 done:
2100 smb2_deltree(tree1, BASEDIR);
2101 return ret;
2105 very simple change notify test
2107 static bool torture_smb2_notify_tcon(struct torture_context *torture,
2108 struct smb2_tree *tree)
2110 bool ret = true;
2111 NTSTATUS status;
2112 union smb_notify notify;
2113 union smb_open io;
2114 struct smb2_handle h1 = {{0}};
2115 struct smb2_request *req = NULL;
2116 struct smb2_tree *tree1 = NULL;
2117 const char *fname = BASEDIR "\\subdir-name";
2119 smb2_deltree(tree, BASEDIR);
2120 smb2_util_rmdir(tree, BASEDIR);
2122 torture_comment(torture, "TESTING SIMPLE CHANGE NOTIFY\n");
2125 get a handle on the directory
2128 ZERO_STRUCT(io.smb2);
2129 io.generic.level = RAW_OPEN_SMB2;
2130 io.smb2.in.create_flags = 0;
2131 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2132 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2133 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL |
2134 FILE_ATTRIBUTE_DIRECTORY;
2135 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2136 NTCREATEX_SHARE_ACCESS_WRITE;
2137 io.smb2.in.alloc_size = 0;
2138 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2139 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2140 io.smb2.in.security_flags = 0;
2141 io.smb2.in.fname = BASEDIR;
2143 status = smb2_create(tree, torture, &(io.smb2));
2144 CHECK_STATUS(status, NT_STATUS_OK);
2145 h1 = io.smb2.out.file.handle;
2147 /* ask for a change notify,
2148 on file or directory name changes */
2149 ZERO_STRUCT(notify.smb2);
2150 notify.smb2.level = RAW_NOTIFY_SMB2;
2151 notify.smb2.in.buffer_size = 1000;
2152 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2153 notify.smb2.in.file.handle = h1;
2154 notify.smb2.in.recursive = true;
2156 torture_comment(torture, "Testing notify mkdir\n");
2157 req = smb2_notify_send(tree, &(notify.smb2));
2158 smb2_cancel(req);
2159 status = smb2_notify_recv(req, torture, &(notify.smb2));
2160 CHECK_STATUS(status, NT_STATUS_CANCELLED);
2162 notify.smb2.in.recursive = true;
2163 req = smb2_notify_send(tree, &(notify.smb2));
2164 status = smb2_util_mkdir(tree, fname);
2165 CHECK_STATUS(status, NT_STATUS_OK);
2167 status = smb2_notify_recv(req, torture, &(notify.smb2));
2168 CHECK_STATUS(status, NT_STATUS_OK);
2170 CHECK_VAL(notify.smb2.out.num_changes, 1);
2171 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2172 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2174 torture_comment(torture, "Testing notify rmdir\n");
2175 req = smb2_notify_send(tree, &(notify.smb2));
2176 status = smb2_util_rmdir(tree, fname);
2177 CHECK_STATUS(status, NT_STATUS_OK);
2179 status = smb2_notify_recv(req, torture, &(notify.smb2));
2180 CHECK_STATUS(status, NT_STATUS_OK);
2181 CHECK_VAL(notify.smb2.out.num_changes, 1);
2182 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2183 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2185 torture_comment(torture, "SIMPLE CHANGE NOTIFY OK\n");
2187 torture_comment(torture, "TESTING WITH SECONDARY TCON\n");
2188 if (!torture_smb2_tree_connect(torture, tree->session, tree, &tree1)) {
2189 torture_warning(torture, "couldn't reconnect to share, bailing\n");
2190 ret = false;
2191 goto done;
2194 torture_comment(torture, "tid1=%d tid2=%d\n",
2195 smb2cli_tcon_current_id(tree->smbXcli),
2196 smb2cli_tcon_current_id(tree1->smbXcli));
2198 torture_comment(torture, "Testing notify mkdir\n");
2199 req = smb2_notify_send(tree, &(notify.smb2));
2200 smb2_util_mkdir(tree1, fname);
2202 status = smb2_notify_recv(req, torture, &(notify.smb2));
2203 CHECK_STATUS(status, NT_STATUS_OK);
2205 CHECK_VAL(notify.smb2.out.num_changes, 1);
2206 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2207 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2209 torture_comment(torture, "Testing notify rmdir\n");
2210 req = smb2_notify_send(tree, &(notify.smb2));
2211 smb2_util_rmdir(tree, fname);
2213 status = smb2_notify_recv(req, torture, &(notify.smb2));
2214 CHECK_STATUS(status, NT_STATUS_OK);
2215 CHECK_VAL(notify.smb2.out.num_changes, 1);
2216 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2217 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2219 torture_comment(torture, "CHANGE NOTIFY WITH TCON OK\n");
2221 torture_comment(torture, "Disconnecting secondary tree\n");
2222 status = smb2_tdis(tree1);
2223 CHECK_STATUS(status, NT_STATUS_OK);
2224 talloc_free(tree1);
2226 torture_comment(torture, "Testing notify mkdir\n");
2227 req = smb2_notify_send(tree, &(notify.smb2));
2228 smb2_util_mkdir(tree, fname);
2230 status = smb2_notify_recv(req, torture, &(notify.smb2));
2231 CHECK_STATUS(status, NT_STATUS_OK);
2233 CHECK_VAL(notify.smb2.out.num_changes, 1);
2234 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2235 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2237 torture_comment(torture, "Testing notify rmdir\n");
2238 req = smb2_notify_send(tree, &(notify.smb2));
2239 smb2_util_rmdir(tree, fname);
2241 status = smb2_notify_recv(req, torture, &(notify.smb2));
2242 CHECK_STATUS(status, NT_STATUS_OK);
2243 CHECK_VAL(notify.smb2.out.num_changes, 1);
2244 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2245 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2247 torture_comment(torture, "CHANGE NOTIFY WITH TDIS OK\n");
2248 done:
2249 smb2_util_close(tree, h1);
2250 smb2_deltree(tree, BASEDIR);
2252 return ret;
2255 static bool torture_smb2_notify_rmdir(struct torture_context *torture,
2256 struct smb2_tree *tree1,
2257 struct smb2_tree *tree2,
2258 bool initial_delete_on_close)
2260 bool ret = true;
2261 NTSTATUS status;
2262 union smb_notify notify = {};
2263 union smb_setfileinfo sfinfo = {};
2264 union smb_open io = {};
2265 struct smb2_handle h = {};
2266 struct smb2_request *req;
2268 torture_comment(torture, "TESTING NOTIFY CANCEL FOR DELETED DIR\n");
2270 smb2_deltree(tree1, BASEDIR);
2271 smb2_util_rmdir(tree1, BASEDIR);
2273 ZERO_STRUCT(io.smb2);
2274 io.generic.level = RAW_OPEN_SMB2;
2275 io.smb2.in.create_flags = 0;
2276 io.smb2.in.desired_access = SEC_FILE_ALL;
2277 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2278 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2279 io.smb2.in.share_access =
2280 NTCREATEX_SHARE_ACCESS_READ |
2281 NTCREATEX_SHARE_ACCESS_WRITE |
2282 NTCREATEX_SHARE_ACCESS_DELETE ;
2283 io.smb2.in.alloc_size = 0;
2284 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2285 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2286 io.smb2.in.security_flags = 0;
2287 io.smb2.in.fname = BASEDIR;
2289 status = smb2_create(tree1, torture, &(io.smb2));
2290 CHECK_STATUS(status, NT_STATUS_OK);
2291 h = io.smb2.out.file.handle;
2293 ZERO_STRUCT(notify.smb2);
2294 notify.smb2.level = RAW_NOTIFY_SMB2;
2295 notify.smb2.in.buffer_size = 1000;
2296 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2297 notify.smb2.in.file.handle = h;
2298 notify.smb2.in.recursive = false;
2300 io.smb2.in.desired_access |= SEC_STD_DELETE;
2301 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
2302 req = smb2_notify_send(tree1, &(notify.smb2));
2304 if (initial_delete_on_close) {
2305 status = smb2_util_rmdir(tree2, BASEDIR);
2306 CHECK_STATUS(status, NT_STATUS_OK);
2307 } else {
2308 status = smb2_create(tree2, torture, &(io.smb2));
2309 CHECK_STATUS(status, NT_STATUS_OK);
2311 sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
2312 sfinfo.generic.in.file.handle = io.smb2.out.file.handle;
2313 sfinfo.disposition_info.in.delete_on_close = 1;
2314 status = smb2_setinfo_file(tree2, &sfinfo);
2315 CHECK_STATUS(status, NT_STATUS_OK);
2317 smb2_util_close(tree2, io.smb2.out.file.handle);
2320 status = smb2_notify_recv(req, torture, &(notify.smb2));
2321 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
2323 done:
2325 smb2_util_close(tree1, h);
2326 smb2_deltree(tree1, BASEDIR);
2328 return ret;
2331 static bool torture_smb2_notify_rmdir1(struct torture_context *torture,
2332 struct smb2_tree *tree)
2334 return torture_smb2_notify_rmdir(torture, tree, tree, false);
2337 static bool torture_smb2_notify_rmdir2(struct torture_context *torture,
2338 struct smb2_tree *tree)
2340 return torture_smb2_notify_rmdir(torture, tree, tree, true);
2343 static bool torture_smb2_notify_rmdir3(struct torture_context *torture,
2344 struct smb2_tree *tree1,
2345 struct smb2_tree *tree2)
2347 return torture_smb2_notify_rmdir(torture, tree1, tree2, false);
2350 static bool torture_smb2_notify_rmdir4(struct torture_context *torture,
2351 struct smb2_tree *tree1,
2352 struct smb2_tree *tree2)
2354 return torture_smb2_notify_rmdir(torture, tree1, tree2, true);
2358 basic testing of SMB2 change notify
2360 struct torture_suite *torture_smb2_notify_init(void)
2362 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "notify");
2364 torture_suite_add_1smb2_test(suite, "valid-req", test_valid_request);
2365 torture_suite_add_1smb2_test(suite, "tcon", torture_smb2_notify_tcon);
2366 torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir);
2367 torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask);
2368 torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
2369 torture_suite_add_1smb2_test(suite, "tdis1", torture_smb2_notify_tree_disconnect_1);
2370 torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
2371 torture_suite_add_1smb2_test(suite, "close", torture_smb2_notify_close);
2372 torture_suite_add_1smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
2373 torture_suite_add_1smb2_test(suite, "session-reconnect", torture_smb2_notify_session_reconnect);
2374 torture_suite_add_2smb2_test(suite, "invalid-reauth", torture_smb2_notify_invalid_reauth);
2375 torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
2376 torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
2377 torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
2378 torture_suite_add_1smb2_test(suite, "file", torture_smb2_notify_file);
2379 torture_suite_add_1smb2_test(suite, "tcp", torture_smb2_notify_tcp_disconnect);
2380 torture_suite_add_2smb2_test(suite, "rec", torture_smb2_notify_recursive);
2381 torture_suite_add_1smb2_test(suite, "overflow", torture_smb2_notify_overflow);
2382 torture_suite_add_1smb2_test(suite, "rmdir1",
2383 torture_smb2_notify_rmdir1);
2384 torture_suite_add_1smb2_test(suite, "rmdir2",
2385 torture_smb2_notify_rmdir2);
2386 torture_suite_add_2smb2_test(suite, "rmdir3",
2387 torture_smb2_notify_rmdir3);
2388 torture_suite_add_2smb2_test(suite, "rmdir4",
2389 torture_smb2_notify_rmdir4);
2391 suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");
2393 return suite;