libcli/smb: pass smbXcli_session to smb2cli_tcon_set_values()
[Samba/gebeck_regimport.git] / source4 / torture / smb2 / notify.c
blobe83b09995828ae69645d722b07cb3383d421bf31
1 /*
2 Unix SMB/CIFS implementation.
4 SMB2 notify test suite
6 Copyright (C) Stefan Metzmacher 2006
7 Copyright (C) Andrew Tridgell 2009
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "../libcli/smb/smbXcli_base.h"
28 #include "torture/torture.h"
29 #include "torture/smb2/proto.h"
30 #include "librpc/gen_ndr/ndr_security.h"
31 #include "libcli/security/security.h"
32 #include "torture/util.h"
34 #include "system/filesys.h"
35 #include "auth/credentials/credentials.h"
36 #include "lib/cmdline/popt_common.h"
37 #include "librpc/gen_ndr/security.h"
39 #include "lib/events/events.h"
41 #include "libcli/raw/libcliraw.h"
42 #include "libcli/raw/raw_proto.h"
43 #include "libcli/libcli.h"
45 #define CHECK_STATUS(status, correct) do { \
46 if (!NT_STATUS_EQUAL(status, correct)) { \
47 torture_result(torture, TORTURE_FAIL, \
48 "(%s) Incorrect status %s - should be %s\n", \
49 __location__, nt_errstr(status), nt_errstr(correct)); \
50 ret = false; \
51 goto done; \
52 }} while (0)
54 #define CHECK_VAL(v, correct) do { \
55 if ((v) != (correct)) { \
56 torture_result(torture, TORTURE_FAIL, \
57 "(%s) wrong value for %s 0x%x should be 0x%x\n", \
58 __location__, #v, (int)v, (int)correct); \
59 ret = false; \
60 goto done; \
61 }} while (0)
63 #define CHECK_WIRE_STR(field, value) do { \
64 if (!field.s || strcmp(field.s, value)) { \
65 torture_result(torture, TORTURE_FAIL, \
66 "(%s) %s [%s] != %s\n", __location__, #field, \
67 field.s, value); \
68 ret = false; \
69 goto done; \
70 }} while (0)
72 #define BASEDIR "test_notify"
73 #define FNAME "smb2-notify01.dat"
75 static bool test_valid_request(struct torture_context *torture,
76 struct smb2_tree *tree)
78 bool ret = true;
79 NTSTATUS status;
80 struct smb2_handle dh;
81 struct smb2_notify n;
82 struct smb2_request *req;
83 uint32_t max_buffer_size;
85 torture_comment(torture, "TESTING VALIDITY OF CHANGE NOTIFY REQUEST\n");
87 smb2_util_unlink(tree, FNAME);
89 status = smb2_util_roothandle(tree, &dh);
90 CHECK_STATUS(status, NT_STATUS_OK);
92 /* 0x00080000 is the default max buffer size for Windows servers
93 * pre-Win7 */
94 max_buffer_size = torture_setting_ulong(torture, "cn_max_buffer_size",
95 0x00080000);
97 n.in.recursive = 0x0000;
98 n.in.buffer_size = max_buffer_size;
99 n.in.file.handle = dh;
100 n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
101 n.in.unknown = 0x00000000;
102 req = smb2_notify_send(tree, &n);
104 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
105 if (tevent_loop_once(torture->ev) != 0) {
106 break;
110 status = torture_setup_complex_file(tree, FNAME);
111 CHECK_STATUS(status, NT_STATUS_OK);
113 status = smb2_notify_recv(req, torture, &n);
114 CHECK_STATUS(status, NT_STATUS_OK);
115 CHECK_VAL(n.out.num_changes, 1);
116 CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_ADDED);
117 CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
120 * if the change response doesn't fit in the buffer
121 * NOTIFY_ENUM_DIR is returned.
123 n.in.buffer_size = 0x00000000;
124 req = smb2_notify_send(tree, &n);
126 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
127 if (tevent_loop_once(torture->ev) != 0) {
128 break;
132 status = torture_setup_complex_file(tree, FNAME);
133 CHECK_STATUS(status, NT_STATUS_OK);
135 status = smb2_notify_recv(req, torture, &n);
136 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
139 * if the change response fits in the buffer we get
140 * NT_STATUS_OK again
142 n.in.buffer_size = max_buffer_size;
143 req = smb2_notify_send(tree, &n);
145 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
146 if (tevent_loop_once(torture->ev) != 0) {
147 break;
151 status = torture_setup_complex_file(tree, FNAME);
152 CHECK_STATUS(status, NT_STATUS_OK);
154 status = smb2_notify_recv(req, torture, &n);
155 CHECK_STATUS(status, NT_STATUS_OK);
156 CHECK_VAL(n.out.num_changes, 3);
157 CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_REMOVED);
158 CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
159 CHECK_VAL(n.out.changes[1].action, NOTIFY_ACTION_ADDED);
160 CHECK_WIRE_STR(n.out.changes[1].name, FNAME);
161 CHECK_VAL(n.out.changes[2].action, NOTIFY_ACTION_MODIFIED);
162 CHECK_WIRE_STR(n.out.changes[2].name, FNAME);
164 /* if the first notify returns NOTIFY_ENUM_DIR, all do */
165 status = smb2_util_close(tree, dh);
166 CHECK_STATUS(status, NT_STATUS_OK);
167 status = smb2_util_roothandle(tree, &dh);
168 CHECK_STATUS(status, NT_STATUS_OK);
170 n.in.recursive = 0x0000;
171 n.in.buffer_size = 0x00000001;
172 n.in.file.handle = dh;
173 n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
174 n.in.unknown = 0x00000000;
175 req = smb2_notify_send(tree, &n);
177 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
178 if (tevent_loop_once(torture->ev) != 0) {
179 break;
183 status = torture_setup_complex_file(tree, FNAME);
184 CHECK_STATUS(status, NT_STATUS_OK);
186 status = smb2_notify_recv(req, torture, &n);
187 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
189 n.in.buffer_size = max_buffer_size;
190 req = smb2_notify_send(tree, &n);
191 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
192 if (tevent_loop_once(torture->ev) != 0) {
193 break;
197 status = torture_setup_complex_file(tree, FNAME);
198 CHECK_STATUS(status, NT_STATUS_OK);
200 status = smb2_notify_recv(req, torture, &n);
201 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
203 /* if the buffer size is too large, we get invalid parameter */
204 n.in.recursive = 0x0000;
205 n.in.buffer_size = max_buffer_size + 1;
206 n.in.file.handle = dh;
207 n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
208 n.in.unknown = 0x00000000;
209 req = smb2_notify_send(tree, &n);
210 status = smb2_notify_recv(req, torture, &n);
211 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
213 done:
214 return ret;
218 basic testing of change notify on directories
220 static bool torture_smb2_notify_dir(struct torture_context *torture,
221 struct smb2_tree *tree1,
222 struct smb2_tree *tree2)
224 bool ret = true;
225 NTSTATUS status;
226 union smb_notify notify;
227 union smb_open io;
228 union smb_close cl;
229 int i, count;
230 struct smb2_handle h1, h2;
231 struct smb2_request *req, *req2;
232 const char *fname = BASEDIR "\\subdir-name";
233 extern int torture_numops;
235 torture_comment(torture, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
237 smb2_deltree(tree1, BASEDIR);
238 smb2_util_rmdir(tree1, BASEDIR);
240 get a handle on the directory
242 ZERO_STRUCT(io.smb2);
243 io.generic.level = RAW_OPEN_SMB2;
244 io.smb2.in.create_flags = 0;
245 io.smb2.in.desired_access = SEC_FILE_ALL;
246 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
247 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
248 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
249 NTCREATEX_SHARE_ACCESS_WRITE;
250 io.smb2.in.alloc_size = 0;
251 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
252 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
253 io.smb2.in.security_flags = 0;
254 io.smb2.in.fname = BASEDIR;
256 status = smb2_create(tree1, torture, &(io.smb2));
257 CHECK_STATUS(status, NT_STATUS_OK);
258 h1 = io.smb2.out.file.handle;
260 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
261 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ;
262 status = smb2_create(tree1, torture, &(io.smb2));
263 CHECK_STATUS(status, NT_STATUS_OK);
264 h2 = io.smb2.out.file.handle;
266 /* ask for a change notify,
267 on file or directory name changes */
268 ZERO_STRUCT(notify.smb2);
269 notify.smb2.level = RAW_NOTIFY_SMB2;
270 notify.smb2.in.buffer_size = 1000;
271 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
272 notify.smb2.in.file.handle = h1;
273 notify.smb2.in.recursive = true;
275 torture_comment(torture, "Testing notify cancel\n");
277 req = smb2_notify_send(tree1, &(notify.smb2));
278 smb2_cancel(req);
279 status = smb2_notify_recv(req, torture, &(notify.smb2));
280 CHECK_STATUS(status, NT_STATUS_CANCELLED);
282 torture_comment(torture, "Testing notify mkdir\n");
284 req = smb2_notify_send(tree1, &(notify.smb2));
285 smb2_util_mkdir(tree2, fname);
287 status = smb2_notify_recv(req, torture, &(notify.smb2));
288 CHECK_STATUS(status, NT_STATUS_OK);
290 CHECK_VAL(notify.smb2.out.num_changes, 1);
291 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
292 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
294 torture_comment(torture, "Testing notify rmdir\n");
296 req = smb2_notify_send(tree1, &(notify.smb2));
297 smb2_util_rmdir(tree2, fname);
299 status = smb2_notify_recv(req, torture, &(notify.smb2));
300 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_REMOVED);
303 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
305 torture_comment(torture,
306 "Testing notify mkdir - rmdir - mkdir - rmdir\n");
308 smb2_util_mkdir(tree2, fname);
309 smb2_util_rmdir(tree2, fname);
310 smb2_util_mkdir(tree2, fname);
311 smb2_util_rmdir(tree2, fname);
312 smb_msleep(200);
313 req = smb2_notify_send(tree1, &(notify.smb2));
314 status = smb2_notify_recv(req, torture, &(notify.smb2));
315 CHECK_STATUS(status, NT_STATUS_OK);
316 CHECK_VAL(notify.smb2.out.num_changes, 4);
317 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
318 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
319 CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_REMOVED);
320 CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name");
321 CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_ADDED);
322 CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name");
323 CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_REMOVED);
324 CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name");
326 count = torture_numops;
327 torture_comment(torture,
328 "Testing buffered notify on create of %d files\n", count);
329 for (i=0;i<count;i++) {
330 struct smb2_handle h12;
331 char *fname2 = talloc_asprintf(torture, BASEDIR "\\test%d.txt",
334 ZERO_STRUCT(io.smb2);
335 io.generic.level = RAW_OPEN_SMB2;
336 io.smb2.in.create_flags = 0;
337 io.smb2.in.desired_access = SEC_FILE_ALL;
338 io.smb2.in.create_options =
339 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
340 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
341 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
342 NTCREATEX_SHARE_ACCESS_WRITE;
343 io.smb2.in.alloc_size = 0;
344 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
345 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
346 io.smb2.in.security_flags = 0;
347 io.smb2.in.fname = fname2;
349 status = smb2_create(tree1, torture, &(io.smb2));
350 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
351 torture_comment(torture, "Failed to create %s \n",
352 fname);
353 ret = false;
354 goto done;
356 h12 = io.smb2.out.file.handle;
357 talloc_free(fname2);
358 smb2_util_close(tree1, h12);
361 /* (1st notify) setup a new notify on a different directory handle.
362 This new notify won't see the events above. */
363 notify.smb2.in.file.handle = h2;
364 req2 = smb2_notify_send(tree1, &(notify.smb2));
366 /* (2nd notify) whereas this notify will see the above buffered events,
367 and it directly returns the buffered events */
368 notify.smb2.in.file.handle = h1;
369 req = smb2_notify_send(tree1, &(notify.smb2));
371 status = smb2_util_unlink(tree1, BASEDIR "\\nonexistent.txt");
372 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
374 /* (1st unlink) as the 2nd notify directly returns,
375 this unlink is only seen by the 1st notify and
376 the 3rd notify (later) */
377 torture_comment(torture,
378 "Testing notify on unlink for the first file\n");
379 status = smb2_util_unlink(tree2, BASEDIR "\\test0.txt");
380 CHECK_STATUS(status, NT_STATUS_OK);
382 /* receive the reply from the 2nd notify */
383 status = smb2_notify_recv(req, torture, &(notify.smb2));
384 CHECK_STATUS(status, NT_STATUS_OK);
386 CHECK_VAL(notify.smb2.out.num_changes, count);
387 for (i=1;i<count;i++) {
388 CHECK_VAL(notify.smb2.out.changes[i].action,
389 NOTIFY_ACTION_ADDED);
391 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
393 torture_comment(torture, "and now from the 1st notify\n");
394 status = smb2_notify_recv(req2, torture, &(notify.smb2));
395 CHECK_STATUS(status, NT_STATUS_OK);
396 CHECK_VAL(notify.smb2.out.num_changes, 1);
397 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
398 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
400 torture_comment(torture,
401 "(3rd notify) this notify will only see the 1st unlink\n");
402 req = smb2_notify_send(tree1, &(notify.smb2));
404 status = smb2_util_unlink(tree1, BASEDIR "\\nonexistent.txt");
405 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
407 for (i=1;i<count;i++) {
408 char *fname2 = talloc_asprintf(torture,
409 BASEDIR "\\test%d.txt", i);
410 status = smb2_util_unlink(tree2, fname2);
411 CHECK_STATUS(status, NT_STATUS_OK);
412 talloc_free(fname2);
415 /* receive the 3rd notify */
416 status = smb2_notify_recv(req, torture, &(notify.smb2));
417 CHECK_STATUS(status, NT_STATUS_OK);
418 CHECK_VAL(notify.smb2.out.num_changes, 1);
419 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
420 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
422 /* and we now see the rest of the unlink calls on both
423 * directory handles */
424 notify.smb2.in.file.handle = h1;
425 sleep(3);
426 req = smb2_notify_send(tree1, &(notify.smb2));
427 status = smb2_notify_recv(req, torture, &(notify.smb2));
428 CHECK_STATUS(status, NT_STATUS_OK);
429 CHECK_VAL(notify.smb2.out.num_changes, count-1);
430 for (i=0;i<notify.smb2.out.num_changes;i++) {
431 CHECK_VAL(notify.smb2.out.changes[i].action,
432 NOTIFY_ACTION_REMOVED);
434 notify.smb2.in.file.handle = h2;
435 req = smb2_notify_send(tree1, &(notify.smb2));
436 status = smb2_notify_recv(req, torture, &(notify.smb2));
437 CHECK_STATUS(status, NT_STATUS_OK);
438 CHECK_VAL(notify.smb2.out.num_changes, count-1);
439 for (i=0;i<notify.smb2.out.num_changes;i++) {
440 CHECK_VAL(notify.smb2.out.changes[i].action,
441 NOTIFY_ACTION_REMOVED);
444 torture_comment(torture,
445 "Testing if a close() on the dir handle triggers the notify reply\n");
447 notify.smb2.in.file.handle = h1;
448 req = smb2_notify_send(tree1, &(notify.smb2));
450 ZERO_STRUCT(cl.smb2);
451 cl.smb2.level = RAW_CLOSE_SMB2;
452 cl.smb2.in.file.handle = h1;
453 status = smb2_close(tree1, &(cl.smb2));
454 CHECK_STATUS(status, NT_STATUS_OK);
456 status = smb2_notify_recv(req, torture, &(notify.smb2));
457 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
458 CHECK_VAL(notify.smb2.out.num_changes, 9);
460 done:
461 smb2_util_close(tree1, h1);
462 smb2_util_close(tree1, h2);
463 smb2_deltree(tree1, BASEDIR);
464 return ret;
467 static struct smb2_handle custom_smb2_create(struct smb2_tree *tree,
468 struct torture_context *torture,
469 struct smb2_create *smb2)
471 struct smb2_handle h1;
472 bool ret = true;
473 NTSTATUS status;
474 smb2_deltree(tree, smb2->in.fname);
475 status = smb2_create(tree, torture, smb2);
476 CHECK_STATUS(status, NT_STATUS_OK);
477 h1 = smb2->out.file.handle;
478 done:
479 return h1;
483 testing of recursive change notify
486 static bool torture_smb2_notify_recursive(struct torture_context *torture,
487 struct smb2_tree *tree1,
488 struct smb2_tree *tree2)
490 bool ret = true;
491 NTSTATUS status;
492 union smb_notify notify;
493 union smb_open io, io1;
494 union smb_setfileinfo sinfo;
495 struct smb2_handle h1;
496 struct smb2_request *req1, *req2;
498 smb2_deltree(tree1, BASEDIR);
499 smb2_util_rmdir(tree1, BASEDIR);
501 torture_comment(torture, "TESTING CHANGE NOTIFY WITH RECURSION\n");
504 get a handle on the directory
506 ZERO_STRUCT(io.smb2);
507 io.generic.level = RAW_OPEN_SMB2;
508 io.smb2.in.create_flags = 0;
509 io.smb2.in.desired_access = SEC_FILE_ALL;
510 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
511 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
512 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
513 NTCREATEX_SHARE_ACCESS_WRITE;
514 io.smb2.in.alloc_size = 0;
515 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
516 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
517 io.smb2.in.security_flags = 0;
518 io.smb2.in.fname = BASEDIR;
520 status = smb2_create(tree1, torture, &(io.smb2));
521 CHECK_STATUS(status, NT_STATUS_OK);
522 h1 = io.smb2.out.file.handle;
524 /* ask for a change notify, on file or directory name
525 changes. Setup both with and without recursion */
526 ZERO_STRUCT(notify.smb2);
527 notify.smb2.level = RAW_NOTIFY_SMB2;
528 notify.smb2.in.buffer_size = 1000;
529 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
530 FILE_NOTIFY_CHANGE_ATTRIBUTES |
531 FILE_NOTIFY_CHANGE_CREATION;
532 notify.smb2.in.file.handle = h1;
534 notify.smb2.in.recursive = true;
535 req1 = smb2_notify_send(tree1, &(notify.smb2));
536 smb2_cancel(req1);
537 status = smb2_notify_recv(req1, torture, &(notify.smb2));
538 CHECK_STATUS(status, NT_STATUS_CANCELLED);
540 notify.smb2.in.recursive = false;
541 req2 = smb2_notify_send(tree1, &(notify.smb2));
542 smb2_cancel(req2);
543 status = smb2_notify_recv(req2, torture, &(notify.smb2));
544 CHECK_STATUS(status, NT_STATUS_CANCELLED);
546 ZERO_STRUCT(io1.smb2);
547 io1.generic.level = RAW_OPEN_SMB2;
548 io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
549 io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
550 SEC_RIGHTS_FILE_WRITE|
551 SEC_RIGHTS_FILE_ALL;
552 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
553 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
554 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
555 NTCREATEX_SHARE_ACCESS_WRITE |
556 NTCREATEX_SHARE_ACCESS_DELETE;
557 io1.smb2.in.alloc_size = 0;
558 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
559 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
560 io1.smb2.in.security_flags = 0;
561 io1.smb2.in.fname = BASEDIR "\\subdir-name";
562 status = smb2_create(tree2, torture, &(io1.smb2));
563 CHECK_STATUS(status, NT_STATUS_OK);
564 smb2_util_close(tree2, io1.smb2.out.file.handle);
566 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname1";
567 status = smb2_create(tree2, torture, &(io1.smb2));
568 CHECK_STATUS(status, NT_STATUS_OK);
569 ZERO_STRUCT(sinfo);
570 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
571 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
572 sinfo.rename_information.in.overwrite = 0;
573 sinfo.rename_information.in.root_fid = 0;
574 sinfo.rename_information.in.new_name =
575 BASEDIR "\\subdir-name\\subname1-r";
576 status = smb2_setinfo_file(tree2, &sinfo);
577 CHECK_STATUS(status, NT_STATUS_OK);
579 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
580 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname2";
581 status = smb2_create(tree2, torture, &(io1.smb2));
582 CHECK_STATUS(status, NT_STATUS_OK);
583 ZERO_STRUCT(sinfo);
584 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
585 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
586 sinfo.rename_information.in.overwrite = true;
587 sinfo.rename_information.in.root_fid = 0;
588 sinfo.rename_information.in.new_name = BASEDIR "\\subname2-r";
589 status = smb2_setinfo_file(tree2, &sinfo);
590 CHECK_STATUS(status, NT_STATUS_OK);
592 io1.smb2.in.fname = BASEDIR "\\subname2-r";
593 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
594 status = smb2_create(tree2, torture, &(io1.smb2));
595 CHECK_STATUS(status, NT_STATUS_OK);
596 ZERO_STRUCT(sinfo);
597 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
598 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
599 sinfo.rename_information.in.overwrite = true;
600 sinfo.rename_information.in.root_fid = 0;
601 sinfo.rename_information.in.new_name = BASEDIR "\\subname3-r";
602 status = smb2_setinfo_file(tree2, &sinfo);
603 CHECK_STATUS(status, NT_STATUS_OK);
605 notify.smb2.in.completion_filter = 0;
606 notify.smb2.in.recursive = true;
607 smb_msleep(200);
608 req1 = smb2_notify_send(tree1, &(notify.smb2));
610 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name\\subname1-r");
611 CHECK_STATUS(status, NT_STATUS_OK);
612 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name");
613 CHECK_STATUS(status, NT_STATUS_OK);
614 status = smb2_util_unlink(tree2, BASEDIR "\\subname3-r");
615 CHECK_STATUS(status, NT_STATUS_OK);
617 notify.smb2.in.recursive = false;
618 req2 = smb2_notify_send(tree1, &(notify.smb2));
620 status = smb2_notify_recv(req1, torture, &(notify.smb2));
621 CHECK_STATUS(status, NT_STATUS_OK);
623 CHECK_VAL(notify.smb2.out.num_changes, 9);
624 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
625 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
626 CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_ADDED);
627 CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name\\subname1");
628 CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_OLD_NAME);
629 CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name\\subname1");
630 CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_NEW_NAME);
631 CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name\\subname1-r");
632 CHECK_VAL(notify.smb2.out.changes[4].action, NOTIFY_ACTION_ADDED);
633 CHECK_WIRE_STR(notify.smb2.out.changes[4].name, "subdir-name\\subname2");
634 CHECK_VAL(notify.smb2.out.changes[5].action, NOTIFY_ACTION_REMOVED);
635 CHECK_WIRE_STR(notify.smb2.out.changes[5].name, "subdir-name\\subname2");
636 CHECK_VAL(notify.smb2.out.changes[6].action, NOTIFY_ACTION_ADDED);
637 CHECK_WIRE_STR(notify.smb2.out.changes[6].name, "subname2-r");
638 CHECK_VAL(notify.smb2.out.changes[7].action, NOTIFY_ACTION_OLD_NAME);
639 CHECK_WIRE_STR(notify.smb2.out.changes[7].name, "subname2-r");
640 CHECK_VAL(notify.smb2.out.changes[8].action, NOTIFY_ACTION_NEW_NAME);
641 CHECK_WIRE_STR(notify.smb2.out.changes[8].name, "subname3-r");
643 done:
644 smb2_deltree(tree1, BASEDIR);
645 return ret;
649 testing of change notify mask change
652 static bool torture_smb2_notify_mask_change(struct torture_context *torture,
653 struct smb2_tree *tree1,
654 struct smb2_tree *tree2)
656 bool ret = true;
657 NTSTATUS status;
658 union smb_notify notify;
659 union smb_open io, io1;
660 struct smb2_handle h1;
661 struct smb2_request *req1, *req2;
662 union smb_setfileinfo sinfo;
664 smb2_deltree(tree1, BASEDIR);
665 smb2_util_rmdir(tree1, BASEDIR);
667 torture_comment(torture, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
670 get a handle on the directory
672 ZERO_STRUCT(io.smb2);
673 io.generic.level = RAW_OPEN_SMB2;
674 io.smb2.in.create_flags = 0;
675 io.smb2.in.desired_access = SEC_FILE_ALL;
676 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
677 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
678 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
679 NTCREATEX_SHARE_ACCESS_WRITE;
680 io.smb2.in.alloc_size = 0;
681 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
682 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
683 io.smb2.in.security_flags = 0;
684 io.smb2.in.fname = BASEDIR;
686 status = smb2_create(tree1, torture, &(io.smb2));
687 CHECK_STATUS(status, NT_STATUS_OK);
688 h1 = io.smb2.out.file.handle;
690 /* ask for a change notify, on file or directory name
691 changes. Setup both with and without recursion */
692 ZERO_STRUCT(notify.smb2);
693 notify.smb2.level = RAW_NOTIFY_SMB2;
694 notify.smb2.in.buffer_size = 1000;
695 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
696 notify.smb2.in.file.handle = h1;
698 notify.smb2.in.recursive = true;
699 req1 = smb2_notify_send(tree1, &(notify.smb2));
701 smb2_cancel(req1);
702 status = smb2_notify_recv(req1, torture, &(notify.smb2));
703 CHECK_STATUS(status, NT_STATUS_CANCELLED);
706 notify.smb2.in.recursive = false;
707 req2 = smb2_notify_send(tree1, &(notify.smb2));
709 smb2_cancel(req2);
710 status = smb2_notify_recv(req2, torture, &(notify.smb2));
711 CHECK_STATUS(status, NT_STATUS_CANCELLED);
713 notify.smb2.in.recursive = true;
714 req1 = smb2_notify_send(tree1, &(notify.smb2));
716 /* Set to hidden then back again. */
717 ZERO_STRUCT(io1.smb2);
718 io1.generic.level = RAW_OPEN_SMB2;
719 io1.smb2.in.create_flags = 0;
720 io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
721 SEC_RIGHTS_FILE_WRITE|
722 SEC_RIGHTS_FILE_ALL;
723 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
724 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
725 NTCREATEX_SHARE_ACCESS_WRITE |
726 NTCREATEX_SHARE_ACCESS_DELETE;
727 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
728 io1.smb2.in.security_flags = 0;
729 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
730 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
731 io1.smb2.in.fname = BASEDIR "\\tname1";
733 smb2_util_close(tree1,
734 custom_smb2_create(tree1, torture, &(io1.smb2)));
735 status = smb2_util_setatr(tree1, BASEDIR "\\tname1",
736 FILE_ATTRIBUTE_HIDDEN);
737 CHECK_STATUS(status, NT_STATUS_OK);
738 smb2_util_unlink(tree1, BASEDIR "\\tname1");
740 status = smb2_notify_recv(req1, torture, &(notify.smb2));
741 CHECK_STATUS(status, NT_STATUS_OK);
743 CHECK_VAL(notify.smb2.out.num_changes, 1);
744 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
745 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
747 /* Now try and change the mask to include other events.
748 * This should not work - once the mask is set on a directory
749 * h1 it seems to be fixed until the fnum is closed. */
751 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
752 FILE_NOTIFY_CHANGE_ATTRIBUTES |
753 FILE_NOTIFY_CHANGE_CREATION;
754 notify.smb2.in.recursive = true;
755 req1 = smb2_notify_send(tree1, &(notify.smb2));
757 notify.smb2.in.recursive = false;
758 req2 = smb2_notify_send(tree1, &(notify.smb2));
760 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
761 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
762 io1.smb2.in.fname = BASEDIR "\\subdir-name";
763 status = smb2_create(tree2, torture, &(io1.smb2));
764 CHECK_STATUS(status, NT_STATUS_OK);
765 smb2_util_close(tree2, io1.smb2.out.file.handle);
767 ZERO_STRUCT(sinfo);
768 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname1";
769 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
770 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
771 status = smb2_create(tree2, torture, &(io1.smb2));
772 CHECK_STATUS(status, NT_STATUS_OK);
773 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
774 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
775 sinfo.rename_information.in.overwrite = true;
776 sinfo.rename_information.in.root_fid = 0;
777 sinfo.rename_information.in.new_name =
778 BASEDIR "\\subdir-name\\subname1-r";
779 status = smb2_setinfo_file(tree2, &sinfo);
780 CHECK_STATUS(status, NT_STATUS_OK);
782 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname2";
783 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
784 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
785 status = smb2_create(tree2, torture, &(io1.smb2));
786 CHECK_STATUS(status, NT_STATUS_OK);
787 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
788 sinfo.rename_information.in.new_name = BASEDIR "\\subname2-r";
789 status = smb2_setinfo_file(tree2, &sinfo);
790 CHECK_STATUS(status, NT_STATUS_OK);
791 smb2_util_close(tree2, io1.smb2.out.file.handle);
793 io1.smb2.in.fname = BASEDIR "\\subname2-r";
794 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
795 status = smb2_create(tree2, torture, &(io1.smb2));
796 CHECK_STATUS(status, NT_STATUS_OK);
797 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
798 sinfo.rename_information.in.new_name = BASEDIR "\\subname3-r";
799 status = smb2_setinfo_file(tree2, &sinfo);
800 CHECK_STATUS(status, NT_STATUS_OK);
801 smb2_util_close(tree2, io1.smb2.out.file.handle);
803 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name\\subname1-r");
804 CHECK_STATUS(status, NT_STATUS_OK);
805 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name");
806 CHECK_STATUS(status, NT_STATUS_OK);
807 status = smb2_util_unlink(tree2, BASEDIR "\\subname3-r");
808 CHECK_STATUS(status, NT_STATUS_OK);
810 status = smb2_notify_recv(req1, torture, &(notify.smb2));
811 CHECK_STATUS(status, NT_STATUS_OK);
813 CHECK_VAL(notify.smb2.out.num_changes, 1);
814 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
815 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname2-r");
817 status = smb2_notify_recv(req2, torture, &(notify.smb2));
818 CHECK_STATUS(status, NT_STATUS_OK);
820 CHECK_VAL(notify.smb2.out.num_changes, 1);
821 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
822 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname3-r");
824 if (!ret) {
825 goto done;
828 done:
829 smb2_deltree(tree1, BASEDIR);
830 return ret;
834 testing of mask bits for change notify
837 static bool torture_smb2_notify_mask(struct torture_context *torture,
838 struct smb2_tree *tree1,
839 struct smb2_tree *tree2)
841 bool ret = true;
842 NTSTATUS status;
843 union smb_notify notify;
844 union smb_open io, io1;
845 struct smb2_handle h1, h2;
846 uint32_t mask;
847 int i;
848 char c = 1;
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");
858 get a handle on the directory
860 ZERO_STRUCT(io.smb2);
861 io.generic.level = RAW_OPEN_SMB2;
862 io.smb2.in.create_flags = 0;
863 io.smb2.in.desired_access = SEC_FILE_ALL;
864 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
865 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
866 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
867 NTCREATEX_SHARE_ACCESS_WRITE;
868 io.smb2.in.alloc_size = 0;
869 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
870 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
871 io.smb2.in.security_flags = 0;
872 io.smb2.in.fname = BASEDIR;
874 ZERO_STRUCT(notify.smb2);
875 notify.smb2.level = RAW_NOTIFY_SMB2;
876 notify.smb2.in.buffer_size = 1000;
877 notify.smb2.in.recursive = true;
879 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
880 expected, nchanges) \
881 do { \
882 do { for (mask=i=0;i<32;i++) { \
883 struct smb2_request *req; \
884 status = smb2_create(tree1, torture, &(io.smb2)); \
885 CHECK_STATUS(status, NT_STATUS_OK); \
886 h1 = io.smb2.out.file.handle; \
887 setup \
888 notify.smb2.in.file.handle = h1; \
889 notify.smb2.in.completion_filter = (1<<i); \
890 /* cancel initial requests so the buffer is setup */ \
891 req = smb2_notify_send(tree1, &(notify.smb2)); \
892 smb2_cancel(req); \
893 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
894 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
895 /* send the change notify request */ \
896 req = smb2_notify_send(tree1, &(notify.smb2)); \
897 op \
898 smb_msleep(200); smb2_cancel(req); \
899 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
900 cleanup \
901 smb2_util_close(tree1, h1); \
902 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
903 CHECK_STATUS(status, NT_STATUS_OK); \
904 /* special case to cope with file rename behaviour */ \
905 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
906 notify.smb2.out.changes[0].action == \
907 NOTIFY_ACTION_MODIFIED && \
908 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
909 Action == NOTIFY_ACTION_OLD_NAME) { \
910 torture_comment(torture, \
911 "(rename file special handling OK)\n"); \
912 } else if (nchanges != notify.smb2.out.num_changes) { \
913 torture_result(torture, TORTURE_FAIL, \
914 "ERROR: nchanges=%d expected=%d "\
915 "action=%d filter=0x%08x\n", \
916 notify.smb2.out.num_changes, \
917 nchanges, \
918 notify.smb2.out.changes[0].action, \
919 notify.smb2.in.completion_filter); \
920 ret = false; \
921 } else if (notify.smb2.out.changes[0].action != Action) { \
922 torture_result(torture, TORTURE_FAIL, \
923 "ERROR: nchanges=%d action=%d " \
924 "expectedAction=%d filter=0x%08x\n", \
925 notify.smb2.out.num_changes, \
926 notify.smb2.out.changes[0].action, \
927 Action, \
928 notify.smb2.in.completion_filter); \
929 ret = false; \
930 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
931 "tname1") != 0) { \
932 torture_result(torture, TORTURE_FAIL, \
933 "ERROR: nchanges=%d action=%d " \
934 "filter=0x%08x name=%s\n", \
935 notify.smb2.out.num_changes, \
936 notify.smb2.out.changes[0].action, \
937 notify.smb2.in.completion_filter, \
938 notify.smb2.out.changes[0].name.s); \
939 ret = false; \
941 mask |= (1<<i); \
943 } while (0); \
944 } while (0);
946 torture_comment(torture, "Testing mkdir\n");
947 NOTIFY_MASK_TEST("Testing mkdir",;,
948 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
949 smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
950 NOTIFY_ACTION_ADDED,
951 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
953 torture_comment(torture, "Testing create file\n");
954 ZERO_STRUCT(io1.smb2);
955 io1.generic.level = RAW_OPEN_SMB2;
956 io1.smb2.in.create_flags = 0;
957 io1.smb2.in.desired_access = SEC_FILE_ALL;
958 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
959 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
960 NTCREATEX_SHARE_ACCESS_WRITE;
961 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
962 io1.smb2.in.security_flags = 0;
963 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
964 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
965 io1.smb2.in.fname = BASEDIR "\\tname1";
967 NOTIFY_MASK_TEST("Testing create file",;,
968 smb2_util_close(tree2, custom_smb2_create(tree2,
969 torture, &(io1.smb2)));,
970 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
971 NOTIFY_ACTION_ADDED,
972 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
974 torture_comment(torture, "Testing unlink\n");
975 NOTIFY_MASK_TEST("Testing unlink",
976 smb2_util_close(tree2, custom_smb2_create(tree2,
977 torture, &(io1.smb2)));,
978 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
980 NOTIFY_ACTION_REMOVED,
981 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
983 torture_comment(torture, "Testing rmdir\n");
984 NOTIFY_MASK_TEST("Testing rmdir",
985 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
986 smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
988 NOTIFY_ACTION_REMOVED,
989 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
991 torture_comment(torture, "Testing rename file\n");
992 ZERO_STRUCT(sinfo);
993 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
994 sinfo.rename_information.in.file.handle = h1;
995 sinfo.rename_information.in.overwrite = true;
996 sinfo.rename_information.in.root_fid = 0;
997 sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
998 NOTIFY_MASK_TEST("Testing rename file",
999 smb2_util_close(tree2, custom_smb2_create(tree2,
1000 torture, &(io1.smb2)));,
1001 smb2_setinfo_file(tree2, &sinfo);,
1002 smb2_util_unlink(tree2, BASEDIR "\\tname2");,
1003 NOTIFY_ACTION_OLD_NAME,
1004 FILE_NOTIFY_CHANGE_FILE_NAME, 2);
1006 torture_comment(torture, "Testing rename dir\n");
1007 ZERO_STRUCT(sinfo);
1008 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1009 sinfo.rename_information.in.file.handle = h1;
1010 sinfo.rename_information.in.overwrite = true;
1011 sinfo.rename_information.in.root_fid = 0;
1012 sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
1013 NOTIFY_MASK_TEST("Testing rename dir",
1014 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
1015 smb2_setinfo_file(tree2, &sinfo);,
1016 smb2_util_rmdir(tree2, BASEDIR "\\tname2");,
1017 NOTIFY_ACTION_OLD_NAME,
1018 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
1020 torture_comment(torture, "Testing set path attribute\n");
1021 NOTIFY_MASK_TEST("Testing set path attribute",
1022 smb2_util_close(tree2, custom_smb2_create(tree2,
1023 torture, &(io.smb2)));,
1024 smb2_util_setatr(tree2, BASEDIR "\\tname1",
1025 FILE_ATTRIBUTE_HIDDEN);,
1026 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1027 NOTIFY_ACTION_MODIFIED,
1028 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
1030 torture_comment(torture, "Testing set path write time\n");
1031 ZERO_STRUCT(sinfo);
1032 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1033 sinfo.generic.in.file.handle = h1;
1034 sinfo.basic_info.in.write_time = 1000;
1035 NOTIFY_MASK_TEST("Testing set path write time",
1036 smb2_util_close(tree2, custom_smb2_create(tree2,
1037 torture, &(io1.smb2)));,
1038 smb2_setinfo_file(tree2, &sinfo);,
1039 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1040 NOTIFY_ACTION_MODIFIED,
1041 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
1043 if (torture_setting_bool(torture, "samba3", false)) {
1044 torture_comment(torture,
1045 "Samba3 does not yet support create times "
1046 "everywhere\n");
1048 else {
1049 ZERO_STRUCT(sinfo);
1050 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1051 sinfo.generic.in.file.handle = h1;
1052 sinfo.basic_info.in.create_time = 0;
1053 torture_comment(torture, "Testing set file create time\n");
1054 NOTIFY_MASK_TEST("Testing set file create time",
1055 smb2_create_complex_file(tree2,
1056 BASEDIR "\\tname1", &h2);,
1057 smb2_setinfo_file(tree2, &sinfo);,
1058 (smb2_util_close(tree2, h2),
1059 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1060 NOTIFY_ACTION_MODIFIED,
1061 FILE_NOTIFY_CHANGE_CREATION, 1);
1064 ZERO_STRUCT(sinfo);
1065 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1066 sinfo.generic.in.file.handle = h1;
1067 sinfo.basic_info.in.access_time = 0;
1068 torture_comment(torture, "Testing set file access time\n");
1069 NOTIFY_MASK_TEST("Testing set file access time",
1070 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1071 smb2_setinfo_file(tree2, &sinfo);,
1072 (smb2_util_close(tree2, h2),
1073 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1074 NOTIFY_ACTION_MODIFIED,
1075 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
1077 ZERO_STRUCT(sinfo);
1078 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1079 sinfo.generic.in.file.handle = h1;
1080 sinfo.basic_info.in.change_time = 0;
1081 torture_comment(torture, "Testing set file change time\n");
1082 NOTIFY_MASK_TEST("Testing set file change time",
1083 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1084 smb2_setinfo_file(tree2, &sinfo);,
1085 (smb2_util_close(tree2, h2),
1086 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1087 NOTIFY_ACTION_MODIFIED,
1088 0, 1);
1091 torture_comment(torture, "Testing write\n");
1092 NOTIFY_MASK_TEST("Testing write",
1093 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1094 smb2_util_write(tree2, h2, &c, 10000, 1);,
1095 (smb2_util_close(tree2, h2),
1096 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1097 NOTIFY_ACTION_MODIFIED,
1098 0, 1);
1100 done:
1101 smb2_deltree(tree1, BASEDIR);
1102 return ret;
1106 basic testing of change notify on files
1108 static bool torture_smb2_notify_file(struct torture_context *torture,
1109 struct smb2_tree *tree)
1111 NTSTATUS status;
1112 bool ret = true;
1113 union smb_open io;
1114 union smb_close cl;
1115 union smb_notify notify;
1116 struct smb2_request *req;
1117 struct smb2_handle h1;
1118 const char *fname = BASEDIR "\\file.txt";
1120 smb2_deltree(tree, BASEDIR);
1121 smb2_util_rmdir(tree, BASEDIR);
1123 torture_comment(torture, "TESTING CHANGE NOTIFY ON FILES\n");
1124 status = torture_smb2_testdir(tree, BASEDIR, &h1);
1125 CHECK_STATUS(status, NT_STATUS_OK);
1127 ZERO_STRUCT(io.smb2);
1128 io.generic.level = RAW_OPEN_SMB2;
1129 io.smb2.in.create_flags = 0;
1130 io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
1131 io.smb2.in.create_options = 0;
1132 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1133 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1134 NTCREATEX_SHARE_ACCESS_WRITE;
1135 io.smb2.in.alloc_size = 0;
1136 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1137 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1138 io.smb2.in.security_flags = 0;
1139 io.smb2.in.fname = fname;
1140 status = smb2_create(tree, torture, &(io.smb2));
1141 CHECK_STATUS(status, NT_STATUS_OK);
1142 h1 = io.smb2.out.file.handle;
1144 /* ask for a change notify,
1145 on file or directory name changes */
1146 ZERO_STRUCT(notify.smb2);
1147 notify.smb2.level = RAW_NOTIFY_SMB2;
1148 notify.smb2.in.file.handle = h1;
1149 notify.smb2.in.buffer_size = 1000;
1150 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
1151 notify.smb2.in.recursive = false;
1153 torture_comment(torture,
1154 "Testing if notifies on file handles are invalid (should be)\n");
1156 req = smb2_notify_send(tree, &(notify.smb2));
1157 status = smb2_notify_recv(req, torture, &(notify.smb2));
1158 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1160 ZERO_STRUCT(cl.smb2);
1161 cl.close.level = RAW_CLOSE_SMB2;
1162 cl.close.in.file.handle = h1;
1163 status = smb2_close(tree, &(cl.smb2));
1164 CHECK_STATUS(status, NT_STATUS_OK);
1166 status = smb2_util_unlink(tree, fname);
1167 CHECK_STATUS(status, NT_STATUS_OK);
1169 done:
1170 smb2_deltree(tree, BASEDIR);
1171 return ret;
1174 basic testing of change notifies followed by a tdis
1177 static bool torture_smb2_notify_tree_disconnect(
1178 struct torture_context *torture,
1179 struct smb2_tree *tree)
1181 bool ret = true;
1182 NTSTATUS status;
1183 union smb_notify notify;
1184 union smb_open io;
1185 struct smb2_handle h1;
1186 struct smb2_request *req;
1188 smb2_deltree(tree, BASEDIR);
1189 smb2_util_rmdir(tree, BASEDIR);
1191 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY "
1192 "TREE-DISCONNECT\n");
1195 get a handle on the directory
1197 ZERO_STRUCT(io.smb2);
1198 io.generic.level = RAW_OPEN_SMB2;
1199 io.smb2.in.create_flags = 0;
1200 io.smb2.in.desired_access = SEC_FILE_ALL;
1201 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1202 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1203 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1204 NTCREATEX_SHARE_ACCESS_WRITE;
1205 io.smb2.in.alloc_size = 0;
1206 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1207 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1208 io.smb2.in.security_flags = 0;
1209 io.smb2.in.fname = BASEDIR;
1211 status = smb2_create(tree, torture, &(io.smb2));
1212 CHECK_STATUS(status, NT_STATUS_OK);
1213 h1 = io.smb2.out.file.handle;
1215 /* ask for a change notify,
1216 on file or directory name changes */
1217 ZERO_STRUCT(notify.smb2);
1218 notify.smb2.level = RAW_NOTIFY_SMB2;
1219 notify.smb2.in.buffer_size = 1000;
1220 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1221 notify.smb2.in.file.handle = h1;
1222 notify.smb2.in.recursive = true;
1224 req = smb2_notify_send(tree, &(notify.smb2));
1225 smb2_cancel(req);
1226 status = smb2_notify_recv(req, torture, &(notify.smb2));
1228 status = smb2_tdis(tree);
1229 CHECK_STATUS(status, NT_STATUS_OK);
1231 req = smb2_notify_send(tree, &(notify.smb2));
1233 smb2_notify_recv(req, torture, &(notify.smb2));
1234 CHECK_STATUS(status, NT_STATUS_OK);
1235 CHECK_VAL(notify.smb2.out.num_changes, 0);
1237 done:
1238 smb2_deltree(tree, BASEDIR);
1239 return ret;
1243 basic testing of change notifies followed by a ulogoff
1246 static bool torture_smb2_notify_ulogoff(struct torture_context *torture,
1247 struct smb2_tree *tree1,
1248 struct smb2_tree *tree2)
1250 bool ret = true;
1251 NTSTATUS status;
1252 union smb_notify notify;
1253 union smb_open io;
1254 struct smb2_handle h1;
1255 struct smb2_request *req;
1257 smb2_deltree(tree1, BASEDIR);
1258 smb2_util_rmdir(tree1, BASEDIR);
1260 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1263 get a handle on the directory
1265 ZERO_STRUCT(io.smb2);
1266 io.generic.level = RAW_OPEN_SMB2;
1267 io.smb2.in.create_flags = 0;
1268 io.smb2.in.desired_access = SEC_FILE_ALL;
1269 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1270 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1271 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1272 NTCREATEX_SHARE_ACCESS_WRITE;
1273 io.smb2.in.alloc_size = 0;
1274 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1275 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1276 io.smb2.in.security_flags = 0;
1277 io.smb2.in.fname = BASEDIR;
1279 status = smb2_create(tree2, torture, &(io.smb2));
1280 CHECK_STATUS(status, NT_STATUS_OK);
1282 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1283 status = smb2_create(tree2, torture, &(io.smb2));
1284 CHECK_STATUS(status, NT_STATUS_OK);
1285 h1 = io.smb2.out.file.handle;
1287 /* ask for a change notify,
1288 on file or directory name changes */
1289 ZERO_STRUCT(notify.smb2);
1290 notify.smb2.level = RAW_NOTIFY_SMB2;
1291 notify.smb2.in.buffer_size = 1000;
1292 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1293 notify.smb2.in.file.handle = h1;
1294 notify.smb2.in.recursive = true;
1296 req = smb2_notify_send(tree1, &(notify.smb2));
1298 status = smb2_logoff(tree2->session);
1299 CHECK_STATUS(status, NT_STATUS_OK);
1301 status = smb2_notify_recv(req, torture, &(notify.smb2));
1302 CHECK_VAL(notify.smb2.out.num_changes, 0);
1304 done:
1305 smb2_deltree(tree1, BASEDIR);
1306 return ret;
1309 static void tcp_dis_handler(struct smb2_transport *t, void *p)
1311 struct smb2_tree *tree = (struct smb2_tree *)p;
1312 smb2_transport_dead(tree->session->transport,
1313 NT_STATUS_LOCAL_DISCONNECT);
1314 t = NULL;
1315 tree = NULL;
1319 basic testing of change notifies followed by tcp disconnect
1322 static bool torture_smb2_notify_tcp_disconnect(
1323 struct torture_context *torture,
1324 struct smb2_tree *tree)
1326 bool ret = true;
1327 NTSTATUS status;
1328 union smb_notify notify;
1329 union smb_open io;
1330 struct smb2_handle h1;
1331 struct smb2_request *req;
1333 smb2_deltree(tree, BASEDIR);
1334 smb2_util_rmdir(tree, BASEDIR);
1336 torture_comment(torture,
1337 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1340 get a handle on the directory
1342 ZERO_STRUCT(io.smb2);
1343 io.generic.level = RAW_OPEN_SMB2;
1344 io.smb2.in.create_flags = 0;
1345 io.smb2.in.desired_access = SEC_FILE_ALL;
1346 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1347 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1348 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1349 NTCREATEX_SHARE_ACCESS_WRITE;
1350 io.smb2.in.alloc_size = 0;
1351 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1352 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1353 io.smb2.in.security_flags = 0;
1354 io.smb2.in.fname = BASEDIR;
1356 status = smb2_create(tree, torture, &(io.smb2));
1357 CHECK_STATUS(status, NT_STATUS_OK);
1358 h1 = io.smb2.out.file.handle;
1360 /* ask for a change notify,
1361 on file or directory name changes */
1362 ZERO_STRUCT(notify.smb2);
1363 notify.smb2.level = RAW_NOTIFY_SMB2;
1364 notify.smb2.in.buffer_size = 1000;
1365 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1366 notify.smb2.in.file.handle = h1;
1367 notify.smb2.in.recursive = true;
1369 req = smb2_notify_send(tree, &(notify.smb2));
1370 smb2_cancel(req);
1371 status = smb2_notify_recv(req, torture, &(notify.smb2));
1372 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1374 notify.smb2.in.recursive = true;
1375 req = smb2_notify_send(tree, &(notify.smb2));
1376 smb2_transport_idle_handler(tree->session->transport,
1377 tcp_dis_handler, 250, tree);
1378 tree = NULL;
1379 status = smb2_notify_recv(req, torture, &(notify.smb2));
1380 CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
1382 done:
1383 return ret;
1387 test setting up two change notify requests on one handle
1390 static bool torture_smb2_notify_double(struct torture_context *torture,
1391 struct smb2_tree *tree1,
1392 struct smb2_tree *tree2)
1394 bool ret = true;
1395 NTSTATUS status;
1396 union smb_notify notify;
1397 union smb_open io;
1398 struct smb2_handle h1;
1399 struct smb2_request *req1, *req2;
1401 smb2_deltree(tree1, BASEDIR);
1402 smb2_util_rmdir(tree1, BASEDIR);
1404 torture_comment(torture,
1405 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1408 get a handle on the directory
1410 ZERO_STRUCT(io.smb2);
1411 io.generic.level = RAW_OPEN_SMB2;
1412 io.smb2.in.create_flags = 0;
1413 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ|
1414 SEC_RIGHTS_FILE_WRITE|
1415 SEC_RIGHTS_FILE_ALL;
1416 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1417 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1418 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1419 NTCREATEX_SHARE_ACCESS_WRITE;
1420 io.smb2.in.alloc_size = 0;
1421 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1422 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1423 io.smb2.in.security_flags = 0;
1424 io.smb2.in.fname = BASEDIR;
1426 status = smb2_create(tree1, torture, &(io.smb2));
1427 CHECK_STATUS(status, NT_STATUS_OK);
1428 h1 = io.smb2.out.file.handle;
1430 /* ask for a change notify,
1431 on file or directory name changes */
1432 ZERO_STRUCT(notify.smb2);
1433 notify.smb2.level = RAW_NOTIFY_SMB2;
1434 notify.smb2.in.buffer_size = 1000;
1435 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1436 notify.smb2.in.file.handle = h1;
1437 notify.smb2.in.recursive = true;
1439 req1 = smb2_notify_send(tree1, &(notify.smb2));
1440 smb2_cancel(req1);
1441 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1442 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1444 req2 = smb2_notify_send(tree1, &(notify.smb2));
1445 smb2_cancel(req2);
1446 status = smb2_notify_recv(req2, torture, &(notify.smb2));
1447 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1449 smb2_util_mkdir(tree2, BASEDIR "\\subdir-name");
1450 req1 = smb2_notify_send(tree1, &(notify.smb2));
1451 req2 = smb2_notify_send(tree1, &(notify.smb2));
1453 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1454 CHECK_STATUS(status, NT_STATUS_OK);
1455 CHECK_VAL(notify.smb2.out.num_changes, 1);
1456 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1458 smb2_util_mkdir(tree2, BASEDIR "\\subdir-name2");
1460 status = smb2_notify_recv(req2, torture, &(notify.smb2));
1461 CHECK_STATUS(status, NT_STATUS_OK);
1462 CHECK_VAL(notify.smb2.out.num_changes, 1);
1463 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name2");
1465 done:
1466 smb2_deltree(tree1, BASEDIR);
1467 return ret;
1472 test multiple change notifies at different depths and with/without recursion
1475 static bool torture_smb2_notify_tree(struct torture_context *torture,
1476 struct smb2_tree *tree)
1478 bool ret = true;
1479 union smb_notify notify;
1480 union smb_open io;
1481 struct smb2_request *req;
1482 struct timeval tv;
1483 struct {
1484 const char *path;
1485 bool recursive;
1486 uint32_t filter;
1487 int expected;
1488 struct smb2_handle h1;
1489 int counted;
1490 } dirs[] = {
1491 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 30 },
1492 {BASEDIR "\\zqy", true, FILE_NOTIFY_CHANGE_NAME, 8 },
1493 {BASEDIR "\\atsy", true, FILE_NOTIFY_CHANGE_NAME, 4 },
1494 {BASEDIR "\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1495 {BASEDIR "\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME, 13 },
1496 {BASEDIR "\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME, 7 },
1497 {BASEDIR "\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1498 {BASEDIR "\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1499 {BASEDIR "\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1500 {BASEDIR "\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1501 {BASEDIR "\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1502 {BASEDIR "\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1503 {BASEDIR "\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME, 40 },
1504 {BASEDIR, true, FILE_NOTIFY_CHANGE_NAME, 40 },
1505 {BASEDIR, false,FILE_NOTIFY_CHANGE_NAME, 6 },
1506 {BASEDIR "\\atsy", false,FILE_NOTIFY_CHANGE_NAME, 4 },
1507 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1508 {BASEDIR "\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1509 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1510 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1512 int i;
1513 NTSTATUS status;
1514 bool all_done = false;
1516 smb2_deltree(tree, BASEDIR);
1517 smb2_util_rmdir(tree, BASEDIR);
1519 torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1521 ZERO_STRUCT(io.smb2);
1522 io.generic.level = RAW_OPEN_SMB2;
1523 io.smb2.in.create_flags = 0;
1524 io.smb2.in.desired_access = SEC_FILE_ALL;
1525 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1526 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1527 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1528 NTCREATEX_SHARE_ACCESS_WRITE;
1529 io.smb2.in.alloc_size = 0;
1530 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1531 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1532 io.smb2.in.security_flags = 0;
1533 io.smb2.in.fname = BASEDIR;
1534 status = smb2_create(tree, torture, &(io.smb2));
1535 CHECK_STATUS(status, NT_STATUS_OK);
1537 ZERO_STRUCT(notify.smb2);
1538 notify.smb2.level = RAW_NOTIFY_SMB2;
1539 notify.smb2.in.buffer_size = 20000;
1542 setup the directory tree, and the notify buffer on each directory
1544 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1545 io.smb2.in.fname = dirs[i].path;
1546 status = smb2_create(tree, torture, &(io.smb2));
1547 CHECK_STATUS(status, NT_STATUS_OK);
1548 dirs[i].h1 = io.smb2.out.file.handle;
1550 notify.smb2.in.completion_filter = dirs[i].filter;
1551 notify.smb2.in.file.handle = dirs[i].h1;
1552 notify.smb2.in.recursive = dirs[i].recursive;
1553 req = smb2_notify_send(tree, &(notify.smb2));
1554 smb2_cancel(req);
1555 status = smb2_notify_recv(req, torture, &(notify.smb2));
1556 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1559 /* trigger 2 events in each dir */
1560 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1561 char *path = talloc_asprintf(torture, "%s\\test.dir",
1562 dirs[i].path);
1563 smb2_util_mkdir(tree, path);
1564 smb2_util_rmdir(tree, path);
1565 talloc_free(path);
1568 /* give a bit of time for the events to propogate */
1569 tv = timeval_current();
1571 do {
1572 /* count events that have happened in each dir */
1573 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1574 notify.smb2.in.file.handle = dirs[i].h1;
1575 req = smb2_notify_send(tree, &(notify.smb2));
1576 smb2_cancel(req);
1577 notify.smb2.out.num_changes = 0;
1578 status = smb2_notify_recv(req, torture,
1579 &(notify.smb2));
1580 dirs[i].counted += notify.smb2.out.num_changes;
1583 all_done = true;
1585 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1586 if (dirs[i].counted != dirs[i].expected) {
1587 all_done = false;
1590 } while (!all_done && timeval_elapsed(&tv) < 20);
1592 torture_comment(torture, "took %.4f seconds to propogate all events\n",
1593 timeval_elapsed(&tv));
1595 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1596 if (dirs[i].counted != dirs[i].expected) {
1597 torture_comment(torture,
1598 "ERROR: i=%d expected %d got %d for '%s'\n",
1599 i, dirs[i].expected, dirs[i].counted,
1600 dirs[i].path);
1601 ret = false;
1606 run from the back, closing and deleting
1608 for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1609 smb2_util_close(tree, dirs[i].h1);
1610 smb2_util_rmdir(tree, dirs[i].path);
1613 done:
1614 smb2_deltree(tree, BASEDIR);
1615 smb2_util_rmdir(tree, BASEDIR);
1616 return ret;
1620 Test response when cached server events exceed single NT NOTFIY response
1621 packet size.
1624 static bool torture_smb2_notify_overflow(struct torture_context *torture,
1625 struct smb2_tree *tree)
1627 bool ret = true;
1628 NTSTATUS status;
1629 union smb_notify notify;
1630 union smb_open io;
1631 struct smb2_handle h1, h2;
1632 int count = 100;
1633 struct smb2_request *req1;
1634 int i;
1636 smb2_deltree(tree, BASEDIR);
1637 smb2_util_rmdir(tree, BASEDIR);
1639 torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1641 /* get a handle on the directory */
1642 ZERO_STRUCT(io.smb2);
1643 io.generic.level = RAW_OPEN_SMB2;
1644 io.smb2.in.create_flags = 0;
1645 io.smb2.in.desired_access = SEC_FILE_ALL;
1646 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1647 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1648 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1649 NTCREATEX_SHARE_ACCESS_WRITE;
1650 io.smb2.in.alloc_size = 0;
1651 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1652 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1653 io.smb2.in.security_flags = 0;
1654 io.smb2.in.fname = BASEDIR;
1656 status = smb2_create(tree, torture, &(io.smb2));
1657 CHECK_STATUS(status, NT_STATUS_OK);
1658 h1 = io.smb2.out.file.handle;
1660 /* ask for a change notify, on name changes. */
1661 ZERO_STRUCT(notify.smb2);
1662 notify.smb2.level = RAW_NOTIFY_NTTRANS;
1663 notify.smb2.in.buffer_size = 1000;
1664 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1665 notify.smb2.in.file.handle = h1;
1667 notify.smb2.in.recursive = true;
1668 req1 = smb2_notify_send(tree, &(notify.smb2));
1670 /* cancel initial requests so the buffer is setup */
1671 smb2_cancel(req1);
1672 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1673 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1675 /* open a lot of files, filling up the server side notify buffer */
1676 torture_comment(torture,
1677 "Testing overflowed buffer notify on create of %d files\n",
1678 count);
1680 for (i=0;i<count;i++) {
1681 char *fname = talloc_asprintf(torture,
1682 BASEDIR "\\test%d.txt", i);
1683 union smb_open io1;
1684 ZERO_STRUCT(io1.smb2);
1685 io1.generic.level = RAW_OPEN_SMB2;
1686 io1.smb2.in.create_flags = 0;
1687 io1.smb2.in.desired_access = SEC_FILE_ALL;
1688 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1689 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1690 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1691 NTCREATEX_SHARE_ACCESS_WRITE;
1692 io1.smb2.in.alloc_size = 0;
1693 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1694 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1695 io1.smb2.in.security_flags = 0;
1696 io1.smb2.in.fname = fname;
1698 h2 = custom_smb2_create(tree, torture, &(io1.smb2));
1699 talloc_free(fname);
1700 smb2_util_close(tree, h2);
1703 req1 = smb2_notify_send(tree, &(notify.smb2));
1704 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1705 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
1706 CHECK_VAL(notify.smb2.out.num_changes, 0);
1708 done:
1709 smb2_deltree(tree, BASEDIR);
1710 return ret;
1714 Test if notifications are returned for changes to the base directory.
1715 They shouldn't be.
1718 static bool torture_smb2_notify_basedir(struct torture_context *torture,
1719 struct smb2_tree *tree1,
1720 struct smb2_tree *tree2)
1722 bool ret = true;
1723 NTSTATUS status;
1724 union smb_notify notify;
1725 union smb_open io;
1726 struct smb2_handle h1;
1727 struct smb2_request *req1;
1729 smb2_deltree(tree1, BASEDIR);
1730 smb2_util_rmdir(tree1, BASEDIR);
1732 torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1734 /* get a handle on the directory */
1735 ZERO_STRUCT(io.smb2);
1736 io.generic.level = RAW_OPEN_SMB2;
1737 io.smb2.in.create_flags = 0;
1738 io.smb2.in.desired_access = SEC_FILE_ALL;
1739 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1740 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1741 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1742 NTCREATEX_SHARE_ACCESS_WRITE;
1743 io.smb2.in.alloc_size = 0;
1744 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1745 io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
1746 io.smb2.in.security_flags = 0;
1747 io.smb2.in.fname = BASEDIR;
1749 status = smb2_create(tree1, torture, &(io.smb2));
1750 CHECK_STATUS(status, NT_STATUS_OK);
1751 h1 = io.smb2.out.file.handle;
1753 /* create a test file that will also be modified */
1754 io.smb2.in.fname = BASEDIR "\\tname1";
1755 io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
1756 status = smb2_create(tree2, torture, &(io.smb2));
1757 CHECK_STATUS(status,NT_STATUS_OK);
1758 smb2_util_close(tree2, io.smb2.out.file.handle);
1760 /* ask for a change notify, on attribute changes. */
1761 ZERO_STRUCT(notify.smb2);
1762 notify.smb2.level = RAW_NOTIFY_SMB2;
1763 notify.smb2.in.buffer_size = 1000;
1764 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
1765 notify.smb2.in.file.handle = h1;
1766 notify.smb2.in.recursive = true;
1768 req1 = smb2_notify_send(tree1, &(notify.smb2));
1770 /* set attribute on the base dir */
1771 smb2_util_setatr(tree2, BASEDIR, FILE_ATTRIBUTE_HIDDEN);
1773 /* set attribute on a file to assure we receive a notification */
1774 smb2_util_setatr(tree2, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN);
1775 smb_msleep(200);
1777 /* check how many responses were given, expect only 1 for the file */
1778 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1779 CHECK_STATUS(status, NT_STATUS_OK);
1780 CHECK_VAL(notify.smb2.out.num_changes, 1);
1781 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
1782 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
1784 done:
1785 smb2_deltree(tree1, BASEDIR);
1786 return ret;
1791 create a secondary tree connect - used to test for a bug in Samba3 messaging
1792 with change notify
1794 static struct smb2_tree *secondary_tcon(struct smb2_tree *tree,
1795 struct torture_context *tctx)
1797 NTSTATUS status;
1798 const char *share, *host;
1799 struct smb2_tree *tree1;
1800 union smb_tcon tcon;
1802 share = torture_setting_string(tctx, "share", NULL);
1803 host = torture_setting_string(tctx, "host", NULL);
1805 torture_comment(tctx,
1806 "create a second tree context on the same session\n");
1807 tree1 = smb2_tree_init(tree->session, tctx, false);
1808 if (tree1 == NULL) {
1809 torture_comment(tctx, "Out of memory\n");
1810 return NULL;
1813 ZERO_STRUCT(tcon.smb2);
1814 tcon.generic.level = RAW_TCON_SMB2;
1815 tcon.smb2.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
1816 status = smb2_tree_connect(tree->session, &(tcon.smb2));
1817 if (!NT_STATUS_IS_OK(status)) {
1818 talloc_free(tree1);
1819 torture_comment(tctx,"Failed to create secondary tree\n");
1820 return NULL;
1823 smb2cli_tcon_set_values(tree1->smbXcli,
1824 tree1->session->smbXcli,
1825 tcon.smb2.out.tid,
1826 tcon.smb2.out.share_type,
1827 tcon.smb2.out.flags,
1828 tcon.smb2.out.capabilities,
1829 tcon.smb2.out.access_mask);
1831 torture_comment(tctx,"tid1=%d tid2=%d\n",
1832 smb2cli_tcon_current_id(tree->smbXcli),
1833 smb2cli_tcon_current_id(tree1->smbXcli));
1835 return tree1;
1840 very simple change notify test
1842 static bool torture_smb2_notify_tcon(struct torture_context *torture,
1843 struct smb2_tree *tree)
1845 bool ret = true;
1846 NTSTATUS status;
1847 union smb_notify notify;
1848 union smb_open io;
1849 struct smb2_handle h1;
1850 struct smb2_request *req = NULL;
1851 struct smb2_tree *tree1 = NULL;
1852 const char *fname = BASEDIR "\\subdir-name";
1854 smb2_deltree(tree, BASEDIR);
1855 smb2_util_rmdir(tree, BASEDIR);
1857 torture_comment(torture, "TESTING SIMPLE CHANGE NOTIFY\n");
1860 get a handle on the directory
1863 ZERO_STRUCT(io.smb2);
1864 io.generic.level = RAW_OPEN_SMB2;
1865 io.smb2.in.create_flags = 0;
1866 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1867 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1868 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL |
1869 FILE_ATTRIBUTE_DIRECTORY;
1870 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1871 NTCREATEX_SHARE_ACCESS_WRITE;
1872 io.smb2.in.alloc_size = 0;
1873 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1874 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1875 io.smb2.in.security_flags = 0;
1876 io.smb2.in.fname = BASEDIR;
1878 status = smb2_create(tree, torture, &(io.smb2));
1879 CHECK_STATUS(status, NT_STATUS_OK);
1880 h1 = io.smb2.out.file.handle;
1882 /* ask for a change notify,
1883 on file or directory name changes */
1884 ZERO_STRUCT(notify.smb2);
1885 notify.smb2.level = RAW_NOTIFY_SMB2;
1886 notify.smb2.in.buffer_size = 1000;
1887 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1888 notify.smb2.in.file.handle = h1;
1889 notify.smb2.in.recursive = true;
1891 torture_comment(torture, "Testing notify mkdir\n");
1892 req = smb2_notify_send(tree, &(notify.smb2));
1893 smb2_cancel(req);
1894 status = smb2_notify_recv(req, torture, &(notify.smb2));
1895 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1897 notify.smb2.in.recursive = true;
1898 req = smb2_notify_send(tree, &(notify.smb2));
1899 status = smb2_util_mkdir(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);
1905 CHECK_VAL(notify.smb2.out.num_changes, 1);
1906 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
1907 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1909 torture_comment(torture, "Testing notify rmdir\n");
1910 req = smb2_notify_send(tree, &(notify.smb2));
1911 status = smb2_util_rmdir(tree, fname);
1912 CHECK_STATUS(status, NT_STATUS_OK);
1914 status = smb2_notify_recv(req, torture, &(notify.smb2));
1915 CHECK_STATUS(status, NT_STATUS_OK);
1916 CHECK_VAL(notify.smb2.out.num_changes, 1);
1917 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
1918 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1920 torture_comment(torture, "SIMPLE CHANGE NOTIFY OK\n");
1922 torture_comment(torture, "TESTING WITH SECONDARY TCON\n");
1923 tree1 = secondary_tcon(tree, torture);
1925 torture_comment(torture, "Testing notify mkdir\n");
1926 req = smb2_notify_send(tree, &(notify.smb2));
1927 smb2_util_mkdir(tree1, fname);
1929 status = smb2_notify_recv(req, torture, &(notify.smb2));
1930 CHECK_STATUS(status, NT_STATUS_OK);
1932 CHECK_VAL(notify.smb2.out.num_changes, 1);
1933 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
1934 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1936 torture_comment(torture, "Testing notify rmdir\n");
1937 req = smb2_notify_send(tree, &(notify.smb2));
1938 smb2_util_rmdir(tree, fname);
1940 status = smb2_notify_recv(req, torture, &(notify.smb2));
1941 CHECK_STATUS(status, NT_STATUS_OK);
1942 CHECK_VAL(notify.smb2.out.num_changes, 1);
1943 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
1944 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1946 torture_comment(torture, "CHANGE NOTIFY WITH TCON OK\n");
1948 torture_comment(torture, "Disconnecting secondary tree\n");
1949 status = smb2_tdis(tree1);
1950 CHECK_STATUS(status, NT_STATUS_OK);
1951 talloc_free(tree1);
1953 torture_comment(torture, "Testing notify mkdir\n");
1954 req = smb2_notify_send(tree, &(notify.smb2));
1955 smb2_util_mkdir(tree, fname);
1957 status = smb2_notify_recv(req, torture, &(notify.smb2));
1958 CHECK_STATUS(status, NT_STATUS_OK);
1960 CHECK_VAL(notify.smb2.out.num_changes, 1);
1961 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
1962 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1964 torture_comment(torture, "Testing notify rmdir\n");
1965 req = smb2_notify_send(tree, &(notify.smb2));
1966 smb2_util_rmdir(tree, fname);
1968 status = smb2_notify_recv(req, torture, &(notify.smb2));
1969 CHECK_STATUS(status, NT_STATUS_OK);
1970 CHECK_VAL(notify.smb2.out.num_changes, 1);
1971 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
1972 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1974 torture_comment(torture, "CHANGE NOTIFY WITH TDIS OK\n");
1975 done:
1976 smb2_util_close(tree, h1);
1977 smb2_deltree(tree, BASEDIR);
1979 return ret;
1983 basic testing of SMB2 change notify
1985 struct torture_suite *torture_smb2_notify_init(void)
1987 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "notify");
1989 torture_suite_add_1smb2_test(suite, "valid-req", test_valid_request);
1990 torture_suite_add_1smb2_test(suite, "tcon", torture_smb2_notify_tcon);
1991 torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir);
1992 torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask);
1993 torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
1994 torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
1995 torture_suite_add_2smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
1996 torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
1997 torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
1998 torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
1999 torture_suite_add_1smb2_test(suite, "file", torture_smb2_notify_file);
2000 torture_suite_add_1smb2_test(suite, "tcp", torture_smb2_notify_tcp_disconnect);
2001 torture_suite_add_2smb2_test(suite, "rec", torture_smb2_notify_recursive);
2002 torture_suite_add_1smb2_test(suite, "overflow", torture_smb2_notify_overflow);
2004 suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");
2006 return suite;