s4:torture/smb2: add smb2.notify.session-reconnect test
[Samba.git] / source4 / torture / smb2 / notify.c
blobd8b32c703e6162bbe16d1874145fb8de224a0e65
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(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(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(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(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(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, h2;
238 struct smb2_request *req, *req2;
239 const char *fname = BASEDIR "\\subdir-name";
240 extern int torture_numops;
242 torture_comment(torture, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
244 smb2_deltree(tree1, BASEDIR);
245 smb2_util_rmdir(tree1, BASEDIR);
247 get a handle on the directory
249 ZERO_STRUCT(io.smb2);
250 io.generic.level = RAW_OPEN_SMB2;
251 io.smb2.in.create_flags = 0;
252 io.smb2.in.desired_access = SEC_FILE_ALL;
253 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
254 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
255 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
256 NTCREATEX_SHARE_ACCESS_WRITE;
257 io.smb2.in.alloc_size = 0;
258 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
259 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
260 io.smb2.in.security_flags = 0;
261 io.smb2.in.fname = BASEDIR;
263 status = smb2_create(tree1, torture, &(io.smb2));
264 CHECK_STATUS(status, NT_STATUS_OK);
265 h1 = io.smb2.out.file.handle;
267 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
268 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ;
269 status = smb2_create(tree1, torture, &(io.smb2));
270 CHECK_STATUS(status, NT_STATUS_OK);
271 h2 = io.smb2.out.file.handle;
273 /* ask for a change notify,
274 on file or directory name changes */
275 ZERO_STRUCT(notify.smb2);
276 notify.smb2.level = RAW_NOTIFY_SMB2;
277 notify.smb2.in.buffer_size = 1000;
278 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
279 notify.smb2.in.file.handle = h1;
280 notify.smb2.in.recursive = true;
282 torture_comment(torture, "Testing notify cancel\n");
284 req = smb2_notify_send(tree1, &(notify.smb2));
285 smb2_cancel(req);
286 status = smb2_notify_recv(req, torture, &(notify.smb2));
287 CHECK_STATUS(status, NT_STATUS_CANCELLED);
289 torture_comment(torture, "Testing notify mkdir\n");
291 req = smb2_notify_send(tree1, &(notify.smb2));
292 smb2_util_mkdir(tree2, fname);
294 status = smb2_notify_recv(req, torture, &(notify.smb2));
295 CHECK_STATUS(status, NT_STATUS_OK);
297 CHECK_VAL(notify.smb2.out.num_changes, 1);
298 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
299 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
301 torture_comment(torture, "Testing notify rmdir\n");
303 req = smb2_notify_send(tree1, &(notify.smb2));
304 smb2_util_rmdir(tree2, fname);
306 status = smb2_notify_recv(req, torture, &(notify.smb2));
307 CHECK_STATUS(status, NT_STATUS_OK);
308 CHECK_VAL(notify.smb2.out.num_changes, 1);
309 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
310 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
312 torture_comment(torture,
313 "Testing notify mkdir - rmdir - mkdir - rmdir\n");
315 smb2_util_mkdir(tree2, fname);
316 smb2_util_rmdir(tree2, fname);
317 smb2_util_mkdir(tree2, fname);
318 smb2_util_rmdir(tree2, fname);
319 smb_msleep(200);
320 req = smb2_notify_send(tree1, &(notify.smb2));
321 status = smb2_notify_recv(req, torture, &(notify.smb2));
322 CHECK_STATUS(status, NT_STATUS_OK);
323 CHECK_VAL(notify.smb2.out.num_changes, 4);
324 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
325 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
326 CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_REMOVED);
327 CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name");
328 CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_ADDED);
329 CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name");
330 CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_REMOVED);
331 CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name");
333 count = torture_numops;
334 torture_comment(torture,
335 "Testing buffered notify on create of %d files\n", count);
336 for (i=0;i<count;i++) {
337 struct smb2_handle h12;
338 char *fname2 = talloc_asprintf(torture, BASEDIR "\\test%d.txt",
341 ZERO_STRUCT(io.smb2);
342 io.generic.level = RAW_OPEN_SMB2;
343 io.smb2.in.create_flags = 0;
344 io.smb2.in.desired_access = SEC_FILE_ALL;
345 io.smb2.in.create_options =
346 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
347 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
348 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
349 NTCREATEX_SHARE_ACCESS_WRITE;
350 io.smb2.in.alloc_size = 0;
351 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
352 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
353 io.smb2.in.security_flags = 0;
354 io.smb2.in.fname = fname2;
356 status = smb2_create(tree1, torture, &(io.smb2));
357 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
358 torture_comment(torture, "Failed to create %s \n",
359 fname);
360 ret = false;
361 goto done;
363 h12 = io.smb2.out.file.handle;
364 talloc_free(fname2);
365 smb2_util_close(tree1, h12);
368 /* (1st notify) setup a new notify on a different directory handle.
369 This new notify won't see the events above. */
370 notify.smb2.in.file.handle = h2;
371 req2 = smb2_notify_send(tree1, &(notify.smb2));
373 /* (2nd notify) whereas this notify will see the above buffered events,
374 and it directly returns the buffered events */
375 notify.smb2.in.file.handle = h1;
376 req = smb2_notify_send(tree1, &(notify.smb2));
378 status = smb2_util_unlink(tree1, BASEDIR "\\nonexistent.txt");
379 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
381 /* (1st unlink) as the 2nd notify directly returns,
382 this unlink is only seen by the 1st notify and
383 the 3rd notify (later) */
384 torture_comment(torture,
385 "Testing notify on unlink for the first file\n");
386 status = smb2_util_unlink(tree2, BASEDIR "\\test0.txt");
387 CHECK_STATUS(status, NT_STATUS_OK);
389 /* receive the reply from the 2nd notify */
390 status = smb2_notify_recv(req, torture, &(notify.smb2));
391 CHECK_STATUS(status, NT_STATUS_OK);
393 CHECK_VAL(notify.smb2.out.num_changes, count);
394 for (i=1;i<count;i++) {
395 CHECK_VAL(notify.smb2.out.changes[i].action,
396 NOTIFY_ACTION_ADDED);
398 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
400 torture_comment(torture, "and now from the 1st notify\n");
401 status = smb2_notify_recv(req2, torture, &(notify.smb2));
402 CHECK_STATUS(status, NT_STATUS_OK);
403 CHECK_VAL(notify.smb2.out.num_changes, 1);
404 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
405 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
407 torture_comment(torture,
408 "(3rd notify) this notify will only see the 1st unlink\n");
409 req = smb2_notify_send(tree1, &(notify.smb2));
411 status = smb2_util_unlink(tree1, BASEDIR "\\nonexistent.txt");
412 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
414 for (i=1;i<count;i++) {
415 char *fname2 = talloc_asprintf(torture,
416 BASEDIR "\\test%d.txt", i);
417 status = smb2_util_unlink(tree2, fname2);
418 CHECK_STATUS(status, NT_STATUS_OK);
419 talloc_free(fname2);
422 /* receive the 3rd notify */
423 status = smb2_notify_recv(req, torture, &(notify.smb2));
424 CHECK_STATUS(status, NT_STATUS_OK);
425 CHECK_VAL(notify.smb2.out.num_changes, 1);
426 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
427 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
429 /* and we now see the rest of the unlink calls on both
430 * directory handles */
431 notify.smb2.in.file.handle = h1;
432 sleep(3);
433 req = smb2_notify_send(tree1, &(notify.smb2));
434 status = smb2_notify_recv(req, torture, &(notify.smb2));
435 CHECK_STATUS(status, NT_STATUS_OK);
436 CHECK_VAL(notify.smb2.out.num_changes, count-1);
437 for (i=0;i<notify.smb2.out.num_changes;i++) {
438 CHECK_VAL(notify.smb2.out.changes[i].action,
439 NOTIFY_ACTION_REMOVED);
441 notify.smb2.in.file.handle = h2;
442 req = smb2_notify_send(tree1, &(notify.smb2));
443 status = smb2_notify_recv(req, torture, &(notify.smb2));
444 CHECK_STATUS(status, NT_STATUS_OK);
445 CHECK_VAL(notify.smb2.out.num_changes, count-1);
446 for (i=0;i<notify.smb2.out.num_changes;i++) {
447 CHECK_VAL(notify.smb2.out.changes[i].action,
448 NOTIFY_ACTION_REMOVED);
451 torture_comment(torture,
452 "Testing if a close() on the dir handle triggers the notify reply\n");
454 notify.smb2.in.file.handle = h1;
455 req = smb2_notify_send(tree1, &(notify.smb2));
457 ZERO_STRUCT(cl.smb2);
458 cl.smb2.level = RAW_CLOSE_SMB2;
459 cl.smb2.in.file.handle = h1;
460 status = smb2_close(tree1, &(cl.smb2));
461 CHECK_STATUS(status, NT_STATUS_OK);
463 status = smb2_notify_recv(req, torture, &(notify.smb2));
464 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
465 CHECK_VAL(notify.smb2.out.num_changes, 9);
467 done:
468 smb2_util_close(tree1, h1);
469 smb2_util_close(tree1, h2);
470 smb2_deltree(tree1, BASEDIR);
471 return ret;
474 static struct smb2_handle custom_smb2_create(struct smb2_tree *tree,
475 struct torture_context *torture,
476 struct smb2_create *smb2)
478 struct smb2_handle h1;
479 bool ret = true;
480 NTSTATUS status;
481 smb2_deltree(tree, smb2->in.fname);
482 status = smb2_create(tree, torture, smb2);
483 CHECK_STATUS(status, NT_STATUS_OK);
484 h1 = smb2->out.file.handle;
485 done:
486 return h1;
490 testing of recursive change notify
493 static bool torture_smb2_notify_recursive(struct torture_context *torture,
494 struct smb2_tree *tree1,
495 struct smb2_tree *tree2)
497 bool ret = true;
498 NTSTATUS status;
499 union smb_notify notify;
500 union smb_open io, io1;
501 union smb_setfileinfo sinfo;
502 struct smb2_handle h1;
503 struct smb2_request *req1, *req2;
505 smb2_deltree(tree1, BASEDIR);
506 smb2_util_rmdir(tree1, BASEDIR);
508 torture_comment(torture, "TESTING CHANGE NOTIFY WITH RECURSION\n");
511 get a handle on the directory
513 ZERO_STRUCT(io.smb2);
514 io.generic.level = RAW_OPEN_SMB2;
515 io.smb2.in.create_flags = 0;
516 io.smb2.in.desired_access = SEC_FILE_ALL;
517 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
518 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
519 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
520 NTCREATEX_SHARE_ACCESS_WRITE;
521 io.smb2.in.alloc_size = 0;
522 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
523 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
524 io.smb2.in.security_flags = 0;
525 io.smb2.in.fname = BASEDIR;
527 status = smb2_create(tree1, torture, &(io.smb2));
528 CHECK_STATUS(status, NT_STATUS_OK);
529 h1 = io.smb2.out.file.handle;
531 /* ask for a change notify, on file or directory name
532 changes. Setup both with and without recursion */
533 ZERO_STRUCT(notify.smb2);
534 notify.smb2.level = RAW_NOTIFY_SMB2;
535 notify.smb2.in.buffer_size = 1000;
536 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
537 FILE_NOTIFY_CHANGE_ATTRIBUTES |
538 FILE_NOTIFY_CHANGE_CREATION;
539 notify.smb2.in.file.handle = h1;
541 notify.smb2.in.recursive = true;
542 req1 = smb2_notify_send(tree1, &(notify.smb2));
543 smb2_cancel(req1);
544 status = smb2_notify_recv(req1, torture, &(notify.smb2));
545 CHECK_STATUS(status, NT_STATUS_CANCELLED);
547 notify.smb2.in.recursive = false;
548 req2 = smb2_notify_send(tree1, &(notify.smb2));
549 smb2_cancel(req2);
550 status = smb2_notify_recv(req2, torture, &(notify.smb2));
551 CHECK_STATUS(status, NT_STATUS_CANCELLED);
553 ZERO_STRUCT(io1.smb2);
554 io1.generic.level = RAW_OPEN_SMB2;
555 io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
556 io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
557 SEC_RIGHTS_FILE_WRITE|
558 SEC_RIGHTS_FILE_ALL;
559 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
560 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
561 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
562 NTCREATEX_SHARE_ACCESS_WRITE |
563 NTCREATEX_SHARE_ACCESS_DELETE;
564 io1.smb2.in.alloc_size = 0;
565 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
566 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
567 io1.smb2.in.security_flags = 0;
568 io1.smb2.in.fname = BASEDIR "\\subdir-name";
569 status = smb2_create(tree2, torture, &(io1.smb2));
570 CHECK_STATUS(status, NT_STATUS_OK);
571 smb2_util_close(tree2, io1.smb2.out.file.handle);
573 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname1";
574 status = smb2_create(tree2, torture, &(io1.smb2));
575 CHECK_STATUS(status, NT_STATUS_OK);
576 ZERO_STRUCT(sinfo);
577 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
578 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
579 sinfo.rename_information.in.overwrite = 0;
580 sinfo.rename_information.in.root_fid = 0;
581 sinfo.rename_information.in.new_name =
582 BASEDIR "\\subdir-name\\subname1-r";
583 status = smb2_setinfo_file(tree2, &sinfo);
584 CHECK_STATUS(status, NT_STATUS_OK);
586 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
587 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname2";
588 status = smb2_create(tree2, torture, &(io1.smb2));
589 CHECK_STATUS(status, NT_STATUS_OK);
590 ZERO_STRUCT(sinfo);
591 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
592 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
593 sinfo.rename_information.in.overwrite = true;
594 sinfo.rename_information.in.root_fid = 0;
595 sinfo.rename_information.in.new_name = BASEDIR "\\subname2-r";
596 status = smb2_setinfo_file(tree2, &sinfo);
597 CHECK_STATUS(status, NT_STATUS_OK);
599 io1.smb2.in.fname = BASEDIR "\\subname2-r";
600 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
601 status = smb2_create(tree2, torture, &(io1.smb2));
602 CHECK_STATUS(status, NT_STATUS_OK);
603 ZERO_STRUCT(sinfo);
604 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
605 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
606 sinfo.rename_information.in.overwrite = true;
607 sinfo.rename_information.in.root_fid = 0;
608 sinfo.rename_information.in.new_name = BASEDIR "\\subname3-r";
609 status = smb2_setinfo_file(tree2, &sinfo);
610 CHECK_STATUS(status, NT_STATUS_OK);
612 notify.smb2.in.completion_filter = 0;
613 notify.smb2.in.recursive = true;
614 smb_msleep(200);
615 req1 = smb2_notify_send(tree1, &(notify.smb2));
617 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name\\subname1-r");
618 CHECK_STATUS(status, NT_STATUS_OK);
619 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name");
620 CHECK_STATUS(status, NT_STATUS_OK);
621 status = smb2_util_unlink(tree2, BASEDIR "\\subname3-r");
622 CHECK_STATUS(status, NT_STATUS_OK);
624 notify.smb2.in.recursive = false;
625 req2 = smb2_notify_send(tree1, &(notify.smb2));
627 status = smb2_notify_recv(req1, torture, &(notify.smb2));
628 CHECK_STATUS(status, NT_STATUS_OK);
630 CHECK_VAL(notify.smb2.out.num_changes, 9);
631 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
632 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
633 CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_ADDED);
634 CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name\\subname1");
635 CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_OLD_NAME);
636 CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name\\subname1");
637 CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_NEW_NAME);
638 CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name\\subname1-r");
639 CHECK_VAL(notify.smb2.out.changes[4].action, NOTIFY_ACTION_ADDED);
640 CHECK_WIRE_STR(notify.smb2.out.changes[4].name, "subdir-name\\subname2");
641 CHECK_VAL(notify.smb2.out.changes[5].action, NOTIFY_ACTION_REMOVED);
642 CHECK_WIRE_STR(notify.smb2.out.changes[5].name, "subdir-name\\subname2");
643 CHECK_VAL(notify.smb2.out.changes[6].action, NOTIFY_ACTION_ADDED);
644 CHECK_WIRE_STR(notify.smb2.out.changes[6].name, "subname2-r");
645 CHECK_VAL(notify.smb2.out.changes[7].action, NOTIFY_ACTION_OLD_NAME);
646 CHECK_WIRE_STR(notify.smb2.out.changes[7].name, "subname2-r");
647 CHECK_VAL(notify.smb2.out.changes[8].action, NOTIFY_ACTION_NEW_NAME);
648 CHECK_WIRE_STR(notify.smb2.out.changes[8].name, "subname3-r");
650 done:
651 smb2_deltree(tree1, BASEDIR);
652 return ret;
656 testing of change notify mask change
659 static bool torture_smb2_notify_mask_change(struct torture_context *torture,
660 struct smb2_tree *tree1,
661 struct smb2_tree *tree2)
663 bool ret = true;
664 NTSTATUS status;
665 union smb_notify notify;
666 union smb_open io, io1;
667 struct smb2_handle h1;
668 struct smb2_request *req1, *req2;
669 union smb_setfileinfo sinfo;
671 smb2_deltree(tree1, BASEDIR);
672 smb2_util_rmdir(tree1, BASEDIR);
674 torture_comment(torture, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
677 get a handle on the directory
679 ZERO_STRUCT(io.smb2);
680 io.generic.level = RAW_OPEN_SMB2;
681 io.smb2.in.create_flags = 0;
682 io.smb2.in.desired_access = SEC_FILE_ALL;
683 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
684 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
685 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
686 NTCREATEX_SHARE_ACCESS_WRITE;
687 io.smb2.in.alloc_size = 0;
688 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
689 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
690 io.smb2.in.security_flags = 0;
691 io.smb2.in.fname = BASEDIR;
693 status = smb2_create(tree1, torture, &(io.smb2));
694 CHECK_STATUS(status, NT_STATUS_OK);
695 h1 = io.smb2.out.file.handle;
697 /* ask for a change notify, on file or directory name
698 changes. Setup both with and without recursion */
699 ZERO_STRUCT(notify.smb2);
700 notify.smb2.level = RAW_NOTIFY_SMB2;
701 notify.smb2.in.buffer_size = 1000;
702 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
703 notify.smb2.in.file.handle = h1;
705 notify.smb2.in.recursive = true;
706 req1 = smb2_notify_send(tree1, &(notify.smb2));
708 smb2_cancel(req1);
709 status = smb2_notify_recv(req1, torture, &(notify.smb2));
710 CHECK_STATUS(status, NT_STATUS_CANCELLED);
713 notify.smb2.in.recursive = false;
714 req2 = smb2_notify_send(tree1, &(notify.smb2));
716 smb2_cancel(req2);
717 status = smb2_notify_recv(req2, torture, &(notify.smb2));
718 CHECK_STATUS(status, NT_STATUS_CANCELLED);
720 notify.smb2.in.recursive = true;
721 req1 = smb2_notify_send(tree1, &(notify.smb2));
723 /* Set to hidden then back again. */
724 ZERO_STRUCT(io1.smb2);
725 io1.generic.level = RAW_OPEN_SMB2;
726 io1.smb2.in.create_flags = 0;
727 io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
728 SEC_RIGHTS_FILE_WRITE|
729 SEC_RIGHTS_FILE_ALL;
730 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
731 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
732 NTCREATEX_SHARE_ACCESS_WRITE |
733 NTCREATEX_SHARE_ACCESS_DELETE;
734 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
735 io1.smb2.in.security_flags = 0;
736 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
737 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
738 io1.smb2.in.fname = BASEDIR "\\tname1";
740 smb2_util_close(tree1,
741 custom_smb2_create(tree1, torture, &(io1.smb2)));
742 status = smb2_util_setatr(tree1, BASEDIR "\\tname1",
743 FILE_ATTRIBUTE_HIDDEN);
744 CHECK_STATUS(status, NT_STATUS_OK);
745 smb2_util_unlink(tree1, BASEDIR "\\tname1");
747 status = smb2_notify_recv(req1, torture, &(notify.smb2));
748 CHECK_STATUS(status, NT_STATUS_OK);
750 CHECK_VAL(notify.smb2.out.num_changes, 1);
751 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
752 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
754 /* Now try and change the mask to include other events.
755 * This should not work - once the mask is set on a directory
756 * h1 it seems to be fixed until the fnum is closed. */
758 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
759 FILE_NOTIFY_CHANGE_ATTRIBUTES |
760 FILE_NOTIFY_CHANGE_CREATION;
761 notify.smb2.in.recursive = true;
762 req1 = smb2_notify_send(tree1, &(notify.smb2));
764 notify.smb2.in.recursive = false;
765 req2 = smb2_notify_send(tree1, &(notify.smb2));
767 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
768 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
769 io1.smb2.in.fname = BASEDIR "\\subdir-name";
770 status = smb2_create(tree2, torture, &(io1.smb2));
771 CHECK_STATUS(status, NT_STATUS_OK);
772 smb2_util_close(tree2, io1.smb2.out.file.handle);
774 ZERO_STRUCT(sinfo);
775 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname1";
776 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
777 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
778 status = smb2_create(tree2, torture, &(io1.smb2));
779 CHECK_STATUS(status, NT_STATUS_OK);
780 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
781 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
782 sinfo.rename_information.in.overwrite = true;
783 sinfo.rename_information.in.root_fid = 0;
784 sinfo.rename_information.in.new_name =
785 BASEDIR "\\subdir-name\\subname1-r";
786 status = smb2_setinfo_file(tree2, &sinfo);
787 CHECK_STATUS(status, NT_STATUS_OK);
789 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname2";
790 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
791 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
792 status = smb2_create(tree2, torture, &(io1.smb2));
793 CHECK_STATUS(status, NT_STATUS_OK);
794 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
795 sinfo.rename_information.in.new_name = BASEDIR "\\subname2-r";
796 status = smb2_setinfo_file(tree2, &sinfo);
797 CHECK_STATUS(status, NT_STATUS_OK);
798 smb2_util_close(tree2, io1.smb2.out.file.handle);
800 io1.smb2.in.fname = BASEDIR "\\subname2-r";
801 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
802 status = smb2_create(tree2, torture, &(io1.smb2));
803 CHECK_STATUS(status, NT_STATUS_OK);
804 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
805 sinfo.rename_information.in.new_name = BASEDIR "\\subname3-r";
806 status = smb2_setinfo_file(tree2, &sinfo);
807 CHECK_STATUS(status, NT_STATUS_OK);
808 smb2_util_close(tree2, io1.smb2.out.file.handle);
810 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name\\subname1-r");
811 CHECK_STATUS(status, NT_STATUS_OK);
812 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name");
813 CHECK_STATUS(status, NT_STATUS_OK);
814 status = smb2_util_unlink(tree2, BASEDIR "\\subname3-r");
815 CHECK_STATUS(status, NT_STATUS_OK);
817 status = smb2_notify_recv(req1, torture, &(notify.smb2));
818 CHECK_STATUS(status, NT_STATUS_OK);
820 CHECK_VAL(notify.smb2.out.num_changes, 1);
821 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
822 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname2-r");
824 status = smb2_notify_recv(req2, torture, &(notify.smb2));
825 CHECK_STATUS(status, NT_STATUS_OK);
827 CHECK_VAL(notify.smb2.out.num_changes, 1);
828 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
829 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname3-r");
831 if (!ret) {
832 goto done;
835 done:
836 smb2_deltree(tree1, BASEDIR);
837 return ret;
841 testing of mask bits for change notify
844 static bool torture_smb2_notify_mask(struct torture_context *torture,
845 struct smb2_tree *tree1,
846 struct smb2_tree *tree2)
848 bool ret = true;
849 NTSTATUS status;
850 union smb_notify notify;
851 union smb_open io, io1;
852 struct smb2_handle h1, h2;
853 uint32_t mask;
854 int i;
855 char c = 1;
856 union smb_setfileinfo sinfo;
858 smb2_deltree(tree1, BASEDIR);
859 smb2_util_rmdir(tree1, BASEDIR);
861 torture_comment(torture, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
865 get a handle on the directory
867 ZERO_STRUCT(io.smb2);
868 io.generic.level = RAW_OPEN_SMB2;
869 io.smb2.in.create_flags = 0;
870 io.smb2.in.desired_access = SEC_FILE_ALL;
871 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
872 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
873 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
874 NTCREATEX_SHARE_ACCESS_WRITE;
875 io.smb2.in.alloc_size = 0;
876 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
877 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
878 io.smb2.in.security_flags = 0;
879 io.smb2.in.fname = BASEDIR;
881 ZERO_STRUCT(notify.smb2);
882 notify.smb2.level = RAW_NOTIFY_SMB2;
883 notify.smb2.in.buffer_size = 1000;
884 notify.smb2.in.recursive = true;
886 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
887 expected, nchanges) \
888 do { \
889 do { for (mask=i=0;i<32;i++) { \
890 struct smb2_request *req; \
891 status = smb2_create(tree1, torture, &(io.smb2)); \
892 CHECK_STATUS(status, NT_STATUS_OK); \
893 h1 = io.smb2.out.file.handle; \
894 setup \
895 notify.smb2.in.file.handle = h1; \
896 notify.smb2.in.completion_filter = (1<<i); \
897 /* cancel initial requests so the buffer is setup */ \
898 req = smb2_notify_send(tree1, &(notify.smb2)); \
899 smb2_cancel(req); \
900 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
901 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
902 /* send the change notify request */ \
903 req = smb2_notify_send(tree1, &(notify.smb2)); \
904 op \
905 smb_msleep(200); smb2_cancel(req); \
906 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
907 cleanup \
908 smb2_util_close(tree1, h1); \
909 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
910 CHECK_STATUS(status, NT_STATUS_OK); \
911 /* special case to cope with file rename behaviour */ \
912 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
913 notify.smb2.out.changes[0].action == \
914 NOTIFY_ACTION_MODIFIED && \
915 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
916 Action == NOTIFY_ACTION_OLD_NAME) { \
917 torture_comment(torture, \
918 "(rename file special handling OK)\n"); \
919 } else if (nchanges != notify.smb2.out.num_changes) { \
920 torture_result(torture, TORTURE_FAIL, \
921 "ERROR: nchanges=%d expected=%d "\
922 "action=%d filter=0x%08x\n", \
923 notify.smb2.out.num_changes, \
924 nchanges, \
925 notify.smb2.out.changes[0].action, \
926 notify.smb2.in.completion_filter); \
927 ret = false; \
928 } else if (notify.smb2.out.changes[0].action != Action) { \
929 torture_result(torture, TORTURE_FAIL, \
930 "ERROR: nchanges=%d action=%d " \
931 "expectedAction=%d filter=0x%08x\n", \
932 notify.smb2.out.num_changes, \
933 notify.smb2.out.changes[0].action, \
934 Action, \
935 notify.smb2.in.completion_filter); \
936 ret = false; \
937 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
938 "tname1") != 0) { \
939 torture_result(torture, TORTURE_FAIL, \
940 "ERROR: nchanges=%d action=%d " \
941 "filter=0x%08x name=%s\n", \
942 notify.smb2.out.num_changes, \
943 notify.smb2.out.changes[0].action, \
944 notify.smb2.in.completion_filter, \
945 notify.smb2.out.changes[0].name.s); \
946 ret = false; \
948 mask |= (1<<i); \
950 } while (0); \
951 } while (0);
953 torture_comment(torture, "Testing mkdir\n");
954 NOTIFY_MASK_TEST("Testing mkdir",;,
955 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
956 smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
957 NOTIFY_ACTION_ADDED,
958 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
960 torture_comment(torture, "Testing create file\n");
961 ZERO_STRUCT(io1.smb2);
962 io1.generic.level = RAW_OPEN_SMB2;
963 io1.smb2.in.create_flags = 0;
964 io1.smb2.in.desired_access = SEC_FILE_ALL;
965 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
966 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
967 NTCREATEX_SHARE_ACCESS_WRITE;
968 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
969 io1.smb2.in.security_flags = 0;
970 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
971 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
972 io1.smb2.in.fname = BASEDIR "\\tname1";
974 NOTIFY_MASK_TEST("Testing create file",;,
975 smb2_util_close(tree2, custom_smb2_create(tree2,
976 torture, &(io1.smb2)));,
977 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
978 NOTIFY_ACTION_ADDED,
979 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
981 torture_comment(torture, "Testing unlink\n");
982 NOTIFY_MASK_TEST("Testing unlink",
983 smb2_util_close(tree2, custom_smb2_create(tree2,
984 torture, &(io1.smb2)));,
985 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
987 NOTIFY_ACTION_REMOVED,
988 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
990 torture_comment(torture, "Testing rmdir\n");
991 NOTIFY_MASK_TEST("Testing rmdir",
992 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
993 smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
995 NOTIFY_ACTION_REMOVED,
996 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
998 torture_comment(torture, "Testing rename file\n");
999 ZERO_STRUCT(sinfo);
1000 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1001 sinfo.rename_information.in.file.handle = h1;
1002 sinfo.rename_information.in.overwrite = true;
1003 sinfo.rename_information.in.root_fid = 0;
1004 sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
1005 NOTIFY_MASK_TEST("Testing rename file",
1006 smb2_util_close(tree2, custom_smb2_create(tree2,
1007 torture, &(io1.smb2)));,
1008 smb2_setinfo_file(tree2, &sinfo);,
1009 smb2_util_unlink(tree2, BASEDIR "\\tname2");,
1010 NOTIFY_ACTION_OLD_NAME,
1011 FILE_NOTIFY_CHANGE_FILE_NAME, 2);
1013 torture_comment(torture, "Testing rename dir\n");
1014 ZERO_STRUCT(sinfo);
1015 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1016 sinfo.rename_information.in.file.handle = h1;
1017 sinfo.rename_information.in.overwrite = true;
1018 sinfo.rename_information.in.root_fid = 0;
1019 sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
1020 NOTIFY_MASK_TEST("Testing rename dir",
1021 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
1022 smb2_setinfo_file(tree2, &sinfo);,
1023 smb2_util_rmdir(tree2, BASEDIR "\\tname2");,
1024 NOTIFY_ACTION_OLD_NAME,
1025 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
1027 torture_comment(torture, "Testing set path attribute\n");
1028 NOTIFY_MASK_TEST("Testing set path attribute",
1029 smb2_util_close(tree2, custom_smb2_create(tree2,
1030 torture, &(io.smb2)));,
1031 smb2_util_setatr(tree2, BASEDIR "\\tname1",
1032 FILE_ATTRIBUTE_HIDDEN);,
1033 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1034 NOTIFY_ACTION_MODIFIED,
1035 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
1037 torture_comment(torture, "Testing set path write time\n");
1038 ZERO_STRUCT(sinfo);
1039 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1040 sinfo.generic.in.file.handle = h1;
1041 sinfo.basic_info.in.write_time = 1000;
1042 NOTIFY_MASK_TEST("Testing set path write time",
1043 smb2_util_close(tree2, custom_smb2_create(tree2,
1044 torture, &(io1.smb2)));,
1045 smb2_setinfo_file(tree2, &sinfo);,
1046 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1047 NOTIFY_ACTION_MODIFIED,
1048 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
1050 if (torture_setting_bool(torture, "samba3", false)) {
1051 torture_comment(torture,
1052 "Samba3 does not yet support create times "
1053 "everywhere\n");
1055 else {
1056 ZERO_STRUCT(sinfo);
1057 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1058 sinfo.generic.in.file.handle = h1;
1059 sinfo.basic_info.in.create_time = 0;
1060 torture_comment(torture, "Testing set file create time\n");
1061 NOTIFY_MASK_TEST("Testing set file create time",
1062 smb2_create_complex_file(tree2,
1063 BASEDIR "\\tname1", &h2);,
1064 smb2_setinfo_file(tree2, &sinfo);,
1065 (smb2_util_close(tree2, h2),
1066 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1067 NOTIFY_ACTION_MODIFIED,
1068 FILE_NOTIFY_CHANGE_CREATION, 1);
1071 ZERO_STRUCT(sinfo);
1072 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1073 sinfo.generic.in.file.handle = h1;
1074 sinfo.basic_info.in.access_time = 0;
1075 torture_comment(torture, "Testing set file access time\n");
1076 NOTIFY_MASK_TEST("Testing set file access time",
1077 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1078 smb2_setinfo_file(tree2, &sinfo);,
1079 (smb2_util_close(tree2, h2),
1080 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1081 NOTIFY_ACTION_MODIFIED,
1082 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
1084 ZERO_STRUCT(sinfo);
1085 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1086 sinfo.generic.in.file.handle = h1;
1087 sinfo.basic_info.in.change_time = 0;
1088 torture_comment(torture, "Testing set file change time\n");
1089 NOTIFY_MASK_TEST("Testing set file change time",
1090 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1091 smb2_setinfo_file(tree2, &sinfo);,
1092 (smb2_util_close(tree2, h2),
1093 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1094 NOTIFY_ACTION_MODIFIED,
1095 0, 1);
1098 torture_comment(torture, "Testing write\n");
1099 NOTIFY_MASK_TEST("Testing write",
1100 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1101 smb2_util_write(tree2, h2, &c, 10000, 1);,
1102 (smb2_util_close(tree2, h2),
1103 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1104 NOTIFY_ACTION_MODIFIED,
1105 0, 1);
1107 done:
1108 smb2_deltree(tree1, BASEDIR);
1109 return ret;
1113 basic testing of change notify on files
1115 static bool torture_smb2_notify_file(struct torture_context *torture,
1116 struct smb2_tree *tree)
1118 NTSTATUS status;
1119 bool ret = true;
1120 union smb_open io;
1121 union smb_close cl;
1122 union smb_notify notify;
1123 struct smb2_request *req;
1124 struct smb2_handle h1;
1125 const char *fname = BASEDIR "\\file.txt";
1127 smb2_deltree(tree, BASEDIR);
1128 smb2_util_rmdir(tree, BASEDIR);
1130 torture_comment(torture, "TESTING CHANGE NOTIFY ON FILES\n");
1131 status = torture_smb2_testdir(tree, BASEDIR, &h1);
1132 CHECK_STATUS(status, NT_STATUS_OK);
1134 ZERO_STRUCT(io.smb2);
1135 io.generic.level = RAW_OPEN_SMB2;
1136 io.smb2.in.create_flags = 0;
1137 io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
1138 io.smb2.in.create_options = 0;
1139 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1140 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1141 NTCREATEX_SHARE_ACCESS_WRITE;
1142 io.smb2.in.alloc_size = 0;
1143 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1144 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1145 io.smb2.in.security_flags = 0;
1146 io.smb2.in.fname = fname;
1147 status = smb2_create(tree, torture, &(io.smb2));
1148 CHECK_STATUS(status, NT_STATUS_OK);
1149 h1 = io.smb2.out.file.handle;
1151 /* ask for a change notify,
1152 on file or directory name changes */
1153 ZERO_STRUCT(notify.smb2);
1154 notify.smb2.level = RAW_NOTIFY_SMB2;
1155 notify.smb2.in.file.handle = h1;
1156 notify.smb2.in.buffer_size = 1000;
1157 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
1158 notify.smb2.in.recursive = false;
1160 torture_comment(torture,
1161 "Testing if notifies on file handles are invalid (should be)\n");
1163 req = smb2_notify_send(tree, &(notify.smb2));
1164 status = smb2_notify_recv(req, torture, &(notify.smb2));
1165 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1167 ZERO_STRUCT(cl.smb2);
1168 cl.close.level = RAW_CLOSE_SMB2;
1169 cl.close.in.file.handle = h1;
1170 status = smb2_close(tree, &(cl.smb2));
1171 CHECK_STATUS(status, NT_STATUS_OK);
1173 status = smb2_util_unlink(tree, fname);
1174 CHECK_STATUS(status, NT_STATUS_OK);
1176 done:
1177 smb2_deltree(tree, BASEDIR);
1178 return ret;
1181 basic testing of change notifies followed by a tdis
1184 static bool torture_smb2_notify_tree_disconnect(
1185 struct torture_context *torture,
1186 struct smb2_tree *tree)
1188 bool ret = true;
1189 NTSTATUS status;
1190 union smb_notify notify;
1191 union smb_open io;
1192 struct smb2_handle h1;
1193 struct smb2_request *req;
1195 smb2_deltree(tree, BASEDIR);
1196 smb2_util_rmdir(tree, BASEDIR);
1198 torture_comment(torture, "TESTING CHANGE NOTIFY+CANCEL FOLLOWED BY "
1199 "TREE-DISCONNECT\n");
1202 get a handle on the directory
1204 ZERO_STRUCT(io.smb2);
1205 io.generic.level = RAW_OPEN_SMB2;
1206 io.smb2.in.create_flags = 0;
1207 io.smb2.in.desired_access = SEC_FILE_ALL;
1208 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1209 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1210 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1211 NTCREATEX_SHARE_ACCESS_WRITE;
1212 io.smb2.in.alloc_size = 0;
1213 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1214 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1215 io.smb2.in.security_flags = 0;
1216 io.smb2.in.fname = BASEDIR;
1218 status = smb2_create(tree, torture, &(io.smb2));
1219 CHECK_STATUS(status, NT_STATUS_OK);
1220 h1 = io.smb2.out.file.handle;
1222 /* ask for a change notify,
1223 on file or directory name changes */
1224 ZERO_STRUCT(notify.smb2);
1225 notify.smb2.level = RAW_NOTIFY_SMB2;
1226 notify.smb2.in.buffer_size = 1000;
1227 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1228 notify.smb2.in.file.handle = h1;
1229 notify.smb2.in.recursive = true;
1231 req = smb2_notify_send(tree, &(notify.smb2));
1232 smb2_cancel(req);
1233 status = smb2_notify_recv(req, torture, &(notify.smb2));
1235 status = smb2_tdis(tree);
1236 CHECK_STATUS(status, NT_STATUS_OK);
1238 req = smb2_notify_send(tree, &(notify.smb2));
1240 smb2_notify_recv(req, torture, &(notify.smb2));
1241 CHECK_STATUS(status, NT_STATUS_OK);
1242 CHECK_VAL(notify.smb2.out.num_changes, 0);
1244 done:
1245 smb2_deltree(tree, BASEDIR);
1246 return ret;
1250 testing of change notifies followed by a tdis - no cancel
1253 static bool torture_smb2_notify_tree_disconnect_1(
1254 struct torture_context *torture,
1255 struct smb2_tree *tree)
1257 bool ret = true;
1258 NTSTATUS status;
1259 union smb_notify notify;
1260 union smb_open io;
1261 struct smb2_handle h1;
1262 struct smb2_request *req;
1264 smb2_deltree(tree, BASEDIR);
1265 smb2_util_rmdir(tree, BASEDIR);
1267 torture_comment(torture, "TESTING CHANGE NOTIFY ASYNC FOLLOWED BY "
1268 "TREE-DISCONNECT\n");
1271 get a handle on the directory
1273 ZERO_STRUCT(io.smb2);
1274 io.generic.level = RAW_OPEN_SMB2;
1275 io.smb2.in.create_flags = 0;
1276 io.smb2.in.desired_access = SEC_FILE_ALL;
1277 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1278 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1279 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1280 NTCREATEX_SHARE_ACCESS_WRITE;
1281 io.smb2.in.alloc_size = 0;
1282 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1283 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1284 io.smb2.in.security_flags = 0;
1285 io.smb2.in.fname = BASEDIR;
1287 status = smb2_create(tree, torture, &(io.smb2));
1288 CHECK_STATUS(status, NT_STATUS_OK);
1289 h1 = io.smb2.out.file.handle;
1291 /* ask for a change notify,
1292 on file or directory name changes */
1293 ZERO_STRUCT(notify.smb2);
1294 notify.smb2.level = RAW_NOTIFY_SMB2;
1295 notify.smb2.in.buffer_size = 1000;
1296 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1297 notify.smb2.in.file.handle = h1;
1298 notify.smb2.in.recursive = true;
1300 req = smb2_notify_send(tree, &(notify.smb2));
1301 WAIT_FOR_ASYNC_RESPONSE(req);
1303 status = smb2_tdis(tree);
1304 CHECK_STATUS(status, NT_STATUS_OK);
1306 status = smb2_notify_recv(req, torture, &(notify.smb2));
1307 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1308 CHECK_VAL(notify.smb2.out.num_changes, 0);
1310 done:
1311 smb2_deltree(tree, BASEDIR);
1312 return ret;
1316 basic testing of change notifies followed by a close
1319 static bool torture_smb2_notify_close(struct torture_context *torture,
1320 struct smb2_tree *tree1)
1322 bool ret = true;
1323 NTSTATUS status;
1324 union smb_notify notify;
1325 union smb_open io;
1326 struct smb2_handle h1;
1327 struct smb2_request *req;
1329 smb2_deltree(tree1, BASEDIR);
1330 smb2_util_rmdir(tree1, BASEDIR);
1332 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1335 get a handle on the directory
1337 ZERO_STRUCT(io.smb2);
1338 io.generic.level = RAW_OPEN_SMB2;
1339 io.smb2.in.create_flags = 0;
1340 io.smb2.in.desired_access = SEC_FILE_ALL;
1341 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1342 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1343 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1344 NTCREATEX_SHARE_ACCESS_WRITE;
1345 io.smb2.in.alloc_size = 0;
1346 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1347 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1348 io.smb2.in.security_flags = 0;
1349 io.smb2.in.fname = BASEDIR;
1351 status = smb2_create(tree1, torture, &(io.smb2));
1352 CHECK_STATUS(status, NT_STATUS_OK);
1354 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1355 status = smb2_create(tree1, torture, &(io.smb2));
1356 CHECK_STATUS(status, NT_STATUS_OK);
1357 h1 = io.smb2.out.file.handle;
1359 /* ask for a change notify,
1360 on file or directory name changes */
1361 ZERO_STRUCT(notify.smb2);
1362 notify.smb2.level = RAW_NOTIFY_SMB2;
1363 notify.smb2.in.buffer_size = 1000;
1364 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1365 notify.smb2.in.file.handle = h1;
1366 notify.smb2.in.recursive = true;
1368 req = smb2_notify_send(tree1, &(notify.smb2));
1370 WAIT_FOR_ASYNC_RESPONSE(req);
1372 status = smb2_util_close(tree1, h1);
1373 CHECK_STATUS(status, NT_STATUS_OK);
1375 status = smb2_notify_recv(req, torture, &(notify.smb2));
1376 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1377 CHECK_VAL(notify.smb2.out.num_changes, 0);
1379 done:
1380 smb2_deltree(tree1, BASEDIR);
1381 return ret;
1385 basic testing of change notifies followed by a ulogoff
1388 static bool torture_smb2_notify_ulogoff(struct torture_context *torture,
1389 struct smb2_tree *tree1)
1391 bool ret = true;
1392 NTSTATUS status;
1393 union smb_notify notify;
1394 union smb_open io;
1395 struct smb2_handle h1;
1396 struct smb2_request *req;
1398 smb2_deltree(tree1, BASEDIR);
1399 smb2_util_rmdir(tree1, BASEDIR);
1401 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1404 get a handle on the directory
1406 ZERO_STRUCT(io.smb2);
1407 io.generic.level = RAW_OPEN_SMB2;
1408 io.smb2.in.create_flags = 0;
1409 io.smb2.in.desired_access = SEC_FILE_ALL;
1410 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1411 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1412 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1413 NTCREATEX_SHARE_ACCESS_WRITE;
1414 io.smb2.in.alloc_size = 0;
1415 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1416 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1417 io.smb2.in.security_flags = 0;
1418 io.smb2.in.fname = BASEDIR;
1420 status = smb2_create(tree1, torture, &(io.smb2));
1421 CHECK_STATUS(status, NT_STATUS_OK);
1423 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1424 status = smb2_create(tree1, torture, &(io.smb2));
1425 CHECK_STATUS(status, NT_STATUS_OK);
1426 h1 = io.smb2.out.file.handle;
1428 /* ask for a change notify,
1429 on file or directory name changes */
1430 ZERO_STRUCT(notify.smb2);
1431 notify.smb2.level = RAW_NOTIFY_SMB2;
1432 notify.smb2.in.buffer_size = 1000;
1433 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1434 notify.smb2.in.file.handle = h1;
1435 notify.smb2.in.recursive = true;
1437 req = smb2_notify_send(tree1, &(notify.smb2));
1439 WAIT_FOR_ASYNC_RESPONSE(req);
1441 status = smb2_logoff(tree1->session);
1442 CHECK_STATUS(status, NT_STATUS_OK);
1444 status = smb2_notify_recv(req, torture, &(notify.smb2));
1445 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1446 CHECK_VAL(notify.smb2.out.num_changes, 0);
1448 done:
1449 smb2_deltree(tree1, BASEDIR);
1450 return ret;
1454 basic testing of change notifies followed by a session reconnect
1457 static bool torture_smb2_notify_session_reconnect(struct torture_context *torture,
1458 struct smb2_tree *tree1)
1460 bool ret = true;
1461 NTSTATUS status;
1462 union smb_notify notify;
1463 union smb_open io;
1464 struct smb2_handle h1;
1465 struct smb2_request *req;
1466 uint64_t previous_session_id = 0;
1467 struct smb2_session *session2 = NULL;
1469 smb2_deltree(tree1, BASEDIR);
1470 smb2_util_rmdir(tree1, BASEDIR);
1472 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY SESSION RECONNECT\n");
1475 get a handle on the directory
1477 ZERO_STRUCT(io.smb2);
1478 io.generic.level = RAW_OPEN_SMB2;
1479 io.smb2.in.create_flags = 0;
1480 io.smb2.in.desired_access = SEC_FILE_ALL;
1481 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1482 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1483 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1484 NTCREATEX_SHARE_ACCESS_WRITE;
1485 io.smb2.in.alloc_size = 0;
1486 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1487 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1488 io.smb2.in.security_flags = 0;
1489 io.smb2.in.fname = BASEDIR;
1491 status = smb2_create(tree1, torture, &(io.smb2));
1492 CHECK_STATUS(status, NT_STATUS_OK);
1494 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1495 status = smb2_create(tree1, torture, &(io.smb2));
1496 CHECK_STATUS(status, NT_STATUS_OK);
1497 h1 = io.smb2.out.file.handle;
1499 /* ask for a change notify,
1500 on file or directory name changes */
1501 ZERO_STRUCT(notify.smb2);
1502 notify.smb2.level = RAW_NOTIFY_SMB2;
1503 notify.smb2.in.buffer_size = 1000;
1504 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1505 notify.smb2.in.file.handle = h1;
1506 notify.smb2.in.recursive = true;
1508 req = smb2_notify_send(tree1, &(notify.smb2));
1510 WAIT_FOR_ASYNC_RESPONSE(req);
1512 previous_session_id = smb2cli_session_current_id(tree1->session->smbXcli);
1513 torture_assert(torture, torture_smb2_session_setup(torture,
1514 tree1->session->transport,
1515 previous_session_id,
1516 torture, &session2),
1517 "session setup with previous_session_id failed");
1519 status = smb2_notify_recv(req, torture, &(notify.smb2));
1520 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1521 CHECK_VAL(notify.smb2.out.num_changes, 0);
1523 status = smb2_logoff(tree1->session);
1524 CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
1526 status = smb2_logoff(session2);
1527 CHECK_STATUS(status, NT_STATUS_OK);
1528 done:
1529 smb2_deltree(tree1, BASEDIR);
1530 return ret;
1534 basic testing of change notifies followed by an invalid reauth
1537 static bool torture_smb2_notify_invalid_reauth(struct torture_context *torture,
1538 struct smb2_tree *tree1,
1539 struct smb2_tree *tree2)
1541 bool ret = true;
1542 NTSTATUS status;
1543 union smb_notify notify;
1544 union smb_open io;
1545 struct smb2_handle h1;
1546 struct smb2_request *req;
1547 struct cli_credentials *invalid_creds;
1549 smb2_deltree(tree2, BASEDIR);
1550 smb2_util_rmdir(tree2, BASEDIR);
1552 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY invalid REAUTH\n");
1555 get a handle on the directory
1557 ZERO_STRUCT(io.smb2);
1558 io.generic.level = RAW_OPEN_SMB2;
1559 io.smb2.in.create_flags = 0;
1560 io.smb2.in.desired_access = SEC_FILE_ALL;
1561 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1562 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1563 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1564 NTCREATEX_SHARE_ACCESS_WRITE;
1565 io.smb2.in.alloc_size = 0;
1566 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1567 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1568 io.smb2.in.security_flags = 0;
1569 io.smb2.in.fname = BASEDIR;
1571 status = smb2_create(tree1, torture, &(io.smb2));
1572 CHECK_STATUS(status, NT_STATUS_OK);
1574 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1575 status = smb2_create(tree1, torture, &(io.smb2));
1576 CHECK_STATUS(status, NT_STATUS_OK);
1577 h1 = io.smb2.out.file.handle;
1579 /* ask for a change notify,
1580 on file or directory name changes */
1581 ZERO_STRUCT(notify.smb2);
1582 notify.smb2.level = RAW_NOTIFY_SMB2;
1583 notify.smb2.in.buffer_size = 1000;
1584 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1585 notify.smb2.in.file.handle = h1;
1586 notify.smb2.in.recursive = true;
1588 req = smb2_notify_send(tree1, &(notify.smb2));
1590 WAIT_FOR_ASYNC_RESPONSE(req);
1592 invalid_creds = cli_credentials_init(torture);
1593 torture_assert(torture, (invalid_creds != NULL), "talloc error");
1594 cli_credentials_set_username(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1595 cli_credentials_set_domain(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1596 cli_credentials_set_password(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1597 cli_credentials_set_realm(invalid_creds, NULL, CRED_SPECIFIED);
1598 cli_credentials_set_workstation(invalid_creds, "", CRED_UNINITIALISED);
1600 status = smb2_session_setup_spnego(tree1->session,
1601 invalid_creds,
1602 0 /* previous_session_id */);
1603 CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE);
1605 status = smb2_notify_recv(req, torture, &(notify.smb2));
1606 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1607 CHECK_VAL(notify.smb2.out.num_changes, 0);
1609 done:
1610 smb2_deltree(tree2, BASEDIR);
1611 return ret;
1614 static void tcp_dis_handler(struct smb2_transport *t, void *p)
1616 struct smb2_tree *tree = (struct smb2_tree *)p;
1617 smb2_transport_dead(tree->session->transport,
1618 NT_STATUS_LOCAL_DISCONNECT);
1619 t = NULL;
1620 tree = NULL;
1624 basic testing of change notifies followed by tcp disconnect
1627 static bool torture_smb2_notify_tcp_disconnect(
1628 struct torture_context *torture,
1629 struct smb2_tree *tree)
1631 bool ret = true;
1632 NTSTATUS status;
1633 union smb_notify notify;
1634 union smb_open io;
1635 struct smb2_handle h1;
1636 struct smb2_request *req;
1638 smb2_deltree(tree, BASEDIR);
1639 smb2_util_rmdir(tree, BASEDIR);
1641 torture_comment(torture,
1642 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1645 get a handle on the directory
1647 ZERO_STRUCT(io.smb2);
1648 io.generic.level = RAW_OPEN_SMB2;
1649 io.smb2.in.create_flags = 0;
1650 io.smb2.in.desired_access = SEC_FILE_ALL;
1651 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1652 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1653 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1654 NTCREATEX_SHARE_ACCESS_WRITE;
1655 io.smb2.in.alloc_size = 0;
1656 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1657 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1658 io.smb2.in.security_flags = 0;
1659 io.smb2.in.fname = BASEDIR;
1661 status = smb2_create(tree, torture, &(io.smb2));
1662 CHECK_STATUS(status, NT_STATUS_OK);
1663 h1 = io.smb2.out.file.handle;
1665 /* ask for a change notify,
1666 on file or directory name changes */
1667 ZERO_STRUCT(notify.smb2);
1668 notify.smb2.level = RAW_NOTIFY_SMB2;
1669 notify.smb2.in.buffer_size = 1000;
1670 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1671 notify.smb2.in.file.handle = h1;
1672 notify.smb2.in.recursive = true;
1674 req = smb2_notify_send(tree, &(notify.smb2));
1675 smb2_cancel(req);
1676 status = smb2_notify_recv(req, torture, &(notify.smb2));
1677 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1679 notify.smb2.in.recursive = true;
1680 req = smb2_notify_send(tree, &(notify.smb2));
1681 smb2_transport_idle_handler(tree->session->transport,
1682 tcp_dis_handler, 250, tree);
1683 tree = NULL;
1684 status = smb2_notify_recv(req, torture, &(notify.smb2));
1685 CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
1687 done:
1688 return ret;
1692 test setting up two change notify requests on one handle
1695 static bool torture_smb2_notify_double(struct torture_context *torture,
1696 struct smb2_tree *tree1,
1697 struct smb2_tree *tree2)
1699 bool ret = true;
1700 NTSTATUS status;
1701 union smb_notify notify;
1702 union smb_open io;
1703 struct smb2_handle h1;
1704 struct smb2_request *req1, *req2;
1706 smb2_deltree(tree1, BASEDIR);
1707 smb2_util_rmdir(tree1, BASEDIR);
1709 torture_comment(torture,
1710 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1713 get a handle on the directory
1715 ZERO_STRUCT(io.smb2);
1716 io.generic.level = RAW_OPEN_SMB2;
1717 io.smb2.in.create_flags = 0;
1718 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ|
1719 SEC_RIGHTS_FILE_WRITE|
1720 SEC_RIGHTS_FILE_ALL;
1721 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1722 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1723 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1724 NTCREATEX_SHARE_ACCESS_WRITE;
1725 io.smb2.in.alloc_size = 0;
1726 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1727 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1728 io.smb2.in.security_flags = 0;
1729 io.smb2.in.fname = BASEDIR;
1731 status = smb2_create(tree1, torture, &(io.smb2));
1732 CHECK_STATUS(status, NT_STATUS_OK);
1733 h1 = io.smb2.out.file.handle;
1735 /* ask for a change notify,
1736 on file or directory name changes */
1737 ZERO_STRUCT(notify.smb2);
1738 notify.smb2.level = RAW_NOTIFY_SMB2;
1739 notify.smb2.in.buffer_size = 1000;
1740 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1741 notify.smb2.in.file.handle = h1;
1742 notify.smb2.in.recursive = true;
1744 req1 = smb2_notify_send(tree1, &(notify.smb2));
1745 smb2_cancel(req1);
1746 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1747 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1749 req2 = smb2_notify_send(tree1, &(notify.smb2));
1750 smb2_cancel(req2);
1751 status = smb2_notify_recv(req2, torture, &(notify.smb2));
1752 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1754 smb2_util_mkdir(tree2, BASEDIR "\\subdir-name");
1755 req1 = smb2_notify_send(tree1, &(notify.smb2));
1756 req2 = smb2_notify_send(tree1, &(notify.smb2));
1758 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1759 CHECK_STATUS(status, NT_STATUS_OK);
1760 CHECK_VAL(notify.smb2.out.num_changes, 1);
1761 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1763 smb2_util_mkdir(tree2, BASEDIR "\\subdir-name2");
1765 status = smb2_notify_recv(req2, torture, &(notify.smb2));
1766 CHECK_STATUS(status, NT_STATUS_OK);
1767 CHECK_VAL(notify.smb2.out.num_changes, 1);
1768 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name2");
1770 done:
1771 smb2_deltree(tree1, BASEDIR);
1772 return ret;
1777 test multiple change notifies at different depths and with/without recursion
1780 static bool torture_smb2_notify_tree(struct torture_context *torture,
1781 struct smb2_tree *tree)
1783 bool ret = true;
1784 union smb_notify notify;
1785 union smb_open io;
1786 struct smb2_request *req;
1787 struct timeval tv;
1788 struct {
1789 const char *path;
1790 bool recursive;
1791 uint32_t filter;
1792 int expected;
1793 struct smb2_handle h1;
1794 int counted;
1795 } dirs[] = {
1796 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 30 },
1797 {BASEDIR "\\zqy", true, FILE_NOTIFY_CHANGE_NAME, 8 },
1798 {BASEDIR "\\atsy", true, FILE_NOTIFY_CHANGE_NAME, 4 },
1799 {BASEDIR "\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1800 {BASEDIR "\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME, 13 },
1801 {BASEDIR "\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME, 7 },
1802 {BASEDIR "\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1803 {BASEDIR "\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1804 {BASEDIR "\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1805 {BASEDIR "\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1806 {BASEDIR "\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1807 {BASEDIR "\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1808 {BASEDIR "\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME, 40 },
1809 {BASEDIR, true, FILE_NOTIFY_CHANGE_NAME, 40 },
1810 {BASEDIR, false,FILE_NOTIFY_CHANGE_NAME, 6 },
1811 {BASEDIR "\\atsy", false,FILE_NOTIFY_CHANGE_NAME, 4 },
1812 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1813 {BASEDIR "\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1814 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1815 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1817 int i;
1818 NTSTATUS status;
1819 bool all_done = false;
1821 smb2_deltree(tree, BASEDIR);
1822 smb2_util_rmdir(tree, BASEDIR);
1824 torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1826 ZERO_STRUCT(io.smb2);
1827 io.generic.level = RAW_OPEN_SMB2;
1828 io.smb2.in.create_flags = 0;
1829 io.smb2.in.desired_access = SEC_FILE_ALL;
1830 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1831 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1832 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1833 NTCREATEX_SHARE_ACCESS_WRITE;
1834 io.smb2.in.alloc_size = 0;
1835 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1836 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1837 io.smb2.in.security_flags = 0;
1838 io.smb2.in.fname = BASEDIR;
1839 status = smb2_create(tree, torture, &(io.smb2));
1840 CHECK_STATUS(status, NT_STATUS_OK);
1842 ZERO_STRUCT(notify.smb2);
1843 notify.smb2.level = RAW_NOTIFY_SMB2;
1844 notify.smb2.in.buffer_size = 20000;
1847 setup the directory tree, and the notify buffer on each directory
1849 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1850 io.smb2.in.fname = dirs[i].path;
1851 status = smb2_create(tree, torture, &(io.smb2));
1852 CHECK_STATUS(status, NT_STATUS_OK);
1853 dirs[i].h1 = io.smb2.out.file.handle;
1855 notify.smb2.in.completion_filter = dirs[i].filter;
1856 notify.smb2.in.file.handle = dirs[i].h1;
1857 notify.smb2.in.recursive = dirs[i].recursive;
1858 req = smb2_notify_send(tree, &(notify.smb2));
1859 smb2_cancel(req);
1860 status = smb2_notify_recv(req, torture, &(notify.smb2));
1861 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1864 /* trigger 2 events in each dir */
1865 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1866 char *path = talloc_asprintf(torture, "%s\\test.dir",
1867 dirs[i].path);
1868 smb2_util_mkdir(tree, path);
1869 smb2_util_rmdir(tree, path);
1870 talloc_free(path);
1873 /* give a bit of time for the events to propogate */
1874 tv = timeval_current();
1876 do {
1877 /* count events that have happened in each dir */
1878 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1879 notify.smb2.in.file.handle = dirs[i].h1;
1880 req = smb2_notify_send(tree, &(notify.smb2));
1881 smb2_cancel(req);
1882 notify.smb2.out.num_changes = 0;
1883 status = smb2_notify_recv(req, torture,
1884 &(notify.smb2));
1885 dirs[i].counted += notify.smb2.out.num_changes;
1888 all_done = true;
1890 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1891 if (dirs[i].counted != dirs[i].expected) {
1892 all_done = false;
1895 } while (!all_done && timeval_elapsed(&tv) < 20);
1897 torture_comment(torture, "took %.4f seconds to propogate all events\n",
1898 timeval_elapsed(&tv));
1900 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1901 if (dirs[i].counted != dirs[i].expected) {
1902 torture_comment(torture,
1903 "ERROR: i=%d expected %d got %d for '%s'\n",
1904 i, dirs[i].expected, dirs[i].counted,
1905 dirs[i].path);
1906 ret = false;
1911 run from the back, closing and deleting
1913 for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1914 smb2_util_close(tree, dirs[i].h1);
1915 smb2_util_rmdir(tree, dirs[i].path);
1918 done:
1919 smb2_deltree(tree, BASEDIR);
1920 smb2_util_rmdir(tree, BASEDIR);
1921 return ret;
1925 Test response when cached server events exceed single NT NOTFIY response
1926 packet size.
1929 static bool torture_smb2_notify_overflow(struct torture_context *torture,
1930 struct smb2_tree *tree)
1932 bool ret = true;
1933 NTSTATUS status;
1934 union smb_notify notify;
1935 union smb_open io;
1936 struct smb2_handle h1, h2;
1937 int count = 100;
1938 struct smb2_request *req1;
1939 int i;
1941 smb2_deltree(tree, BASEDIR);
1942 smb2_util_rmdir(tree, BASEDIR);
1944 torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1946 /* get a handle on the directory */
1947 ZERO_STRUCT(io.smb2);
1948 io.generic.level = RAW_OPEN_SMB2;
1949 io.smb2.in.create_flags = 0;
1950 io.smb2.in.desired_access = SEC_FILE_ALL;
1951 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1952 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1953 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1954 NTCREATEX_SHARE_ACCESS_WRITE;
1955 io.smb2.in.alloc_size = 0;
1956 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1957 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1958 io.smb2.in.security_flags = 0;
1959 io.smb2.in.fname = BASEDIR;
1961 status = smb2_create(tree, torture, &(io.smb2));
1962 CHECK_STATUS(status, NT_STATUS_OK);
1963 h1 = io.smb2.out.file.handle;
1965 /* ask for a change notify, on name changes. */
1966 ZERO_STRUCT(notify.smb2);
1967 notify.smb2.level = RAW_NOTIFY_NTTRANS;
1968 notify.smb2.in.buffer_size = 1000;
1969 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1970 notify.smb2.in.file.handle = h1;
1972 notify.smb2.in.recursive = true;
1973 req1 = smb2_notify_send(tree, &(notify.smb2));
1975 /* cancel initial requests so the buffer is setup */
1976 smb2_cancel(req1);
1977 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1978 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1980 /* open a lot of files, filling up the server side notify buffer */
1981 torture_comment(torture,
1982 "Testing overflowed buffer notify on create of %d files\n",
1983 count);
1985 for (i=0;i<count;i++) {
1986 char *fname = talloc_asprintf(torture,
1987 BASEDIR "\\test%d.txt", i);
1988 union smb_open io1;
1989 ZERO_STRUCT(io1.smb2);
1990 io1.generic.level = RAW_OPEN_SMB2;
1991 io1.smb2.in.create_flags = 0;
1992 io1.smb2.in.desired_access = SEC_FILE_ALL;
1993 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1994 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1995 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1996 NTCREATEX_SHARE_ACCESS_WRITE;
1997 io1.smb2.in.alloc_size = 0;
1998 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1999 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2000 io1.smb2.in.security_flags = 0;
2001 io1.smb2.in.fname = fname;
2003 h2 = custom_smb2_create(tree, torture, &(io1.smb2));
2004 talloc_free(fname);
2005 smb2_util_close(tree, h2);
2008 req1 = smb2_notify_send(tree, &(notify.smb2));
2009 status = smb2_notify_recv(req1, torture, &(notify.smb2));
2010 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
2011 CHECK_VAL(notify.smb2.out.num_changes, 0);
2013 done:
2014 smb2_deltree(tree, BASEDIR);
2015 return ret;
2019 Test if notifications are returned for changes to the base directory.
2020 They shouldn't be.
2023 static bool torture_smb2_notify_basedir(struct torture_context *torture,
2024 struct smb2_tree *tree1,
2025 struct smb2_tree *tree2)
2027 bool ret = true;
2028 NTSTATUS status;
2029 union smb_notify notify;
2030 union smb_open io;
2031 struct smb2_handle h1;
2032 struct smb2_request *req1;
2034 smb2_deltree(tree1, BASEDIR);
2035 smb2_util_rmdir(tree1, BASEDIR);
2037 torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
2039 /* get a handle on the directory */
2040 ZERO_STRUCT(io.smb2);
2041 io.generic.level = RAW_OPEN_SMB2;
2042 io.smb2.in.create_flags = 0;
2043 io.smb2.in.desired_access = SEC_FILE_ALL;
2044 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2045 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2046 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2047 NTCREATEX_SHARE_ACCESS_WRITE;
2048 io.smb2.in.alloc_size = 0;
2049 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2050 io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
2051 io.smb2.in.security_flags = 0;
2052 io.smb2.in.fname = BASEDIR;
2054 status = smb2_create(tree1, torture, &(io.smb2));
2055 CHECK_STATUS(status, NT_STATUS_OK);
2056 h1 = io.smb2.out.file.handle;
2058 /* create a test file that will also be modified */
2059 io.smb2.in.fname = BASEDIR "\\tname1";
2060 io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
2061 status = smb2_create(tree2, torture, &(io.smb2));
2062 CHECK_STATUS(status,NT_STATUS_OK);
2063 smb2_util_close(tree2, io.smb2.out.file.handle);
2065 /* ask for a change notify, on attribute changes. */
2066 ZERO_STRUCT(notify.smb2);
2067 notify.smb2.level = RAW_NOTIFY_SMB2;
2068 notify.smb2.in.buffer_size = 1000;
2069 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
2070 notify.smb2.in.file.handle = h1;
2071 notify.smb2.in.recursive = true;
2073 req1 = smb2_notify_send(tree1, &(notify.smb2));
2075 /* set attribute on the base dir */
2076 smb2_util_setatr(tree2, BASEDIR, FILE_ATTRIBUTE_HIDDEN);
2078 /* set attribute on a file to assure we receive a notification */
2079 smb2_util_setatr(tree2, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN);
2080 smb_msleep(200);
2082 /* check how many responses were given, expect only 1 for the file */
2083 status = smb2_notify_recv(req1, torture, &(notify.smb2));
2084 CHECK_STATUS(status, NT_STATUS_OK);
2085 CHECK_VAL(notify.smb2.out.num_changes, 1);
2086 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
2087 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
2089 done:
2090 smb2_deltree(tree1, BASEDIR);
2091 return ret;
2096 create a secondary tree connect - used to test for a bug in Samba3 messaging
2097 with change notify
2099 static struct smb2_tree *secondary_tcon(struct smb2_tree *tree,
2100 struct torture_context *tctx)
2102 NTSTATUS status;
2103 const char *share, *host;
2104 struct smb2_tree *tree1;
2105 union smb_tcon tcon;
2107 share = torture_setting_string(tctx, "share", NULL);
2108 host = torture_setting_string(tctx, "host", NULL);
2110 torture_comment(tctx,
2111 "create a second tree context on the same session\n");
2112 tree1 = smb2_tree_init(tree->session, tctx, false);
2113 if (tree1 == NULL) {
2114 torture_comment(tctx, "Out of memory\n");
2115 return NULL;
2118 ZERO_STRUCT(tcon.smb2);
2119 tcon.generic.level = RAW_TCON_SMB2;
2120 tcon.smb2.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
2121 status = smb2_tree_connect(tree->session, &(tcon.smb2));
2122 if (!NT_STATUS_IS_OK(status)) {
2123 talloc_free(tree1);
2124 torture_comment(tctx,"Failed to create secondary tree\n");
2125 return NULL;
2128 smb2cli_tcon_set_values(tree1->smbXcli,
2129 tree1->session->smbXcli,
2130 tcon.smb2.out.tid,
2131 tcon.smb2.out.share_type,
2132 tcon.smb2.out.flags,
2133 tcon.smb2.out.capabilities,
2134 tcon.smb2.out.access_mask);
2136 torture_comment(tctx,"tid1=%d tid2=%d\n",
2137 smb2cli_tcon_current_id(tree->smbXcli),
2138 smb2cli_tcon_current_id(tree1->smbXcli));
2140 return tree1;
2145 very simple change notify test
2147 static bool torture_smb2_notify_tcon(struct torture_context *torture,
2148 struct smb2_tree *tree)
2150 bool ret = true;
2151 NTSTATUS status;
2152 union smb_notify notify;
2153 union smb_open io;
2154 struct smb2_handle h1;
2155 struct smb2_request *req = NULL;
2156 struct smb2_tree *tree1 = NULL;
2157 const char *fname = BASEDIR "\\subdir-name";
2159 smb2_deltree(tree, BASEDIR);
2160 smb2_util_rmdir(tree, BASEDIR);
2162 torture_comment(torture, "TESTING SIMPLE CHANGE NOTIFY\n");
2165 get a handle on the directory
2168 ZERO_STRUCT(io.smb2);
2169 io.generic.level = RAW_OPEN_SMB2;
2170 io.smb2.in.create_flags = 0;
2171 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2172 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2173 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL |
2174 FILE_ATTRIBUTE_DIRECTORY;
2175 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2176 NTCREATEX_SHARE_ACCESS_WRITE;
2177 io.smb2.in.alloc_size = 0;
2178 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2179 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2180 io.smb2.in.security_flags = 0;
2181 io.smb2.in.fname = BASEDIR;
2183 status = smb2_create(tree, torture, &(io.smb2));
2184 CHECK_STATUS(status, NT_STATUS_OK);
2185 h1 = io.smb2.out.file.handle;
2187 /* ask for a change notify,
2188 on file or directory name changes */
2189 ZERO_STRUCT(notify.smb2);
2190 notify.smb2.level = RAW_NOTIFY_SMB2;
2191 notify.smb2.in.buffer_size = 1000;
2192 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2193 notify.smb2.in.file.handle = h1;
2194 notify.smb2.in.recursive = true;
2196 torture_comment(torture, "Testing notify mkdir\n");
2197 req = smb2_notify_send(tree, &(notify.smb2));
2198 smb2_cancel(req);
2199 status = smb2_notify_recv(req, torture, &(notify.smb2));
2200 CHECK_STATUS(status, NT_STATUS_CANCELLED);
2202 notify.smb2.in.recursive = true;
2203 req = smb2_notify_send(tree, &(notify.smb2));
2204 status = smb2_util_mkdir(tree, fname);
2205 CHECK_STATUS(status, NT_STATUS_OK);
2207 status = smb2_notify_recv(req, torture, &(notify.smb2));
2208 CHECK_STATUS(status, NT_STATUS_OK);
2210 CHECK_VAL(notify.smb2.out.num_changes, 1);
2211 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2212 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2214 torture_comment(torture, "Testing notify rmdir\n");
2215 req = smb2_notify_send(tree, &(notify.smb2));
2216 status = smb2_util_rmdir(tree, fname);
2217 CHECK_STATUS(status, NT_STATUS_OK);
2219 status = smb2_notify_recv(req, torture, &(notify.smb2));
2220 CHECK_STATUS(status, NT_STATUS_OK);
2221 CHECK_VAL(notify.smb2.out.num_changes, 1);
2222 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2223 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2225 torture_comment(torture, "SIMPLE CHANGE NOTIFY OK\n");
2227 torture_comment(torture, "TESTING WITH SECONDARY TCON\n");
2228 tree1 = secondary_tcon(tree, torture);
2230 torture_comment(torture, "Testing notify mkdir\n");
2231 req = smb2_notify_send(tree, &(notify.smb2));
2232 smb2_util_mkdir(tree1, fname);
2234 status = smb2_notify_recv(req, torture, &(notify.smb2));
2235 CHECK_STATUS(status, NT_STATUS_OK);
2237 CHECK_VAL(notify.smb2.out.num_changes, 1);
2238 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2239 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2241 torture_comment(torture, "Testing notify rmdir\n");
2242 req = smb2_notify_send(tree, &(notify.smb2));
2243 smb2_util_rmdir(tree, fname);
2245 status = smb2_notify_recv(req, torture, &(notify.smb2));
2246 CHECK_STATUS(status, NT_STATUS_OK);
2247 CHECK_VAL(notify.smb2.out.num_changes, 1);
2248 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2249 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2251 torture_comment(torture, "CHANGE NOTIFY WITH TCON OK\n");
2253 torture_comment(torture, "Disconnecting secondary tree\n");
2254 status = smb2_tdis(tree1);
2255 CHECK_STATUS(status, NT_STATUS_OK);
2256 talloc_free(tree1);
2258 torture_comment(torture, "Testing notify mkdir\n");
2259 req = smb2_notify_send(tree, &(notify.smb2));
2260 smb2_util_mkdir(tree, fname);
2262 status = smb2_notify_recv(req, torture, &(notify.smb2));
2263 CHECK_STATUS(status, NT_STATUS_OK);
2265 CHECK_VAL(notify.smb2.out.num_changes, 1);
2266 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2267 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2269 torture_comment(torture, "Testing notify rmdir\n");
2270 req = smb2_notify_send(tree, &(notify.smb2));
2271 smb2_util_rmdir(tree, fname);
2273 status = smb2_notify_recv(req, torture, &(notify.smb2));
2274 CHECK_STATUS(status, NT_STATUS_OK);
2275 CHECK_VAL(notify.smb2.out.num_changes, 1);
2276 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2277 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2279 torture_comment(torture, "CHANGE NOTIFY WITH TDIS OK\n");
2280 done:
2281 smb2_util_close(tree, h1);
2282 smb2_deltree(tree, BASEDIR);
2284 return ret;
2288 basic testing of SMB2 change notify
2290 struct torture_suite *torture_smb2_notify_init(void)
2292 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "notify");
2294 torture_suite_add_1smb2_test(suite, "valid-req", test_valid_request);
2295 torture_suite_add_1smb2_test(suite, "tcon", torture_smb2_notify_tcon);
2296 torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir);
2297 torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask);
2298 torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
2299 torture_suite_add_1smb2_test(suite, "tdis1", torture_smb2_notify_tree_disconnect_1);
2300 torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
2301 torture_suite_add_1smb2_test(suite, "close", torture_smb2_notify_close);
2302 torture_suite_add_1smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
2303 torture_suite_add_1smb2_test(suite, "session-reconnect", torture_smb2_notify_session_reconnect);
2304 torture_suite_add_2smb2_test(suite, "invalid-reauth", torture_smb2_notify_invalid_reauth);
2305 torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
2306 torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
2307 torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
2308 torture_suite_add_1smb2_test(suite, "file", torture_smb2_notify_file);
2309 torture_suite_add_1smb2_test(suite, "tcp", torture_smb2_notify_tcp_disconnect);
2310 torture_suite_add_2smb2_test(suite, "rec", torture_smb2_notify_recursive);
2311 torture_suite_add_1smb2_test(suite, "overflow", torture_smb2_notify_overflow);
2313 suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");
2315 return suite;