2 Unix SMB/CIFS implementation.
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/>.
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)); \
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); \
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, \
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) { \
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)
87 struct smb2_handle dh;
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
101 max_buffer_size = torture_setting_ulong(torture, "cn_max_buffer_size",
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) {
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) {
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
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) {
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) {
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) {
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);
225 basic testing of change notify on directories
228 #define BASEDIR_DIR BASEDIR "_DIR"
230 static bool torture_smb2_notify_dir(struct torture_context *torture,
231 struct smb2_tree *tree1,
232 struct smb2_tree *tree2)
236 union smb_notify notify;
240 struct smb2_handle h1 = {{0}};
241 struct smb2_handle h2 = {{0}};
242 struct smb2_request *req, *req2;
243 const char *fname = BASEDIR_DIR "\\subdir-name";
244 extern int torture_numops;
246 torture_comment(torture, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
248 smb2_deltree(tree1, BASEDIR_DIR);
249 smb2_util_rmdir(tree1, BASEDIR_DIR);
251 get a handle on the directory
253 ZERO_STRUCT(io.smb2);
254 io.generic.level = RAW_OPEN_SMB2;
255 io.smb2.in.create_flags = 0;
256 io.smb2.in.desired_access = SEC_FILE_ALL;
257 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
258 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
259 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
260 NTCREATEX_SHARE_ACCESS_WRITE;
261 io.smb2.in.alloc_size = 0;
262 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
263 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
264 io.smb2.in.security_flags = 0;
265 io.smb2.in.fname = BASEDIR_DIR;
267 status = smb2_create(tree1, torture, &(io.smb2));
268 CHECK_STATUS(status, NT_STATUS_OK);
269 h1 = io.smb2.out.file.handle;
271 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
272 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ;
273 status = smb2_create(tree1, torture, &(io.smb2));
274 CHECK_STATUS(status, NT_STATUS_OK);
275 h2 = io.smb2.out.file.handle;
277 /* ask for a change notify,
278 on file or directory name changes */
279 ZERO_STRUCT(notify.smb2);
280 notify.smb2.level = RAW_NOTIFY_SMB2;
281 notify.smb2.in.buffer_size = 1000;
282 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
283 notify.smb2.in.file.handle = h1;
284 notify.smb2.in.recursive = true;
286 torture_comment(torture, "Testing notify cancel\n");
288 req = smb2_notify_send(tree1, &(notify.smb2));
290 status = smb2_notify_recv(req, torture, &(notify.smb2));
291 CHECK_STATUS(status, NT_STATUS_CANCELLED);
293 torture_comment(torture, "Testing notify mkdir\n");
295 req = smb2_notify_send(tree1, &(notify.smb2));
296 smb2_util_mkdir(tree2, fname);
298 status = smb2_notify_recv(req, torture, &(notify.smb2));
299 CHECK_STATUS(status, NT_STATUS_OK);
301 CHECK_VAL(notify.smb2.out.num_changes, 1);
302 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
303 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
305 torture_comment(torture, "Testing notify rmdir\n");
307 req = smb2_notify_send(tree1, &(notify.smb2));
308 smb2_util_rmdir(tree2, fname);
310 status = smb2_notify_recv(req, torture, &(notify.smb2));
311 CHECK_STATUS(status, NT_STATUS_OK);
312 CHECK_VAL(notify.smb2.out.num_changes, 1);
313 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
314 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
316 torture_comment(torture,
317 "Testing notify mkdir - rmdir - mkdir - rmdir\n");
319 smb2_util_mkdir(tree2, fname);
320 smb2_util_rmdir(tree2, fname);
321 smb2_util_mkdir(tree2, fname);
322 smb2_util_rmdir(tree2, fname);
324 req = smb2_notify_send(tree1, &(notify.smb2));
325 status = smb2_notify_recv(req, torture, &(notify.smb2));
326 CHECK_STATUS(status, NT_STATUS_OK);
327 CHECK_VAL(notify.smb2.out.num_changes, 4);
328 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
329 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
330 CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_REMOVED);
331 CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name");
332 CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_ADDED);
333 CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name");
334 CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_REMOVED);
335 CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name");
337 count = torture_numops;
338 torture_comment(torture,
339 "Testing buffered notify on create of %d files\n", count);
340 for (i=0;i<count;i++) {
341 struct smb2_handle h12;
342 char *fname2 = talloc_asprintf(torture,
343 BASEDIR_DIR "\\test%d.txt",
346 ZERO_STRUCT(io.smb2);
347 io.generic.level = RAW_OPEN_SMB2;
348 io.smb2.in.create_flags = 0;
349 io.smb2.in.desired_access = SEC_FILE_ALL;
350 io.smb2.in.create_options =
351 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
352 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
353 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
354 NTCREATEX_SHARE_ACCESS_WRITE;
355 io.smb2.in.alloc_size = 0;
356 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
357 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
358 io.smb2.in.security_flags = 0;
359 io.smb2.in.fname = fname2;
361 status = smb2_create(tree1, torture, &(io.smb2));
362 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
363 torture_comment(torture, "Failed to create %s \n",
368 h12 = io.smb2.out.file.handle;
370 smb2_util_close(tree1, h12);
373 /* (1st notify) setup a new notify on a different directory handle.
374 This new notify won't see the events above. */
375 notify.smb2.in.file.handle = h2;
376 req2 = smb2_notify_send(tree1, &(notify.smb2));
378 /* (2nd notify) whereas this notify will see the above buffered events,
379 and it directly returns the buffered events */
380 notify.smb2.in.file.handle = h1;
381 req = smb2_notify_send(tree1, &(notify.smb2));
383 status = smb2_util_unlink(tree1, BASEDIR_DIR "\\nonexistent.txt");
384 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
386 /* (1st unlink) as the 2nd notify directly returns,
387 this unlink is only seen by the 1st notify and
388 the 3rd notify (later) */
389 torture_comment(torture,
390 "Testing notify on unlink for the first file\n");
391 status = smb2_util_unlink(tree2, BASEDIR_DIR "\\test0.txt");
392 CHECK_STATUS(status, NT_STATUS_OK);
394 /* receive the reply from the 2nd notify */
395 status = smb2_notify_recv(req, torture, &(notify.smb2));
396 CHECK_STATUS(status, NT_STATUS_OK);
398 CHECK_VAL(notify.smb2.out.num_changes, count);
399 for (i=1;i<count;i++) {
400 CHECK_VAL(notify.smb2.out.changes[i].action,
401 NOTIFY_ACTION_ADDED);
403 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
405 torture_comment(torture, "and now from the 1st notify\n");
406 status = smb2_notify_recv(req2, torture, &(notify.smb2));
407 CHECK_STATUS(status, NT_STATUS_OK);
408 CHECK_VAL(notify.smb2.out.num_changes, 1);
409 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
410 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
412 torture_comment(torture,
413 "(3rd notify) this notify will only see the 1st unlink\n");
414 req = smb2_notify_send(tree1, &(notify.smb2));
416 status = smb2_util_unlink(tree1, BASEDIR_DIR "\\nonexistent.txt");
417 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
419 for (i=1;i<count;i++) {
420 char *fname2 = talloc_asprintf(torture,
421 BASEDIR_DIR "\\test%d.txt", i);
422 status = smb2_util_unlink(tree2, fname2);
423 CHECK_STATUS(status, NT_STATUS_OK);
427 /* receive the 3rd notify */
428 status = smb2_notify_recv(req, torture, &(notify.smb2));
429 CHECK_STATUS(status, NT_STATUS_OK);
430 CHECK_VAL(notify.smb2.out.num_changes, 1);
431 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
432 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
434 /* and we now see the rest of the unlink calls on both
435 * directory handles */
436 notify.smb2.in.file.handle = h1;
438 req = smb2_notify_send(tree1, &(notify.smb2));
439 status = smb2_notify_recv(req, torture, &(notify.smb2));
440 CHECK_STATUS(status, NT_STATUS_OK);
441 CHECK_VAL(notify.smb2.out.num_changes, count-1);
442 for (i=0;i<notify.smb2.out.num_changes;i++) {
443 CHECK_VAL(notify.smb2.out.changes[i].action,
444 NOTIFY_ACTION_REMOVED);
446 notify.smb2.in.file.handle = h2;
447 req = smb2_notify_send(tree1, &(notify.smb2));
448 status = smb2_notify_recv(req, torture, &(notify.smb2));
449 CHECK_STATUS(status, NT_STATUS_OK);
450 CHECK_VAL(notify.smb2.out.num_changes, count-1);
451 for (i=0;i<notify.smb2.out.num_changes;i++) {
452 CHECK_VAL(notify.smb2.out.changes[i].action,
453 NOTIFY_ACTION_REMOVED);
456 torture_comment(torture,
457 "Testing if a close() on the dir handle triggers the notify reply\n");
459 notify.smb2.in.file.handle = h1;
460 req = smb2_notify_send(tree1, &(notify.smb2));
462 ZERO_STRUCT(cl.smb2);
463 cl.smb2.level = RAW_CLOSE_SMB2;
464 cl.smb2.in.file.handle = h1;
465 status = smb2_close(tree1, &(cl.smb2));
466 CHECK_STATUS(status, NT_STATUS_OK);
468 status = smb2_notify_recv(req, torture, &(notify.smb2));
469 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
470 CHECK_VAL(notify.smb2.out.num_changes, 9);
473 smb2_util_close(tree1, h1);
474 smb2_util_close(tree1, h2);
475 smb2_deltree(tree1, BASEDIR_DIR);
479 static struct smb2_handle custom_smb2_create(struct smb2_tree *tree,
480 struct torture_context *torture,
481 struct smb2_create *smb2)
483 struct smb2_handle h1;
486 smb2_deltree(tree, smb2->in.fname);
487 status = smb2_create(tree, torture, smb2);
488 CHECK_STATUS(status, NT_STATUS_OK);
489 h1 = smb2->out.file.handle;
492 h1 = (struct smb2_handle) {
500 testing of recursive change notify
503 #define BASEDIR_REC BASEDIR "_REC"
505 static bool torture_smb2_notify_recursive(struct torture_context *torture,
506 struct smb2_tree *tree1,
507 struct smb2_tree *tree2)
511 union smb_notify notify;
512 union smb_open io, io1;
513 union smb_setfileinfo sinfo;
514 struct smb2_handle h1;
515 struct smb2_request *req1, *req2;
517 smb2_deltree(tree1, BASEDIR_REC);
518 smb2_util_rmdir(tree1, BASEDIR_REC);
520 torture_comment(torture, "TESTING CHANGE NOTIFY WITH RECURSION\n");
523 get a handle on the directory
525 ZERO_STRUCT(io.smb2);
526 io.generic.level = RAW_OPEN_SMB2;
527 io.smb2.in.create_flags = 0;
528 io.smb2.in.desired_access = SEC_FILE_ALL;
529 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
530 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
531 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
532 NTCREATEX_SHARE_ACCESS_WRITE;
533 io.smb2.in.alloc_size = 0;
534 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
535 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
536 io.smb2.in.security_flags = 0;
537 io.smb2.in.fname = BASEDIR_REC;
539 status = smb2_create(tree1, torture, &(io.smb2));
540 CHECK_STATUS(status, NT_STATUS_OK);
541 h1 = io.smb2.out.file.handle;
543 /* ask for a change notify, on file or directory name
544 changes. Setup both with and without recursion */
545 ZERO_STRUCT(notify.smb2);
546 notify.smb2.level = RAW_NOTIFY_SMB2;
547 notify.smb2.in.buffer_size = 1000;
548 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
549 FILE_NOTIFY_CHANGE_ATTRIBUTES |
550 FILE_NOTIFY_CHANGE_CREATION;
551 notify.smb2.in.file.handle = h1;
553 notify.smb2.in.recursive = true;
554 req1 = smb2_notify_send(tree1, &(notify.smb2));
556 status = smb2_notify_recv(req1, torture, &(notify.smb2));
557 CHECK_STATUS(status, NT_STATUS_CANCELLED);
559 notify.smb2.in.recursive = false;
560 req2 = smb2_notify_send(tree1, &(notify.smb2));
562 status = smb2_notify_recv(req2, torture, &(notify.smb2));
563 CHECK_STATUS(status, NT_STATUS_CANCELLED);
565 ZERO_STRUCT(io1.smb2);
566 io1.generic.level = RAW_OPEN_SMB2;
567 io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
568 io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
569 SEC_RIGHTS_FILE_WRITE|
571 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
572 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
573 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
574 NTCREATEX_SHARE_ACCESS_WRITE |
575 NTCREATEX_SHARE_ACCESS_DELETE;
576 io1.smb2.in.alloc_size = 0;
577 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
578 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
579 io1.smb2.in.security_flags = 0;
580 io1.smb2.in.fname = BASEDIR_REC "\\subdir-name";
581 status = smb2_create(tree2, torture, &(io1.smb2));
582 CHECK_STATUS(status, NT_STATUS_OK);
583 smb2_util_close(tree2, io1.smb2.out.file.handle);
585 io1.smb2.in.fname = BASEDIR_REC "\\subdir-name\\subname1";
586 status = smb2_create(tree2, torture, &(io1.smb2));
587 CHECK_STATUS(status, NT_STATUS_OK);
589 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
590 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
591 sinfo.rename_information.in.overwrite = 0;
592 sinfo.rename_information.in.root_fid = 0;
593 sinfo.rename_information.in.new_name =
594 BASEDIR_REC "\\subdir-name\\subname1-r";
595 status = smb2_setinfo_file(tree2, &sinfo);
596 CHECK_STATUS(status, NT_STATUS_OK);
598 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
599 io1.smb2.in.fname = BASEDIR_REC "\\subdir-name\\subname2";
600 status = smb2_create(tree2, torture, &(io1.smb2));
601 CHECK_STATUS(status, NT_STATUS_OK);
603 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
604 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
605 sinfo.rename_information.in.overwrite = true;
606 sinfo.rename_information.in.root_fid = 0;
607 sinfo.rename_information.in.new_name = BASEDIR_REC "\\subname2-r";
608 status = smb2_setinfo_file(tree2, &sinfo);
609 CHECK_STATUS(status, NT_STATUS_OK);
611 io1.smb2.in.fname = BASEDIR_REC "\\subname2-r";
612 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
613 status = smb2_create(tree2, torture, &(io1.smb2));
614 CHECK_STATUS(status, NT_STATUS_OK);
616 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
617 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
618 sinfo.rename_information.in.overwrite = true;
619 sinfo.rename_information.in.root_fid = 0;
620 sinfo.rename_information.in.new_name = BASEDIR_REC "\\subname3-r";
621 status = smb2_setinfo_file(tree2, &sinfo);
622 CHECK_STATUS(status, NT_STATUS_OK);
624 notify.smb2.in.completion_filter = 0;
625 notify.smb2.in.recursive = true;
627 req1 = smb2_notify_send(tree1, &(notify.smb2));
629 status = smb2_util_rmdir(tree2,
630 BASEDIR_REC "\\subdir-name\\subname1-r");
631 CHECK_STATUS(status, NT_STATUS_OK);
632 status = smb2_util_rmdir(tree2,
633 BASEDIR_REC "\\subdir-name");
634 CHECK_STATUS(status, NT_STATUS_OK);
635 status = smb2_util_unlink(tree2, BASEDIR_REC "\\subname3-r");
636 CHECK_STATUS(status, NT_STATUS_OK);
638 notify.smb2.in.recursive = false;
639 req2 = smb2_notify_send(tree1, &(notify.smb2));
641 status = smb2_notify_recv(req1, torture, &(notify.smb2));
642 CHECK_STATUS(status, NT_STATUS_OK);
644 CHECK_VAL(notify.smb2.out.num_changes, 9);
645 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
646 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
647 CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_ADDED);
648 CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name\\subname1");
649 CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_OLD_NAME);
650 CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name\\subname1");
651 CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_NEW_NAME);
652 CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name\\subname1-r");
653 CHECK_VAL(notify.smb2.out.changes[4].action, NOTIFY_ACTION_ADDED);
654 CHECK_WIRE_STR(notify.smb2.out.changes[4].name, "subdir-name\\subname2");
655 CHECK_VAL(notify.smb2.out.changes[5].action, NOTIFY_ACTION_REMOVED);
656 CHECK_WIRE_STR(notify.smb2.out.changes[5].name, "subdir-name\\subname2");
657 CHECK_VAL(notify.smb2.out.changes[6].action, NOTIFY_ACTION_ADDED);
658 CHECK_WIRE_STR(notify.smb2.out.changes[6].name, "subname2-r");
659 CHECK_VAL(notify.smb2.out.changes[7].action, NOTIFY_ACTION_OLD_NAME);
660 CHECK_WIRE_STR(notify.smb2.out.changes[7].name, "subname2-r");
661 CHECK_VAL(notify.smb2.out.changes[8].action, NOTIFY_ACTION_NEW_NAME);
662 CHECK_WIRE_STR(notify.smb2.out.changes[8].name, "subname3-r");
665 smb2_deltree(tree1, BASEDIR_REC);
670 testing of change notify mask change
673 #define BASEDIR_MC BASEDIR "_MC"
675 static bool torture_smb2_notify_mask_change(struct torture_context *torture,
676 struct smb2_tree *tree1,
677 struct smb2_tree *tree2)
681 union smb_notify notify;
682 union smb_open io, io1;
683 struct smb2_handle h1;
684 struct smb2_request *req1, *req2;
685 union smb_setfileinfo sinfo;
687 smb2_deltree(tree1, BASEDIR_MC);
688 smb2_util_rmdir(tree1, BASEDIR_MC);
690 torture_comment(torture, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
693 get a handle on the directory
695 ZERO_STRUCT(io.smb2);
696 io.generic.level = RAW_OPEN_SMB2;
697 io.smb2.in.create_flags = 0;
698 io.smb2.in.desired_access = SEC_FILE_ALL;
699 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
700 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
701 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
702 NTCREATEX_SHARE_ACCESS_WRITE;
703 io.smb2.in.alloc_size = 0;
704 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
705 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
706 io.smb2.in.security_flags = 0;
707 io.smb2.in.fname = BASEDIR_MC;
709 status = smb2_create(tree1, torture, &(io.smb2));
710 CHECK_STATUS(status, NT_STATUS_OK);
711 h1 = io.smb2.out.file.handle;
713 /* ask for a change notify, on file or directory name
714 changes. Setup both with and without recursion */
715 ZERO_STRUCT(notify.smb2);
716 notify.smb2.level = RAW_NOTIFY_SMB2;
717 notify.smb2.in.buffer_size = 1000;
718 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
719 notify.smb2.in.file.handle = h1;
721 notify.smb2.in.recursive = true;
722 req1 = smb2_notify_send(tree1, &(notify.smb2));
725 status = smb2_notify_recv(req1, torture, &(notify.smb2));
726 CHECK_STATUS(status, NT_STATUS_CANCELLED);
729 notify.smb2.in.recursive = false;
730 req2 = smb2_notify_send(tree1, &(notify.smb2));
733 status = smb2_notify_recv(req2, torture, &(notify.smb2));
734 CHECK_STATUS(status, NT_STATUS_CANCELLED);
736 notify.smb2.in.recursive = true;
737 req1 = smb2_notify_send(tree1, &(notify.smb2));
739 /* Set to hidden then back again. */
740 ZERO_STRUCT(io1.smb2);
741 io1.generic.level = RAW_OPEN_SMB2;
742 io1.smb2.in.create_flags = 0;
743 io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
744 SEC_RIGHTS_FILE_WRITE|
746 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
747 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
748 NTCREATEX_SHARE_ACCESS_WRITE |
749 NTCREATEX_SHARE_ACCESS_DELETE;
750 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
751 io1.smb2.in.security_flags = 0;
752 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
753 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
754 io1.smb2.in.fname = BASEDIR_MC "\\tname1";
756 smb2_util_close(tree1,
757 custom_smb2_create(tree1, torture, &(io1.smb2)));
758 status = smb2_util_setatr(tree1, BASEDIR_MC "\\tname1",
759 FILE_ATTRIBUTE_HIDDEN);
760 CHECK_STATUS(status, NT_STATUS_OK);
761 smb2_util_unlink(tree1, BASEDIR_MC "\\tname1");
763 status = smb2_notify_recv(req1, torture, &(notify.smb2));
764 CHECK_STATUS(status, NT_STATUS_OK);
766 CHECK_VAL(notify.smb2.out.num_changes, 1);
767 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
768 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
770 /* Now try and change the mask to include other events.
771 * This should not work - once the mask is set on a directory
772 * h1 it seems to be fixed until the fnum is closed. */
774 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
775 FILE_NOTIFY_CHANGE_ATTRIBUTES |
776 FILE_NOTIFY_CHANGE_CREATION;
777 notify.smb2.in.recursive = true;
778 req1 = smb2_notify_send(tree1, &(notify.smb2));
780 notify.smb2.in.recursive = false;
781 req2 = smb2_notify_send(tree1, &(notify.smb2));
783 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
784 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
785 io1.smb2.in.fname = BASEDIR_MC "\\subdir-name";
786 status = smb2_create(tree2, torture, &(io1.smb2));
787 CHECK_STATUS(status, NT_STATUS_OK);
788 smb2_util_close(tree2, io1.smb2.out.file.handle);
791 io1.smb2.in.fname = BASEDIR_MC "\\subdir-name\\subname1";
792 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
793 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
794 status = smb2_create(tree2, torture, &(io1.smb2));
795 CHECK_STATUS(status, NT_STATUS_OK);
796 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
797 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
798 sinfo.rename_information.in.overwrite = true;
799 sinfo.rename_information.in.root_fid = 0;
800 sinfo.rename_information.in.new_name =
801 BASEDIR_MC "\\subdir-name\\subname1-r";
802 status = smb2_setinfo_file(tree2, &sinfo);
803 CHECK_STATUS(status, NT_STATUS_OK);
805 io1.smb2.in.fname = BASEDIR_MC "\\subdir-name\\subname2";
806 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
807 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
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_MC "\\subname2-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 io1.smb2.in.fname = BASEDIR_MC "\\subname2-r";
817 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
818 status = smb2_create(tree2, torture, &(io1.smb2));
819 CHECK_STATUS(status, NT_STATUS_OK);
820 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
821 sinfo.rename_information.in.new_name = BASEDIR_MC "\\subname3-r";
822 status = smb2_setinfo_file(tree2, &sinfo);
823 CHECK_STATUS(status, NT_STATUS_OK);
824 smb2_util_close(tree2, io1.smb2.out.file.handle);
826 status = smb2_util_rmdir(tree2, BASEDIR_MC "\\subdir-name\\subname1-r");
827 CHECK_STATUS(status, NT_STATUS_OK);
828 status = smb2_util_rmdir(tree2, BASEDIR_MC "\\subdir-name");
829 CHECK_STATUS(status, NT_STATUS_OK);
830 status = smb2_util_unlink(tree2, BASEDIR_MC "\\subname3-r");
831 CHECK_STATUS(status, NT_STATUS_OK);
833 status = smb2_notify_recv(req1, torture, &(notify.smb2));
834 CHECK_STATUS(status, NT_STATUS_OK);
836 CHECK_VAL(notify.smb2.out.num_changes, 1);
837 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
838 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname2-r");
840 status = smb2_notify_recv(req2, torture, &(notify.smb2));
841 CHECK_STATUS(status, NT_STATUS_OK);
843 CHECK_VAL(notify.smb2.out.num_changes, 1);
844 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
845 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname3-r");
852 smb2_deltree(tree1, BASEDIR_MC);
857 testing of mask bits for change notify
860 #define BASEDIR_MSK BASEDIR "_MSK"
862 static bool torture_smb2_notify_mask(struct torture_context *torture,
863 struct smb2_tree *tree1,
864 struct smb2_tree *tree2)
868 union smb_notify notify;
869 union smb_open io, io1;
870 struct smb2_handle h1, h2;
874 union smb_setfileinfo sinfo;
876 smb2_deltree(tree1, BASEDIR_MSK);
877 smb2_util_rmdir(tree1, BASEDIR_MSK);
879 torture_comment(torture, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
885 get a handle on the directory
887 ZERO_STRUCT(io.smb2);
888 io.generic.level = RAW_OPEN_SMB2;
889 io.smb2.in.create_flags = 0;
890 io.smb2.in.desired_access = SEC_FILE_ALL;
891 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
892 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
893 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
894 NTCREATEX_SHARE_ACCESS_WRITE;
895 io.smb2.in.alloc_size = 0;
896 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
897 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
898 io.smb2.in.security_flags = 0;
899 io.smb2.in.fname = BASEDIR_MSK;
901 ZERO_STRUCT(notify.smb2);
902 notify.smb2.level = RAW_NOTIFY_SMB2;
903 notify.smb2.in.buffer_size = 1000;
904 notify.smb2.in.recursive = true;
906 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
907 expected, nchanges) \
909 do { for (mask=i=0;i<32;i++) { \
910 struct smb2_request *req; \
911 status = smb2_create(tree1, torture, &(io.smb2)); \
912 CHECK_STATUS(status, NT_STATUS_OK); \
913 h1 = io.smb2.out.file.handle; \
915 notify.smb2.in.file.handle = h1; \
916 notify.smb2.in.completion_filter = (1<<i); \
917 /* cancel initial requests so the buffer is setup */ \
918 req = smb2_notify_send(tree1, &(notify.smb2)); \
920 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
921 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
922 /* send the change notify request */ \
923 req = smb2_notify_send(tree1, &(notify.smb2)); \
925 smb_msleep(200); smb2_cancel(req); \
926 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
928 smb2_util_close(tree1, h1); \
929 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
930 CHECK_STATUS(status, NT_STATUS_OK); \
931 /* special case to cope with file rename behaviour */ \
932 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
933 notify.smb2.out.changes[0].action == \
934 NOTIFY_ACTION_MODIFIED && \
935 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
936 Action == NOTIFY_ACTION_OLD_NAME) { \
937 torture_comment(torture, \
938 "(rename file special handling OK)\n"); \
939 } else if (nchanges != notify.smb2.out.num_changes) { \
940 torture_result(torture, TORTURE_FAIL, \
941 "ERROR: nchanges=%d expected=%d "\
942 "action=%d filter=0x%08x\n", \
943 notify.smb2.out.num_changes, \
945 notify.smb2.out.changes[0].action, \
946 notify.smb2.in.completion_filter); \
948 } else if (notify.smb2.out.changes[0].action != Action) { \
949 torture_result(torture, TORTURE_FAIL, \
950 "ERROR: nchanges=%d action=%d " \
951 "expectedAction=%d filter=0x%08x\n", \
952 notify.smb2.out.num_changes, \
953 notify.smb2.out.changes[0].action, \
955 notify.smb2.in.completion_filter); \
957 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
959 torture_result(torture, TORTURE_FAIL, \
960 "ERROR: nchanges=%d action=%d " \
961 "filter=0x%08x name=%s\n", \
962 notify.smb2.out.num_changes, \
963 notify.smb2.out.changes[0].action, \
964 notify.smb2.in.completion_filter, \
965 notify.smb2.out.changes[0].name.s); \
973 torture_comment(torture, "Testing mkdir\n");
974 NOTIFY_MASK_TEST("Testing mkdir",;,
975 smb2_util_mkdir(tree2, BASEDIR_MSK "\\tname1");,
976 smb2_util_rmdir(tree2, BASEDIR_MSK "\\tname1");,
978 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
980 torture_comment(torture, "Testing create file\n");
981 ZERO_STRUCT(io1.smb2);
982 io1.generic.level = RAW_OPEN_SMB2;
983 io1.smb2.in.create_flags = 0;
984 io1.smb2.in.desired_access = SEC_FILE_ALL;
985 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
986 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
987 NTCREATEX_SHARE_ACCESS_WRITE;
988 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
989 io1.smb2.in.security_flags = 0;
990 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
991 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
992 io1.smb2.in.fname = BASEDIR_MSK "\\tname1";
994 NOTIFY_MASK_TEST("Testing create file",;,
995 smb2_util_close(tree2, custom_smb2_create(tree2,
996 torture, &(io1.smb2)));,
997 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
999 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
1001 torture_comment(torture, "Testing unlink\n");
1002 NOTIFY_MASK_TEST("Testing unlink",
1003 smb2_util_close(tree2, custom_smb2_create(tree2,
1004 torture, &(io1.smb2)));,
1005 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
1007 NOTIFY_ACTION_REMOVED,
1008 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
1010 torture_comment(torture, "Testing rmdir\n");
1011 NOTIFY_MASK_TEST("Testing rmdir",
1012 smb2_util_mkdir(tree2, BASEDIR_MSK "\\tname1");,
1013 smb2_util_rmdir(tree2, BASEDIR_MSK "\\tname1");,
1015 NOTIFY_ACTION_REMOVED,
1016 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
1018 torture_comment(torture, "Testing rename file\n");
1020 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1021 sinfo.rename_information.in.file.handle = h1;
1022 sinfo.rename_information.in.overwrite = true;
1023 sinfo.rename_information.in.root_fid = 0;
1024 sinfo.rename_information.in.new_name = BASEDIR_MSK "\\tname2";
1025 NOTIFY_MASK_TEST("Testing rename file",
1026 smb2_util_close(tree2, custom_smb2_create(tree2,
1027 torture, &(io1.smb2)));,
1028 smb2_setinfo_file(tree2, &sinfo);,
1029 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname2");,
1030 NOTIFY_ACTION_OLD_NAME,
1031 FILE_NOTIFY_CHANGE_FILE_NAME, 2);
1033 torture_comment(torture, "Testing rename dir\n");
1035 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1036 sinfo.rename_information.in.file.handle = h1;
1037 sinfo.rename_information.in.overwrite = true;
1038 sinfo.rename_information.in.root_fid = 0;
1039 sinfo.rename_information.in.new_name = BASEDIR_MSK "\\tname2";
1040 NOTIFY_MASK_TEST("Testing rename dir",
1041 smb2_util_mkdir(tree2, BASEDIR_MSK "\\tname1");,
1042 smb2_setinfo_file(tree2, &sinfo);,
1043 smb2_util_rmdir(tree2, BASEDIR_MSK "\\tname2");,
1044 NOTIFY_ACTION_OLD_NAME,
1045 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
1047 torture_comment(torture, "Testing set path attribute\n");
1048 NOTIFY_MASK_TEST("Testing set path attribute",
1049 smb2_util_close(tree2, custom_smb2_create(tree2,
1050 torture, &(io.smb2)));,
1051 smb2_util_setatr(tree2, BASEDIR_MSK "\\tname1",
1052 FILE_ATTRIBUTE_HIDDEN);,
1053 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
1054 NOTIFY_ACTION_MODIFIED,
1055 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
1057 torture_comment(torture, "Testing set path write time\n");
1059 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1060 sinfo.generic.in.file.handle = h1;
1061 sinfo.basic_info.in.write_time = 1000;
1062 NOTIFY_MASK_TEST("Testing set path write time",
1063 smb2_util_close(tree2, custom_smb2_create(tree2,
1064 torture, &(io1.smb2)));,
1065 smb2_setinfo_file(tree2, &sinfo);,
1066 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
1067 NOTIFY_ACTION_MODIFIED,
1068 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
1070 if (torture_setting_bool(torture, "samba3", false)) {
1071 torture_comment(torture,
1072 "Samba3 does not yet support create times "
1077 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1078 sinfo.generic.in.file.handle = h1;
1079 sinfo.basic_info.in.create_time = 0;
1080 torture_comment(torture, "Testing set file create time\n");
1081 NOTIFY_MASK_TEST("Testing set file create time",
1082 smb2_create_complex_file(torture, tree2,
1083 BASEDIR_MSK "\\tname1", &h2);,
1084 smb2_setinfo_file(tree2, &sinfo);,
1085 (smb2_util_close(tree2, h2),
1086 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
1087 NOTIFY_ACTION_MODIFIED,
1088 FILE_NOTIFY_CHANGE_CREATION, 1);
1092 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1093 sinfo.generic.in.file.handle = h1;
1094 sinfo.basic_info.in.access_time = 0;
1095 torture_comment(torture, "Testing set file access time\n");
1096 NOTIFY_MASK_TEST("Testing set file access time",
1097 smb2_create_complex_file(torture,
1099 BASEDIR_MSK "\\tname1",
1101 smb2_setinfo_file(tree2, &sinfo);,
1102 (smb2_util_close(tree2, h2),
1103 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
1104 NOTIFY_ACTION_MODIFIED,
1105 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
1108 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1109 sinfo.generic.in.file.handle = h1;
1110 sinfo.basic_info.in.change_time = 0;
1111 torture_comment(torture, "Testing set file change time\n");
1112 NOTIFY_MASK_TEST("Testing set file change time",
1113 smb2_create_complex_file(torture,
1115 BASEDIR_MSK "\\tname1",
1117 smb2_setinfo_file(tree2, &sinfo);,
1118 (smb2_util_close(tree2, h2),
1119 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
1120 NOTIFY_ACTION_MODIFIED,
1124 torture_comment(torture, "Testing write\n");
1125 NOTIFY_MASK_TEST("Testing write",
1126 smb2_create_complex_file(torture,
1128 BASEDIR_MSK "\\tname1",
1130 smb2_util_write(tree2, h2, &c, 10000, 1);,
1131 (smb2_util_close(tree2, h2),
1132 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
1133 NOTIFY_ACTION_MODIFIED,
1137 smb2_deltree(tree1, BASEDIR_MSK);
1141 #define BASEDIR_FL BASEDIR "_FL"
1143 basic testing of change notify on files
1145 static bool torture_smb2_notify_file(struct torture_context *torture,
1146 struct smb2_tree *tree)
1152 union smb_notify notify;
1153 struct smb2_request *req;
1154 struct smb2_handle h1;
1155 const char *fname = BASEDIR_FL "\\file.txt";
1157 smb2_deltree(tree, BASEDIR_FL);
1158 smb2_util_rmdir(tree, BASEDIR_FL);
1160 torture_comment(torture, "TESTING CHANGE NOTIFY ON FILES\n");
1161 status = torture_smb2_testdir(tree, BASEDIR_FL, &h1);
1162 CHECK_STATUS(status, NT_STATUS_OK);
1164 ZERO_STRUCT(io.smb2);
1165 io.generic.level = RAW_OPEN_SMB2;
1166 io.smb2.in.create_flags = 0;
1167 io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
1168 io.smb2.in.create_options = 0;
1169 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1170 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1171 NTCREATEX_SHARE_ACCESS_WRITE;
1172 io.smb2.in.alloc_size = 0;
1173 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1174 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1175 io.smb2.in.security_flags = 0;
1176 io.smb2.in.fname = fname;
1177 status = smb2_create(tree, torture, &(io.smb2));
1178 CHECK_STATUS(status, NT_STATUS_OK);
1179 h1 = io.smb2.out.file.handle;
1181 /* ask for a change notify,
1182 on file or directory name changes */
1183 ZERO_STRUCT(notify.smb2);
1184 notify.smb2.level = RAW_NOTIFY_SMB2;
1185 notify.smb2.in.file.handle = h1;
1186 notify.smb2.in.buffer_size = 1000;
1187 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
1188 notify.smb2.in.recursive = false;
1190 torture_comment(torture,
1191 "Testing if notifies on file handles are invalid (should be)\n");
1193 req = smb2_notify_send(tree, &(notify.smb2));
1194 status = smb2_notify_recv(req, torture, &(notify.smb2));
1195 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1197 ZERO_STRUCT(cl.smb2);
1198 cl.close.level = RAW_CLOSE_SMB2;
1199 cl.close.in.file.handle = h1;
1200 status = smb2_close(tree, &(cl.smb2));
1201 CHECK_STATUS(status, NT_STATUS_OK);
1203 status = smb2_util_unlink(tree, fname);
1204 CHECK_STATUS(status, NT_STATUS_OK);
1207 smb2_deltree(tree, BASEDIR_FL);
1211 basic testing of change notifies followed by a tdis
1214 #define BASEDIR_TD BASEDIR "_TD"
1216 static bool torture_smb2_notify_tree_disconnect(
1217 struct torture_context *torture,
1218 struct smb2_tree *tree)
1222 union smb_notify notify;
1224 struct smb2_handle h1;
1225 struct smb2_request *req;
1227 smb2_deltree(tree, BASEDIR_TD);
1228 smb2_util_rmdir(tree, BASEDIR_TD);
1230 torture_comment(torture, "TESTING CHANGE NOTIFY+CANCEL FOLLOWED BY "
1231 "TREE-DISCONNECT\n");
1234 get a handle on the directory
1236 ZERO_STRUCT(io.smb2);
1237 io.generic.level = RAW_OPEN_SMB2;
1238 io.smb2.in.create_flags = 0;
1239 io.smb2.in.desired_access = SEC_FILE_ALL;
1240 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1241 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1242 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1243 NTCREATEX_SHARE_ACCESS_WRITE;
1244 io.smb2.in.alloc_size = 0;
1245 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1246 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1247 io.smb2.in.security_flags = 0;
1248 io.smb2.in.fname = BASEDIR_TD;
1250 status = smb2_create(tree, torture, &(io.smb2));
1251 CHECK_STATUS(status, NT_STATUS_OK);
1252 h1 = io.smb2.out.file.handle;
1254 /* ask for a change notify,
1255 on file or directory name changes */
1256 ZERO_STRUCT(notify.smb2);
1257 notify.smb2.level = RAW_NOTIFY_SMB2;
1258 notify.smb2.in.buffer_size = 1000;
1259 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1260 notify.smb2.in.file.handle = h1;
1261 notify.smb2.in.recursive = true;
1263 req = smb2_notify_send(tree, &(notify.smb2));
1265 status = smb2_notify_recv(req, torture, &(notify.smb2));
1267 status = smb2_tdis(tree);
1268 CHECK_STATUS(status, NT_STATUS_OK);
1270 req = smb2_notify_send(tree, &(notify.smb2));
1272 smb2_notify_recv(req, torture, &(notify.smb2));
1273 CHECK_STATUS(status, NT_STATUS_OK);
1274 CHECK_VAL(notify.smb2.out.num_changes, 0);
1277 smb2_deltree(tree, BASEDIR_TD);
1282 testing of change notifies followed by a tdis - no cancel
1285 #define BASEDIR_NTDIS BASEDIR "_NTDIS"
1287 static bool torture_smb2_notify_tree_disconnect_1(
1288 struct torture_context *torture,
1289 struct smb2_tree *tree)
1293 union smb_notify notify;
1295 struct smb2_handle h1;
1296 struct smb2_request *req;
1298 smb2_deltree(tree, BASEDIR_NTDIS);
1299 smb2_util_rmdir(tree, BASEDIR_NTDIS);
1301 torture_comment(torture, "TESTING CHANGE NOTIFY ASYNC FOLLOWED BY "
1302 "TREE-DISCONNECT\n");
1305 get a handle on the directory
1307 ZERO_STRUCT(io.smb2);
1308 io.generic.level = RAW_OPEN_SMB2;
1309 io.smb2.in.create_flags = 0;
1310 io.smb2.in.desired_access = SEC_FILE_ALL;
1311 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1312 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1313 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1314 NTCREATEX_SHARE_ACCESS_WRITE;
1315 io.smb2.in.alloc_size = 0;
1316 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1317 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1318 io.smb2.in.security_flags = 0;
1319 io.smb2.in.fname = BASEDIR_NTDIS;
1321 status = smb2_create(tree, torture, &(io.smb2));
1322 CHECK_STATUS(status, NT_STATUS_OK);
1323 h1 = io.smb2.out.file.handle;
1325 /* ask for a change notify,
1326 on file or directory name changes */
1327 ZERO_STRUCT(notify.smb2);
1328 notify.smb2.level = RAW_NOTIFY_SMB2;
1329 notify.smb2.in.buffer_size = 1000;
1330 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1331 notify.smb2.in.file.handle = h1;
1332 notify.smb2.in.recursive = true;
1334 req = smb2_notify_send(tree, &(notify.smb2));
1335 WAIT_FOR_ASYNC_RESPONSE(req);
1337 status = smb2_tdis(tree);
1338 CHECK_STATUS(status, NT_STATUS_OK);
1340 status = smb2_notify_recv(req, torture, &(notify.smb2));
1341 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1342 CHECK_VAL(notify.smb2.out.num_changes, 0);
1345 smb2_deltree(tree, BASEDIR_NTDIS);
1350 basic testing of change notifies followed by a close
1353 #define BASEDIR_CNC BASEDIR "_CNC"
1355 static bool torture_smb2_notify_close(struct torture_context *torture,
1356 struct smb2_tree *tree1)
1360 union smb_notify notify;
1362 struct smb2_handle h1;
1363 struct smb2_request *req;
1365 smb2_deltree(tree1, BASEDIR_CNC);
1366 smb2_util_rmdir(tree1, BASEDIR_CNC);
1368 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1371 get a handle on the directory
1373 ZERO_STRUCT(io.smb2);
1374 io.generic.level = RAW_OPEN_SMB2;
1375 io.smb2.in.create_flags = 0;
1376 io.smb2.in.desired_access = SEC_FILE_ALL;
1377 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1378 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1379 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1380 NTCREATEX_SHARE_ACCESS_WRITE;
1381 io.smb2.in.alloc_size = 0;
1382 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1383 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1384 io.smb2.in.security_flags = 0;
1385 io.smb2.in.fname = BASEDIR_CNC;
1387 status = smb2_create(tree1, torture, &(io.smb2));
1388 CHECK_STATUS(status, NT_STATUS_OK);
1390 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1391 status = smb2_create(tree1, torture, &(io.smb2));
1392 CHECK_STATUS(status, NT_STATUS_OK);
1393 h1 = io.smb2.out.file.handle;
1395 /* ask for a change notify,
1396 on file or directory name changes */
1397 ZERO_STRUCT(notify.smb2);
1398 notify.smb2.level = RAW_NOTIFY_SMB2;
1399 notify.smb2.in.buffer_size = 1000;
1400 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1401 notify.smb2.in.file.handle = h1;
1402 notify.smb2.in.recursive = true;
1404 req = smb2_notify_send(tree1, &(notify.smb2));
1406 WAIT_FOR_ASYNC_RESPONSE(req);
1408 status = smb2_util_close(tree1, h1);
1409 CHECK_STATUS(status, NT_STATUS_OK);
1411 status = smb2_notify_recv(req, torture, &(notify.smb2));
1412 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1413 CHECK_VAL(notify.smb2.out.num_changes, 0);
1416 smb2_deltree(tree1, BASEDIR_CNC);
1421 basic testing of change notifies followed by a ulogoff
1424 #define BASEDIR_NUL BASEDIR "_NUL"
1425 static bool torture_smb2_notify_ulogoff(struct torture_context *torture,
1426 struct smb2_tree *tree1)
1430 union smb_notify notify;
1432 struct smb2_handle h1;
1433 struct smb2_request *req;
1435 smb2_deltree(tree1, BASEDIR_NUL);
1436 smb2_util_rmdir(tree1, BASEDIR_NUL);
1438 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1441 get a handle on the directory
1443 ZERO_STRUCT(io.smb2);
1444 io.generic.level = RAW_OPEN_SMB2;
1445 io.smb2.in.create_flags = 0;
1446 io.smb2.in.desired_access = SEC_FILE_ALL;
1447 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1448 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1449 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1450 NTCREATEX_SHARE_ACCESS_WRITE;
1451 io.smb2.in.alloc_size = 0;
1452 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1453 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1454 io.smb2.in.security_flags = 0;
1455 io.smb2.in.fname = BASEDIR_NUL;
1457 status = smb2_create(tree1, torture, &(io.smb2));
1458 CHECK_STATUS(status, NT_STATUS_OK);
1460 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1461 status = smb2_create(tree1, torture, &(io.smb2));
1462 CHECK_STATUS(status, NT_STATUS_OK);
1463 h1 = io.smb2.out.file.handle;
1465 /* ask for a change notify,
1466 on file or directory name changes */
1467 ZERO_STRUCT(notify.smb2);
1468 notify.smb2.level = RAW_NOTIFY_SMB2;
1469 notify.smb2.in.buffer_size = 1000;
1470 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1471 notify.smb2.in.file.handle = h1;
1472 notify.smb2.in.recursive = true;
1474 req = smb2_notify_send(tree1, &(notify.smb2));
1476 WAIT_FOR_ASYNC_RESPONSE(req);
1478 status = smb2_logoff(tree1->session);
1479 CHECK_STATUS(status, NT_STATUS_OK);
1481 status = smb2_notify_recv(req, torture, &(notify.smb2));
1482 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1483 CHECK_VAL(notify.smb2.out.num_changes, 0);
1486 smb2_deltree(tree1, BASEDIR_NUL);
1491 basic testing of change notifies followed by a session reconnect
1494 #define BASEDIR_NSR BASEDIR "_NSR"
1496 static bool torture_smb2_notify_session_reconnect(struct torture_context *torture,
1497 struct smb2_tree *tree1)
1501 union smb_notify notify;
1503 struct smb2_handle h1;
1504 struct smb2_request *req;
1505 uint64_t previous_session_id = 0;
1506 struct smb2_session *session2 = NULL;
1508 smb2_deltree(tree1, BASEDIR_NSR);
1509 smb2_util_rmdir(tree1, BASEDIR_NSR);
1511 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY SESSION RECONNECT\n");
1514 get a handle on the directory
1516 ZERO_STRUCT(io.smb2);
1517 io.generic.level = RAW_OPEN_SMB2;
1518 io.smb2.in.create_flags = 0;
1519 io.smb2.in.desired_access = SEC_FILE_ALL;
1520 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1521 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1522 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1523 NTCREATEX_SHARE_ACCESS_WRITE;
1524 io.smb2.in.alloc_size = 0;
1525 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1526 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1527 io.smb2.in.security_flags = 0;
1528 io.smb2.in.fname = BASEDIR_NSR;
1530 status = smb2_create(tree1, torture, &(io.smb2));
1531 CHECK_STATUS(status, NT_STATUS_OK);
1533 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1534 status = smb2_create(tree1, torture, &(io.smb2));
1535 CHECK_STATUS(status, NT_STATUS_OK);
1536 h1 = io.smb2.out.file.handle;
1538 /* ask for a change notify,
1539 on file or directory name changes */
1540 ZERO_STRUCT(notify.smb2);
1541 notify.smb2.level = RAW_NOTIFY_SMB2;
1542 notify.smb2.in.buffer_size = 1000;
1543 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1544 notify.smb2.in.file.handle = h1;
1545 notify.smb2.in.recursive = true;
1547 req = smb2_notify_send(tree1, &(notify.smb2));
1549 WAIT_FOR_ASYNC_RESPONSE(req);
1551 previous_session_id = smb2cli_session_current_id(tree1->session->smbXcli);
1552 torture_assert(torture, torture_smb2_session_setup(torture,
1553 tree1->session->transport,
1554 previous_session_id,
1555 torture, &session2),
1556 "session setup with previous_session_id failed");
1558 status = smb2_notify_recv(req, torture, &(notify.smb2));
1559 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1560 CHECK_VAL(notify.smb2.out.num_changes, 0);
1562 status = smb2_logoff(tree1->session);
1563 CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
1565 status = smb2_logoff(session2);
1566 CHECK_STATUS(status, NT_STATUS_OK);
1568 smb2_deltree(tree1, BASEDIR_NSR);
1573 basic testing of change notifies followed by an invalid reauth
1576 #define BASEDIR_IR BASEDIR "_IR"
1578 static bool torture_smb2_notify_invalid_reauth(struct torture_context *torture,
1579 struct smb2_tree *tree1,
1580 struct smb2_tree *tree2)
1584 union smb_notify notify;
1586 struct smb2_handle h1;
1587 struct smb2_request *req;
1588 struct cli_credentials *invalid_creds;
1590 smb2_deltree(tree2, BASEDIR_IR);
1591 smb2_util_rmdir(tree2, BASEDIR_IR);
1593 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY invalid REAUTH\n");
1596 get a handle on the directory
1598 ZERO_STRUCT(io.smb2);
1599 io.generic.level = RAW_OPEN_SMB2;
1600 io.smb2.in.create_flags = 0;
1601 io.smb2.in.desired_access = SEC_FILE_ALL;
1602 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1603 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1604 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1605 NTCREATEX_SHARE_ACCESS_WRITE;
1606 io.smb2.in.alloc_size = 0;
1607 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1608 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1609 io.smb2.in.security_flags = 0;
1610 io.smb2.in.fname = BASEDIR_IR;
1612 status = smb2_create(tree1, torture, &(io.smb2));
1613 CHECK_STATUS(status, NT_STATUS_OK);
1615 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1616 status = smb2_create(tree1, torture, &(io.smb2));
1617 CHECK_STATUS(status, NT_STATUS_OK);
1618 h1 = io.smb2.out.file.handle;
1620 /* ask for a change notify,
1621 on file or directory name changes */
1622 ZERO_STRUCT(notify.smb2);
1623 notify.smb2.level = RAW_NOTIFY_SMB2;
1624 notify.smb2.in.buffer_size = 1000;
1625 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1626 notify.smb2.in.file.handle = h1;
1627 notify.smb2.in.recursive = true;
1629 req = smb2_notify_send(tree1, &(notify.smb2));
1631 WAIT_FOR_ASYNC_RESPONSE(req);
1633 invalid_creds = cli_credentials_init(torture);
1634 torture_assert(torture, (invalid_creds != NULL), "talloc error");
1635 cli_credentials_set_username(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1636 cli_credentials_set_domain(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1637 cli_credentials_set_password(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1638 cli_credentials_set_realm(invalid_creds, NULL, CRED_SPECIFIED);
1639 cli_credentials_set_workstation(invalid_creds, "", CRED_UNINITIALISED);
1641 status = smb2_session_setup_spnego(tree1->session,
1643 0 /* previous_session_id */);
1644 CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE);
1646 status = smb2_notify_recv(req, torture, &(notify.smb2));
1647 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1648 CHECK_VAL(notify.smb2.out.num_changes, 0);
1651 smb2_deltree(tree2, BASEDIR_IR);
1655 static void tcp_dis_handler(struct smb2_transport *t, void *p)
1657 struct smb2_tree *tree = (struct smb2_tree *)p;
1658 smb2_transport_dead(tree->session->transport,
1659 NT_STATUS_LOCAL_DISCONNECT);
1665 basic testing of change notifies followed by tcp disconnect
1668 #define BASEDIR_NTCPD BASEDIR "_NTCPD"
1670 static bool torture_smb2_notify_tcp_disconnect(
1671 struct torture_context *torture,
1672 struct smb2_tree *tree)
1676 union smb_notify notify;
1678 struct smb2_handle h1;
1679 struct smb2_request *req;
1681 smb2_deltree(tree, BASEDIR_NTCPD);
1682 smb2_util_rmdir(tree, BASEDIR_NTCPD);
1684 torture_comment(torture,
1685 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1688 get a handle on the directory
1690 ZERO_STRUCT(io.smb2);
1691 io.generic.level = RAW_OPEN_SMB2;
1692 io.smb2.in.create_flags = 0;
1693 io.smb2.in.desired_access = SEC_FILE_ALL;
1694 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1695 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1696 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1697 NTCREATEX_SHARE_ACCESS_WRITE;
1698 io.smb2.in.alloc_size = 0;
1699 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1700 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1701 io.smb2.in.security_flags = 0;
1702 io.smb2.in.fname = BASEDIR_NTCPD;
1704 status = smb2_create(tree, torture, &(io.smb2));
1705 CHECK_STATUS(status, NT_STATUS_OK);
1706 h1 = io.smb2.out.file.handle;
1708 /* ask for a change notify,
1709 on file or directory name changes */
1710 ZERO_STRUCT(notify.smb2);
1711 notify.smb2.level = RAW_NOTIFY_SMB2;
1712 notify.smb2.in.buffer_size = 1000;
1713 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1714 notify.smb2.in.file.handle = h1;
1715 notify.smb2.in.recursive = true;
1717 req = smb2_notify_send(tree, &(notify.smb2));
1719 status = smb2_notify_recv(req, torture, &(notify.smb2));
1720 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1722 notify.smb2.in.recursive = true;
1723 req = smb2_notify_send(tree, &(notify.smb2));
1724 smb2_transport_idle_handler(tree->session->transport,
1725 tcp_dis_handler, 250000, tree);
1727 status = smb2_notify_recv(req, torture, &(notify.smb2));
1728 CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
1735 test setting up two change notify requests on one handle
1738 #define BASEDIR_NDOH BASEDIR "_NDOH"
1740 static bool torture_smb2_notify_double(struct torture_context *torture,
1741 struct smb2_tree *tree1,
1742 struct smb2_tree *tree2)
1746 union smb_notify notify;
1748 struct smb2_handle h1;
1749 struct smb2_request *req1, *req2;
1751 smb2_deltree(tree1, BASEDIR_NDOH);
1752 smb2_util_rmdir(tree1, BASEDIR_NDOH);
1754 torture_comment(torture,
1755 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1758 get a handle on the directory
1760 ZERO_STRUCT(io.smb2);
1761 io.generic.level = RAW_OPEN_SMB2;
1762 io.smb2.in.create_flags = 0;
1763 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ|
1764 SEC_RIGHTS_FILE_WRITE|
1765 SEC_RIGHTS_FILE_ALL;
1766 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1767 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1768 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1769 NTCREATEX_SHARE_ACCESS_WRITE;
1770 io.smb2.in.alloc_size = 0;
1771 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1772 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1773 io.smb2.in.security_flags = 0;
1774 io.smb2.in.fname = BASEDIR_NDOH;
1776 status = smb2_create(tree1, torture, &(io.smb2));
1777 CHECK_STATUS(status, NT_STATUS_OK);
1778 h1 = io.smb2.out.file.handle;
1780 /* ask for a change notify,
1781 on file or directory name changes */
1782 ZERO_STRUCT(notify.smb2);
1783 notify.smb2.level = RAW_NOTIFY_SMB2;
1784 notify.smb2.in.buffer_size = 1000;
1785 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1786 notify.smb2.in.file.handle = h1;
1787 notify.smb2.in.recursive = true;
1789 req1 = smb2_notify_send(tree1, &(notify.smb2));
1791 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1792 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1794 req2 = smb2_notify_send(tree1, &(notify.smb2));
1796 status = smb2_notify_recv(req2, torture, &(notify.smb2));
1797 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1799 smb2_util_mkdir(tree2, BASEDIR_NDOH "\\subdir-name");
1800 req1 = smb2_notify_send(tree1, &(notify.smb2));
1801 req2 = smb2_notify_send(tree1, &(notify.smb2));
1803 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1804 CHECK_STATUS(status, NT_STATUS_OK);
1805 CHECK_VAL(notify.smb2.out.num_changes, 1);
1806 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1808 smb2_util_mkdir(tree2, BASEDIR_NDOH "\\subdir-name2");
1810 status = smb2_notify_recv(req2, torture, &(notify.smb2));
1811 CHECK_STATUS(status, NT_STATUS_OK);
1812 CHECK_VAL(notify.smb2.out.num_changes, 1);
1813 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name2");
1816 smb2_deltree(tree1, BASEDIR_NDOH);
1822 test multiple change notifies at different depths and with/without recursion
1825 #define BASEDIR_TREE BASEDIR "_TREE"
1827 static bool torture_smb2_notify_tree(struct torture_context *torture,
1828 struct smb2_tree *tree)
1831 union smb_notify notify;
1833 struct smb2_request *req;
1840 struct smb2_handle h1;
1844 .path = BASEDIR_TREE "\\abc",
1846 .filter = FILE_NOTIFY_CHANGE_NAME,
1850 .path = BASEDIR_TREE "\\zqy",
1852 .filter = FILE_NOTIFY_CHANGE_NAME,
1856 .path = BASEDIR_TREE "\\atsy",
1858 .filter = FILE_NOTIFY_CHANGE_NAME,
1862 .path = BASEDIR_TREE "\\abc\\foo",
1864 .filter = FILE_NOTIFY_CHANGE_NAME,
1868 .path = BASEDIR_TREE "\\abc\\blah",
1870 .filter = FILE_NOTIFY_CHANGE_NAME,
1874 .path = BASEDIR_TREE "\\abc\\blah",
1876 .filter = FILE_NOTIFY_CHANGE_NAME,
1880 .path = BASEDIR_TREE "\\abc\\blah\\a",
1882 .filter = FILE_NOTIFY_CHANGE_NAME,
1886 .path = BASEDIR_TREE "\\abc\\blah\\b",
1888 .filter = FILE_NOTIFY_CHANGE_NAME,
1892 .path = BASEDIR_TREE "\\abc\\blah\\c",
1894 .filter = FILE_NOTIFY_CHANGE_NAME,
1898 .path = BASEDIR_TREE "\\abc\\fooblah",
1900 .filter = FILE_NOTIFY_CHANGE_NAME,
1904 .path = BASEDIR_TREE "\\zqy\\xx",
1906 .filter = FILE_NOTIFY_CHANGE_NAME,
1910 .path = BASEDIR_TREE "\\zqy\\yyy",
1912 .filter = FILE_NOTIFY_CHANGE_NAME,
1916 .path = BASEDIR_TREE "\\zqy\\..",
1918 .filter = FILE_NOTIFY_CHANGE_NAME,
1922 .path = BASEDIR_TREE,
1924 .filter = FILE_NOTIFY_CHANGE_NAME,
1928 .path = BASEDIR_TREE,
1930 .filter = FILE_NOTIFY_CHANGE_NAME,
1934 .path = BASEDIR_TREE "\\atsy",
1936 .filter = FILE_NOTIFY_CHANGE_NAME,
1940 .path = BASEDIR_TREE "\\abc",
1942 .filter = FILE_NOTIFY_CHANGE_NAME,
1946 .path = BASEDIR_TREE "\\abc",
1948 .filter = FILE_NOTIFY_CHANGE_FILE_NAME,
1952 .path = BASEDIR_TREE "\\abc",
1954 .filter = FILE_NOTIFY_CHANGE_FILE_NAME,
1958 .path = BASEDIR_TREE "\\abc",
1960 .filter = FILE_NOTIFY_CHANGE_NAME,
1966 bool all_done = false;
1968 smb2_deltree(tree, BASEDIR_TREE);
1969 smb2_util_rmdir(tree, BASEDIR_TREE);
1971 torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1973 ZERO_STRUCT(io.smb2);
1974 io.generic.level = RAW_OPEN_SMB2;
1975 io.smb2.in.create_flags = 0;
1976 io.smb2.in.desired_access = SEC_FILE_ALL;
1977 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1978 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1979 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1980 NTCREATEX_SHARE_ACCESS_WRITE;
1981 io.smb2.in.alloc_size = 0;
1982 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1983 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1984 io.smb2.in.security_flags = 0;
1985 io.smb2.in.fname = BASEDIR_TREE;
1986 status = smb2_create(tree, torture, &(io.smb2));
1987 CHECK_STATUS(status, NT_STATUS_OK);
1989 ZERO_STRUCT(notify.smb2);
1990 notify.smb2.level = RAW_NOTIFY_SMB2;
1991 notify.smb2.in.buffer_size = 20000;
1994 setup the directory tree, and the notify buffer on each directory
1996 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1997 io.smb2.in.fname = dirs[i].path;
1998 status = smb2_create(tree, torture, &(io.smb2));
1999 CHECK_STATUS(status, NT_STATUS_OK);
2000 dirs[i].h1 = io.smb2.out.file.handle;
2002 notify.smb2.in.completion_filter = dirs[i].filter;
2003 notify.smb2.in.file.handle = dirs[i].h1;
2004 notify.smb2.in.recursive = dirs[i].recursive;
2005 req = smb2_notify_send(tree, &(notify.smb2));
2007 status = smb2_notify_recv(req, torture, &(notify.smb2));
2008 CHECK_STATUS(status, NT_STATUS_CANCELLED);
2011 /* trigger 2 events in each dir */
2012 for (i=0;i<ARRAY_SIZE(dirs);i++) {
2013 char *path = talloc_asprintf(torture, "%s\\test.dir",
2015 smb2_util_mkdir(tree, path);
2016 smb2_util_rmdir(tree, path);
2020 /* give a bit of time for the events to propagate */
2021 tv = timeval_current();
2024 /* count events that have happened in each dir */
2025 for (i=0;i<ARRAY_SIZE(dirs);i++) {
2026 notify.smb2.in.completion_filter = dirs[i].filter;
2027 notify.smb2.in.file.handle = dirs[i].h1;
2028 notify.smb2.in.recursive = dirs[i].recursive;
2029 req = smb2_notify_send(tree, &(notify.smb2));
2031 notify.smb2.out.num_changes = 0;
2032 status = smb2_notify_recv(req, torture,
2034 dirs[i].counted += notify.smb2.out.num_changes;
2039 for (i=0;i<ARRAY_SIZE(dirs);i++) {
2040 if (dirs[i].counted != dirs[i].expected) {
2044 } while (!all_done && timeval_elapsed(&tv) < 20);
2046 torture_comment(torture, "took %.4f seconds to propagate all events\n",
2047 timeval_elapsed(&tv));
2049 for (i=0;i<ARRAY_SIZE(dirs);i++) {
2050 if (dirs[i].counted != dirs[i].expected) {
2051 torture_comment(torture,
2052 "ERROR: i=%d expected %d got %d for '%s'\n",
2053 i, dirs[i].expected, dirs[i].counted,
2060 run from the back, closing and deleting
2062 for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
2063 smb2_util_close(tree, dirs[i].h1);
2064 smb2_util_rmdir(tree, dirs[i].path);
2068 smb2_deltree(tree, BASEDIR_TREE);
2069 smb2_util_rmdir(tree, BASEDIR_TREE);
2074 Test response when cached server events exceed single NT NOTFIY response
2078 #define BASEDIR_OVF BASEDIR "_OVF"
2080 static bool torture_smb2_notify_overflow(struct torture_context *torture,
2081 struct smb2_tree *tree)
2085 union smb_notify notify;
2087 struct smb2_handle h1, h2;
2089 struct smb2_request *req1;
2092 smb2_deltree(tree, BASEDIR_OVF);
2093 smb2_util_rmdir(tree, BASEDIR_OVF);
2095 torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
2097 /* get a handle on the directory */
2098 ZERO_STRUCT(io.smb2);
2099 io.generic.level = RAW_OPEN_SMB2;
2100 io.smb2.in.create_flags = 0;
2101 io.smb2.in.desired_access = SEC_FILE_ALL;
2102 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2103 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2104 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2105 NTCREATEX_SHARE_ACCESS_WRITE;
2106 io.smb2.in.alloc_size = 0;
2107 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2108 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2109 io.smb2.in.security_flags = 0;
2110 io.smb2.in.fname = BASEDIR_OVF;
2112 status = smb2_create(tree, torture, &(io.smb2));
2113 CHECK_STATUS(status, NT_STATUS_OK);
2114 h1 = io.smb2.out.file.handle;
2116 /* ask for a change notify, on name changes. */
2117 ZERO_STRUCT(notify.smb2);
2118 notify.smb2.level = RAW_NOTIFY_NTTRANS;
2119 notify.smb2.in.buffer_size = 1000;
2120 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2121 notify.smb2.in.file.handle = h1;
2123 notify.smb2.in.recursive = true;
2124 req1 = smb2_notify_send(tree, &(notify.smb2));
2126 /* cancel initial requests so the buffer is setup */
2128 status = smb2_notify_recv(req1, torture, &(notify.smb2));
2129 CHECK_STATUS(status, NT_STATUS_CANCELLED);
2131 /* open a lot of files, filling up the server side notify buffer */
2132 torture_comment(torture,
2133 "Testing overflowed buffer notify on create of %d files\n",
2136 for (i=0;i<count;i++) {
2137 char *fname = talloc_asprintf(torture,
2138 BASEDIR_OVF "\\test%d.txt", i);
2140 ZERO_STRUCT(io1.smb2);
2141 io1.generic.level = RAW_OPEN_SMB2;
2142 io1.smb2.in.create_flags = 0;
2143 io1.smb2.in.desired_access = SEC_FILE_ALL;
2144 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2145 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2146 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2147 NTCREATEX_SHARE_ACCESS_WRITE;
2148 io1.smb2.in.alloc_size = 0;
2149 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2150 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2151 io1.smb2.in.security_flags = 0;
2152 io1.smb2.in.fname = fname;
2154 h2 = custom_smb2_create(tree, torture, &(io1.smb2));
2156 smb2_util_close(tree, h2);
2159 req1 = smb2_notify_send(tree, &(notify.smb2));
2160 status = smb2_notify_recv(req1, torture, &(notify.smb2));
2161 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
2162 CHECK_VAL(notify.smb2.out.num_changes, 0);
2165 smb2_deltree(tree, BASEDIR_OVF);
2170 Test if notifications are returned for changes to the base directory.
2174 #define BASEDIR_BAS BASEDIR "_BAS"
2176 static bool torture_smb2_notify_basedir(struct torture_context *torture,
2177 struct smb2_tree *tree1,
2178 struct smb2_tree *tree2)
2182 union smb_notify notify;
2184 struct smb2_handle h1;
2185 struct smb2_request *req1;
2187 smb2_deltree(tree1, BASEDIR_BAS);
2188 smb2_util_rmdir(tree1, BASEDIR_BAS);
2190 torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
2192 /* get a handle on the directory */
2193 ZERO_STRUCT(io.smb2);
2194 io.generic.level = RAW_OPEN_SMB2;
2195 io.smb2.in.create_flags = 0;
2196 io.smb2.in.desired_access = SEC_FILE_ALL;
2197 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2198 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2199 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2200 NTCREATEX_SHARE_ACCESS_WRITE;
2201 io.smb2.in.alloc_size = 0;
2202 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2203 io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
2204 io.smb2.in.security_flags = 0;
2205 io.smb2.in.fname = BASEDIR_BAS;
2207 status = smb2_create(tree1, torture, &(io.smb2));
2208 CHECK_STATUS(status, NT_STATUS_OK);
2209 h1 = io.smb2.out.file.handle;
2211 /* create a test file that will also be modified */
2212 io.smb2.in.fname = BASEDIR_BAS "\\tname1";
2213 io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
2214 status = smb2_create(tree2, torture, &(io.smb2));
2215 CHECK_STATUS(status,NT_STATUS_OK);
2216 smb2_util_close(tree2, io.smb2.out.file.handle);
2218 /* ask for a change notify, on attribute changes. */
2219 ZERO_STRUCT(notify.smb2);
2220 notify.smb2.level = RAW_NOTIFY_SMB2;
2221 notify.smb2.in.buffer_size = 1000;
2222 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
2223 notify.smb2.in.file.handle = h1;
2224 notify.smb2.in.recursive = true;
2226 req1 = smb2_notify_send(tree1, &(notify.smb2));
2228 /* set attribute on the base dir */
2229 smb2_util_setatr(tree2, BASEDIR_BAS, FILE_ATTRIBUTE_HIDDEN);
2231 /* set attribute on a file to assure we receive a notification */
2232 smb2_util_setatr(tree2, BASEDIR_BAS "\\tname1", FILE_ATTRIBUTE_HIDDEN);
2235 /* check how many responses were given, expect only 1 for the file */
2236 status = smb2_notify_recv(req1, torture, &(notify.smb2));
2237 CHECK_STATUS(status, NT_STATUS_OK);
2238 CHECK_VAL(notify.smb2.out.num_changes, 1);
2239 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
2240 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
2243 smb2_deltree(tree1, BASEDIR_BAS);
2248 very simple change notify test
2251 #define BASEDIR_TCON BASEDIR "_TCON"
2253 static bool torture_smb2_notify_tcon(struct torture_context *torture,
2254 struct smb2_tree *tree)
2258 union smb_notify notify;
2260 struct smb2_handle h1 = {{0}};
2261 struct smb2_request *req = NULL;
2262 struct smb2_tree *tree1 = NULL;
2263 const char *fname = BASEDIR_TCON "\\subdir-name";
2265 smb2_deltree(tree, BASEDIR_TCON);
2266 smb2_util_rmdir(tree, BASEDIR_TCON);
2268 torture_comment(torture, "TESTING SIMPLE CHANGE NOTIFY\n");
2271 get a handle on the directory
2274 ZERO_STRUCT(io.smb2);
2275 io.generic.level = RAW_OPEN_SMB2;
2276 io.smb2.in.create_flags = 0;
2277 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2278 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2279 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL |
2280 FILE_ATTRIBUTE_DIRECTORY;
2281 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2282 NTCREATEX_SHARE_ACCESS_WRITE;
2283 io.smb2.in.alloc_size = 0;
2284 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2285 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2286 io.smb2.in.security_flags = 0;
2287 io.smb2.in.fname = BASEDIR_TCON;
2289 status = smb2_create(tree, torture, &(io.smb2));
2290 CHECK_STATUS(status, NT_STATUS_OK);
2291 h1 = io.smb2.out.file.handle;
2293 /* ask for a change notify,
2294 on file or directory name changes */
2295 ZERO_STRUCT(notify.smb2);
2296 notify.smb2.level = RAW_NOTIFY_SMB2;
2297 notify.smb2.in.buffer_size = 1000;
2298 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2299 notify.smb2.in.file.handle = h1;
2300 notify.smb2.in.recursive = true;
2302 torture_comment(torture, "Testing notify mkdir\n");
2303 req = smb2_notify_send(tree, &(notify.smb2));
2305 status = smb2_notify_recv(req, torture, &(notify.smb2));
2306 CHECK_STATUS(status, NT_STATUS_CANCELLED);
2308 notify.smb2.in.recursive = true;
2309 req = smb2_notify_send(tree, &(notify.smb2));
2310 status = smb2_util_mkdir(tree, fname);
2311 CHECK_STATUS(status, NT_STATUS_OK);
2313 status = smb2_notify_recv(req, torture, &(notify.smb2));
2314 CHECK_STATUS(status, NT_STATUS_OK);
2316 CHECK_VAL(notify.smb2.out.num_changes, 1);
2317 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2318 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2320 torture_comment(torture, "Testing notify rmdir\n");
2321 req = smb2_notify_send(tree, &(notify.smb2));
2322 status = smb2_util_rmdir(tree, fname);
2323 CHECK_STATUS(status, NT_STATUS_OK);
2325 status = smb2_notify_recv(req, torture, &(notify.smb2));
2326 CHECK_STATUS(status, NT_STATUS_OK);
2327 CHECK_VAL(notify.smb2.out.num_changes, 1);
2328 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2329 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2331 torture_comment(torture, "SIMPLE CHANGE NOTIFY OK\n");
2333 torture_comment(torture, "TESTING WITH SECONDARY TCON\n");
2334 if (!torture_smb2_tree_connect(torture, tree->session, tree, &tree1)) {
2335 torture_warning(torture, "couldn't reconnect to share, bailing\n");
2340 torture_comment(torture, "tid1=%d tid2=%d\n",
2341 smb2cli_tcon_current_id(tree->smbXcli),
2342 smb2cli_tcon_current_id(tree1->smbXcli));
2344 torture_comment(torture, "Testing notify mkdir\n");
2345 req = smb2_notify_send(tree, &(notify.smb2));
2346 smb2_util_mkdir(tree1, fname);
2348 status = smb2_notify_recv(req, torture, &(notify.smb2));
2349 CHECK_STATUS(status, NT_STATUS_OK);
2351 CHECK_VAL(notify.smb2.out.num_changes, 1);
2352 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2353 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2355 torture_comment(torture, "Testing notify rmdir\n");
2356 req = smb2_notify_send(tree, &(notify.smb2));
2357 smb2_util_rmdir(tree, fname);
2359 status = smb2_notify_recv(req, torture, &(notify.smb2));
2360 CHECK_STATUS(status, NT_STATUS_OK);
2361 CHECK_VAL(notify.smb2.out.num_changes, 1);
2362 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2363 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2365 torture_comment(torture, "CHANGE NOTIFY WITH TCON OK\n");
2367 torture_comment(torture, "Disconnecting secondary tree\n");
2368 status = smb2_tdis(tree1);
2369 CHECK_STATUS(status, NT_STATUS_OK);
2372 torture_comment(torture, "Testing notify mkdir\n");
2373 req = smb2_notify_send(tree, &(notify.smb2));
2374 smb2_util_mkdir(tree, fname);
2376 status = smb2_notify_recv(req, torture, &(notify.smb2));
2377 CHECK_STATUS(status, NT_STATUS_OK);
2379 CHECK_VAL(notify.smb2.out.num_changes, 1);
2380 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2381 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2383 torture_comment(torture, "Testing notify rmdir\n");
2384 req = smb2_notify_send(tree, &(notify.smb2));
2385 smb2_util_rmdir(tree, fname);
2387 status = smb2_notify_recv(req, torture, &(notify.smb2));
2388 CHECK_STATUS(status, NT_STATUS_OK);
2389 CHECK_VAL(notify.smb2.out.num_changes, 1);
2390 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2391 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2393 torture_comment(torture, "CHANGE NOTIFY WITH TDIS OK\n");
2395 smb2_util_close(tree, h1);
2396 smb2_deltree(tree, BASEDIR_TCON);
2401 #define BASEDIR_RMD BASEDIR "_RMD"
2403 static bool torture_smb2_notify_rmdir(struct torture_context *torture,
2404 struct smb2_tree *tree1,
2405 struct smb2_tree *tree2,
2406 bool initial_delete_on_close)
2410 union smb_notify notify = {};
2411 union smb_setfileinfo sfinfo = {};
2412 union smb_open io = {};
2413 struct smb2_handle h = {};
2414 struct smb2_request *req;
2416 torture_comment(torture, "TESTING NOTIFY CANCEL FOR DELETED DIR\n");
2418 smb2_deltree(tree1, BASEDIR_RMD);
2419 smb2_util_rmdir(tree1, BASEDIR_RMD);
2421 ZERO_STRUCT(io.smb2);
2422 io.generic.level = RAW_OPEN_SMB2;
2423 io.smb2.in.create_flags = 0;
2424 io.smb2.in.desired_access = SEC_FILE_ALL;
2425 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2426 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2427 io.smb2.in.share_access =
2428 NTCREATEX_SHARE_ACCESS_READ |
2429 NTCREATEX_SHARE_ACCESS_WRITE |
2430 NTCREATEX_SHARE_ACCESS_DELETE ;
2431 io.smb2.in.alloc_size = 0;
2432 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2433 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2434 io.smb2.in.security_flags = 0;
2435 io.smb2.in.fname = BASEDIR_RMD;
2437 status = smb2_create(tree1, torture, &(io.smb2));
2438 CHECK_STATUS(status, NT_STATUS_OK);
2439 h = io.smb2.out.file.handle;
2441 ZERO_STRUCT(notify.smb2);
2442 notify.smb2.level = RAW_NOTIFY_SMB2;
2443 notify.smb2.in.buffer_size = 1000;
2444 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2445 notify.smb2.in.file.handle = h;
2446 notify.smb2.in.recursive = false;
2448 io.smb2.in.desired_access |= SEC_STD_DELETE;
2449 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
2450 req = smb2_notify_send(tree1, &(notify.smb2));
2452 if (initial_delete_on_close) {
2453 status = smb2_util_rmdir(tree2, BASEDIR_RMD);
2454 CHECK_STATUS(status, NT_STATUS_OK);
2456 status = smb2_create(tree2, torture, &(io.smb2));
2457 CHECK_STATUS(status, NT_STATUS_OK);
2459 sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
2460 sfinfo.generic.in.file.handle = io.smb2.out.file.handle;
2461 sfinfo.disposition_info.in.delete_on_close = 1;
2462 status = smb2_setinfo_file(tree2, &sfinfo);
2463 CHECK_STATUS(status, NT_STATUS_OK);
2465 smb2_util_close(tree2, io.smb2.out.file.handle);
2468 status = smb2_notify_recv(req, torture, &(notify.smb2));
2469 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
2473 smb2_util_close(tree1, h);
2474 smb2_deltree(tree1, BASEDIR_RMD);
2479 static bool torture_smb2_notify_rmdir1(struct torture_context *torture,
2480 struct smb2_tree *tree)
2482 return torture_smb2_notify_rmdir(torture, tree, tree, false);
2485 static bool torture_smb2_notify_rmdir2(struct torture_context *torture,
2486 struct smb2_tree *tree)
2488 return torture_smb2_notify_rmdir(torture, tree, tree, true);
2491 static bool torture_smb2_notify_rmdir3(struct torture_context *torture,
2492 struct smb2_tree *tree1,
2493 struct smb2_tree *tree2)
2495 return torture_smb2_notify_rmdir(torture, tree1, tree2, false);
2498 static bool torture_smb2_notify_rmdir4(struct torture_context *torture,
2499 struct smb2_tree *tree1,
2500 struct smb2_tree *tree2)
2502 return torture_smb2_notify_rmdir(torture, tree1, tree2, true);
2505 static void notify_timeout(struct tevent_context *ev,
2506 struct tevent_timer *te,
2507 struct timeval current_time,
2510 struct smb2_request *req = talloc_get_type_abort(
2511 private_data, struct smb2_request);
2516 #define BASEDIR_INR BASEDIR "_INR"
2518 static bool torture_smb2_inotify_rename(struct torture_context *torture,
2519 struct smb2_tree *tree1,
2520 struct smb2_tree *tree2)
2523 struct smb2_notify notify;
2524 struct notify_changes change1 = {0};
2525 struct notify_changes change2 = {0};
2526 struct smb2_create create;
2527 union smb_setfileinfo sinfo;
2528 struct smb2_handle h1 = {{0}};
2529 struct smb2_handle h2 = {{0}};
2530 struct smb2_request *req;
2531 struct tevent_timer *te = NULL;
2534 smb2_deltree(tree1, BASEDIR_INR);
2536 torture_comment(torture, "Testing change notify of a rename with inotify\n");
2538 status = torture_smb2_testdir(tree1, BASEDIR_INR, &h1);
2539 torture_assert_ntstatus_ok_goto(torture, status, ok, done, "torture_smb2_testdir failed");
2541 ZERO_STRUCT(create);
2542 create.in.desired_access = SEC_RIGHTS_FILE_READ |
2543 SEC_RIGHTS_FILE_WRITE|
2544 SEC_RIGHTS_FILE_ALL;
2545 create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2546 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2547 create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2548 NTCREATEX_SHARE_ACCESS_WRITE |
2549 NTCREATEX_SHARE_ACCESS_DELETE;
2550 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2551 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2552 create.in.fname = BASEDIR_INR "\\subdir-name";
2554 status = smb2_create(tree2, torture, &create);
2555 torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_create failed\n");
2556 h2 = create.out.file.handle;
2558 ZERO_STRUCT(notify);
2559 notify.level = RAW_NOTIFY_SMB2;
2560 notify.in.buffer_size = 4096;
2561 notify.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2562 notify.in.file.handle = h1;
2563 notify.in.recursive = true;
2564 req = smb2_notify_send(tree1, ¬ify);
2565 torture_assert_not_null_goto(torture, req, ok, done, "smb2_notify_send failed\n");
2567 while (!NT_STATUS_EQUAL(req->status, STATUS_PENDING)) {
2568 if (tevent_loop_once(torture->ev) != 0) {
2574 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
2575 sinfo.rename_information.in.file.handle = h2;
2576 sinfo.rename_information.in.new_name = BASEDIR_INR "\\subdir-name-r";
2578 status = smb2_setinfo_file(tree2, &sinfo);
2579 torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_setinfo_file failed\n");
2581 smb2_util_close(tree2, h2);
2583 te = tevent_add_timer(torture->ev,
2585 tevent_timeval_current_ofs(1, 0),
2588 torture_assert_not_null_goto(torture, te, ok, done, "tevent_add_timer failed\n");
2590 status = smb2_notify_recv(req, torture, ¬ify);
2591 torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_notify_recv failed\n");
2593 torture_assert_goto(torture, notify.out.num_changes == 1 || notify.out.num_changes == 2,
2594 ok, done, "bad notify\n");
2596 change1 = notify.out.changes[0];
2597 if (notify.out.num_changes == 2) {
2598 change2 = notify.out.changes[1];
2601 * We may only get one event at a time, so check for the
2602 * matching second event for the oldname/newname or
2603 * removed/added pair.
2605 ZERO_STRUCT(notify);
2606 notify.level = RAW_NOTIFY_SMB2;
2607 notify.in.buffer_size = 4096;
2608 notify.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2609 notify.in.file.handle = h1;
2610 notify.in.recursive = true;
2611 req = smb2_notify_send(tree1, ¬ify);
2612 torture_assert_not_null_goto(torture, req, ok, done, "smb2_notify_send failed\n");
2614 status = smb2_notify_recv(req, torture, ¬ify);
2615 torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_notify_recv failed\n");
2617 torture_assert_goto(torture, notify.out.num_changes == 1, ok, done,
2620 change2 = notify.out.changes[0];
2623 if ((change1.action != NOTIFY_ACTION_OLD_NAME) &&
2624 (change1.action != NOTIFY_ACTION_REMOVED))
2626 torture_fail_goto(torture, done, "bad change notification\n");
2628 torture_assert_str_equal_goto(torture, change1.name.s, "subdir-name",
2629 ok, done, "bad change notification\n");
2631 if ((change2.action != NOTIFY_ACTION_NEW_NAME) &&
2632 (change2.action != NOTIFY_ACTION_ADDED))
2634 torture_fail_goto(torture, done, "bad change notification\n");
2636 torture_assert_str_equal_goto(torture, change2.name.s, "subdir-name-r",
2637 ok, done, "bad change notification\n");
2641 if (!smb2_util_handle_empty(h1)) {
2642 smb2_util_close(tree1, h1);
2644 if (!smb2_util_handle_empty(h2)) {
2645 smb2_util_close(tree2, h2);
2648 smb2_deltree(tree1, BASEDIR_INR);
2653 basic testing of SMB2 change notify
2655 struct torture_suite *torture_smb2_notify_init(TALLOC_CTX *ctx)
2657 struct torture_suite *suite = torture_suite_create(ctx, "notify");
2659 torture_suite_add_1smb2_test(suite, "valid-req", test_valid_request);
2660 torture_suite_add_1smb2_test(suite, "tcon", torture_smb2_notify_tcon);
2661 torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir);
2662 torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask);
2663 torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
2664 torture_suite_add_1smb2_test(suite, "tdis1", torture_smb2_notify_tree_disconnect_1);
2665 torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
2666 torture_suite_add_1smb2_test(suite, "close", torture_smb2_notify_close);
2667 torture_suite_add_1smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
2668 torture_suite_add_1smb2_test(suite, "session-reconnect", torture_smb2_notify_session_reconnect);
2669 torture_suite_add_2smb2_test(suite, "invalid-reauth", torture_smb2_notify_invalid_reauth);
2670 torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
2671 torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
2672 torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
2673 torture_suite_add_1smb2_test(suite, "file", torture_smb2_notify_file);
2674 torture_suite_add_1smb2_test(suite, "tcp", torture_smb2_notify_tcp_disconnect);
2675 torture_suite_add_2smb2_test(suite, "rec", torture_smb2_notify_recursive);
2676 torture_suite_add_1smb2_test(suite, "overflow", torture_smb2_notify_overflow);
2677 torture_suite_add_1smb2_test(suite, "rmdir1",
2678 torture_smb2_notify_rmdir1);
2679 torture_suite_add_1smb2_test(suite, "rmdir2",
2680 torture_smb2_notify_rmdir2);
2681 torture_suite_add_2smb2_test(suite, "rmdir3",
2682 torture_smb2_notify_rmdir3);
2683 torture_suite_add_2smb2_test(suite, "rmdir4",
2684 torture_smb2_notify_rmdir4);
2686 suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");
2692 basic testing of SMB2 change notify
2694 struct torture_suite *torture_smb2_notify_inotify_init(TALLOC_CTX *ctx)
2696 struct torture_suite *suite = torture_suite_create(ctx, "notify-inotify");
2698 suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests that use inotify");
2700 torture_suite_add_2smb2_test(suite, "inotify-rename", torture_smb2_inotify_rename);