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"
27 #include "torture/torture.h"
28 #include "torture/smb2/proto.h"
29 #include "librpc/gen_ndr/ndr_security.h"
30 #include "libcli/security/security.h"
31 #include "torture/util.h"
33 #include "system/filesys.h"
34 #include "auth/credentials/credentials.h"
35 #include "lib/cmdline/popt_common.h"
36 #include "librpc/gen_ndr/security.h"
38 #include "lib/events/events.h"
40 #include "libcli/raw/libcliraw.h"
41 #include "libcli/raw/raw_proto.h"
42 #include "libcli/libcli.h"
44 #define CHECK_STATUS(status, correct) do { \
45 if (!NT_STATUS_EQUAL(status, correct)) { \
46 torture_result(torture, TORTURE_FAIL, \
47 "(%s) Incorrect status %s - should be %s\n", \
48 __location__, nt_errstr(status), nt_errstr(correct)); \
53 #define CHECK_VAL(v, correct) do { \
54 if ((v) != (correct)) { \
55 torture_result(torture, TORTURE_FAIL, \
56 "(%s) wrong value for %s 0x%x should be 0x%x\n", \
57 __location__, #v, (int)v, (int)correct); \
62 #define CHECK_WIRE_STR(field, value) do { \
63 if (!field.s || strcmp(field.s, value)) { \
64 torture_result(torture, TORTURE_FAIL, \
65 "(%s) %s [%s] != %s\n", __location__, #field, \
71 #define BASEDIR "test_notify"
72 #define FNAME "smb2-notify01.dat"
74 static bool test_valid_request(struct torture_context *torture,
75 struct smb2_tree *tree)
79 struct smb2_handle dh;
81 struct smb2_request *req;
82 uint32_t max_buffer_size;
84 torture_comment(torture, "TESTING VALIDITY OF CHANGE NOTIFY REQUEST\n");
86 smb2_util_unlink(tree, FNAME);
88 status = smb2_util_roothandle(tree, &dh);
89 CHECK_STATUS(status, NT_STATUS_OK);
91 /* 0x00080000 is the default max buffer size for Windows servers
93 max_buffer_size = torture_setting_ulong(torture, "cn_max_buffer_size",
96 n.in.recursive = 0x0000;
97 n.in.buffer_size = max_buffer_size;
98 n.in.file.handle = dh;
99 n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
100 n.in.unknown = 0x00000000;
101 req = smb2_notify_send(tree, &n);
103 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
104 if (tevent_loop_once(torture->ev) != 0) {
109 status = torture_setup_complex_file(tree, FNAME);
110 CHECK_STATUS(status, NT_STATUS_OK);
112 status = smb2_notify_recv(req, torture, &n);
113 CHECK_STATUS(status, NT_STATUS_OK);
114 CHECK_VAL(n.out.num_changes, 1);
115 CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_ADDED);
116 CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
119 * if the change response doesn't fit in the buffer
120 * NOTIFY_ENUM_DIR is returned.
122 n.in.buffer_size = 0x00000000;
123 req = smb2_notify_send(tree, &n);
125 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
126 if (tevent_loop_once(torture->ev) != 0) {
131 status = torture_setup_complex_file(tree, FNAME);
132 CHECK_STATUS(status, NT_STATUS_OK);
134 status = smb2_notify_recv(req, torture, &n);
135 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
138 * if the change response fits in the buffer we get
141 n.in.buffer_size = max_buffer_size;
142 req = smb2_notify_send(tree, &n);
144 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
145 if (tevent_loop_once(torture->ev) != 0) {
150 status = torture_setup_complex_file(tree, FNAME);
151 CHECK_STATUS(status, NT_STATUS_OK);
153 status = smb2_notify_recv(req, torture, &n);
154 CHECK_STATUS(status, NT_STATUS_OK);
155 CHECK_VAL(n.out.num_changes, 3);
156 CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_REMOVED);
157 CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
158 CHECK_VAL(n.out.changes[1].action, NOTIFY_ACTION_ADDED);
159 CHECK_WIRE_STR(n.out.changes[1].name, FNAME);
160 CHECK_VAL(n.out.changes[2].action, NOTIFY_ACTION_MODIFIED);
161 CHECK_WIRE_STR(n.out.changes[2].name, FNAME);
163 /* if the first notify returns NOTIFY_ENUM_DIR, all do */
164 status = smb2_util_close(tree, dh);
165 CHECK_STATUS(status, NT_STATUS_OK);
166 status = smb2_util_roothandle(tree, &dh);
167 CHECK_STATUS(status, NT_STATUS_OK);
169 n.in.recursive = 0x0000;
170 n.in.buffer_size = 0x00000001;
171 n.in.file.handle = dh;
172 n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
173 n.in.unknown = 0x00000000;
174 req = smb2_notify_send(tree, &n);
176 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
177 if (tevent_loop_once(torture->ev) != 0) {
182 status = torture_setup_complex_file(tree, FNAME);
183 CHECK_STATUS(status, NT_STATUS_OK);
185 status = smb2_notify_recv(req, torture, &n);
186 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
188 n.in.buffer_size = max_buffer_size;
189 req = smb2_notify_send(tree, &n);
190 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
191 if (tevent_loop_once(torture->ev) != 0) {
196 status = torture_setup_complex_file(tree, FNAME);
197 CHECK_STATUS(status, NT_STATUS_OK);
199 status = smb2_notify_recv(req, torture, &n);
200 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
202 /* if the buffer size is too large, we get invalid parameter */
203 n.in.recursive = 0x0000;
204 n.in.buffer_size = max_buffer_size + 1;
205 n.in.file.handle = dh;
206 n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
207 n.in.unknown = 0x00000000;
208 req = smb2_notify_send(tree, &n);
209 status = smb2_notify_recv(req, torture, &n);
210 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
217 basic testing of change notify on directories
219 static bool torture_smb2_notify_dir(struct torture_context *torture,
220 struct smb2_tree *tree1,
221 struct smb2_tree *tree2)
225 union smb_notify notify;
229 struct smb2_handle h1, h2;
230 struct smb2_request *req, *req2;
231 const char *fname = BASEDIR "\\subdir-name";
232 extern int torture_numops;
234 torture_comment(torture, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
236 smb2_deltree(tree1, BASEDIR);
237 smb2_util_rmdir(tree1, BASEDIR);
239 get a handle on the directory
241 ZERO_STRUCT(io.smb2);
242 io.generic.level = RAW_OPEN_SMB2;
243 io.smb2.in.create_flags = 0;
244 io.smb2.in.desired_access = SEC_FILE_ALL;
245 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
246 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
247 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
248 NTCREATEX_SHARE_ACCESS_WRITE;
249 io.smb2.in.alloc_size = 0;
250 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
251 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
252 io.smb2.in.security_flags = 0;
253 io.smb2.in.fname = BASEDIR;
255 status = smb2_create(tree1, torture, &(io.smb2));
256 CHECK_STATUS(status, NT_STATUS_OK);
257 h1 = io.smb2.out.file.handle;
259 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
260 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ;
261 status = smb2_create(tree1, torture, &(io.smb2));
262 CHECK_STATUS(status, NT_STATUS_OK);
263 h2 = io.smb2.out.file.handle;
265 /* ask for a change notify,
266 on file or directory name changes */
267 ZERO_STRUCT(notify.smb2);
268 notify.smb2.level = RAW_NOTIFY_SMB2;
269 notify.smb2.in.buffer_size = 1000;
270 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
271 notify.smb2.in.file.handle = h1;
272 notify.smb2.in.recursive = true;
274 torture_comment(torture, "Testing notify cancel\n");
276 req = smb2_notify_send(tree1, &(notify.smb2));
278 status = smb2_notify_recv(req, torture, &(notify.smb2));
279 CHECK_STATUS(status, NT_STATUS_CANCELLED);
281 torture_comment(torture, "Testing notify mkdir\n");
283 req = smb2_notify_send(tree1, &(notify.smb2));
284 smb2_util_mkdir(tree2, fname);
286 status = smb2_notify_recv(req, torture, &(notify.smb2));
287 CHECK_STATUS(status, NT_STATUS_OK);
289 CHECK_VAL(notify.smb2.out.num_changes, 1);
290 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
291 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
293 torture_comment(torture, "Testing notify rmdir\n");
295 req = smb2_notify_send(tree1, &(notify.smb2));
296 smb2_util_rmdir(tree2, fname);
298 status = smb2_notify_recv(req, torture, &(notify.smb2));
299 CHECK_STATUS(status, NT_STATUS_OK);
300 CHECK_VAL(notify.smb2.out.num_changes, 1);
301 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
302 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
304 torture_comment(torture,
305 "Testing notify mkdir - rmdir - mkdir - rmdir\n");
307 smb2_util_mkdir(tree2, fname);
308 smb2_util_rmdir(tree2, fname);
309 smb2_util_mkdir(tree2, fname);
310 smb2_util_rmdir(tree2, fname);
312 req = smb2_notify_send(tree1, &(notify.smb2));
313 status = smb2_notify_recv(req, torture, &(notify.smb2));
314 CHECK_STATUS(status, NT_STATUS_OK);
315 CHECK_VAL(notify.smb2.out.num_changes, 4);
316 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
317 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
318 CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_REMOVED);
319 CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name");
320 CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_ADDED);
321 CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name");
322 CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_REMOVED);
323 CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name");
325 count = torture_numops;
326 torture_comment(torture,
327 "Testing buffered notify on create of %d files\n", count);
328 for (i=0;i<count;i++) {
329 struct smb2_handle h12;
330 char *fname2 = talloc_asprintf(torture, BASEDIR "\\test%d.txt",
333 ZERO_STRUCT(io.smb2);
334 io.generic.level = RAW_OPEN_SMB2;
335 io.smb2.in.create_flags = 0;
336 io.smb2.in.desired_access = SEC_FILE_ALL;
337 io.smb2.in.create_options =
338 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
339 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
340 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
341 NTCREATEX_SHARE_ACCESS_WRITE;
342 io.smb2.in.alloc_size = 0;
343 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
344 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
345 io.smb2.in.security_flags = 0;
346 io.smb2.in.fname = fname2;
348 status = smb2_create(tree1, torture, &(io.smb2));
349 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
350 torture_comment(torture, "Failed to create %s \n",
355 h12 = io.smb2.out.file.handle;
357 smb2_util_close(tree1, h12);
360 /* (1st notify) setup a new notify on a different directory handle.
361 This new notify won't see the events above. */
362 notify.smb2.in.file.handle = h2;
363 req2 = smb2_notify_send(tree1, &(notify.smb2));
365 /* (2nd notify) whereas this notify will see the above buffered events,
366 and it directly returns the buffered events */
367 notify.smb2.in.file.handle = h1;
368 req = smb2_notify_send(tree1, &(notify.smb2));
370 status = smb2_util_unlink(tree1, BASEDIR "\\nonexistant.txt");
371 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
373 /* (1st unlink) as the 2nd notify directly returns,
374 this unlink is only seen by the 1st notify and
375 the 3rd notify (later) */
376 torture_comment(torture,
377 "Testing notify on unlink for the first file\n");
378 status = smb2_util_unlink(tree2, BASEDIR "\\test0.txt");
379 CHECK_STATUS(status, NT_STATUS_OK);
381 /* receive the reply from the 2nd notify */
382 status = smb2_notify_recv(req, torture, &(notify.smb2));
383 CHECK_STATUS(status, NT_STATUS_OK);
385 CHECK_VAL(notify.smb2.out.num_changes, count);
386 for (i=1;i<count;i++) {
387 CHECK_VAL(notify.smb2.out.changes[i].action,
388 NOTIFY_ACTION_ADDED);
390 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
392 torture_comment(torture, "and now from the 1st notify\n");
393 status = smb2_notify_recv(req2, torture, &(notify.smb2));
394 CHECK_STATUS(status, NT_STATUS_OK);
395 CHECK_VAL(notify.smb2.out.num_changes, 1);
396 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
397 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
399 torture_comment(torture,
400 "(3rd notify) this notify will only see the 1st unlink\n");
401 req = smb2_notify_send(tree1, &(notify.smb2));
403 status = smb2_util_unlink(tree1, BASEDIR "\\nonexistant.txt");
404 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
406 for (i=1;i<count;i++) {
407 char *fname2 = talloc_asprintf(torture,
408 BASEDIR "\\test%d.txt", i);
409 status = smb2_util_unlink(tree2, fname2);
410 CHECK_STATUS(status, NT_STATUS_OK);
414 /* receive the 3rd notify */
415 status = smb2_notify_recv(req, torture, &(notify.smb2));
416 CHECK_STATUS(status, NT_STATUS_OK);
417 CHECK_VAL(notify.smb2.out.num_changes, 1);
418 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
419 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
421 /* and we now see the rest of the unlink calls on both
422 * directory handles */
423 notify.smb2.in.file.handle = h1;
425 req = smb2_notify_send(tree1, &(notify.smb2));
426 status = smb2_notify_recv(req, torture, &(notify.smb2));
427 CHECK_STATUS(status, NT_STATUS_OK);
428 CHECK_VAL(notify.smb2.out.num_changes, count-1);
429 for (i=0;i<notify.smb2.out.num_changes;i++) {
430 CHECK_VAL(notify.smb2.out.changes[i].action,
431 NOTIFY_ACTION_REMOVED);
433 notify.smb2.in.file.handle = h2;
434 req = smb2_notify_send(tree1, &(notify.smb2));
435 status = smb2_notify_recv(req, torture, &(notify.smb2));
436 CHECK_STATUS(status, NT_STATUS_OK);
437 CHECK_VAL(notify.smb2.out.num_changes, count-1);
438 for (i=0;i<notify.smb2.out.num_changes;i++) {
439 CHECK_VAL(notify.smb2.out.changes[i].action,
440 NOTIFY_ACTION_REMOVED);
443 torture_comment(torture,
444 "Testing if a close() on the dir handle triggers the notify reply\n");
446 notify.smb2.in.file.handle = h1;
447 req = smb2_notify_send(tree1, &(notify.smb2));
449 ZERO_STRUCT(cl.smb2);
450 cl.smb2.level = RAW_CLOSE_SMB2;
451 cl.smb2.in.file.handle = h1;
452 status = smb2_close(tree1, &(cl.smb2));
453 CHECK_STATUS(status, NT_STATUS_OK);
455 status = smb2_notify_recv(req, torture, &(notify.smb2));
456 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
457 CHECK_VAL(notify.smb2.out.num_changes, 9);
460 smb2_util_close(tree1, h1);
461 smb2_util_close(tree1, h2);
462 smb2_deltree(tree1, BASEDIR);
466 static struct smb2_handle custom_smb2_create(struct smb2_tree *tree,
467 struct torture_context *torture,
468 struct smb2_create *smb2)
470 struct smb2_handle h1;
473 smb2_deltree(tree, smb2->in.fname);
474 status = smb2_create(tree, torture, smb2);
475 CHECK_STATUS(status, NT_STATUS_OK);
476 h1 = smb2->out.file.handle;
482 testing of recursive change notify
485 static bool torture_smb2_notify_recursive(struct torture_context *torture,
486 struct smb2_tree *tree1,
487 struct smb2_tree *tree2)
491 union smb_notify notify;
492 union smb_open io, io1;
493 union smb_setfileinfo sinfo;
494 struct smb2_handle h1;
495 struct smb2_request *req1, *req2;
497 smb2_deltree(tree1, BASEDIR);
498 smb2_util_rmdir(tree1, BASEDIR);
500 torture_comment(torture, "TESTING CHANGE NOTIFY WITH RECURSION\n");
503 get a handle on the directory
505 ZERO_STRUCT(io.smb2);
506 io.generic.level = RAW_OPEN_SMB2;
507 io.smb2.in.create_flags = 0;
508 io.smb2.in.desired_access = SEC_FILE_ALL;
509 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
510 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
511 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
512 NTCREATEX_SHARE_ACCESS_WRITE;
513 io.smb2.in.alloc_size = 0;
514 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
515 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
516 io.smb2.in.security_flags = 0;
517 io.smb2.in.fname = BASEDIR;
519 status = smb2_create(tree1, torture, &(io.smb2));
520 CHECK_STATUS(status, NT_STATUS_OK);
521 h1 = io.smb2.out.file.handle;
523 /* ask for a change notify, on file or directory name
524 changes. Setup both with and without recursion */
525 ZERO_STRUCT(notify.smb2);
526 notify.smb2.level = RAW_NOTIFY_SMB2;
527 notify.smb2.in.buffer_size = 1000;
528 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
529 FILE_NOTIFY_CHANGE_ATTRIBUTES |
530 FILE_NOTIFY_CHANGE_CREATION;
531 notify.smb2.in.file.handle = h1;
533 notify.smb2.in.recursive = true;
534 req1 = smb2_notify_send(tree1, &(notify.smb2));
536 status = smb2_notify_recv(req1, torture, &(notify.smb2));
537 CHECK_STATUS(status, NT_STATUS_CANCELLED);
539 notify.smb2.in.recursive = false;
540 req2 = smb2_notify_send(tree1, &(notify.smb2));
542 status = smb2_notify_recv(req2, torture, &(notify.smb2));
543 CHECK_STATUS(status, NT_STATUS_CANCELLED);
545 ZERO_STRUCT(io1.smb2);
546 io1.generic.level = RAW_OPEN_SMB2;
547 io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
548 io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
549 SEC_RIGHTS_FILE_WRITE|
551 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
552 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
553 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
554 NTCREATEX_SHARE_ACCESS_WRITE |
555 NTCREATEX_SHARE_ACCESS_DELETE;
556 io1.smb2.in.alloc_size = 0;
557 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
558 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
559 io1.smb2.in.security_flags = 0;
560 io1.smb2.in.fname = BASEDIR "\\subdir-name";
561 status = smb2_create(tree2, torture, &(io1.smb2));
562 CHECK_STATUS(status, NT_STATUS_OK);
563 smb2_util_close(tree2, io1.smb2.out.file.handle);
565 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname1";
566 status = smb2_create(tree2, torture, &(io1.smb2));
567 CHECK_STATUS(status, NT_STATUS_OK);
569 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
570 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
571 sinfo.rename_information.in.overwrite = 0;
572 sinfo.rename_information.in.root_fid = 0;
573 sinfo.rename_information.in.new_name =
574 BASEDIR "\\subdir-name\\subname1-r";
575 status = smb2_setinfo_file(tree2, &sinfo);
576 CHECK_STATUS(status, NT_STATUS_OK);
578 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
579 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname2";
580 status = smb2_create(tree2, torture, &(io1.smb2));
581 CHECK_STATUS(status, NT_STATUS_OK);
583 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
584 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
585 sinfo.rename_information.in.overwrite = true;
586 sinfo.rename_information.in.root_fid = 0;
587 sinfo.rename_information.in.new_name = BASEDIR "\\subname2-r";
588 status = smb2_setinfo_file(tree2, &sinfo);
589 CHECK_STATUS(status, NT_STATUS_OK);
591 io1.smb2.in.fname = BASEDIR "\\subname2-r";
592 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
593 status = smb2_create(tree2, torture, &(io1.smb2));
594 CHECK_STATUS(status, NT_STATUS_OK);
596 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
597 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
598 sinfo.rename_information.in.overwrite = true;
599 sinfo.rename_information.in.root_fid = 0;
600 sinfo.rename_information.in.new_name = BASEDIR "\\subname3-r";
601 status = smb2_setinfo_file(tree2, &sinfo);
602 CHECK_STATUS(status, NT_STATUS_OK);
604 notify.smb2.in.completion_filter = 0;
605 notify.smb2.in.recursive = true;
607 req1 = smb2_notify_send(tree1, &(notify.smb2));
609 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name\\subname1-r");
610 CHECK_STATUS(status, NT_STATUS_OK);
611 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name");
612 CHECK_STATUS(status, NT_STATUS_OK);
613 status = smb2_util_unlink(tree2, BASEDIR "\\subname3-r");
614 CHECK_STATUS(status, NT_STATUS_OK);
616 notify.smb2.in.recursive = false;
617 req2 = smb2_notify_send(tree1, &(notify.smb2));
619 status = smb2_notify_recv(req1, torture, &(notify.smb2));
620 CHECK_STATUS(status, NT_STATUS_OK);
622 CHECK_VAL(notify.smb2.out.num_changes, 9);
623 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
624 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
625 CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_ADDED);
626 CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name\\subname1");
627 CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_OLD_NAME);
628 CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name\\subname1");
629 CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_NEW_NAME);
630 CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name\\subname1-r");
631 CHECK_VAL(notify.smb2.out.changes[4].action, NOTIFY_ACTION_ADDED);
632 CHECK_WIRE_STR(notify.smb2.out.changes[4].name, "subdir-name\\subname2");
633 CHECK_VAL(notify.smb2.out.changes[5].action, NOTIFY_ACTION_REMOVED);
634 CHECK_WIRE_STR(notify.smb2.out.changes[5].name, "subdir-name\\subname2");
635 CHECK_VAL(notify.smb2.out.changes[6].action, NOTIFY_ACTION_ADDED);
636 CHECK_WIRE_STR(notify.smb2.out.changes[6].name, "subname2-r");
637 CHECK_VAL(notify.smb2.out.changes[7].action, NOTIFY_ACTION_OLD_NAME);
638 CHECK_WIRE_STR(notify.smb2.out.changes[7].name, "subname2-r");
639 CHECK_VAL(notify.smb2.out.changes[8].action, NOTIFY_ACTION_NEW_NAME);
640 CHECK_WIRE_STR(notify.smb2.out.changes[8].name, "subname3-r");
643 smb2_deltree(tree1, BASEDIR);
648 testing of change notify mask change
651 static bool torture_smb2_notify_mask_change(struct torture_context *torture,
652 struct smb2_tree *tree1,
653 struct smb2_tree *tree2)
657 union smb_notify notify;
658 union smb_open io, io1;
659 struct smb2_handle h1;
660 struct smb2_request *req1, *req2;
661 union smb_setfileinfo sinfo;
663 smb2_deltree(tree1, BASEDIR);
664 smb2_util_rmdir(tree1, BASEDIR);
666 torture_comment(torture, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
669 get a handle on the directory
671 ZERO_STRUCT(io.smb2);
672 io.generic.level = RAW_OPEN_SMB2;
673 io.smb2.in.create_flags = 0;
674 io.smb2.in.desired_access = SEC_FILE_ALL;
675 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
676 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
677 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
678 NTCREATEX_SHARE_ACCESS_WRITE;
679 io.smb2.in.alloc_size = 0;
680 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
681 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
682 io.smb2.in.security_flags = 0;
683 io.smb2.in.fname = BASEDIR;
685 status = smb2_create(tree1, torture, &(io.smb2));
686 CHECK_STATUS(status, NT_STATUS_OK);
687 h1 = io.smb2.out.file.handle;
689 /* ask for a change notify, on file or directory name
690 changes. Setup both with and without recursion */
691 ZERO_STRUCT(notify.smb2);
692 notify.smb2.level = RAW_NOTIFY_SMB2;
693 notify.smb2.in.buffer_size = 1000;
694 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
695 notify.smb2.in.file.handle = h1;
697 notify.smb2.in.recursive = true;
698 req1 = smb2_notify_send(tree1, &(notify.smb2));
701 status = smb2_notify_recv(req1, torture, &(notify.smb2));
702 CHECK_STATUS(status, NT_STATUS_CANCELLED);
705 notify.smb2.in.recursive = false;
706 req2 = smb2_notify_send(tree1, &(notify.smb2));
709 status = smb2_notify_recv(req2, torture, &(notify.smb2));
710 CHECK_STATUS(status, NT_STATUS_CANCELLED);
712 notify.smb2.in.recursive = true;
713 req1 = smb2_notify_send(tree1, &(notify.smb2));
715 /* Set to hidden then back again. */
716 ZERO_STRUCT(io1.smb2);
717 io1.generic.level = RAW_OPEN_SMB2;
718 io1.smb2.in.create_flags = 0;
719 io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
720 SEC_RIGHTS_FILE_WRITE|
722 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
723 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
724 NTCREATEX_SHARE_ACCESS_WRITE |
725 NTCREATEX_SHARE_ACCESS_DELETE;
726 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
727 io1.smb2.in.security_flags = 0;
728 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
729 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
730 io1.smb2.in.fname = BASEDIR "\\tname1";
732 smb2_util_close(tree1,
733 custom_smb2_create(tree1, torture, &(io1.smb2)));
734 status = smb2_util_setatr(tree1, BASEDIR "\\tname1",
735 FILE_ATTRIBUTE_HIDDEN);
736 CHECK_STATUS(status, NT_STATUS_OK);
737 smb2_util_unlink(tree1, BASEDIR "\\tname1");
739 status = smb2_notify_recv(req1, torture, &(notify.smb2));
740 CHECK_STATUS(status, NT_STATUS_OK);
742 CHECK_VAL(notify.smb2.out.num_changes, 1);
743 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
744 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
746 /* Now try and change the mask to include other events.
747 * This should not work - once the mask is set on a directory
748 * h1 it seems to be fixed until the fnum is closed. */
750 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
751 FILE_NOTIFY_CHANGE_ATTRIBUTES |
752 FILE_NOTIFY_CHANGE_CREATION;
753 notify.smb2.in.recursive = true;
754 req1 = smb2_notify_send(tree1, &(notify.smb2));
756 notify.smb2.in.recursive = false;
757 req2 = smb2_notify_send(tree1, &(notify.smb2));
759 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
760 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
761 io1.smb2.in.fname = BASEDIR "\\subdir-name";
762 status = smb2_create(tree2, torture, &(io1.smb2));
763 CHECK_STATUS(status, NT_STATUS_OK);
764 smb2_util_close(tree2, io1.smb2.out.file.handle);
767 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname1";
768 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
769 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
770 status = smb2_create(tree2, torture, &(io1.smb2));
771 CHECK_STATUS(status, NT_STATUS_OK);
772 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
773 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
774 sinfo.rename_information.in.overwrite = true;
775 sinfo.rename_information.in.root_fid = 0;
776 sinfo.rename_information.in.new_name =
777 BASEDIR "\\subdir-name\\subname1-r";
778 status = smb2_setinfo_file(tree2, &sinfo);
779 CHECK_STATUS(status, NT_STATUS_OK);
781 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname2";
782 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
783 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
784 status = smb2_create(tree2, torture, &(io1.smb2));
785 CHECK_STATUS(status, NT_STATUS_OK);
786 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
787 sinfo.rename_information.in.new_name = BASEDIR "\\subname2-r";
788 status = smb2_setinfo_file(tree2, &sinfo);
789 CHECK_STATUS(status, NT_STATUS_OK);
790 smb2_util_close(tree2, io1.smb2.out.file.handle);
792 io1.smb2.in.fname = BASEDIR "\\subname2-r";
793 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
794 status = smb2_create(tree2, torture, &(io1.smb2));
795 CHECK_STATUS(status, NT_STATUS_OK);
796 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
797 sinfo.rename_information.in.new_name = BASEDIR "\\subname3-r";
798 status = smb2_setinfo_file(tree2, &sinfo);
799 CHECK_STATUS(status, NT_STATUS_OK);
800 smb2_util_close(tree2, io1.smb2.out.file.handle);
802 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name\\subname1-r");
803 CHECK_STATUS(status, NT_STATUS_OK);
804 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name");
805 CHECK_STATUS(status, NT_STATUS_OK);
806 status = smb2_util_unlink(tree2, BASEDIR "\\subname3-r");
807 CHECK_STATUS(status, NT_STATUS_OK);
809 status = smb2_notify_recv(req1, torture, &(notify.smb2));
810 CHECK_STATUS(status, NT_STATUS_OK);
812 CHECK_VAL(notify.smb2.out.num_changes, 1);
813 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
814 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname2-r");
816 status = smb2_notify_recv(req2, torture, &(notify.smb2));
817 CHECK_STATUS(status, NT_STATUS_OK);
819 CHECK_VAL(notify.smb2.out.num_changes, 1);
820 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
821 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname3-r");
828 smb2_deltree(tree1, BASEDIR);
833 testing of mask bits for change notify
836 static bool torture_smb2_notify_mask(struct torture_context *torture,
837 struct smb2_tree *tree1,
838 struct smb2_tree *tree2)
842 union smb_notify notify;
843 union smb_open io, io1;
844 struct smb2_handle h1, h2;
849 union smb_setfileinfo sinfo;
851 smb2_deltree(tree1, BASEDIR);
852 smb2_util_rmdir(tree1, BASEDIR);
854 torture_comment(torture, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
856 tv = timeval_current_ofs(1000, 0);
859 get a handle on the directory
861 ZERO_STRUCT(io.smb2);
862 io.generic.level = RAW_OPEN_SMB2;
863 io.smb2.in.create_flags = 0;
864 io.smb2.in.desired_access = SEC_FILE_ALL;
865 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
866 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
867 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
868 NTCREATEX_SHARE_ACCESS_WRITE;
869 io.smb2.in.alloc_size = 0;
870 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
871 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
872 io.smb2.in.security_flags = 0;
873 io.smb2.in.fname = BASEDIR;
875 ZERO_STRUCT(notify.smb2);
876 notify.smb2.level = RAW_NOTIFY_SMB2;
877 notify.smb2.in.buffer_size = 1000;
878 notify.smb2.in.recursive = true;
880 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
881 expected, nchanges) \
883 do { for (mask=i=0;i<32;i++) { \
884 struct smb2_request *req; \
885 status = smb2_create(tree1, torture, &(io.smb2)); \
886 CHECK_STATUS(status, NT_STATUS_OK); \
887 h1 = io.smb2.out.file.handle; \
889 notify.smb2.in.file.handle = h1; \
890 notify.smb2.in.completion_filter = (1<<i); \
891 /* cancel initial requests so the buffer is setup */ \
892 req = smb2_notify_send(tree1, &(notify.smb2)); \
894 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
895 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
896 /* send the change notify request */ \
897 req = smb2_notify_send(tree1, &(notify.smb2)); \
899 smb_msleep(200); smb2_cancel(req); \
900 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
902 smb2_util_close(tree1, h1); \
903 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
904 CHECK_STATUS(status, NT_STATUS_OK); \
905 /* special case to cope with file rename behaviour */ \
906 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
907 notify.smb2.out.changes[0].action == \
908 NOTIFY_ACTION_MODIFIED && \
909 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
910 Action == NOTIFY_ACTION_OLD_NAME) { \
911 torture_comment(torture, \
912 "(rename file special handling OK)\n"); \
913 } else if (nchanges != notify.smb2.out.num_changes) { \
914 torture_result(torture, TORTURE_FAIL, \
915 "ERROR: nchanges=%d expected=%d "\
916 "action=%d filter=0x%08x\n", \
917 notify.smb2.out.num_changes, \
919 notify.smb2.out.changes[0].action, \
920 notify.smb2.in.completion_filter); \
922 } else if (notify.smb2.out.changes[0].action != Action) { \
923 torture_result(torture, TORTURE_FAIL, \
924 "ERROR: nchanges=%d action=%d " \
925 "expectedAction=%d filter=0x%08x\n", \
926 notify.smb2.out.num_changes, \
927 notify.smb2.out.changes[0].action, \
929 notify.smb2.in.completion_filter); \
931 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
933 torture_result(torture, TORTURE_FAIL, \
934 "ERROR: nchanges=%d action=%d " \
935 "filter=0x%08x name=%s\n", \
936 notify.smb2.out.num_changes, \
937 notify.smb2.out.changes[0].action, \
938 notify.smb2.in.completion_filter, \
939 notify.smb2.out.changes[0].name.s); \
947 torture_comment(torture, "Testing mkdir\n");
948 NOTIFY_MASK_TEST("Testing mkdir",;,
949 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
950 smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
952 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
954 torture_comment(torture, "Testing create file\n");
955 ZERO_STRUCT(io1.smb2);
956 io1.generic.level = RAW_OPEN_SMB2;
957 io1.smb2.in.create_flags = 0;
958 io1.smb2.in.desired_access = SEC_FILE_ALL;
959 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
960 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
961 NTCREATEX_SHARE_ACCESS_WRITE;
962 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
963 io1.smb2.in.security_flags = 0;
964 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
965 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
966 io1.smb2.in.fname = BASEDIR "\\tname1";
968 NOTIFY_MASK_TEST("Testing create file",;,
969 smb2_util_close(tree2, custom_smb2_create(tree2,
970 torture, &(io1.smb2)));,
971 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
973 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
975 torture_comment(torture, "Testing unlink\n");
976 NOTIFY_MASK_TEST("Testing unlink",
977 smb2_util_close(tree2, custom_smb2_create(tree2,
978 torture, &(io1.smb2)));,
979 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
981 NOTIFY_ACTION_REMOVED,
982 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
984 torture_comment(torture, "Testing rmdir\n");
985 NOTIFY_MASK_TEST("Testing rmdir",
986 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
987 smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
989 NOTIFY_ACTION_REMOVED,
990 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
992 torture_comment(torture, "Testing rename file\n");
994 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
995 sinfo.rename_information.in.file.handle = h1;
996 sinfo.rename_information.in.overwrite = true;
997 sinfo.rename_information.in.root_fid = 0;
998 sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
999 NOTIFY_MASK_TEST("Testing rename file",
1000 smb2_util_close(tree2, custom_smb2_create(tree2,
1001 torture, &(io1.smb2)));,
1002 smb2_setinfo_file(tree2, &sinfo);,
1003 smb2_util_unlink(tree2, BASEDIR "\\tname2");,
1004 NOTIFY_ACTION_OLD_NAME,
1005 FILE_NOTIFY_CHANGE_FILE_NAME, 2);
1007 torture_comment(torture, "Testing rename dir\n");
1009 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1010 sinfo.rename_information.in.file.handle = h1;
1011 sinfo.rename_information.in.overwrite = true;
1012 sinfo.rename_information.in.root_fid = 0;
1013 sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
1014 NOTIFY_MASK_TEST("Testing rename dir",
1015 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
1016 smb2_setinfo_file(tree2, &sinfo);,
1017 smb2_util_rmdir(tree2, BASEDIR "\\tname2");,
1018 NOTIFY_ACTION_OLD_NAME,
1019 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
1021 torture_comment(torture, "Testing set path attribute\n");
1022 NOTIFY_MASK_TEST("Testing set path attribute",
1023 smb2_util_close(tree2, custom_smb2_create(tree2,
1024 torture, &(io.smb2)));,
1025 smb2_util_setatr(tree2, BASEDIR "\\tname1",
1026 FILE_ATTRIBUTE_HIDDEN);,
1027 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1028 NOTIFY_ACTION_MODIFIED,
1029 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
1031 torture_comment(torture, "Testing set path write time\n");
1033 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1034 sinfo.generic.in.file.handle = h1;
1035 sinfo.basic_info.in.write_time = 1000;
1036 NOTIFY_MASK_TEST("Testing set path write time",
1037 smb2_util_close(tree2, custom_smb2_create(tree2,
1038 torture, &(io1.smb2)));,
1039 smb2_setinfo_file(tree2, &sinfo);,
1040 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1041 NOTIFY_ACTION_MODIFIED,
1042 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
1044 if (torture_setting_bool(torture, "samba3", false)) {
1045 torture_comment(torture,
1046 "Samba3 does not yet support create times "
1051 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1052 sinfo.generic.in.file.handle = h1;
1053 sinfo.basic_info.in.create_time = 0;
1054 torture_comment(torture, "Testing set file create time\n");
1055 NOTIFY_MASK_TEST("Testing set file create time",
1056 smb2_create_complex_file(tree2,
1057 BASEDIR "\\tname1", &h2);,
1058 smb2_setinfo_file(tree2, &sinfo);,
1059 (smb2_util_close(tree2, h2),
1060 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1061 NOTIFY_ACTION_MODIFIED,
1062 FILE_NOTIFY_CHANGE_CREATION, 1);
1066 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1067 sinfo.generic.in.file.handle = h1;
1068 sinfo.basic_info.in.access_time = 0;
1069 torture_comment(torture, "Testing set file access time\n");
1070 NOTIFY_MASK_TEST("Testing set file access time",
1071 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1072 smb2_setinfo_file(tree2, &sinfo);,
1073 (smb2_util_close(tree2, h2),
1074 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1075 NOTIFY_ACTION_MODIFIED,
1076 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
1079 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1080 sinfo.generic.in.file.handle = h1;
1081 sinfo.basic_info.in.change_time = 0;
1082 torture_comment(torture, "Testing set file change time\n");
1083 NOTIFY_MASK_TEST("Testing set file change time",
1084 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1085 smb2_setinfo_file(tree2, &sinfo);,
1086 (smb2_util_close(tree2, h2),
1087 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1088 NOTIFY_ACTION_MODIFIED,
1092 torture_comment(torture, "Testing write\n");
1093 NOTIFY_MASK_TEST("Testing write",
1094 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1095 smb2_util_write(tree2, h2, &c, 10000, 1);,
1096 (smb2_util_close(tree2, h2),
1097 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1098 NOTIFY_ACTION_MODIFIED,
1102 smb2_deltree(tree1, BASEDIR);
1107 basic testing of change notify on files
1109 static bool torture_smb2_notify_file(struct torture_context *torture,
1110 struct smb2_tree *tree)
1116 union smb_notify notify;
1117 struct smb2_request *req;
1118 struct smb2_handle h1;
1119 const char *fname = BASEDIR "\\file.txt";
1121 smb2_deltree(tree, BASEDIR);
1122 smb2_util_rmdir(tree, BASEDIR);
1124 torture_comment(torture, "TESTING CHANGE NOTIFY ON FILES\n");
1125 status = torture_smb2_testdir(tree, BASEDIR, &h1);
1126 CHECK_STATUS(status, NT_STATUS_OK);
1128 ZERO_STRUCT(io.smb2);
1129 io.generic.level = RAW_OPEN_SMB2;
1130 io.smb2.in.create_flags = 0;
1131 io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
1132 io.smb2.in.create_options = 0;
1133 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1134 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1135 NTCREATEX_SHARE_ACCESS_WRITE;
1136 io.smb2.in.alloc_size = 0;
1137 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1138 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1139 io.smb2.in.security_flags = 0;
1140 io.smb2.in.fname = fname;
1141 status = smb2_create(tree, torture, &(io.smb2));
1142 CHECK_STATUS(status, NT_STATUS_OK);
1143 h1 = io.smb2.out.file.handle;
1145 /* ask for a change notify,
1146 on file or directory name changes */
1147 ZERO_STRUCT(notify.smb2);
1148 notify.smb2.level = RAW_NOTIFY_SMB2;
1149 notify.smb2.in.file.handle = h1;
1150 notify.smb2.in.buffer_size = 1000;
1151 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
1152 notify.smb2.in.recursive = false;
1154 torture_comment(torture,
1155 "Testing if notifies on file handles are invalid (should be)\n");
1157 req = smb2_notify_send(tree, &(notify.smb2));
1158 status = smb2_notify_recv(req, torture, &(notify.smb2));
1159 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1161 ZERO_STRUCT(cl.smb2);
1162 cl.close.level = RAW_CLOSE_SMB2;
1163 cl.close.in.file.handle = h1;
1164 status = smb2_close(tree, &(cl.smb2));
1165 CHECK_STATUS(status, NT_STATUS_OK);
1167 status = smb2_util_unlink(tree, fname);
1168 CHECK_STATUS(status, NT_STATUS_OK);
1171 smb2_deltree(tree, BASEDIR);
1175 basic testing of change notifies followed by a tdis
1178 static bool torture_smb2_notify_tree_disconnect(
1179 struct torture_context *torture,
1180 struct smb2_tree *tree)
1184 union smb_notify notify;
1186 struct smb2_handle h1;
1187 struct smb2_request *req;
1189 smb2_deltree(tree, BASEDIR);
1190 smb2_util_rmdir(tree, BASEDIR);
1192 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY "
1193 "TREE-DISCONNECT\n");
1196 get a handle on the directory
1198 ZERO_STRUCT(io.smb2);
1199 io.generic.level = RAW_OPEN_SMB2;
1200 io.smb2.in.create_flags = 0;
1201 io.smb2.in.desired_access = SEC_FILE_ALL;
1202 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1203 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1204 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1205 NTCREATEX_SHARE_ACCESS_WRITE;
1206 io.smb2.in.alloc_size = 0;
1207 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1208 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1209 io.smb2.in.security_flags = 0;
1210 io.smb2.in.fname = BASEDIR;
1212 status = smb2_create(tree, torture, &(io.smb2));
1213 CHECK_STATUS(status, NT_STATUS_OK);
1214 h1 = io.smb2.out.file.handle;
1216 /* ask for a change notify,
1217 on file or directory name changes */
1218 ZERO_STRUCT(notify.smb2);
1219 notify.smb2.level = RAW_NOTIFY_SMB2;
1220 notify.smb2.in.buffer_size = 1000;
1221 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1222 notify.smb2.in.file.handle = h1;
1223 notify.smb2.in.recursive = true;
1225 req = smb2_notify_send(tree, &(notify.smb2));
1227 status = smb2_notify_recv(req, torture, &(notify.smb2));
1229 status = smb2_tdis(tree);
1230 CHECK_STATUS(status, NT_STATUS_OK);
1232 req = smb2_notify_send(tree, &(notify.smb2));
1234 smb2_notify_recv(req, torture, &(notify.smb2));
1235 CHECK_STATUS(status, NT_STATUS_OK);
1236 CHECK_VAL(notify.smb2.out.num_changes, 0);
1239 smb2_deltree(tree, BASEDIR);
1244 basic testing of change notifies followed by a ulogoff
1247 static bool torture_smb2_notify_ulogoff(struct torture_context *torture,
1248 struct smb2_tree *tree1,
1249 struct smb2_tree *tree2)
1253 union smb_notify notify;
1255 struct smb2_handle h1;
1256 struct smb2_request *req;
1258 smb2_deltree(tree1, BASEDIR);
1259 smb2_util_rmdir(tree1, BASEDIR);
1261 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1264 get a handle on the directory
1266 ZERO_STRUCT(io.smb2);
1267 io.generic.level = RAW_OPEN_SMB2;
1268 io.smb2.in.create_flags = 0;
1269 io.smb2.in.desired_access = SEC_FILE_ALL;
1270 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1271 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1272 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1273 NTCREATEX_SHARE_ACCESS_WRITE;
1274 io.smb2.in.alloc_size = 0;
1275 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1276 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1277 io.smb2.in.security_flags = 0;
1278 io.smb2.in.fname = BASEDIR;
1280 status = smb2_create(tree2, torture, &(io.smb2));
1281 CHECK_STATUS(status, NT_STATUS_OK);
1283 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1284 status = smb2_create(tree2, torture, &(io.smb2));
1285 CHECK_STATUS(status, NT_STATUS_OK);
1286 h1 = io.smb2.out.file.handle;
1288 /* ask for a change notify,
1289 on file or directory name changes */
1290 ZERO_STRUCT(notify.smb2);
1291 notify.smb2.level = RAW_NOTIFY_SMB2;
1292 notify.smb2.in.buffer_size = 1000;
1293 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1294 notify.smb2.in.file.handle = h1;
1295 notify.smb2.in.recursive = true;
1297 req = smb2_notify_send(tree1, &(notify.smb2));
1299 status = smb2_logoff(tree2->session);
1300 CHECK_STATUS(status, NT_STATUS_OK);
1302 status = smb2_notify_recv(req, torture, &(notify.smb2));
1303 CHECK_VAL(notify.smb2.out.num_changes, 0);
1306 smb2_deltree(tree1, BASEDIR);
1310 static void tcp_dis_handler(struct smb2_transport *t, void *p)
1312 struct smb2_tree *tree = (struct smb2_tree *)p;
1313 smb2_transport_dead(tree->session->transport,
1314 NT_STATUS_LOCAL_DISCONNECT);
1320 basic testing of change notifies followed by tcp disconnect
1323 static bool torture_smb2_notify_tcp_disconnect(
1324 struct torture_context *torture,
1325 struct smb2_tree *tree)
1329 union smb_notify notify;
1331 struct smb2_handle h1;
1332 struct smb2_request *req;
1334 smb2_deltree(tree, BASEDIR);
1335 smb2_util_rmdir(tree, BASEDIR);
1337 torture_comment(torture,
1338 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1341 get a handle on the directory
1343 ZERO_STRUCT(io.smb2);
1344 io.generic.level = RAW_OPEN_SMB2;
1345 io.smb2.in.create_flags = 0;
1346 io.smb2.in.desired_access = SEC_FILE_ALL;
1347 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1348 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1349 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1350 NTCREATEX_SHARE_ACCESS_WRITE;
1351 io.smb2.in.alloc_size = 0;
1352 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1353 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1354 io.smb2.in.security_flags = 0;
1355 io.smb2.in.fname = BASEDIR;
1357 status = smb2_create(tree, torture, &(io.smb2));
1358 CHECK_STATUS(status, NT_STATUS_OK);
1359 h1 = io.smb2.out.file.handle;
1361 /* ask for a change notify,
1362 on file or directory name changes */
1363 ZERO_STRUCT(notify.smb2);
1364 notify.smb2.level = RAW_NOTIFY_SMB2;
1365 notify.smb2.in.buffer_size = 1000;
1366 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1367 notify.smb2.in.file.handle = h1;
1368 notify.smb2.in.recursive = true;
1370 req = smb2_notify_send(tree, &(notify.smb2));
1372 status = smb2_notify_recv(req, torture, &(notify.smb2));
1373 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1375 notify.smb2.in.recursive = true;
1376 req = smb2_notify_send(tree, &(notify.smb2));
1377 smb2_transport_idle_handler(tree->session->transport,
1378 tcp_dis_handler, 250, tree);
1380 status = smb2_notify_recv(req, torture, &(notify.smb2));
1381 CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
1388 test setting up two change notify requests on one handle
1391 static bool torture_smb2_notify_double(struct torture_context *torture,
1392 struct smb2_tree *tree1,
1393 struct smb2_tree *tree2)
1397 union smb_notify notify;
1399 struct smb2_handle h1;
1400 struct smb2_request *req1, *req2;
1402 smb2_deltree(tree1, BASEDIR);
1403 smb2_util_rmdir(tree1, BASEDIR);
1405 torture_comment(torture,
1406 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1409 get a handle on the directory
1411 ZERO_STRUCT(io.smb2);
1412 io.generic.level = RAW_OPEN_SMB2;
1413 io.smb2.in.create_flags = 0;
1414 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ|
1415 SEC_RIGHTS_FILE_WRITE|
1416 SEC_RIGHTS_FILE_ALL;
1417 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1418 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1419 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1420 NTCREATEX_SHARE_ACCESS_WRITE;
1421 io.smb2.in.alloc_size = 0;
1422 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1423 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1424 io.smb2.in.security_flags = 0;
1425 io.smb2.in.fname = BASEDIR;
1427 status = smb2_create(tree1, torture, &(io.smb2));
1428 CHECK_STATUS(status, NT_STATUS_OK);
1429 h1 = io.smb2.out.file.handle;
1431 /* ask for a change notify,
1432 on file or directory name changes */
1433 ZERO_STRUCT(notify.smb2);
1434 notify.smb2.level = RAW_NOTIFY_SMB2;
1435 notify.smb2.in.buffer_size = 1000;
1436 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1437 notify.smb2.in.file.handle = h1;
1438 notify.smb2.in.recursive = true;
1440 req1 = smb2_notify_send(tree1, &(notify.smb2));
1442 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1443 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1445 req2 = smb2_notify_send(tree1, &(notify.smb2));
1447 status = smb2_notify_recv(req2, torture, &(notify.smb2));
1448 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1450 smb2_util_mkdir(tree2, BASEDIR "\\subdir-name");
1451 req1 = smb2_notify_send(tree1, &(notify.smb2));
1452 req2 = smb2_notify_send(tree1, &(notify.smb2));
1454 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1455 CHECK_STATUS(status, NT_STATUS_OK);
1456 CHECK_VAL(notify.smb2.out.num_changes, 1);
1457 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1459 smb2_util_mkdir(tree2, BASEDIR "\\subdir-name2");
1461 status = smb2_notify_recv(req2, torture, &(notify.smb2));
1462 CHECK_STATUS(status, NT_STATUS_OK);
1463 CHECK_VAL(notify.smb2.out.num_changes, 1);
1464 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name2");
1467 smb2_deltree(tree1, BASEDIR);
1473 test multiple change notifies at different depths and with/without recursion
1476 static bool torture_smb2_notify_tree(struct torture_context *torture,
1477 struct smb2_tree *tree)
1480 union smb_notify notify;
1482 struct smb2_request *req;
1489 struct smb2_handle h1;
1492 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 30 },
1493 {BASEDIR "\\zqy", true, FILE_NOTIFY_CHANGE_NAME, 8 },
1494 {BASEDIR "\\atsy", true, FILE_NOTIFY_CHANGE_NAME, 4 },
1495 {BASEDIR "\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1496 {BASEDIR "\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME, 13 },
1497 {BASEDIR "\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME, 7 },
1498 {BASEDIR "\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1499 {BASEDIR "\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1500 {BASEDIR "\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1501 {BASEDIR "\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1502 {BASEDIR "\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1503 {BASEDIR "\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1504 {BASEDIR "\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME, 40 },
1505 {BASEDIR, true, FILE_NOTIFY_CHANGE_NAME, 40 },
1506 {BASEDIR, false,FILE_NOTIFY_CHANGE_NAME, 6 },
1507 {BASEDIR "\\atsy", false,FILE_NOTIFY_CHANGE_NAME, 4 },
1508 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1509 {BASEDIR "\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1510 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1511 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1515 bool all_done = false;
1517 smb2_deltree(tree, BASEDIR);
1518 smb2_util_rmdir(tree, BASEDIR);
1520 torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1522 ZERO_STRUCT(io.smb2);
1523 io.generic.level = RAW_OPEN_SMB2;
1524 io.smb2.in.create_flags = 0;
1525 io.smb2.in.desired_access = SEC_FILE_ALL;
1526 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1527 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1528 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1529 NTCREATEX_SHARE_ACCESS_WRITE;
1530 io.smb2.in.alloc_size = 0;
1531 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1532 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1533 io.smb2.in.security_flags = 0;
1534 io.smb2.in.fname = BASEDIR;
1535 status = smb2_create(tree, torture, &(io.smb2));
1536 CHECK_STATUS(status, NT_STATUS_OK);
1538 ZERO_STRUCT(notify.smb2);
1539 notify.smb2.level = RAW_NOTIFY_SMB2;
1540 notify.smb2.in.buffer_size = 20000;
1543 setup the directory tree, and the notify buffer on each directory
1545 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1546 io.smb2.in.fname = dirs[i].path;
1547 status = smb2_create(tree, torture, &(io.smb2));
1548 CHECK_STATUS(status, NT_STATUS_OK);
1549 dirs[i].h1 = io.smb2.out.file.handle;
1551 notify.smb2.in.completion_filter = dirs[i].filter;
1552 notify.smb2.in.file.handle = dirs[i].h1;
1553 notify.smb2.in.recursive = dirs[i].recursive;
1554 req = smb2_notify_send(tree, &(notify.smb2));
1556 status = smb2_notify_recv(req, torture, &(notify.smb2));
1557 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1560 /* trigger 2 events in each dir */
1561 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1562 char *path = talloc_asprintf(torture, "%s\\test.dir",
1564 smb2_util_mkdir(tree, path);
1565 smb2_util_rmdir(tree, path);
1569 /* give a bit of time for the events to propogate */
1570 tv = timeval_current();
1573 /* count events that have happened in each dir */
1574 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1575 notify.smb2.in.file.handle = dirs[i].h1;
1576 req = smb2_notify_send(tree, &(notify.smb2));
1578 notify.smb2.out.num_changes = 0;
1579 status = smb2_notify_recv(req, torture,
1581 dirs[i].counted += notify.smb2.out.num_changes;
1586 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1587 if (dirs[i].counted != dirs[i].expected) {
1591 } while (!all_done && timeval_elapsed(&tv) < 20);
1593 torture_comment(torture, "took %.4f seconds to propogate all events\n",
1594 timeval_elapsed(&tv));
1596 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1597 if (dirs[i].counted != dirs[i].expected) {
1598 torture_comment(torture,
1599 "ERROR: i=%d expected %d got %d for '%s'\n",
1600 i, dirs[i].expected, dirs[i].counted,
1607 run from the back, closing and deleting
1609 for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1610 smb2_util_close(tree, dirs[i].h1);
1611 smb2_util_rmdir(tree, dirs[i].path);
1615 smb2_deltree(tree, BASEDIR);
1616 smb2_util_rmdir(tree, BASEDIR);
1621 Test response when cached server events exceed single NT NOTFIY response
1625 static bool torture_smb2_notify_overflow(struct torture_context *torture,
1626 struct smb2_tree *tree)
1630 union smb_notify notify;
1632 struct smb2_handle h1, h2;
1634 struct smb2_request *req1;
1637 smb2_deltree(tree, BASEDIR);
1638 smb2_util_rmdir(tree, BASEDIR);
1640 torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1642 /* get a handle on the directory */
1643 ZERO_STRUCT(io.smb2);
1644 io.generic.level = RAW_OPEN_SMB2;
1645 io.smb2.in.create_flags = 0;
1646 io.smb2.in.desired_access = SEC_FILE_ALL;
1647 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1648 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1649 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1650 NTCREATEX_SHARE_ACCESS_WRITE;
1651 io.smb2.in.alloc_size = 0;
1652 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1653 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1654 io.smb2.in.security_flags = 0;
1655 io.smb2.in.fname = BASEDIR;
1657 status = smb2_create(tree, torture, &(io.smb2));
1658 CHECK_STATUS(status, NT_STATUS_OK);
1659 h1 = io.smb2.out.file.handle;
1661 /* ask for a change notify, on name changes. */
1662 ZERO_STRUCT(notify.smb2);
1663 notify.smb2.level = RAW_NOTIFY_NTTRANS;
1664 notify.smb2.in.buffer_size = 1000;
1665 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1666 notify.smb2.in.file.handle = h1;
1668 notify.smb2.in.recursive = true;
1669 req1 = smb2_notify_send(tree, &(notify.smb2));
1671 /* cancel initial requests so the buffer is setup */
1673 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1674 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1676 /* open a lot of files, filling up the server side notify buffer */
1677 torture_comment(torture,
1678 "Testing overflowed buffer notify on create of %d files\n",
1681 for (i=0;i<count;i++) {
1682 char *fname = talloc_asprintf(torture,
1683 BASEDIR "\\test%d.txt", i);
1685 ZERO_STRUCT(io1.smb2);
1686 io1.generic.level = RAW_OPEN_SMB2;
1687 io1.smb2.in.create_flags = 0;
1688 io1.smb2.in.desired_access = SEC_FILE_ALL;
1689 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1690 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1691 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1692 NTCREATEX_SHARE_ACCESS_WRITE;
1693 io1.smb2.in.alloc_size = 0;
1694 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1695 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1696 io1.smb2.in.security_flags = 0;
1697 io1.smb2.in.fname = fname;
1699 h2 = custom_smb2_create(tree, torture, &(io1.smb2));
1701 smb2_util_close(tree, h2);
1704 req1 = smb2_notify_send(tree, &(notify.smb2));
1705 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1706 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
1707 CHECK_VAL(notify.smb2.out.num_changes, 0);
1710 smb2_deltree(tree, BASEDIR);
1715 Test if notifications are returned for changes to the base directory.
1719 static bool torture_smb2_notify_basedir(struct torture_context *torture,
1720 struct smb2_tree *tree1,
1721 struct smb2_tree *tree2)
1725 union smb_notify notify;
1727 struct smb2_handle h1;
1728 struct smb2_request *req1;
1730 smb2_deltree(tree1, BASEDIR);
1731 smb2_util_rmdir(tree1, BASEDIR);
1733 torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1735 /* get a handle on the directory */
1736 ZERO_STRUCT(io.smb2);
1737 io.generic.level = RAW_OPEN_SMB2;
1738 io.smb2.in.create_flags = 0;
1739 io.smb2.in.desired_access = SEC_FILE_ALL;
1740 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1741 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1742 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1743 NTCREATEX_SHARE_ACCESS_WRITE;
1744 io.smb2.in.alloc_size = 0;
1745 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1746 io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
1747 io.smb2.in.security_flags = 0;
1748 io.smb2.in.fname = BASEDIR;
1750 status = smb2_create(tree1, torture, &(io.smb2));
1751 CHECK_STATUS(status, NT_STATUS_OK);
1752 h1 = io.smb2.out.file.handle;
1754 /* create a test file that will also be modified */
1755 io.smb2.in.fname = BASEDIR "\\tname1";
1756 io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
1757 status = smb2_create(tree2, torture, &(io.smb2));
1758 CHECK_STATUS(status,NT_STATUS_OK);
1759 smb2_util_close(tree2, io.smb2.out.file.handle);
1761 /* ask for a change notify, on attribute changes. */
1762 ZERO_STRUCT(notify.smb2);
1763 notify.smb2.level = RAW_NOTIFY_SMB2;
1764 notify.smb2.in.buffer_size = 1000;
1765 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
1766 notify.smb2.in.file.handle = h1;
1767 notify.smb2.in.recursive = true;
1769 req1 = smb2_notify_send(tree1, &(notify.smb2));
1771 /* set attribute on the base dir */
1772 smb2_util_setatr(tree2, BASEDIR, FILE_ATTRIBUTE_HIDDEN);
1774 /* set attribute on a file to assure we receive a notification */
1775 smb2_util_setatr(tree2, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN);
1778 /* check how many responses were given, expect only 1 for the file */
1779 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1780 CHECK_STATUS(status, NT_STATUS_OK);
1781 CHECK_VAL(notify.smb2.out.num_changes, 1);
1782 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
1783 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
1786 smb2_deltree(tree1, BASEDIR);
1792 create a secondary tree connect - used to test for a bug in Samba3 messaging
1795 static struct smb2_tree *secondary_tcon(struct smb2_tree *tree,
1796 struct torture_context *tctx)
1799 const char *share, *host;
1800 struct smb2_tree *tree1;
1801 union smb_tcon tcon;
1803 share = torture_setting_string(tctx, "share", NULL);
1804 host = torture_setting_string(tctx, "host", NULL);
1806 torture_comment(tctx,
1807 "create a second tree context on the same session\n");
1808 tree1 = smb2_tree_init(tree->session, tctx, false);
1810 ZERO_STRUCT(tcon.smb2);
1811 tcon.generic.level = RAW_TCON_SMB2;
1812 tcon.smb2.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
1813 status = smb2_tree_connect(tree, &(tcon.smb2));
1814 if (!NT_STATUS_IS_OK(status)) {
1816 torture_comment(tctx,"Failed to create secondary tree\n");
1820 tree1->tid = tcon.smb2.out.tid;
1821 torture_comment(tctx,"tid1=%d tid2=%d\n", tree->tid, tree1->tid);
1828 very simple change notify test
1830 static bool torture_smb2_notify_tcon(struct torture_context *torture,
1831 struct smb2_tree *tree)
1835 union smb_notify notify;
1837 struct smb2_handle h1;
1838 struct smb2_request *req = NULL;
1839 struct smb2_tree *tree1 = NULL;
1840 const char *fname = BASEDIR "\\subdir-name";
1842 smb2_deltree(tree, BASEDIR);
1843 smb2_util_rmdir(tree, BASEDIR);
1845 torture_comment(torture, "TESTING SIMPLE CHANGE NOTIFY\n");
1848 get a handle on the directory
1851 ZERO_STRUCT(io.smb2);
1852 io.generic.level = RAW_OPEN_SMB2;
1853 io.smb2.in.create_flags = 0;
1854 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1855 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1856 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL |
1857 FILE_ATTRIBUTE_DIRECTORY;
1858 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1859 NTCREATEX_SHARE_ACCESS_WRITE;
1860 io.smb2.in.alloc_size = 0;
1861 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1862 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1863 io.smb2.in.security_flags = 0;
1864 io.smb2.in.fname = BASEDIR;
1866 status = smb2_create(tree, torture, &(io.smb2));
1867 CHECK_STATUS(status, NT_STATUS_OK);
1868 h1 = io.smb2.out.file.handle;
1870 /* ask for a change notify,
1871 on file or directory name changes */
1872 ZERO_STRUCT(notify.smb2);
1873 notify.smb2.level = RAW_NOTIFY_SMB2;
1874 notify.smb2.in.buffer_size = 1000;
1875 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1876 notify.smb2.in.file.handle = h1;
1877 notify.smb2.in.recursive = true;
1879 torture_comment(torture, "Testing notify mkdir\n");
1880 req = smb2_notify_send(tree, &(notify.smb2));
1882 status = smb2_notify_recv(req, torture, &(notify.smb2));
1883 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1885 notify.smb2.in.recursive = true;
1886 req = smb2_notify_send(tree, &(notify.smb2));
1887 status = smb2_util_mkdir(tree, fname);
1888 CHECK_STATUS(status, NT_STATUS_OK);
1890 status = smb2_notify_recv(req, torture, &(notify.smb2));
1891 CHECK_STATUS(status, NT_STATUS_OK);
1893 CHECK_VAL(notify.smb2.out.num_changes, 1);
1894 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
1895 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1897 torture_comment(torture, "Testing notify rmdir\n");
1898 req = smb2_notify_send(tree, &(notify.smb2));
1899 status = smb2_util_rmdir(tree, fname);
1900 CHECK_STATUS(status, NT_STATUS_OK);
1902 status = smb2_notify_recv(req, torture, &(notify.smb2));
1903 CHECK_STATUS(status, NT_STATUS_OK);
1904 CHECK_VAL(notify.smb2.out.num_changes, 1);
1905 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
1906 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1908 torture_comment(torture, "SIMPLE CHANGE NOTIFY OK\n");
1910 torture_comment(torture, "TESTING WITH SECONDARY TCON\n");
1911 tree1 = secondary_tcon(tree, torture);
1913 torture_comment(torture, "Testing notify mkdir\n");
1914 req = smb2_notify_send(tree, &(notify.smb2));
1915 smb2_util_mkdir(tree1, fname);
1917 status = smb2_notify_recv(req, torture, &(notify.smb2));
1918 CHECK_STATUS(status, NT_STATUS_OK);
1920 CHECK_VAL(notify.smb2.out.num_changes, 1);
1921 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
1922 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1924 torture_comment(torture, "Testing notify rmdir\n");
1925 req = smb2_notify_send(tree, &(notify.smb2));
1926 smb2_util_rmdir(tree, fname);
1928 status = smb2_notify_recv(req, torture, &(notify.smb2));
1929 CHECK_STATUS(status, NT_STATUS_OK);
1930 CHECK_VAL(notify.smb2.out.num_changes, 1);
1931 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
1932 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1934 torture_comment(torture, "CHANGE NOTIFY WITH TCON OK\n");
1936 torture_comment(torture, "Disconnecting secondary tree\n");
1937 status = smb2_tdis(tree1);
1938 CHECK_STATUS(status, NT_STATUS_OK);
1941 torture_comment(torture, "Testing notify mkdir\n");
1942 req = smb2_notify_send(tree, &(notify.smb2));
1943 smb2_util_mkdir(tree, fname);
1945 status = smb2_notify_recv(req, torture, &(notify.smb2));
1946 CHECK_STATUS(status, NT_STATUS_OK);
1948 CHECK_VAL(notify.smb2.out.num_changes, 1);
1949 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
1950 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1952 torture_comment(torture, "Testing notify rmdir\n");
1953 req = smb2_notify_send(tree, &(notify.smb2));
1954 smb2_util_rmdir(tree, fname);
1956 status = smb2_notify_recv(req, torture, &(notify.smb2));
1957 CHECK_STATUS(status, NT_STATUS_OK);
1958 CHECK_VAL(notify.smb2.out.num_changes, 1);
1959 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
1960 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1962 torture_comment(torture, "CHANGE NOTIFY WITH TDIS OK\n");
1964 smb2_util_close(tree, h1);
1965 smb2_deltree(tree, BASEDIR);
1971 basic testing of SMB2 change notify
1973 struct torture_suite *torture_smb2_notify_init(void)
1975 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "notify");
1977 torture_suite_add_1smb2_test(suite, "valid-req", test_valid_request);
1978 torture_suite_add_1smb2_test(suite, "tcon", torture_smb2_notify_tcon);
1979 torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir);
1980 torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask);
1981 torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
1982 torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
1983 torture_suite_add_2smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
1984 torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
1985 torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
1986 torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
1987 torture_suite_add_1smb2_test(suite, "file", torture_smb2_notify_file);
1988 torture_suite_add_1smb2_test(suite, "tcp", torture_smb2_notify_tcp_disconnect);
1989 torture_suite_add_2smb2_test(suite, "rec", torture_smb2_notify_recursive);
1990 torture_suite_add_1smb2_test(suite, "overflow", torture_smb2_notify_overflow);
1992 suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");