s3: Make winbindd_lookup_names static
[Samba.git] / source4 / torture / smb2 / notify.c
blob80c560be0073672ef6c21f188e0f73b578c2559d
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"
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)); \
49 ret = false; \
50 goto done; \
51 }} while (0)
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); \
58 ret = false; \
59 goto done; \
60 }} while (0)
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, \
66 field.s, value); \
67 ret = false; \
68 goto done; \
69 }} while (0)
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)
77 bool ret = true;
78 NTSTATUS status;
79 struct smb2_handle dh;
80 struct smb2_notify n;
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
92 * pre-Win7 */
93 max_buffer_size = torture_setting_ulong(torture, "cn_max_buffer_size",
94 0x00080000);
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 (event_loop_once(req->transport->socket->event.ctx) != 0) {
105 break;
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 (event_loop_once(req->transport->socket->event.ctx) != 0) {
127 break;
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
139 * NT_STATUS_OK again
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 (event_loop_once(req->transport->socket->event.ctx) != 0) {
146 break;
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 (event_loop_once(req->transport->socket->event.ctx) != 0) {
178 break;
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 (event_loop_once(req->transport->socket->event.ctx) != 0) {
192 break;
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);
212 done:
213 return ret;
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)
223 bool ret = true;
224 NTSTATUS status;
225 union smb_notify notify;
226 union smb_open io;
227 union smb_close cl;
228 int i, count;
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));
277 smb2_cancel(req);
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);
311 smb_msleep(200);
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",
351 fname);
352 ret = false;
353 goto done;
355 h12 = io.smb2.out.file.handle;
356 talloc_free(fname2);
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);
411 talloc_free(fname2);
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;
424 sleep(3);
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);
459 done:
460 smb2_util_close(tree1, h1);
461 smb2_util_close(tree1, h2);
462 smb2_deltree(tree1, BASEDIR);
463 return ret;
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;
471 bool ret = true;
472 NTSTATUS status;
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;
477 done:
478 return h1;
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)
489 bool ret = true;
490 NTSTATUS status;
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));
535 smb2_cancel(req1);
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));
541 smb2_cancel(req2);
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|
550 SEC_RIGHTS_FILE_ALL;
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);
568 ZERO_STRUCT(sinfo);
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);
582 ZERO_STRUCT(sinfo);
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);
595 ZERO_STRUCT(sinfo);
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;
606 smb_msleep(200);
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");
642 done:
643 smb2_deltree(tree1, BASEDIR);
644 return ret;
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)
655 bool ret = true;
656 NTSTATUS status;
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));
700 smb2_cancel(req1);
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));
708 smb2_cancel(req2);
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|
721 SEC_RIGHTS_FILE_ALL;
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);
766 ZERO_STRUCT(sinfo);
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");
823 if (!ret) {
824 goto done;
827 done:
828 smb2_deltree(tree1, BASEDIR);
829 return ret;
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)
840 bool ret = true;
841 NTSTATUS status;
842 union smb_notify notify;
843 union smb_open io, io1;
844 struct smb2_handle h1, h2;
845 uint32_t mask;
846 int i;
847 char c = 1;
848 struct timeval tv;
849 NTTIME t;
850 union smb_setfileinfo sinfo;
852 smb2_deltree(tree1, BASEDIR);
853 smb2_util_rmdir(tree1, BASEDIR);
855 torture_comment(torture, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
857 tv = timeval_current_ofs(1000, 0);
858 t = timeval_to_nttime(&tv);
861 get a handle on the directory
863 ZERO_STRUCT(io.smb2);
864 io.generic.level = RAW_OPEN_SMB2;
865 io.smb2.in.create_flags = 0;
866 io.smb2.in.desired_access = SEC_FILE_ALL;
867 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
868 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
869 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
870 NTCREATEX_SHARE_ACCESS_WRITE;
871 io.smb2.in.alloc_size = 0;
872 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
873 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
874 io.smb2.in.security_flags = 0;
875 io.smb2.in.fname = BASEDIR;
877 ZERO_STRUCT(notify.smb2);
878 notify.smb2.level = RAW_NOTIFY_SMB2;
879 notify.smb2.in.buffer_size = 1000;
880 notify.smb2.in.recursive = true;
882 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
883 expected, nchanges) \
884 do { \
885 do { for (mask=i=0;i<32;i++) { \
886 struct smb2_request *req; \
887 status = smb2_create(tree1, torture, &(io.smb2)); \
888 CHECK_STATUS(status, NT_STATUS_OK); \
889 h1 = io.smb2.out.file.handle; \
890 setup \
891 notify.smb2.in.file.handle = h1; \
892 notify.smb2.in.completion_filter = (1<<i); \
893 /* cancel initial requests so the buffer is setup */ \
894 req = smb2_notify_send(tree1, &(notify.smb2)); \
895 smb2_cancel(req); \
896 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
897 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
898 /* send the change notify request */ \
899 req = smb2_notify_send(tree1, &(notify.smb2)); \
900 op \
901 smb_msleep(200); smb2_cancel(req); \
902 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
903 cleanup \
904 smb2_util_close(tree1, h1); \
905 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
906 CHECK_STATUS(status, NT_STATUS_OK); \
907 /* special case to cope with file rename behaviour */ \
908 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
909 notify.smb2.out.changes[0].action == \
910 NOTIFY_ACTION_MODIFIED && \
911 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
912 Action == NOTIFY_ACTION_OLD_NAME) { \
913 torture_comment(torture, \
914 "(rename file special handling OK)\n"); \
915 } else if (nchanges != notify.smb2.out.num_changes) { \
916 torture_result(torture, TORTURE_FAIL, \
917 "ERROR: nchanges=%d expected=%d "\
918 "action=%d filter=0x%08x\n", \
919 notify.smb2.out.num_changes, \
920 nchanges, \
921 notify.smb2.out.changes[0].action, \
922 notify.smb2.in.completion_filter); \
923 ret = false; \
924 } else if (notify.smb2.out.changes[0].action != Action) { \
925 torture_result(torture, TORTURE_FAIL, \
926 "ERROR: nchanges=%d action=%d " \
927 "expectedAction=%d filter=0x%08x\n", \
928 notify.smb2.out.num_changes, \
929 notify.smb2.out.changes[0].action, \
930 Action, \
931 notify.smb2.in.completion_filter); \
932 ret = false; \
933 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
934 "tname1") != 0) { \
935 torture_result(torture, TORTURE_FAIL, \
936 "ERROR: nchanges=%d action=%d " \
937 "filter=0x%08x name=%s\n", \
938 notify.smb2.out.num_changes, \
939 notify.smb2.out.changes[0].action, \
940 notify.smb2.in.completion_filter, \
941 notify.smb2.out.changes[0].name.s); \
942 ret = false; \
944 mask |= (1<<i); \
946 } while (0); \
947 } while (0);
949 torture_comment(torture, "Testing mkdir\n");
950 NOTIFY_MASK_TEST("Testing mkdir",;,
951 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
952 smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
953 NOTIFY_ACTION_ADDED,
954 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
956 torture_comment(torture, "Testing create file\n");
957 ZERO_STRUCT(io1.smb2);
958 io1.generic.level = RAW_OPEN_SMB2;
959 io1.smb2.in.create_flags = 0;
960 io1.smb2.in.desired_access = SEC_FILE_ALL;
961 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
962 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
963 NTCREATEX_SHARE_ACCESS_WRITE;
964 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
965 io1.smb2.in.security_flags = 0;
966 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
967 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
968 io1.smb2.in.fname = BASEDIR "\\tname1";
970 NOTIFY_MASK_TEST("Testing create file",;,
971 smb2_util_close(tree2, custom_smb2_create(tree2,
972 torture, &(io1.smb2)));,
973 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
974 NOTIFY_ACTION_ADDED,
975 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
977 torture_comment(torture, "Testing unlink\n");
978 NOTIFY_MASK_TEST("Testing unlink",
979 smb2_util_close(tree2, custom_smb2_create(tree2,
980 torture, &(io1.smb2)));,
981 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
983 NOTIFY_ACTION_REMOVED,
984 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
986 torture_comment(torture, "Testing rmdir\n");
987 NOTIFY_MASK_TEST("Testing rmdir",
988 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
989 smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
991 NOTIFY_ACTION_REMOVED,
992 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
994 torture_comment(torture, "Testing rename file\n");
995 ZERO_STRUCT(sinfo);
996 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
997 sinfo.rename_information.in.file.handle = h1;
998 sinfo.rename_information.in.overwrite = true;
999 sinfo.rename_information.in.root_fid = 0;
1000 sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
1001 NOTIFY_MASK_TEST("Testing rename file",
1002 smb2_util_close(tree2, custom_smb2_create(tree2,
1003 torture, &(io1.smb2)));,
1004 smb2_setinfo_file(tree2, &sinfo);,
1005 smb2_util_unlink(tree2, BASEDIR "\\tname2");,
1006 NOTIFY_ACTION_OLD_NAME,
1007 FILE_NOTIFY_CHANGE_FILE_NAME, 2);
1009 torture_comment(torture, "Testing rename dir\n");
1010 ZERO_STRUCT(sinfo);
1011 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1012 sinfo.rename_information.in.file.handle = h1;
1013 sinfo.rename_information.in.overwrite = true;
1014 sinfo.rename_information.in.root_fid = 0;
1015 sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
1016 NOTIFY_MASK_TEST("Testing rename dir",
1017 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
1018 smb2_setinfo_file(tree2, &sinfo);,
1019 smb2_util_rmdir(tree2, BASEDIR "\\tname2");,
1020 NOTIFY_ACTION_OLD_NAME,
1021 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
1023 torture_comment(torture, "Testing set path attribute\n");
1024 NOTIFY_MASK_TEST("Testing set path attribute",
1025 smb2_util_close(tree2, custom_smb2_create(tree2,
1026 torture, &(io.smb2)));,
1027 smb2_util_setatr(tree2, BASEDIR "\\tname1",
1028 FILE_ATTRIBUTE_HIDDEN);,
1029 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1030 NOTIFY_ACTION_MODIFIED,
1031 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
1033 torture_comment(torture, "Testing set path write time\n");
1034 ZERO_STRUCT(sinfo);
1035 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1036 sinfo.generic.in.file.handle = h1;
1037 sinfo.basic_info.in.write_time = 1000;
1038 NOTIFY_MASK_TEST("Testing set path write time",
1039 smb2_util_close(tree2, custom_smb2_create(tree2,
1040 torture, &(io1.smb2)));,
1041 smb2_setinfo_file(tree2, &sinfo);,
1042 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1043 NOTIFY_ACTION_MODIFIED,
1044 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
1046 if (torture_setting_bool(torture, "samba3", false)) {
1047 torture_comment(torture,
1048 "Samba3 does not yet support create times "
1049 "everywhere\n");
1051 else {
1052 ZERO_STRUCT(sinfo);
1053 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1054 sinfo.generic.in.file.handle = h1;
1055 sinfo.basic_info.in.create_time = 0;
1056 torture_comment(torture, "Testing set file create time\n");
1057 NOTIFY_MASK_TEST("Testing set file create time",
1058 smb2_create_complex_file(tree2,
1059 BASEDIR "\\tname1", &h2);,
1060 smb2_setinfo_file(tree2, &sinfo);,
1061 (smb2_util_close(tree2, h2),
1062 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1063 NOTIFY_ACTION_MODIFIED,
1064 FILE_NOTIFY_CHANGE_CREATION, 1);
1067 ZERO_STRUCT(sinfo);
1068 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1069 sinfo.generic.in.file.handle = h1;
1070 sinfo.basic_info.in.access_time = 0;
1071 torture_comment(torture, "Testing set file access time\n");
1072 NOTIFY_MASK_TEST("Testing set file access time",
1073 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1074 smb2_setinfo_file(tree2, &sinfo);,
1075 (smb2_util_close(tree2, h2),
1076 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1077 NOTIFY_ACTION_MODIFIED,
1078 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
1080 ZERO_STRUCT(sinfo);
1081 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1082 sinfo.generic.in.file.handle = h1;
1083 sinfo.basic_info.in.change_time = 0;
1084 torture_comment(torture, "Testing set file change time\n");
1085 NOTIFY_MASK_TEST("Testing set file change time",
1086 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1087 smb2_setinfo_file(tree2, &sinfo);,
1088 (smb2_util_close(tree2, h2),
1089 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1090 NOTIFY_ACTION_MODIFIED,
1091 0, 1);
1094 torture_comment(torture, "Testing write\n");
1095 NOTIFY_MASK_TEST("Testing write",
1096 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1097 smb2_util_write(tree2, h2, &c, 10000, 1);,
1098 (smb2_util_close(tree2, h2),
1099 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1100 NOTIFY_ACTION_MODIFIED,
1101 0, 1);
1103 done:
1104 smb2_deltree(tree1, BASEDIR);
1105 return ret;
1109 basic testing of change notify on files
1111 static bool torture_smb2_notify_file(struct torture_context *torture,
1112 struct smb2_tree *tree)
1114 NTSTATUS status;
1115 bool ret = true;
1116 union smb_open io;
1117 union smb_close cl;
1118 union smb_notify notify;
1119 struct smb2_request *req;
1120 struct smb2_handle h1;
1121 const char *fname = BASEDIR "\\file.txt";
1123 smb2_deltree(tree, BASEDIR);
1124 smb2_util_rmdir(tree, BASEDIR);
1126 torture_comment(torture, "TESTING CHANGE NOTIFY ON FILES\n");
1127 status = torture_smb2_testdir(tree, BASEDIR, &h1);
1128 CHECK_STATUS(status, NT_STATUS_OK);
1130 ZERO_STRUCT(io.smb2);
1131 io.generic.level = RAW_OPEN_SMB2;
1132 io.smb2.in.create_flags = 0;
1133 io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
1134 io.smb2.in.create_options = 0;
1135 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1136 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1137 NTCREATEX_SHARE_ACCESS_WRITE;
1138 io.smb2.in.alloc_size = 0;
1139 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1140 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1141 io.smb2.in.security_flags = 0;
1142 io.smb2.in.fname = fname;
1143 status = smb2_create(tree, torture, &(io.smb2));
1144 CHECK_STATUS(status, NT_STATUS_OK);
1145 h1 = io.smb2.out.file.handle;
1147 /* ask for a change notify,
1148 on file or directory name changes */
1149 ZERO_STRUCT(notify.smb2);
1150 notify.smb2.level = RAW_NOTIFY_SMB2;
1151 notify.smb2.in.file.handle = h1;
1152 notify.smb2.in.buffer_size = 1000;
1153 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
1154 notify.smb2.in.recursive = false;
1156 torture_comment(torture,
1157 "Testing if notifies on file handles are invalid (should be)\n");
1159 req = smb2_notify_send(tree, &(notify.smb2));
1160 status = smb2_notify_recv(req, torture, &(notify.smb2));
1161 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1163 ZERO_STRUCT(cl.smb2);
1164 cl.close.level = RAW_CLOSE_SMB2;
1165 cl.close.in.file.handle = h1;
1166 status = smb2_close(tree, &(cl.smb2));
1167 CHECK_STATUS(status, NT_STATUS_OK);
1169 status = smb2_util_unlink(tree, fname);
1170 CHECK_STATUS(status, NT_STATUS_OK);
1172 done:
1173 smb2_deltree(tree, BASEDIR);
1174 return ret;
1177 basic testing of change notifies followed by a tdis
1180 static bool torture_smb2_notify_tree_disconnect(
1181 struct torture_context *torture,
1182 struct smb2_tree *tree)
1184 bool ret = true;
1185 NTSTATUS status;
1186 union smb_notify notify;
1187 union smb_open io;
1188 struct smb2_handle h1;
1189 struct smb2_request *req;
1191 smb2_deltree(tree, BASEDIR);
1192 smb2_util_rmdir(tree, BASEDIR);
1194 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY "
1195 "TREE-DISCONNECT\n");
1198 get a handle on the directory
1200 ZERO_STRUCT(io.smb2);
1201 io.generic.level = RAW_OPEN_SMB2;
1202 io.smb2.in.create_flags = 0;
1203 io.smb2.in.desired_access = SEC_FILE_ALL;
1204 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1205 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1206 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1207 NTCREATEX_SHARE_ACCESS_WRITE;
1208 io.smb2.in.alloc_size = 0;
1209 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1210 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1211 io.smb2.in.security_flags = 0;
1212 io.smb2.in.fname = BASEDIR;
1214 status = smb2_create(tree, torture, &(io.smb2));
1215 CHECK_STATUS(status, NT_STATUS_OK);
1216 h1 = io.smb2.out.file.handle;
1218 /* ask for a change notify,
1219 on file or directory name changes */
1220 ZERO_STRUCT(notify.smb2);
1221 notify.smb2.level = RAW_NOTIFY_SMB2;
1222 notify.smb2.in.buffer_size = 1000;
1223 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1224 notify.smb2.in.file.handle = h1;
1225 notify.smb2.in.recursive = true;
1227 req = smb2_notify_send(tree, &(notify.smb2));
1228 smb2_cancel(req);
1229 status = smb2_notify_recv(req, torture, &(notify.smb2));
1231 status = smb2_tdis(tree);
1232 CHECK_STATUS(status, NT_STATUS_OK);
1234 req = smb2_notify_send(tree, &(notify.smb2));
1236 smb2_notify_recv(req, torture, &(notify.smb2));
1237 CHECK_STATUS(status, NT_STATUS_OK);
1238 CHECK_VAL(notify.smb2.out.num_changes, 0);
1240 done:
1241 smb2_deltree(tree, BASEDIR);
1242 return ret;
1246 basic testing of change notifies followed by a ulogoff
1249 static bool torture_smb2_notify_ulogoff(struct torture_context *torture,
1250 struct smb2_tree *tree1,
1251 struct smb2_tree *tree2)
1253 bool ret = true;
1254 NTSTATUS status;
1255 union smb_notify notify;
1256 union smb_open io;
1257 struct smb2_handle h1;
1258 struct smb2_request *req;
1260 smb2_deltree(tree1, BASEDIR);
1261 smb2_util_rmdir(tree1, BASEDIR);
1263 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1266 get a handle on the directory
1268 ZERO_STRUCT(io.smb2);
1269 io.generic.level = RAW_OPEN_SMB2;
1270 io.smb2.in.create_flags = 0;
1271 io.smb2.in.desired_access = SEC_FILE_ALL;
1272 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1273 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1274 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1275 NTCREATEX_SHARE_ACCESS_WRITE;
1276 io.smb2.in.alloc_size = 0;
1277 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1278 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1279 io.smb2.in.security_flags = 0;
1280 io.smb2.in.fname = BASEDIR;
1282 status = smb2_create(tree2, torture, &(io.smb2));
1283 CHECK_STATUS(status, NT_STATUS_OK);
1285 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1286 status = smb2_create(tree2, torture, &(io.smb2));
1287 CHECK_STATUS(status, NT_STATUS_OK);
1288 h1 = io.smb2.out.file.handle;
1290 /* ask for a change notify,
1291 on file or directory name changes */
1292 ZERO_STRUCT(notify.smb2);
1293 notify.smb2.level = RAW_NOTIFY_SMB2;
1294 notify.smb2.in.buffer_size = 1000;
1295 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1296 notify.smb2.in.file.handle = h1;
1297 notify.smb2.in.recursive = true;
1299 req = smb2_notify_send(tree1, &(notify.smb2));
1301 status = smb2_logoff(tree2->session);
1302 CHECK_STATUS(status, NT_STATUS_OK);
1304 status = smb2_notify_recv(req, torture, &(notify.smb2));
1305 CHECK_VAL(notify.smb2.out.num_changes, 0);
1307 done:
1308 smb2_deltree(tree1, BASEDIR);
1309 return ret;
1312 static void tcp_dis_handler(struct smb2_transport *t, void *p)
1314 struct smb2_tree *tree = (struct smb2_tree *)p;
1315 smb2_transport_dead(tree->session->transport,
1316 NT_STATUS_LOCAL_DISCONNECT);
1317 t = NULL;
1318 tree = NULL;
1322 basic testing of change notifies followed by tcp disconnect
1325 static bool torture_smb2_notify_tcp_disconnect(
1326 struct torture_context *torture,
1327 struct smb2_tree *tree)
1329 bool ret = true;
1330 NTSTATUS status;
1331 union smb_notify notify;
1332 union smb_open io;
1333 struct smb2_handle h1;
1334 struct smb2_request *req;
1336 smb2_deltree(tree, BASEDIR);
1337 smb2_util_rmdir(tree, BASEDIR);
1339 torture_comment(torture,
1340 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1343 get a handle on the directory
1345 ZERO_STRUCT(io.smb2);
1346 io.generic.level = RAW_OPEN_SMB2;
1347 io.smb2.in.create_flags = 0;
1348 io.smb2.in.desired_access = SEC_FILE_ALL;
1349 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1350 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1351 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1352 NTCREATEX_SHARE_ACCESS_WRITE;
1353 io.smb2.in.alloc_size = 0;
1354 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1355 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1356 io.smb2.in.security_flags = 0;
1357 io.smb2.in.fname = BASEDIR;
1359 status = smb2_create(tree, torture, &(io.smb2));
1360 CHECK_STATUS(status, NT_STATUS_OK);
1361 h1 = io.smb2.out.file.handle;
1363 /* ask for a change notify,
1364 on file or directory name changes */
1365 ZERO_STRUCT(notify.smb2);
1366 notify.smb2.level = RAW_NOTIFY_SMB2;
1367 notify.smb2.in.buffer_size = 1000;
1368 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1369 notify.smb2.in.file.handle = h1;
1370 notify.smb2.in.recursive = true;
1372 req = smb2_notify_send(tree, &(notify.smb2));
1373 smb2_cancel(req);
1374 status = smb2_notify_recv(req, torture, &(notify.smb2));
1375 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1377 notify.smb2.in.recursive = true;
1378 req = smb2_notify_send(tree, &(notify.smb2));
1379 smb2_transport_idle_handler(tree->session->transport,
1380 tcp_dis_handler, 250, tree);
1381 tree = NULL;
1382 status = smb2_notify_recv(req, torture, &(notify.smb2));
1383 CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
1385 done:
1386 return ret;
1390 test setting up two change notify requests on one handle
1393 static bool torture_smb2_notify_double(struct torture_context *torture,
1394 struct smb2_tree *tree1,
1395 struct smb2_tree *tree2)
1397 bool ret = true;
1398 NTSTATUS status;
1399 union smb_notify notify;
1400 union smb_open io;
1401 struct smb2_handle h1;
1402 struct smb2_request *req1, *req2;
1404 smb2_deltree(tree1, BASEDIR);
1405 smb2_util_rmdir(tree1, BASEDIR);
1407 torture_comment(torture,
1408 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1411 get a handle on the directory
1413 ZERO_STRUCT(io.smb2);
1414 io.generic.level = RAW_OPEN_SMB2;
1415 io.smb2.in.create_flags = 0;
1416 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ|
1417 SEC_RIGHTS_FILE_WRITE|
1418 SEC_RIGHTS_FILE_ALL;
1419 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1420 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1421 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1422 NTCREATEX_SHARE_ACCESS_WRITE;
1423 io.smb2.in.alloc_size = 0;
1424 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1425 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1426 io.smb2.in.security_flags = 0;
1427 io.smb2.in.fname = BASEDIR;
1429 status = smb2_create(tree1, torture, &(io.smb2));
1430 CHECK_STATUS(status, NT_STATUS_OK);
1431 h1 = io.smb2.out.file.handle;
1433 /* ask for a change notify,
1434 on file or directory name changes */
1435 ZERO_STRUCT(notify.smb2);
1436 notify.smb2.level = RAW_NOTIFY_SMB2;
1437 notify.smb2.in.buffer_size = 1000;
1438 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1439 notify.smb2.in.file.handle = h1;
1440 notify.smb2.in.recursive = true;
1442 req1 = smb2_notify_send(tree1, &(notify.smb2));
1443 smb2_cancel(req1);
1444 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1445 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1447 req2 = smb2_notify_send(tree1, &(notify.smb2));
1448 smb2_cancel(req2);
1449 status = smb2_notify_recv(req2, torture, &(notify.smb2));
1450 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1452 smb2_util_mkdir(tree2, BASEDIR "\\subdir-name");
1453 req1 = smb2_notify_send(tree1, &(notify.smb2));
1454 req2 = smb2_notify_send(tree1, &(notify.smb2));
1456 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1457 CHECK_STATUS(status, NT_STATUS_OK);
1458 CHECK_VAL(notify.smb2.out.num_changes, 1);
1459 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1461 smb2_util_mkdir(tree2, BASEDIR "\\subdir-name2");
1463 status = smb2_notify_recv(req2, torture, &(notify.smb2));
1464 CHECK_STATUS(status, NT_STATUS_OK);
1465 CHECK_VAL(notify.smb2.out.num_changes, 1);
1466 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name2");
1468 done:
1469 smb2_deltree(tree1, BASEDIR);
1470 return ret;
1475 test multiple change notifies at different depths and with/without recursion
1478 static bool torture_smb2_notify_tree(struct torture_context *torture,
1479 struct smb2_tree *tree)
1481 bool ret = true;
1482 union smb_notify notify;
1483 union smb_open io;
1484 struct smb2_request *req;
1485 struct timeval tv;
1486 struct {
1487 const char *path;
1488 bool recursive;
1489 uint32_t filter;
1490 int expected;
1491 struct smb2_handle h1;
1492 int counted;
1493 } dirs[] = {
1494 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 30 },
1495 {BASEDIR "\\zqy", true, FILE_NOTIFY_CHANGE_NAME, 8 },
1496 {BASEDIR "\\atsy", true, FILE_NOTIFY_CHANGE_NAME, 4 },
1497 {BASEDIR "\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1498 {BASEDIR "\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME, 13 },
1499 {BASEDIR "\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME, 7 },
1500 {BASEDIR "\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1501 {BASEDIR "\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1502 {BASEDIR "\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1503 {BASEDIR "\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1504 {BASEDIR "\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1505 {BASEDIR "\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1506 {BASEDIR "\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME, 40 },
1507 {BASEDIR, true, FILE_NOTIFY_CHANGE_NAME, 40 },
1508 {BASEDIR, false,FILE_NOTIFY_CHANGE_NAME, 6 },
1509 {BASEDIR "\\atsy", false,FILE_NOTIFY_CHANGE_NAME, 4 },
1510 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1511 {BASEDIR "\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1512 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1513 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1515 int i;
1516 NTSTATUS status;
1517 bool all_done = false;
1519 smb2_deltree(tree, BASEDIR);
1520 smb2_util_rmdir(tree, BASEDIR);
1522 torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1524 ZERO_STRUCT(io.smb2);
1525 io.generic.level = RAW_OPEN_SMB2;
1526 io.smb2.in.create_flags = 0;
1527 io.smb2.in.desired_access = SEC_FILE_ALL;
1528 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1529 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1530 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1531 NTCREATEX_SHARE_ACCESS_WRITE;
1532 io.smb2.in.alloc_size = 0;
1533 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1534 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1535 io.smb2.in.security_flags = 0;
1536 io.smb2.in.fname = BASEDIR;
1537 status = smb2_create(tree, torture, &(io.smb2));
1538 CHECK_STATUS(status, NT_STATUS_OK);
1540 ZERO_STRUCT(notify.smb2);
1541 notify.smb2.level = RAW_NOTIFY_SMB2;
1542 notify.smb2.in.buffer_size = 20000;
1545 setup the directory tree, and the notify buffer on each directory
1547 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1548 io.smb2.in.fname = dirs[i].path;
1549 status = smb2_create(tree, torture, &(io.smb2));
1550 CHECK_STATUS(status, NT_STATUS_OK);
1551 dirs[i].h1 = io.smb2.out.file.handle;
1553 notify.smb2.in.completion_filter = dirs[i].filter;
1554 notify.smb2.in.file.handle = dirs[i].h1;
1555 notify.smb2.in.recursive = dirs[i].recursive;
1556 req = smb2_notify_send(tree, &(notify.smb2));
1557 smb2_cancel(req);
1558 status = smb2_notify_recv(req, torture, &(notify.smb2));
1559 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1562 /* trigger 2 events in each dir */
1563 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1564 char *path = talloc_asprintf(torture, "%s\\test.dir",
1565 dirs[i].path);
1566 smb2_util_mkdir(tree, path);
1567 smb2_util_rmdir(tree, path);
1568 talloc_free(path);
1571 /* give a bit of time for the events to propogate */
1572 tv = timeval_current();
1574 do {
1575 /* count events that have happened in each dir */
1576 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1577 notify.smb2.in.file.handle = dirs[i].h1;
1578 req = smb2_notify_send(tree, &(notify.smb2));
1579 smb2_cancel(req);
1580 notify.smb2.out.num_changes = 0;
1581 status = smb2_notify_recv(req, torture,
1582 &(notify.smb2));
1583 dirs[i].counted += notify.smb2.out.num_changes;
1586 all_done = true;
1588 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1589 if (dirs[i].counted != dirs[i].expected) {
1590 all_done = false;
1593 } while (!all_done && timeval_elapsed(&tv) < 20);
1595 torture_comment(torture, "took %.4f seconds to propogate all events\n",
1596 timeval_elapsed(&tv));
1598 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1599 if (dirs[i].counted != dirs[i].expected) {
1600 torture_comment(torture,
1601 "ERROR: i=%d expected %d got %d for '%s'\n",
1602 i, dirs[i].expected, dirs[i].counted,
1603 dirs[i].path);
1604 ret = false;
1609 run from the back, closing and deleting
1611 for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1612 smb2_util_close(tree, dirs[i].h1);
1613 smb2_util_rmdir(tree, dirs[i].path);
1616 done:
1617 smb2_deltree(tree, BASEDIR);
1618 smb2_util_rmdir(tree, BASEDIR);
1619 return ret;
1623 Test response when cached server events exceed single NT NOTFIY response
1624 packet size.
1627 static bool torture_smb2_notify_overflow(struct torture_context *torture,
1628 struct smb2_tree *tree)
1630 bool ret = true;
1631 NTSTATUS status;
1632 union smb_notify notify;
1633 union smb_open io;
1634 struct smb2_handle h1, h2;
1635 int count = 100;
1636 struct smb2_request *req1;
1637 int i;
1639 smb2_deltree(tree, BASEDIR);
1640 smb2_util_rmdir(tree, BASEDIR);
1642 torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1644 /* get a handle on the directory */
1645 ZERO_STRUCT(io.smb2);
1646 io.generic.level = RAW_OPEN_SMB2;
1647 io.smb2.in.create_flags = 0;
1648 io.smb2.in.desired_access = SEC_FILE_ALL;
1649 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1650 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1651 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1652 NTCREATEX_SHARE_ACCESS_WRITE;
1653 io.smb2.in.alloc_size = 0;
1654 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1655 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1656 io.smb2.in.security_flags = 0;
1657 io.smb2.in.fname = BASEDIR;
1659 status = smb2_create(tree, torture, &(io.smb2));
1660 CHECK_STATUS(status, NT_STATUS_OK);
1661 h1 = io.smb2.out.file.handle;
1663 /* ask for a change notify, on name changes. */
1664 ZERO_STRUCT(notify.smb2);
1665 notify.smb2.level = RAW_NOTIFY_NTTRANS;
1666 notify.smb2.in.buffer_size = 1000;
1667 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1668 notify.smb2.in.file.handle = h1;
1670 notify.smb2.in.recursive = true;
1671 req1 = smb2_notify_send(tree, &(notify.smb2));
1673 /* cancel initial requests so the buffer is setup */
1674 smb2_cancel(req1);
1675 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1676 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1678 /* open a lot of files, filling up the server side notify buffer */
1679 torture_comment(torture,
1680 "Testing overflowed buffer notify on create of %d files\n",
1681 count);
1683 for (i=0;i<count;i++) {
1684 char *fname = talloc_asprintf(torture,
1685 BASEDIR "\\test%d.txt", i);
1686 union smb_open io1;
1687 ZERO_STRUCT(io1.smb2);
1688 io1.generic.level = RAW_OPEN_SMB2;
1689 io1.smb2.in.create_flags = 0;
1690 io1.smb2.in.desired_access = SEC_FILE_ALL;
1691 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1692 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1693 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1694 NTCREATEX_SHARE_ACCESS_WRITE;
1695 io1.smb2.in.alloc_size = 0;
1696 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1697 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1698 io1.smb2.in.security_flags = 0;
1699 io1.smb2.in.fname = fname;
1701 h2 = custom_smb2_create(tree, torture, &(io1.smb2));
1702 talloc_free(fname);
1703 smb2_util_close(tree, h2);
1706 req1 = smb2_notify_send(tree, &(notify.smb2));
1707 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1708 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
1709 CHECK_VAL(notify.smb2.out.num_changes, 0);
1711 done:
1712 smb2_deltree(tree, BASEDIR);
1713 return ret;
1717 Test if notifications are returned for changes to the base directory.
1718 They shouldn't be.
1721 static bool torture_smb2_notify_basedir(struct torture_context *torture,
1722 struct smb2_tree *tree1,
1723 struct smb2_tree *tree2)
1725 bool ret = true;
1726 NTSTATUS status;
1727 union smb_notify notify;
1728 union smb_open io;
1729 struct smb2_handle h1;
1730 struct smb2_request *req1;
1732 smb2_deltree(tree1, BASEDIR);
1733 smb2_util_rmdir(tree1, BASEDIR);
1735 torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1737 /* get a handle on the directory */
1738 ZERO_STRUCT(io.smb2);
1739 io.generic.level = RAW_OPEN_SMB2;
1740 io.smb2.in.create_flags = 0;
1741 io.smb2.in.desired_access = SEC_FILE_ALL;
1742 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1743 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1744 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1745 NTCREATEX_SHARE_ACCESS_WRITE;
1746 io.smb2.in.alloc_size = 0;
1747 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1748 io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
1749 io.smb2.in.security_flags = 0;
1750 io.smb2.in.fname = BASEDIR;
1752 status = smb2_create(tree1, torture, &(io.smb2));
1753 CHECK_STATUS(status, NT_STATUS_OK);
1754 h1 = io.smb2.out.file.handle;
1756 /* create a test file that will also be modified */
1757 io.smb2.in.fname = BASEDIR "\\tname1";
1758 io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
1759 status = smb2_create(tree2, torture, &(io.smb2));
1760 CHECK_STATUS(status,NT_STATUS_OK);
1761 smb2_util_close(tree2, io.smb2.out.file.handle);
1763 /* ask for a change notify, on attribute changes. */
1764 ZERO_STRUCT(notify.smb2);
1765 notify.smb2.level = RAW_NOTIFY_SMB2;
1766 notify.smb2.in.buffer_size = 1000;
1767 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
1768 notify.smb2.in.file.handle = h1;
1769 notify.smb2.in.recursive = true;
1771 req1 = smb2_notify_send(tree1, &(notify.smb2));
1773 /* set attribute on the base dir */
1774 smb2_util_setatr(tree2, BASEDIR, FILE_ATTRIBUTE_HIDDEN);
1776 /* set attribute on a file to assure we receive a notification */
1777 smb2_util_setatr(tree2, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN);
1778 smb_msleep(200);
1780 /* check how many responses were given, expect only 1 for the file */
1781 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1782 CHECK_STATUS(status, NT_STATUS_OK);
1783 CHECK_VAL(notify.smb2.out.num_changes, 1);
1784 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
1785 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
1787 done:
1788 smb2_deltree(tree1, BASEDIR);
1789 return ret;
1794 create a secondary tree connect - used to test for a bug in Samba3 messaging
1795 with change notify
1797 static struct smb2_tree *secondary_tcon(struct smb2_tree *tree,
1798 struct torture_context *tctx)
1800 NTSTATUS status;
1801 const char *share, *host;
1802 struct smb2_tree *tree1;
1803 union smb_tcon tcon;
1805 share = torture_setting_string(tctx, "share", NULL);
1806 host = torture_setting_string(tctx, "host", NULL);
1808 torture_comment(tctx,
1809 "create a second tree context on the same session\n");
1810 tree1 = smb2_tree_init(tree->session, tctx, false);
1812 ZERO_STRUCT(tcon.smb2);
1813 tcon.generic.level = RAW_TCON_SMB2;
1814 tcon.smb2.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
1815 status = smb2_tree_connect(tree, &(tcon.smb2));
1816 if (!NT_STATUS_IS_OK(status)) {
1817 talloc_free(tree);
1818 torture_comment(tctx,"Failed to create secondary tree\n");
1819 return NULL;
1822 tree1->tid = tcon.smb2.out.tid;
1823 torture_comment(tctx,"tid1=%d tid2=%d\n", tree->tid, tree1->tid);
1825 return tree1;
1830 very simple change notify test
1832 static bool torture_smb2_notify_tcon(struct torture_context *torture,
1833 struct smb2_tree *tree)
1835 bool ret = true;
1836 NTSTATUS status;
1837 union smb_notify notify;
1838 union smb_open io;
1839 struct smb2_handle h1;
1840 struct smb2_request *req = NULL;
1841 struct smb2_tree *tree1 = NULL;
1842 const char *fname = BASEDIR "\\subdir-name";
1844 smb2_deltree(tree, BASEDIR);
1845 smb2_util_rmdir(tree, BASEDIR);
1847 torture_comment(torture, "TESTING SIMPLE CHANGE NOTIFY\n");
1850 get a handle on the directory
1853 ZERO_STRUCT(io.smb2);
1854 io.generic.level = RAW_OPEN_SMB2;
1855 io.smb2.in.create_flags = 0;
1856 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1857 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1858 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL |
1859 FILE_ATTRIBUTE_DIRECTORY;
1860 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1861 NTCREATEX_SHARE_ACCESS_WRITE;
1862 io.smb2.in.alloc_size = 0;
1863 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1864 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1865 io.smb2.in.security_flags = 0;
1866 io.smb2.in.fname = BASEDIR;
1868 status = smb2_create(tree, torture, &(io.smb2));
1869 CHECK_STATUS(status, NT_STATUS_OK);
1870 h1 = io.smb2.out.file.handle;
1872 /* ask for a change notify,
1873 on file or directory name changes */
1874 ZERO_STRUCT(notify.smb2);
1875 notify.smb2.level = RAW_NOTIFY_SMB2;
1876 notify.smb2.in.buffer_size = 1000;
1877 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1878 notify.smb2.in.file.handle = h1;
1879 notify.smb2.in.recursive = true;
1881 torture_comment(torture, "Testing notify mkdir\n");
1882 req = smb2_notify_send(tree, &(notify.smb2));
1883 smb2_cancel(req);
1884 status = smb2_notify_recv(req, torture, &(notify.smb2));
1885 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1887 notify.smb2.in.recursive = true;
1888 req = smb2_notify_send(tree, &(notify.smb2));
1889 status = smb2_util_mkdir(tree, fname);
1890 CHECK_STATUS(status, NT_STATUS_OK);
1892 status = smb2_notify_recv(req, torture, &(notify.smb2));
1893 CHECK_STATUS(status, NT_STATUS_OK);
1895 CHECK_VAL(notify.smb2.out.num_changes, 1);
1896 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
1897 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1899 torture_comment(torture, "Testing notify rmdir\n");
1900 req = smb2_notify_send(tree, &(notify.smb2));
1901 status = smb2_util_rmdir(tree, fname);
1902 CHECK_STATUS(status, NT_STATUS_OK);
1904 status = smb2_notify_recv(req, torture, &(notify.smb2));
1905 CHECK_STATUS(status, NT_STATUS_OK);
1906 CHECK_VAL(notify.smb2.out.num_changes, 1);
1907 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
1908 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1910 torture_comment(torture, "SIMPLE CHANGE NOTIFY OK\n");
1912 torture_comment(torture, "TESTING WITH SECONDARY TCON\n");
1913 tree1 = secondary_tcon(tree, torture);
1915 torture_comment(torture, "Testing notify mkdir\n");
1916 req = smb2_notify_send(tree, &(notify.smb2));
1917 smb2_util_mkdir(tree1, fname);
1919 status = smb2_notify_recv(req, torture, &(notify.smb2));
1920 CHECK_STATUS(status, NT_STATUS_OK);
1922 CHECK_VAL(notify.smb2.out.num_changes, 1);
1923 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
1924 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1926 torture_comment(torture, "Testing notify rmdir\n");
1927 req = smb2_notify_send(tree, &(notify.smb2));
1928 smb2_util_rmdir(tree, fname);
1930 status = smb2_notify_recv(req, torture, &(notify.smb2));
1931 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_REMOVED);
1934 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1936 torture_comment(torture, "CHANGE NOTIFY WITH TCON OK\n");
1938 torture_comment(torture, "Disconnecting secondary tree\n");
1939 status = smb2_tdis(tree1);
1940 CHECK_STATUS(status, NT_STATUS_OK);
1941 talloc_free(tree1);
1943 torture_comment(torture, "Testing notify mkdir\n");
1944 req = smb2_notify_send(tree, &(notify.smb2));
1945 smb2_util_mkdir(tree, fname);
1947 status = smb2_notify_recv(req, torture, &(notify.smb2));
1948 CHECK_STATUS(status, NT_STATUS_OK);
1950 CHECK_VAL(notify.smb2.out.num_changes, 1);
1951 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
1952 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1954 torture_comment(torture, "Testing notify rmdir\n");
1955 req = smb2_notify_send(tree, &(notify.smb2));
1956 smb2_util_rmdir(tree, fname);
1958 status = smb2_notify_recv(req, torture, &(notify.smb2));
1959 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_REMOVED);
1962 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1964 torture_comment(torture, "CHANGE NOTIFY WITH TDIS OK\n");
1965 done:
1966 smb2_util_close(tree, h1);
1967 smb2_deltree(tree, BASEDIR);
1969 return ret;
1973 basic testing of SMB2 change notify
1975 struct torture_suite *torture_smb2_notify_init(void)
1977 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "notify");
1979 torture_suite_add_1smb2_test(suite, "valid-req", test_valid_request);
1980 torture_suite_add_1smb2_test(suite, "tcon", torture_smb2_notify_tcon);
1981 torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir);
1982 torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask);
1983 torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
1984 torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
1985 torture_suite_add_2smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
1986 torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
1987 torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
1988 torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
1989 torture_suite_add_1smb2_test(suite, "file", torture_smb2_notify_file);
1990 torture_suite_add_1smb2_test(suite, "tcp", torture_smb2_notify_tcp_disconnect);
1991 torture_suite_add_2smb2_test(suite, "rec", torture_smb2_notify_recursive);
1992 torture_suite_add_1smb2_test(suite, "overflow", torture_smb2_notify_overflow);
1994 suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");
1996 return suite;