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, 250, 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;
1843 {BASEDIR_TREE "\\abc",
1844 true, FILE_NOTIFY_CHANGE_NAME, 30 },
1845 {BASEDIR_TREE "\\zqy",
1846 true, FILE_NOTIFY_CHANGE_NAME, 8 },
1847 {BASEDIR_TREE "\\atsy",
1848 true, FILE_NOTIFY_CHANGE_NAME, 4 },
1849 {BASEDIR_TREE "\\abc\\foo",
1850 true, FILE_NOTIFY_CHANGE_NAME, 2 },
1851 {BASEDIR_TREE "\\abc\\blah",
1852 true, FILE_NOTIFY_CHANGE_NAME, 13 },
1853 {BASEDIR_TREE "\\abc\\blah",
1854 false, FILE_NOTIFY_CHANGE_NAME, 7 },
1855 {BASEDIR_TREE "\\abc\\blah\\a",
1856 true, FILE_NOTIFY_CHANGE_NAME, 2 },
1857 {BASEDIR_TREE "\\abc\\blah\\b",
1858 true, FILE_NOTIFY_CHANGE_NAME, 2 },
1859 {BASEDIR_TREE "\\abc\\blah\\c",
1860 true, FILE_NOTIFY_CHANGE_NAME, 2 },
1861 {BASEDIR_TREE "\\abc\\fooblah",
1862 true, FILE_NOTIFY_CHANGE_NAME, 2 },
1863 {BASEDIR_TREE "\\zqy\\xx",
1864 true, FILE_NOTIFY_CHANGE_NAME, 2 },
1865 {BASEDIR_TREE "\\zqy\\yyy",
1866 true, FILE_NOTIFY_CHANGE_NAME, 2 },
1867 {BASEDIR_TREE "\\zqy\\..",
1868 true, FILE_NOTIFY_CHANGE_NAME, 40 },
1870 true, FILE_NOTIFY_CHANGE_NAME, 40 },
1872 false,FILE_NOTIFY_CHANGE_NAME, 6 },
1873 {BASEDIR_TREE "\\atsy",
1874 false,FILE_NOTIFY_CHANGE_NAME, 4 },
1875 {BASEDIR_TREE "\\abc",
1876 true, FILE_NOTIFY_CHANGE_NAME, 24 },
1877 {BASEDIR_TREE "\\abc",
1878 false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1879 {BASEDIR_TREE "\\abc",
1880 true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1881 {BASEDIR_TREE "\\abc",
1882 true, FILE_NOTIFY_CHANGE_NAME, 24 },
1886 bool all_done = false;
1888 smb2_deltree(tree, BASEDIR_TREE);
1889 smb2_util_rmdir(tree, BASEDIR_TREE);
1891 torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1893 ZERO_STRUCT(io.smb2);
1894 io.generic.level = RAW_OPEN_SMB2;
1895 io.smb2.in.create_flags = 0;
1896 io.smb2.in.desired_access = SEC_FILE_ALL;
1897 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1898 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1899 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1900 NTCREATEX_SHARE_ACCESS_WRITE;
1901 io.smb2.in.alloc_size = 0;
1902 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1903 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1904 io.smb2.in.security_flags = 0;
1905 io.smb2.in.fname = BASEDIR_TREE;
1906 status = smb2_create(tree, torture, &(io.smb2));
1907 CHECK_STATUS(status, NT_STATUS_OK);
1909 ZERO_STRUCT(notify.smb2);
1910 notify.smb2.level = RAW_NOTIFY_SMB2;
1911 notify.smb2.in.buffer_size = 20000;
1914 setup the directory tree, and the notify buffer on each directory
1916 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1917 io.smb2.in.fname = dirs[i].path;
1918 status = smb2_create(tree, torture, &(io.smb2));
1919 CHECK_STATUS(status, NT_STATUS_OK);
1920 dirs[i].h1 = io.smb2.out.file.handle;
1922 notify.smb2.in.completion_filter = dirs[i].filter;
1923 notify.smb2.in.file.handle = dirs[i].h1;
1924 notify.smb2.in.recursive = dirs[i].recursive;
1925 req = smb2_notify_send(tree, &(notify.smb2));
1927 status = smb2_notify_recv(req, torture, &(notify.smb2));
1928 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1931 /* trigger 2 events in each dir */
1932 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1933 char *path = talloc_asprintf(torture, "%s\\test.dir",
1935 smb2_util_mkdir(tree, path);
1936 smb2_util_rmdir(tree, path);
1940 /* give a bit of time for the events to propagate */
1941 tv = timeval_current();
1944 /* count events that have happened in each dir */
1945 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1946 notify.smb2.in.completion_filter = dirs[i].filter;
1947 notify.smb2.in.file.handle = dirs[i].h1;
1948 notify.smb2.in.recursive = dirs[i].recursive;
1949 req = smb2_notify_send(tree, &(notify.smb2));
1951 notify.smb2.out.num_changes = 0;
1952 status = smb2_notify_recv(req, torture,
1954 dirs[i].counted += notify.smb2.out.num_changes;
1959 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1960 if (dirs[i].counted != dirs[i].expected) {
1964 } while (!all_done && timeval_elapsed(&tv) < 20);
1966 torture_comment(torture, "took %.4f seconds to propagate all events\n",
1967 timeval_elapsed(&tv));
1969 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1970 if (dirs[i].counted != dirs[i].expected) {
1971 torture_comment(torture,
1972 "ERROR: i=%d expected %d got %d for '%s'\n",
1973 i, dirs[i].expected, dirs[i].counted,
1980 run from the back, closing and deleting
1982 for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1983 smb2_util_close(tree, dirs[i].h1);
1984 smb2_util_rmdir(tree, dirs[i].path);
1988 smb2_deltree(tree, BASEDIR_TREE);
1989 smb2_util_rmdir(tree, BASEDIR_TREE);
1994 Test response when cached server events exceed single NT NOTFIY response
1998 #define BASEDIR_OVF BASEDIR "_OVF"
2000 static bool torture_smb2_notify_overflow(struct torture_context *torture,
2001 struct smb2_tree *tree)
2005 union smb_notify notify;
2007 struct smb2_handle h1, h2;
2009 struct smb2_request *req1;
2012 smb2_deltree(tree, BASEDIR_OVF);
2013 smb2_util_rmdir(tree, BASEDIR_OVF);
2015 torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
2017 /* get a handle on the directory */
2018 ZERO_STRUCT(io.smb2);
2019 io.generic.level = RAW_OPEN_SMB2;
2020 io.smb2.in.create_flags = 0;
2021 io.smb2.in.desired_access = SEC_FILE_ALL;
2022 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2023 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2024 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2025 NTCREATEX_SHARE_ACCESS_WRITE;
2026 io.smb2.in.alloc_size = 0;
2027 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2028 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2029 io.smb2.in.security_flags = 0;
2030 io.smb2.in.fname = BASEDIR_OVF;
2032 status = smb2_create(tree, torture, &(io.smb2));
2033 CHECK_STATUS(status, NT_STATUS_OK);
2034 h1 = io.smb2.out.file.handle;
2036 /* ask for a change notify, on name changes. */
2037 ZERO_STRUCT(notify.smb2);
2038 notify.smb2.level = RAW_NOTIFY_NTTRANS;
2039 notify.smb2.in.buffer_size = 1000;
2040 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2041 notify.smb2.in.file.handle = h1;
2043 notify.smb2.in.recursive = true;
2044 req1 = smb2_notify_send(tree, &(notify.smb2));
2046 /* cancel initial requests so the buffer is setup */
2048 status = smb2_notify_recv(req1, torture, &(notify.smb2));
2049 CHECK_STATUS(status, NT_STATUS_CANCELLED);
2051 /* open a lot of files, filling up the server side notify buffer */
2052 torture_comment(torture,
2053 "Testing overflowed buffer notify on create of %d files\n",
2056 for (i=0;i<count;i++) {
2057 char *fname = talloc_asprintf(torture,
2058 BASEDIR_OVF "\\test%d.txt", i);
2060 ZERO_STRUCT(io1.smb2);
2061 io1.generic.level = RAW_OPEN_SMB2;
2062 io1.smb2.in.create_flags = 0;
2063 io1.smb2.in.desired_access = SEC_FILE_ALL;
2064 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2065 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2066 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2067 NTCREATEX_SHARE_ACCESS_WRITE;
2068 io1.smb2.in.alloc_size = 0;
2069 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2070 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2071 io1.smb2.in.security_flags = 0;
2072 io1.smb2.in.fname = fname;
2074 h2 = custom_smb2_create(tree, torture, &(io1.smb2));
2076 smb2_util_close(tree, h2);
2079 req1 = smb2_notify_send(tree, &(notify.smb2));
2080 status = smb2_notify_recv(req1, torture, &(notify.smb2));
2081 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
2082 CHECK_VAL(notify.smb2.out.num_changes, 0);
2085 smb2_deltree(tree, BASEDIR_OVF);
2090 Test if notifications are returned for changes to the base directory.
2094 #define BASEDIR_BAS BASEDIR "_BAS"
2096 static bool torture_smb2_notify_basedir(struct torture_context *torture,
2097 struct smb2_tree *tree1,
2098 struct smb2_tree *tree2)
2102 union smb_notify notify;
2104 struct smb2_handle h1;
2105 struct smb2_request *req1;
2107 smb2_deltree(tree1, BASEDIR_BAS);
2108 smb2_util_rmdir(tree1, BASEDIR_BAS);
2110 torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
2112 /* get a handle on the directory */
2113 ZERO_STRUCT(io.smb2);
2114 io.generic.level = RAW_OPEN_SMB2;
2115 io.smb2.in.create_flags = 0;
2116 io.smb2.in.desired_access = SEC_FILE_ALL;
2117 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2118 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2119 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2120 NTCREATEX_SHARE_ACCESS_WRITE;
2121 io.smb2.in.alloc_size = 0;
2122 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2123 io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
2124 io.smb2.in.security_flags = 0;
2125 io.smb2.in.fname = BASEDIR_BAS;
2127 status = smb2_create(tree1, torture, &(io.smb2));
2128 CHECK_STATUS(status, NT_STATUS_OK);
2129 h1 = io.smb2.out.file.handle;
2131 /* create a test file that will also be modified */
2132 io.smb2.in.fname = BASEDIR_BAS "\\tname1";
2133 io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
2134 status = smb2_create(tree2, torture, &(io.smb2));
2135 CHECK_STATUS(status,NT_STATUS_OK);
2136 smb2_util_close(tree2, io.smb2.out.file.handle);
2138 /* ask for a change notify, on attribute changes. */
2139 ZERO_STRUCT(notify.smb2);
2140 notify.smb2.level = RAW_NOTIFY_SMB2;
2141 notify.smb2.in.buffer_size = 1000;
2142 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
2143 notify.smb2.in.file.handle = h1;
2144 notify.smb2.in.recursive = true;
2146 req1 = smb2_notify_send(tree1, &(notify.smb2));
2148 /* set attribute on the base dir */
2149 smb2_util_setatr(tree2, BASEDIR_BAS, FILE_ATTRIBUTE_HIDDEN);
2151 /* set attribute on a file to assure we receive a notification */
2152 smb2_util_setatr(tree2, BASEDIR_BAS "\\tname1", FILE_ATTRIBUTE_HIDDEN);
2155 /* check how many responses were given, expect only 1 for the file */
2156 status = smb2_notify_recv(req1, torture, &(notify.smb2));
2157 CHECK_STATUS(status, NT_STATUS_OK);
2158 CHECK_VAL(notify.smb2.out.num_changes, 1);
2159 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
2160 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
2163 smb2_deltree(tree1, BASEDIR_BAS);
2168 very simple change notify test
2171 #define BASEDIR_TCON BASEDIR "_TCON"
2173 static bool torture_smb2_notify_tcon(struct torture_context *torture,
2174 struct smb2_tree *tree)
2178 union smb_notify notify;
2180 struct smb2_handle h1 = {{0}};
2181 struct smb2_request *req = NULL;
2182 struct smb2_tree *tree1 = NULL;
2183 const char *fname = BASEDIR_TCON "\\subdir-name";
2185 smb2_deltree(tree, BASEDIR_TCON);
2186 smb2_util_rmdir(tree, BASEDIR_TCON);
2188 torture_comment(torture, "TESTING SIMPLE CHANGE NOTIFY\n");
2191 get a handle on the directory
2194 ZERO_STRUCT(io.smb2);
2195 io.generic.level = RAW_OPEN_SMB2;
2196 io.smb2.in.create_flags = 0;
2197 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2198 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2199 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL |
2200 FILE_ATTRIBUTE_DIRECTORY;
2201 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2202 NTCREATEX_SHARE_ACCESS_WRITE;
2203 io.smb2.in.alloc_size = 0;
2204 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2205 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2206 io.smb2.in.security_flags = 0;
2207 io.smb2.in.fname = BASEDIR_TCON;
2209 status = smb2_create(tree, torture, &(io.smb2));
2210 CHECK_STATUS(status, NT_STATUS_OK);
2211 h1 = io.smb2.out.file.handle;
2213 /* ask for a change notify,
2214 on file or directory name changes */
2215 ZERO_STRUCT(notify.smb2);
2216 notify.smb2.level = RAW_NOTIFY_SMB2;
2217 notify.smb2.in.buffer_size = 1000;
2218 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2219 notify.smb2.in.file.handle = h1;
2220 notify.smb2.in.recursive = true;
2222 torture_comment(torture, "Testing notify mkdir\n");
2223 req = smb2_notify_send(tree, &(notify.smb2));
2225 status = smb2_notify_recv(req, torture, &(notify.smb2));
2226 CHECK_STATUS(status, NT_STATUS_CANCELLED);
2228 notify.smb2.in.recursive = true;
2229 req = smb2_notify_send(tree, &(notify.smb2));
2230 status = smb2_util_mkdir(tree, fname);
2231 CHECK_STATUS(status, NT_STATUS_OK);
2233 status = smb2_notify_recv(req, torture, &(notify.smb2));
2234 CHECK_STATUS(status, NT_STATUS_OK);
2236 CHECK_VAL(notify.smb2.out.num_changes, 1);
2237 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2238 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2240 torture_comment(torture, "Testing notify rmdir\n");
2241 req = smb2_notify_send(tree, &(notify.smb2));
2242 status = smb2_util_rmdir(tree, fname);
2243 CHECK_STATUS(status, NT_STATUS_OK);
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, "SIMPLE CHANGE NOTIFY OK\n");
2253 torture_comment(torture, "TESTING WITH SECONDARY TCON\n");
2254 if (!torture_smb2_tree_connect(torture, tree->session, tree, &tree1)) {
2255 torture_warning(torture, "couldn't reconnect to share, bailing\n");
2260 torture_comment(torture, "tid1=%d tid2=%d\n",
2261 smb2cli_tcon_current_id(tree->smbXcli),
2262 smb2cli_tcon_current_id(tree1->smbXcli));
2264 torture_comment(torture, "Testing notify mkdir\n");
2265 req = smb2_notify_send(tree, &(notify.smb2));
2266 smb2_util_mkdir(tree1, fname);
2268 status = smb2_notify_recv(req, torture, &(notify.smb2));
2269 CHECK_STATUS(status, NT_STATUS_OK);
2271 CHECK_VAL(notify.smb2.out.num_changes, 1);
2272 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2273 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2275 torture_comment(torture, "Testing notify rmdir\n");
2276 req = smb2_notify_send(tree, &(notify.smb2));
2277 smb2_util_rmdir(tree, fname);
2279 status = smb2_notify_recv(req, torture, &(notify.smb2));
2280 CHECK_STATUS(status, NT_STATUS_OK);
2281 CHECK_VAL(notify.smb2.out.num_changes, 1);
2282 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2283 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2285 torture_comment(torture, "CHANGE NOTIFY WITH TCON OK\n");
2287 torture_comment(torture, "Disconnecting secondary tree\n");
2288 status = smb2_tdis(tree1);
2289 CHECK_STATUS(status, NT_STATUS_OK);
2292 torture_comment(torture, "Testing notify mkdir\n");
2293 req = smb2_notify_send(tree, &(notify.smb2));
2294 smb2_util_mkdir(tree, fname);
2296 status = smb2_notify_recv(req, torture, &(notify.smb2));
2297 CHECK_STATUS(status, NT_STATUS_OK);
2299 CHECK_VAL(notify.smb2.out.num_changes, 1);
2300 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2301 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2303 torture_comment(torture, "Testing notify rmdir\n");
2304 req = smb2_notify_send(tree, &(notify.smb2));
2305 smb2_util_rmdir(tree, fname);
2307 status = smb2_notify_recv(req, torture, &(notify.smb2));
2308 CHECK_STATUS(status, NT_STATUS_OK);
2309 CHECK_VAL(notify.smb2.out.num_changes, 1);
2310 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2311 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2313 torture_comment(torture, "CHANGE NOTIFY WITH TDIS OK\n");
2315 smb2_util_close(tree, h1);
2316 smb2_deltree(tree, BASEDIR_TCON);
2321 #define BASEDIR_RMD BASEDIR "_RMD"
2323 static bool torture_smb2_notify_rmdir(struct torture_context *torture,
2324 struct smb2_tree *tree1,
2325 struct smb2_tree *tree2,
2326 bool initial_delete_on_close)
2330 union smb_notify notify = {};
2331 union smb_setfileinfo sfinfo = {};
2332 union smb_open io = {};
2333 struct smb2_handle h = {};
2334 struct smb2_request *req;
2336 torture_comment(torture, "TESTING NOTIFY CANCEL FOR DELETED DIR\n");
2338 smb2_deltree(tree1, BASEDIR_RMD);
2339 smb2_util_rmdir(tree1, BASEDIR_RMD);
2341 ZERO_STRUCT(io.smb2);
2342 io.generic.level = RAW_OPEN_SMB2;
2343 io.smb2.in.create_flags = 0;
2344 io.smb2.in.desired_access = SEC_FILE_ALL;
2345 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2346 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2347 io.smb2.in.share_access =
2348 NTCREATEX_SHARE_ACCESS_READ |
2349 NTCREATEX_SHARE_ACCESS_WRITE |
2350 NTCREATEX_SHARE_ACCESS_DELETE ;
2351 io.smb2.in.alloc_size = 0;
2352 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2353 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2354 io.smb2.in.security_flags = 0;
2355 io.smb2.in.fname = BASEDIR_RMD;
2357 status = smb2_create(tree1, torture, &(io.smb2));
2358 CHECK_STATUS(status, NT_STATUS_OK);
2359 h = io.smb2.out.file.handle;
2361 ZERO_STRUCT(notify.smb2);
2362 notify.smb2.level = RAW_NOTIFY_SMB2;
2363 notify.smb2.in.buffer_size = 1000;
2364 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2365 notify.smb2.in.file.handle = h;
2366 notify.smb2.in.recursive = false;
2368 io.smb2.in.desired_access |= SEC_STD_DELETE;
2369 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
2370 req = smb2_notify_send(tree1, &(notify.smb2));
2372 if (initial_delete_on_close) {
2373 status = smb2_util_rmdir(tree2, BASEDIR_RMD);
2374 CHECK_STATUS(status, NT_STATUS_OK);
2376 status = smb2_create(tree2, torture, &(io.smb2));
2377 CHECK_STATUS(status, NT_STATUS_OK);
2379 sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
2380 sfinfo.generic.in.file.handle = io.smb2.out.file.handle;
2381 sfinfo.disposition_info.in.delete_on_close = 1;
2382 status = smb2_setinfo_file(tree2, &sfinfo);
2383 CHECK_STATUS(status, NT_STATUS_OK);
2385 smb2_util_close(tree2, io.smb2.out.file.handle);
2388 status = smb2_notify_recv(req, torture, &(notify.smb2));
2389 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
2393 smb2_util_close(tree1, h);
2394 smb2_deltree(tree1, BASEDIR_RMD);
2399 static bool torture_smb2_notify_rmdir1(struct torture_context *torture,
2400 struct smb2_tree *tree)
2402 return torture_smb2_notify_rmdir(torture, tree, tree, false);
2405 static bool torture_smb2_notify_rmdir2(struct torture_context *torture,
2406 struct smb2_tree *tree)
2408 return torture_smb2_notify_rmdir(torture, tree, tree, true);
2411 static bool torture_smb2_notify_rmdir3(struct torture_context *torture,
2412 struct smb2_tree *tree1,
2413 struct smb2_tree *tree2)
2415 return torture_smb2_notify_rmdir(torture, tree1, tree2, false);
2418 static bool torture_smb2_notify_rmdir4(struct torture_context *torture,
2419 struct smb2_tree *tree1,
2420 struct smb2_tree *tree2)
2422 return torture_smb2_notify_rmdir(torture, tree1, tree2, true);
2425 static void notify_timeout(struct tevent_context *ev,
2426 struct tevent_timer *te,
2427 struct timeval current_time,
2430 struct smb2_request *req = talloc_get_type_abort(
2431 private_data, struct smb2_request);
2436 #define BASEDIR_INR BASEDIR "_INR"
2438 static bool torture_smb2_inotify_rename(struct torture_context *torture,
2439 struct smb2_tree *tree1,
2440 struct smb2_tree *tree2)
2443 struct smb2_notify notify;
2444 struct notify_changes change1 = {0};
2445 struct notify_changes change2 = {0};
2446 struct smb2_create create;
2447 union smb_setfileinfo sinfo;
2448 struct smb2_handle h1 = {{0}};
2449 struct smb2_handle h2 = {{0}};
2450 struct smb2_request *req;
2451 struct tevent_timer *te = NULL;
2454 smb2_deltree(tree1, BASEDIR_INR);
2456 torture_comment(torture, "Testing change notify of a rename with inotify\n");
2458 status = torture_smb2_testdir(tree1, BASEDIR_INR, &h1);
2459 torture_assert_ntstatus_ok_goto(torture, status, ok, done, "torture_smb2_testdir failed");
2461 ZERO_STRUCT(create);
2462 create.in.desired_access = SEC_RIGHTS_FILE_READ |
2463 SEC_RIGHTS_FILE_WRITE|
2464 SEC_RIGHTS_FILE_ALL;
2465 create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2466 create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2467 create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2468 NTCREATEX_SHARE_ACCESS_WRITE |
2469 NTCREATEX_SHARE_ACCESS_DELETE;
2470 create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2471 create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2472 create.in.fname = BASEDIR_INR "\\subdir-name";
2474 status = smb2_create(tree2, torture, &create);
2475 torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_create failed\n");
2476 h2 = create.out.file.handle;
2478 ZERO_STRUCT(notify);
2479 notify.level = RAW_NOTIFY_SMB2;
2480 notify.in.buffer_size = 4096;
2481 notify.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2482 notify.in.file.handle = h1;
2483 notify.in.recursive = true;
2484 req = smb2_notify_send(tree1, ¬ify);
2485 torture_assert_not_null_goto(torture, req, ok, done, "smb2_notify_send failed\n");
2487 while (!NT_STATUS_EQUAL(req->status, STATUS_PENDING)) {
2488 if (tevent_loop_once(torture->ev) != 0) {
2494 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
2495 sinfo.rename_information.in.file.handle = h2;
2496 sinfo.rename_information.in.new_name = BASEDIR_INR "\\subdir-name-r";
2498 status = smb2_setinfo_file(tree2, &sinfo);
2499 torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_setinfo_file failed\n");
2501 smb2_util_close(tree2, h2);
2503 te = tevent_add_timer(torture->ev,
2505 tevent_timeval_current_ofs(1, 0),
2508 torture_assert_not_null_goto(torture, te, ok, done, "tevent_add_timer failed\n");
2510 status = smb2_notify_recv(req, torture, ¬ify);
2511 torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_notify_recv failed\n");
2513 torture_assert_goto(torture, notify.out.num_changes == 1 || notify.out.num_changes == 2,
2514 ok, done, "bad notify\n");
2516 change1 = notify.out.changes[0];
2517 if (notify.out.num_changes == 2) {
2518 change2 = notify.out.changes[1];
2521 * We may only get one event at a time, so check for the
2522 * matching second event for the oldname/newname or
2523 * removed/added pair.
2525 ZERO_STRUCT(notify);
2526 notify.level = RAW_NOTIFY_SMB2;
2527 notify.in.buffer_size = 4096;
2528 notify.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2529 notify.in.file.handle = h1;
2530 notify.in.recursive = true;
2531 req = smb2_notify_send(tree1, ¬ify);
2532 torture_assert_not_null_goto(torture, req, ok, done, "smb2_notify_send failed\n");
2534 status = smb2_notify_recv(req, torture, ¬ify);
2535 torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_notify_recv failed\n");
2537 torture_assert_goto(torture, notify.out.num_changes == 1, ok, done,
2540 change2 = notify.out.changes[0];
2543 if ((change1.action != NOTIFY_ACTION_OLD_NAME) &&
2544 (change1.action != NOTIFY_ACTION_REMOVED))
2546 torture_fail_goto(torture, done, "bad change notification\n");
2548 torture_assert_str_equal_goto(torture, change1.name.s, "subdir-name",
2549 ok, done, "bad change notification\n");
2551 if ((change2.action != NOTIFY_ACTION_NEW_NAME) &&
2552 (change2.action != NOTIFY_ACTION_ADDED))
2554 torture_fail_goto(torture, done, "bad change notification\n");
2556 torture_assert_str_equal_goto(torture, change2.name.s, "subdir-name-r",
2557 ok, done, "bad change notification\n");
2561 if (!smb2_util_handle_empty(h1)) {
2562 smb2_util_close(tree2, h1);
2564 if (!smb2_util_handle_empty(h2)) {
2565 smb2_util_close(tree2, h2);
2568 smb2_deltree(tree1, BASEDIR_INR);
2573 basic testing of SMB2 change notify
2575 struct torture_suite *torture_smb2_notify_init(TALLOC_CTX *ctx)
2577 struct torture_suite *suite = torture_suite_create(ctx, "notify");
2579 torture_suite_add_1smb2_test(suite, "valid-req", test_valid_request);
2580 torture_suite_add_1smb2_test(suite, "tcon", torture_smb2_notify_tcon);
2581 torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir);
2582 torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask);
2583 torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
2584 torture_suite_add_1smb2_test(suite, "tdis1", torture_smb2_notify_tree_disconnect_1);
2585 torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
2586 torture_suite_add_1smb2_test(suite, "close", torture_smb2_notify_close);
2587 torture_suite_add_1smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
2588 torture_suite_add_1smb2_test(suite, "session-reconnect", torture_smb2_notify_session_reconnect);
2589 torture_suite_add_2smb2_test(suite, "invalid-reauth", torture_smb2_notify_invalid_reauth);
2590 torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
2591 torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
2592 torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
2593 torture_suite_add_1smb2_test(suite, "file", torture_smb2_notify_file);
2594 torture_suite_add_1smb2_test(suite, "tcp", torture_smb2_notify_tcp_disconnect);
2595 torture_suite_add_2smb2_test(suite, "rec", torture_smb2_notify_recursive);
2596 torture_suite_add_1smb2_test(suite, "overflow", torture_smb2_notify_overflow);
2597 torture_suite_add_1smb2_test(suite, "rmdir1",
2598 torture_smb2_notify_rmdir1);
2599 torture_suite_add_1smb2_test(suite, "rmdir2",
2600 torture_smb2_notify_rmdir2);
2601 torture_suite_add_2smb2_test(suite, "rmdir3",
2602 torture_smb2_notify_rmdir3);
2603 torture_suite_add_2smb2_test(suite, "rmdir4",
2604 torture_smb2_notify_rmdir4);
2606 suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");
2612 basic testing of SMB2 change notify
2614 struct torture_suite *torture_smb2_notify_inotify_init(TALLOC_CTX *ctx)
2616 struct torture_suite *suite = torture_suite_create(ctx, "notify-inotify");
2618 suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests that use inotify");
2620 torture_suite_add_2smb2_test(suite, "inotify-rename", torture_smb2_inotify_rename);