smbtorture: Correctly initialize notify request in smb2.notify.tree
[Samba.git] / source4 / torture / smb2 / notify.c
blobde4ff58bbfdf6a7ac1a94ec497586399c72817f1
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 WAIT_FOR_ASYNC_RESPONSE(req) \
73 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \
74 if (tevent_loop_once(torture->ev) != 0) { \
75 break; \
76 } \
79 #define BASEDIR "test_notify"
80 #define FNAME "smb2-notify01.dat"
82 static bool test_valid_request(struct torture_context *torture,
83 struct smb2_tree *tree)
85 bool ret = true;
86 NTSTATUS status;
87 struct smb2_handle dh;
88 struct smb2_notify n;
89 struct smb2_request *req;
90 uint32_t max_buffer_size;
92 torture_comment(torture, "TESTING VALIDITY OF CHANGE NOTIFY REQUEST\n");
94 smb2_util_unlink(tree, FNAME);
96 status = smb2_util_roothandle(tree, &dh);
97 CHECK_STATUS(status, NT_STATUS_OK);
99 /* 0x00080000 is the default max buffer size for Windows servers
100 * pre-Win7 */
101 max_buffer_size = torture_setting_ulong(torture, "cn_max_buffer_size",
102 0x00080000);
104 n.in.recursive = 0x0000;
105 n.in.buffer_size = max_buffer_size;
106 n.in.file.handle = dh;
107 n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
108 n.in.unknown = 0x00000000;
109 req = smb2_notify_send(tree, &n);
111 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
112 if (tevent_loop_once(torture->ev) != 0) {
113 break;
117 status = torture_setup_complex_file(tree, FNAME);
118 CHECK_STATUS(status, NT_STATUS_OK);
120 status = smb2_notify_recv(req, torture, &n);
121 CHECK_STATUS(status, NT_STATUS_OK);
122 CHECK_VAL(n.out.num_changes, 1);
123 CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_ADDED);
124 CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
127 * if the change response doesn't fit in the buffer
128 * NOTIFY_ENUM_DIR is returned.
130 n.in.buffer_size = 0x00000000;
131 req = smb2_notify_send(tree, &n);
133 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
134 if (tevent_loop_once(torture->ev) != 0) {
135 break;
139 status = torture_setup_complex_file(tree, FNAME);
140 CHECK_STATUS(status, NT_STATUS_OK);
142 status = smb2_notify_recv(req, torture, &n);
143 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
146 * if the change response fits in the buffer we get
147 * NT_STATUS_OK again
149 n.in.buffer_size = max_buffer_size;
150 req = smb2_notify_send(tree, &n);
152 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
153 if (tevent_loop_once(torture->ev) != 0) {
154 break;
158 status = torture_setup_complex_file(tree, FNAME);
159 CHECK_STATUS(status, NT_STATUS_OK);
161 status = smb2_notify_recv(req, torture, &n);
162 CHECK_STATUS(status, NT_STATUS_OK);
163 CHECK_VAL(n.out.num_changes, 3);
164 CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_REMOVED);
165 CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
166 CHECK_VAL(n.out.changes[1].action, NOTIFY_ACTION_ADDED);
167 CHECK_WIRE_STR(n.out.changes[1].name, FNAME);
168 CHECK_VAL(n.out.changes[2].action, NOTIFY_ACTION_MODIFIED);
169 CHECK_WIRE_STR(n.out.changes[2].name, FNAME);
171 /* if the first notify returns NOTIFY_ENUM_DIR, all do */
172 status = smb2_util_close(tree, dh);
173 CHECK_STATUS(status, NT_STATUS_OK);
174 status = smb2_util_roothandle(tree, &dh);
175 CHECK_STATUS(status, NT_STATUS_OK);
177 n.in.recursive = 0x0000;
178 n.in.buffer_size = 0x00000001;
179 n.in.file.handle = dh;
180 n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
181 n.in.unknown = 0x00000000;
182 req = smb2_notify_send(tree, &n);
184 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
185 if (tevent_loop_once(torture->ev) != 0) {
186 break;
190 status = torture_setup_complex_file(tree, FNAME);
191 CHECK_STATUS(status, NT_STATUS_OK);
193 status = smb2_notify_recv(req, torture, &n);
194 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
196 n.in.buffer_size = max_buffer_size;
197 req = smb2_notify_send(tree, &n);
198 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
199 if (tevent_loop_once(torture->ev) != 0) {
200 break;
204 status = torture_setup_complex_file(tree, FNAME);
205 CHECK_STATUS(status, NT_STATUS_OK);
207 status = smb2_notify_recv(req, torture, &n);
208 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
210 /* if the buffer size is too large, we get invalid parameter */
211 n.in.recursive = 0x0000;
212 n.in.buffer_size = max_buffer_size + 1;
213 n.in.file.handle = dh;
214 n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
215 n.in.unknown = 0x00000000;
216 req = smb2_notify_send(tree, &n);
217 status = smb2_notify_recv(req, torture, &n);
218 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
220 done:
221 return ret;
225 basic testing of change notify on directories
227 static bool torture_smb2_notify_dir(struct torture_context *torture,
228 struct smb2_tree *tree1,
229 struct smb2_tree *tree2)
231 bool ret = true;
232 NTSTATUS status;
233 union smb_notify notify;
234 union smb_open io;
235 union smb_close cl;
236 int i, count;
237 struct smb2_handle h1, h2;
238 struct smb2_request *req, *req2;
239 const char *fname = BASEDIR "\\subdir-name";
240 extern int torture_numops;
242 torture_comment(torture, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
244 smb2_deltree(tree1, BASEDIR);
245 smb2_util_rmdir(tree1, BASEDIR);
247 get a handle on the directory
249 ZERO_STRUCT(io.smb2);
250 io.generic.level = RAW_OPEN_SMB2;
251 io.smb2.in.create_flags = 0;
252 io.smb2.in.desired_access = SEC_FILE_ALL;
253 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
254 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
255 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
256 NTCREATEX_SHARE_ACCESS_WRITE;
257 io.smb2.in.alloc_size = 0;
258 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
259 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
260 io.smb2.in.security_flags = 0;
261 io.smb2.in.fname = BASEDIR;
263 status = smb2_create(tree1, torture, &(io.smb2));
264 CHECK_STATUS(status, NT_STATUS_OK);
265 h1 = io.smb2.out.file.handle;
267 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
268 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ;
269 status = smb2_create(tree1, torture, &(io.smb2));
270 CHECK_STATUS(status, NT_STATUS_OK);
271 h2 = io.smb2.out.file.handle;
273 /* ask for a change notify,
274 on file or directory name changes */
275 ZERO_STRUCT(notify.smb2);
276 notify.smb2.level = RAW_NOTIFY_SMB2;
277 notify.smb2.in.buffer_size = 1000;
278 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
279 notify.smb2.in.file.handle = h1;
280 notify.smb2.in.recursive = true;
282 torture_comment(torture, "Testing notify cancel\n");
284 req = smb2_notify_send(tree1, &(notify.smb2));
285 smb2_cancel(req);
286 status = smb2_notify_recv(req, torture, &(notify.smb2));
287 CHECK_STATUS(status, NT_STATUS_CANCELLED);
289 torture_comment(torture, "Testing notify mkdir\n");
291 req = smb2_notify_send(tree1, &(notify.smb2));
292 smb2_util_mkdir(tree2, fname);
294 status = smb2_notify_recv(req, torture, &(notify.smb2));
295 CHECK_STATUS(status, NT_STATUS_OK);
297 CHECK_VAL(notify.smb2.out.num_changes, 1);
298 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
299 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
301 torture_comment(torture, "Testing notify rmdir\n");
303 req = smb2_notify_send(tree1, &(notify.smb2));
304 smb2_util_rmdir(tree2, fname);
306 status = smb2_notify_recv(req, torture, &(notify.smb2));
307 CHECK_STATUS(status, NT_STATUS_OK);
308 CHECK_VAL(notify.smb2.out.num_changes, 1);
309 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
310 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
312 torture_comment(torture,
313 "Testing notify mkdir - rmdir - mkdir - rmdir\n");
315 smb2_util_mkdir(tree2, fname);
316 smb2_util_rmdir(tree2, fname);
317 smb2_util_mkdir(tree2, fname);
318 smb2_util_rmdir(tree2, fname);
319 smb_msleep(200);
320 req = smb2_notify_send(tree1, &(notify.smb2));
321 status = smb2_notify_recv(req, torture, &(notify.smb2));
322 CHECK_STATUS(status, NT_STATUS_OK);
323 CHECK_VAL(notify.smb2.out.num_changes, 4);
324 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
325 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
326 CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_REMOVED);
327 CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name");
328 CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_ADDED);
329 CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name");
330 CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_REMOVED);
331 CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name");
333 count = torture_numops;
334 torture_comment(torture,
335 "Testing buffered notify on create of %d files\n", count);
336 for (i=0;i<count;i++) {
337 struct smb2_handle h12;
338 char *fname2 = talloc_asprintf(torture, BASEDIR "\\test%d.txt",
341 ZERO_STRUCT(io.smb2);
342 io.generic.level = RAW_OPEN_SMB2;
343 io.smb2.in.create_flags = 0;
344 io.smb2.in.desired_access = SEC_FILE_ALL;
345 io.smb2.in.create_options =
346 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
347 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
348 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
349 NTCREATEX_SHARE_ACCESS_WRITE;
350 io.smb2.in.alloc_size = 0;
351 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
352 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
353 io.smb2.in.security_flags = 0;
354 io.smb2.in.fname = fname2;
356 status = smb2_create(tree1, torture, &(io.smb2));
357 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
358 torture_comment(torture, "Failed to create %s \n",
359 fname);
360 ret = false;
361 goto done;
363 h12 = io.smb2.out.file.handle;
364 talloc_free(fname2);
365 smb2_util_close(tree1, h12);
368 /* (1st notify) setup a new notify on a different directory handle.
369 This new notify won't see the events above. */
370 notify.smb2.in.file.handle = h2;
371 req2 = smb2_notify_send(tree1, &(notify.smb2));
373 /* (2nd notify) whereas this notify will see the above buffered events,
374 and it directly returns the buffered events */
375 notify.smb2.in.file.handle = h1;
376 req = smb2_notify_send(tree1, &(notify.smb2));
378 status = smb2_util_unlink(tree1, BASEDIR "\\nonexistent.txt");
379 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
381 /* (1st unlink) as the 2nd notify directly returns,
382 this unlink is only seen by the 1st notify and
383 the 3rd notify (later) */
384 torture_comment(torture,
385 "Testing notify on unlink for the first file\n");
386 status = smb2_util_unlink(tree2, BASEDIR "\\test0.txt");
387 CHECK_STATUS(status, NT_STATUS_OK);
389 /* receive the reply from the 2nd notify */
390 status = smb2_notify_recv(req, torture, &(notify.smb2));
391 CHECK_STATUS(status, NT_STATUS_OK);
393 CHECK_VAL(notify.smb2.out.num_changes, count);
394 for (i=1;i<count;i++) {
395 CHECK_VAL(notify.smb2.out.changes[i].action,
396 NOTIFY_ACTION_ADDED);
398 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
400 torture_comment(torture, "and now from the 1st notify\n");
401 status = smb2_notify_recv(req2, torture, &(notify.smb2));
402 CHECK_STATUS(status, NT_STATUS_OK);
403 CHECK_VAL(notify.smb2.out.num_changes, 1);
404 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
405 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
407 torture_comment(torture,
408 "(3rd notify) this notify will only see the 1st unlink\n");
409 req = smb2_notify_send(tree1, &(notify.smb2));
411 status = smb2_util_unlink(tree1, BASEDIR "\\nonexistent.txt");
412 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
414 for (i=1;i<count;i++) {
415 char *fname2 = talloc_asprintf(torture,
416 BASEDIR "\\test%d.txt", i);
417 status = smb2_util_unlink(tree2, fname2);
418 CHECK_STATUS(status, NT_STATUS_OK);
419 talloc_free(fname2);
422 /* receive the 3rd notify */
423 status = smb2_notify_recv(req, torture, &(notify.smb2));
424 CHECK_STATUS(status, NT_STATUS_OK);
425 CHECK_VAL(notify.smb2.out.num_changes, 1);
426 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
427 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
429 /* and we now see the rest of the unlink calls on both
430 * directory handles */
431 notify.smb2.in.file.handle = h1;
432 sleep(3);
433 req = smb2_notify_send(tree1, &(notify.smb2));
434 status = smb2_notify_recv(req, torture, &(notify.smb2));
435 CHECK_STATUS(status, NT_STATUS_OK);
436 CHECK_VAL(notify.smb2.out.num_changes, count-1);
437 for (i=0;i<notify.smb2.out.num_changes;i++) {
438 CHECK_VAL(notify.smb2.out.changes[i].action,
439 NOTIFY_ACTION_REMOVED);
441 notify.smb2.in.file.handle = h2;
442 req = smb2_notify_send(tree1, &(notify.smb2));
443 status = smb2_notify_recv(req, torture, &(notify.smb2));
444 CHECK_STATUS(status, NT_STATUS_OK);
445 CHECK_VAL(notify.smb2.out.num_changes, count-1);
446 for (i=0;i<notify.smb2.out.num_changes;i++) {
447 CHECK_VAL(notify.smb2.out.changes[i].action,
448 NOTIFY_ACTION_REMOVED);
451 torture_comment(torture,
452 "Testing if a close() on the dir handle triggers the notify reply\n");
454 notify.smb2.in.file.handle = h1;
455 req = smb2_notify_send(tree1, &(notify.smb2));
457 ZERO_STRUCT(cl.smb2);
458 cl.smb2.level = RAW_CLOSE_SMB2;
459 cl.smb2.in.file.handle = h1;
460 status = smb2_close(tree1, &(cl.smb2));
461 CHECK_STATUS(status, NT_STATUS_OK);
463 status = smb2_notify_recv(req, torture, &(notify.smb2));
464 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
465 CHECK_VAL(notify.smb2.out.num_changes, 9);
467 done:
468 smb2_util_close(tree1, h1);
469 smb2_util_close(tree1, h2);
470 smb2_deltree(tree1, BASEDIR);
471 return ret;
474 static struct smb2_handle custom_smb2_create(struct smb2_tree *tree,
475 struct torture_context *torture,
476 struct smb2_create *smb2)
478 struct smb2_handle h1;
479 bool ret = true;
480 NTSTATUS status;
481 smb2_deltree(tree, smb2->in.fname);
482 status = smb2_create(tree, torture, smb2);
483 CHECK_STATUS(status, NT_STATUS_OK);
484 h1 = smb2->out.file.handle;
485 done:
486 if (!ret) {
487 h1 = (struct smb2_handle) {
488 .data = { 0 , 0},
491 return h1;
495 testing of recursive change notify
498 static bool torture_smb2_notify_recursive(struct torture_context *torture,
499 struct smb2_tree *tree1,
500 struct smb2_tree *tree2)
502 bool ret = true;
503 NTSTATUS status;
504 union smb_notify notify;
505 union smb_open io, io1;
506 union smb_setfileinfo sinfo;
507 struct smb2_handle h1;
508 struct smb2_request *req1, *req2;
510 smb2_deltree(tree1, BASEDIR);
511 smb2_util_rmdir(tree1, BASEDIR);
513 torture_comment(torture, "TESTING CHANGE NOTIFY WITH RECURSION\n");
516 get a handle on the directory
518 ZERO_STRUCT(io.smb2);
519 io.generic.level = RAW_OPEN_SMB2;
520 io.smb2.in.create_flags = 0;
521 io.smb2.in.desired_access = SEC_FILE_ALL;
522 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
523 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
524 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
525 NTCREATEX_SHARE_ACCESS_WRITE;
526 io.smb2.in.alloc_size = 0;
527 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
528 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
529 io.smb2.in.security_flags = 0;
530 io.smb2.in.fname = BASEDIR;
532 status = smb2_create(tree1, torture, &(io.smb2));
533 CHECK_STATUS(status, NT_STATUS_OK);
534 h1 = io.smb2.out.file.handle;
536 /* ask for a change notify, on file or directory name
537 changes. Setup both with and without recursion */
538 ZERO_STRUCT(notify.smb2);
539 notify.smb2.level = RAW_NOTIFY_SMB2;
540 notify.smb2.in.buffer_size = 1000;
541 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
542 FILE_NOTIFY_CHANGE_ATTRIBUTES |
543 FILE_NOTIFY_CHANGE_CREATION;
544 notify.smb2.in.file.handle = h1;
546 notify.smb2.in.recursive = true;
547 req1 = smb2_notify_send(tree1, &(notify.smb2));
548 smb2_cancel(req1);
549 status = smb2_notify_recv(req1, torture, &(notify.smb2));
550 CHECK_STATUS(status, NT_STATUS_CANCELLED);
552 notify.smb2.in.recursive = false;
553 req2 = smb2_notify_send(tree1, &(notify.smb2));
554 smb2_cancel(req2);
555 status = smb2_notify_recv(req2, torture, &(notify.smb2));
556 CHECK_STATUS(status, NT_STATUS_CANCELLED);
558 ZERO_STRUCT(io1.smb2);
559 io1.generic.level = RAW_OPEN_SMB2;
560 io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
561 io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
562 SEC_RIGHTS_FILE_WRITE|
563 SEC_RIGHTS_FILE_ALL;
564 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
565 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
566 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
567 NTCREATEX_SHARE_ACCESS_WRITE |
568 NTCREATEX_SHARE_ACCESS_DELETE;
569 io1.smb2.in.alloc_size = 0;
570 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
571 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
572 io1.smb2.in.security_flags = 0;
573 io1.smb2.in.fname = BASEDIR "\\subdir-name";
574 status = smb2_create(tree2, torture, &(io1.smb2));
575 CHECK_STATUS(status, NT_STATUS_OK);
576 smb2_util_close(tree2, io1.smb2.out.file.handle);
578 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname1";
579 status = smb2_create(tree2, torture, &(io1.smb2));
580 CHECK_STATUS(status, NT_STATUS_OK);
581 ZERO_STRUCT(sinfo);
582 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
583 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
584 sinfo.rename_information.in.overwrite = 0;
585 sinfo.rename_information.in.root_fid = 0;
586 sinfo.rename_information.in.new_name =
587 BASEDIR "\\subdir-name\\subname1-r";
588 status = smb2_setinfo_file(tree2, &sinfo);
589 CHECK_STATUS(status, NT_STATUS_OK);
591 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
592 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname2";
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 "\\subname2-r";
601 status = smb2_setinfo_file(tree2, &sinfo);
602 CHECK_STATUS(status, NT_STATUS_OK);
604 io1.smb2.in.fname = BASEDIR "\\subname2-r";
605 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
606 status = smb2_create(tree2, torture, &(io1.smb2));
607 CHECK_STATUS(status, NT_STATUS_OK);
608 ZERO_STRUCT(sinfo);
609 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
610 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
611 sinfo.rename_information.in.overwrite = true;
612 sinfo.rename_information.in.root_fid = 0;
613 sinfo.rename_information.in.new_name = BASEDIR "\\subname3-r";
614 status = smb2_setinfo_file(tree2, &sinfo);
615 CHECK_STATUS(status, NT_STATUS_OK);
617 notify.smb2.in.completion_filter = 0;
618 notify.smb2.in.recursive = true;
619 smb_msleep(200);
620 req1 = smb2_notify_send(tree1, &(notify.smb2));
622 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name\\subname1-r");
623 CHECK_STATUS(status, NT_STATUS_OK);
624 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name");
625 CHECK_STATUS(status, NT_STATUS_OK);
626 status = smb2_util_unlink(tree2, BASEDIR "\\subname3-r");
627 CHECK_STATUS(status, NT_STATUS_OK);
629 notify.smb2.in.recursive = false;
630 req2 = smb2_notify_send(tree1, &(notify.smb2));
632 status = smb2_notify_recv(req1, torture, &(notify.smb2));
633 CHECK_STATUS(status, NT_STATUS_OK);
635 CHECK_VAL(notify.smb2.out.num_changes, 9);
636 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
637 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
638 CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_ADDED);
639 CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name\\subname1");
640 CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_OLD_NAME);
641 CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name\\subname1");
642 CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_NEW_NAME);
643 CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name\\subname1-r");
644 CHECK_VAL(notify.smb2.out.changes[4].action, NOTIFY_ACTION_ADDED);
645 CHECK_WIRE_STR(notify.smb2.out.changes[4].name, "subdir-name\\subname2");
646 CHECK_VAL(notify.smb2.out.changes[5].action, NOTIFY_ACTION_REMOVED);
647 CHECK_WIRE_STR(notify.smb2.out.changes[5].name, "subdir-name\\subname2");
648 CHECK_VAL(notify.smb2.out.changes[6].action, NOTIFY_ACTION_ADDED);
649 CHECK_WIRE_STR(notify.smb2.out.changes[6].name, "subname2-r");
650 CHECK_VAL(notify.smb2.out.changes[7].action, NOTIFY_ACTION_OLD_NAME);
651 CHECK_WIRE_STR(notify.smb2.out.changes[7].name, "subname2-r");
652 CHECK_VAL(notify.smb2.out.changes[8].action, NOTIFY_ACTION_NEW_NAME);
653 CHECK_WIRE_STR(notify.smb2.out.changes[8].name, "subname3-r");
655 done:
656 smb2_deltree(tree1, BASEDIR);
657 return ret;
661 testing of change notify mask change
664 static bool torture_smb2_notify_mask_change(struct torture_context *torture,
665 struct smb2_tree *tree1,
666 struct smb2_tree *tree2)
668 bool ret = true;
669 NTSTATUS status;
670 union smb_notify notify;
671 union smb_open io, io1;
672 struct smb2_handle h1;
673 struct smb2_request *req1, *req2;
674 union smb_setfileinfo sinfo;
676 smb2_deltree(tree1, BASEDIR);
677 smb2_util_rmdir(tree1, BASEDIR);
679 torture_comment(torture, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
682 get a handle on the directory
684 ZERO_STRUCT(io.smb2);
685 io.generic.level = RAW_OPEN_SMB2;
686 io.smb2.in.create_flags = 0;
687 io.smb2.in.desired_access = SEC_FILE_ALL;
688 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
689 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
690 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
691 NTCREATEX_SHARE_ACCESS_WRITE;
692 io.smb2.in.alloc_size = 0;
693 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
694 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
695 io.smb2.in.security_flags = 0;
696 io.smb2.in.fname = BASEDIR;
698 status = smb2_create(tree1, torture, &(io.smb2));
699 CHECK_STATUS(status, NT_STATUS_OK);
700 h1 = io.smb2.out.file.handle;
702 /* ask for a change notify, on file or directory name
703 changes. Setup both with and without recursion */
704 ZERO_STRUCT(notify.smb2);
705 notify.smb2.level = RAW_NOTIFY_SMB2;
706 notify.smb2.in.buffer_size = 1000;
707 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
708 notify.smb2.in.file.handle = h1;
710 notify.smb2.in.recursive = true;
711 req1 = smb2_notify_send(tree1, &(notify.smb2));
713 smb2_cancel(req1);
714 status = smb2_notify_recv(req1, torture, &(notify.smb2));
715 CHECK_STATUS(status, NT_STATUS_CANCELLED);
718 notify.smb2.in.recursive = false;
719 req2 = smb2_notify_send(tree1, &(notify.smb2));
721 smb2_cancel(req2);
722 status = smb2_notify_recv(req2, torture, &(notify.smb2));
723 CHECK_STATUS(status, NT_STATUS_CANCELLED);
725 notify.smb2.in.recursive = true;
726 req1 = smb2_notify_send(tree1, &(notify.smb2));
728 /* Set to hidden then back again. */
729 ZERO_STRUCT(io1.smb2);
730 io1.generic.level = RAW_OPEN_SMB2;
731 io1.smb2.in.create_flags = 0;
732 io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
733 SEC_RIGHTS_FILE_WRITE|
734 SEC_RIGHTS_FILE_ALL;
735 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
736 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
737 NTCREATEX_SHARE_ACCESS_WRITE |
738 NTCREATEX_SHARE_ACCESS_DELETE;
739 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
740 io1.smb2.in.security_flags = 0;
741 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
742 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
743 io1.smb2.in.fname = BASEDIR "\\tname1";
745 smb2_util_close(tree1,
746 custom_smb2_create(tree1, torture, &(io1.smb2)));
747 status = smb2_util_setatr(tree1, BASEDIR "\\tname1",
748 FILE_ATTRIBUTE_HIDDEN);
749 CHECK_STATUS(status, NT_STATUS_OK);
750 smb2_util_unlink(tree1, BASEDIR "\\tname1");
752 status = smb2_notify_recv(req1, torture, &(notify.smb2));
753 CHECK_STATUS(status, NT_STATUS_OK);
755 CHECK_VAL(notify.smb2.out.num_changes, 1);
756 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
757 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
759 /* Now try and change the mask to include other events.
760 * This should not work - once the mask is set on a directory
761 * h1 it seems to be fixed until the fnum is closed. */
763 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
764 FILE_NOTIFY_CHANGE_ATTRIBUTES |
765 FILE_NOTIFY_CHANGE_CREATION;
766 notify.smb2.in.recursive = true;
767 req1 = smb2_notify_send(tree1, &(notify.smb2));
769 notify.smb2.in.recursive = false;
770 req2 = smb2_notify_send(tree1, &(notify.smb2));
772 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
773 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
774 io1.smb2.in.fname = BASEDIR "\\subdir-name";
775 status = smb2_create(tree2, torture, &(io1.smb2));
776 CHECK_STATUS(status, NT_STATUS_OK);
777 smb2_util_close(tree2, io1.smb2.out.file.handle);
779 ZERO_STRUCT(sinfo);
780 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname1";
781 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
782 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
783 status = smb2_create(tree2, torture, &(io1.smb2));
784 CHECK_STATUS(status, NT_STATUS_OK);
785 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
786 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
787 sinfo.rename_information.in.overwrite = true;
788 sinfo.rename_information.in.root_fid = 0;
789 sinfo.rename_information.in.new_name =
790 BASEDIR "\\subdir-name\\subname1-r";
791 status = smb2_setinfo_file(tree2, &sinfo);
792 CHECK_STATUS(status, NT_STATUS_OK);
794 io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname2";
795 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
796 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
797 status = smb2_create(tree2, torture, &(io1.smb2));
798 CHECK_STATUS(status, NT_STATUS_OK);
799 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
800 sinfo.rename_information.in.new_name = BASEDIR "\\subname2-r";
801 status = smb2_setinfo_file(tree2, &sinfo);
802 CHECK_STATUS(status, NT_STATUS_OK);
803 smb2_util_close(tree2, io1.smb2.out.file.handle);
805 io1.smb2.in.fname = BASEDIR "\\subname2-r";
806 io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
807 status = smb2_create(tree2, torture, &(io1.smb2));
808 CHECK_STATUS(status, NT_STATUS_OK);
809 sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
810 sinfo.rename_information.in.new_name = BASEDIR "\\subname3-r";
811 status = smb2_setinfo_file(tree2, &sinfo);
812 CHECK_STATUS(status, NT_STATUS_OK);
813 smb2_util_close(tree2, io1.smb2.out.file.handle);
815 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name\\subname1-r");
816 CHECK_STATUS(status, NT_STATUS_OK);
817 status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name");
818 CHECK_STATUS(status, NT_STATUS_OK);
819 status = smb2_util_unlink(tree2, BASEDIR "\\subname3-r");
820 CHECK_STATUS(status, NT_STATUS_OK);
822 status = smb2_notify_recv(req1, torture, &(notify.smb2));
823 CHECK_STATUS(status, NT_STATUS_OK);
825 CHECK_VAL(notify.smb2.out.num_changes, 1);
826 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
827 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname2-r");
829 status = smb2_notify_recv(req2, torture, &(notify.smb2));
830 CHECK_STATUS(status, NT_STATUS_OK);
832 CHECK_VAL(notify.smb2.out.num_changes, 1);
833 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
834 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname3-r");
836 if (!ret) {
837 goto done;
840 done:
841 smb2_deltree(tree1, BASEDIR);
842 return ret;
846 testing of mask bits for change notify
849 static bool torture_smb2_notify_mask(struct torture_context *torture,
850 struct smb2_tree *tree1,
851 struct smb2_tree *tree2)
853 bool ret = true;
854 NTSTATUS status;
855 union smb_notify notify;
856 union smb_open io, io1;
857 struct smb2_handle h1, h2;
858 uint32_t mask;
859 int i;
860 char c = 1;
861 union smb_setfileinfo sinfo;
863 smb2_deltree(tree1, BASEDIR);
864 smb2_util_rmdir(tree1, BASEDIR);
866 torture_comment(torture, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
869 ZERO_STRUCT(h1);
870 ZERO_STRUCT(h2);
872 get a handle on the directory
874 ZERO_STRUCT(io.smb2);
875 io.generic.level = RAW_OPEN_SMB2;
876 io.smb2.in.create_flags = 0;
877 io.smb2.in.desired_access = SEC_FILE_ALL;
878 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
879 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
880 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
881 NTCREATEX_SHARE_ACCESS_WRITE;
882 io.smb2.in.alloc_size = 0;
883 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
884 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
885 io.smb2.in.security_flags = 0;
886 io.smb2.in.fname = BASEDIR;
888 ZERO_STRUCT(notify.smb2);
889 notify.smb2.level = RAW_NOTIFY_SMB2;
890 notify.smb2.in.buffer_size = 1000;
891 notify.smb2.in.recursive = true;
893 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
894 expected, nchanges) \
895 do { \
896 do { for (mask=i=0;i<32;i++) { \
897 struct smb2_request *req; \
898 status = smb2_create(tree1, torture, &(io.smb2)); \
899 CHECK_STATUS(status, NT_STATUS_OK); \
900 h1 = io.smb2.out.file.handle; \
901 setup \
902 notify.smb2.in.file.handle = h1; \
903 notify.smb2.in.completion_filter = (1<<i); \
904 /* cancel initial requests so the buffer is setup */ \
905 req = smb2_notify_send(tree1, &(notify.smb2)); \
906 smb2_cancel(req); \
907 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
908 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
909 /* send the change notify request */ \
910 req = smb2_notify_send(tree1, &(notify.smb2)); \
911 op \
912 smb_msleep(200); smb2_cancel(req); \
913 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
914 cleanup \
915 smb2_util_close(tree1, h1); \
916 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
917 CHECK_STATUS(status, NT_STATUS_OK); \
918 /* special case to cope with file rename behaviour */ \
919 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
920 notify.smb2.out.changes[0].action == \
921 NOTIFY_ACTION_MODIFIED && \
922 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
923 Action == NOTIFY_ACTION_OLD_NAME) { \
924 torture_comment(torture, \
925 "(rename file special handling OK)\n"); \
926 } else if (nchanges != notify.smb2.out.num_changes) { \
927 torture_result(torture, TORTURE_FAIL, \
928 "ERROR: nchanges=%d expected=%d "\
929 "action=%d filter=0x%08x\n", \
930 notify.smb2.out.num_changes, \
931 nchanges, \
932 notify.smb2.out.changes[0].action, \
933 notify.smb2.in.completion_filter); \
934 ret = false; \
935 } else if (notify.smb2.out.changes[0].action != Action) { \
936 torture_result(torture, TORTURE_FAIL, \
937 "ERROR: nchanges=%d action=%d " \
938 "expectedAction=%d filter=0x%08x\n", \
939 notify.smb2.out.num_changes, \
940 notify.smb2.out.changes[0].action, \
941 Action, \
942 notify.smb2.in.completion_filter); \
943 ret = false; \
944 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
945 "tname1") != 0) { \
946 torture_result(torture, TORTURE_FAIL, \
947 "ERROR: nchanges=%d action=%d " \
948 "filter=0x%08x name=%s\n", \
949 notify.smb2.out.num_changes, \
950 notify.smb2.out.changes[0].action, \
951 notify.smb2.in.completion_filter, \
952 notify.smb2.out.changes[0].name.s); \
953 ret = false; \
955 mask |= (1<<i); \
957 } while (0); \
958 } while (0);
960 torture_comment(torture, "Testing mkdir\n");
961 NOTIFY_MASK_TEST("Testing mkdir",;,
962 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
963 smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
964 NOTIFY_ACTION_ADDED,
965 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
967 torture_comment(torture, "Testing create file\n");
968 ZERO_STRUCT(io1.smb2);
969 io1.generic.level = RAW_OPEN_SMB2;
970 io1.smb2.in.create_flags = 0;
971 io1.smb2.in.desired_access = SEC_FILE_ALL;
972 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
973 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
974 NTCREATEX_SHARE_ACCESS_WRITE;
975 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
976 io1.smb2.in.security_flags = 0;
977 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
978 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
979 io1.smb2.in.fname = BASEDIR "\\tname1";
981 NOTIFY_MASK_TEST("Testing create file",;,
982 smb2_util_close(tree2, custom_smb2_create(tree2,
983 torture, &(io1.smb2)));,
984 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
985 NOTIFY_ACTION_ADDED,
986 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
988 torture_comment(torture, "Testing unlink\n");
989 NOTIFY_MASK_TEST("Testing unlink",
990 smb2_util_close(tree2, custom_smb2_create(tree2,
991 torture, &(io1.smb2)));,
992 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
994 NOTIFY_ACTION_REMOVED,
995 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
997 torture_comment(torture, "Testing rmdir\n");
998 NOTIFY_MASK_TEST("Testing rmdir",
999 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
1000 smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
1002 NOTIFY_ACTION_REMOVED,
1003 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
1005 torture_comment(torture, "Testing rename file\n");
1006 ZERO_STRUCT(sinfo);
1007 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1008 sinfo.rename_information.in.file.handle = h1;
1009 sinfo.rename_information.in.overwrite = true;
1010 sinfo.rename_information.in.root_fid = 0;
1011 sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
1012 NOTIFY_MASK_TEST("Testing rename file",
1013 smb2_util_close(tree2, custom_smb2_create(tree2,
1014 torture, &(io1.smb2)));,
1015 smb2_setinfo_file(tree2, &sinfo);,
1016 smb2_util_unlink(tree2, BASEDIR "\\tname2");,
1017 NOTIFY_ACTION_OLD_NAME,
1018 FILE_NOTIFY_CHANGE_FILE_NAME, 2);
1020 torture_comment(torture, "Testing rename dir\n");
1021 ZERO_STRUCT(sinfo);
1022 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1023 sinfo.rename_information.in.file.handle = h1;
1024 sinfo.rename_information.in.overwrite = true;
1025 sinfo.rename_information.in.root_fid = 0;
1026 sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
1027 NOTIFY_MASK_TEST("Testing rename dir",
1028 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
1029 smb2_setinfo_file(tree2, &sinfo);,
1030 smb2_util_rmdir(tree2, BASEDIR "\\tname2");,
1031 NOTIFY_ACTION_OLD_NAME,
1032 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
1034 torture_comment(torture, "Testing set path attribute\n");
1035 NOTIFY_MASK_TEST("Testing set path attribute",
1036 smb2_util_close(tree2, custom_smb2_create(tree2,
1037 torture, &(io.smb2)));,
1038 smb2_util_setatr(tree2, BASEDIR "\\tname1",
1039 FILE_ATTRIBUTE_HIDDEN);,
1040 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1041 NOTIFY_ACTION_MODIFIED,
1042 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
1044 torture_comment(torture, "Testing set path write time\n");
1045 ZERO_STRUCT(sinfo);
1046 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1047 sinfo.generic.in.file.handle = h1;
1048 sinfo.basic_info.in.write_time = 1000;
1049 NOTIFY_MASK_TEST("Testing set path write time",
1050 smb2_util_close(tree2, custom_smb2_create(tree2,
1051 torture, &(io1.smb2)));,
1052 smb2_setinfo_file(tree2, &sinfo);,
1053 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1054 NOTIFY_ACTION_MODIFIED,
1055 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
1057 if (torture_setting_bool(torture, "samba3", false)) {
1058 torture_comment(torture,
1059 "Samba3 does not yet support create times "
1060 "everywhere\n");
1062 else {
1063 ZERO_STRUCT(sinfo);
1064 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1065 sinfo.generic.in.file.handle = h1;
1066 sinfo.basic_info.in.create_time = 0;
1067 torture_comment(torture, "Testing set file create time\n");
1068 NOTIFY_MASK_TEST("Testing set file create time",
1069 smb2_create_complex_file(tree2,
1070 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_CREATION, 1);
1078 ZERO_STRUCT(sinfo);
1079 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1080 sinfo.generic.in.file.handle = h1;
1081 sinfo.basic_info.in.access_time = 0;
1082 torture_comment(torture, "Testing set file access time\n");
1083 NOTIFY_MASK_TEST("Testing set file access time",
1084 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1085 smb2_setinfo_file(tree2, &sinfo);,
1086 (smb2_util_close(tree2, h2),
1087 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1088 NOTIFY_ACTION_MODIFIED,
1089 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
1091 ZERO_STRUCT(sinfo);
1092 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1093 sinfo.generic.in.file.handle = h1;
1094 sinfo.basic_info.in.change_time = 0;
1095 torture_comment(torture, "Testing set file change time\n");
1096 NOTIFY_MASK_TEST("Testing set file change time",
1097 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1098 smb2_setinfo_file(tree2, &sinfo);,
1099 (smb2_util_close(tree2, h2),
1100 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1101 NOTIFY_ACTION_MODIFIED,
1102 0, 1);
1105 torture_comment(torture, "Testing write\n");
1106 NOTIFY_MASK_TEST("Testing write",
1107 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1108 smb2_util_write(tree2, h2, &c, 10000, 1);,
1109 (smb2_util_close(tree2, h2),
1110 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1111 NOTIFY_ACTION_MODIFIED,
1112 0, 1);
1114 done:
1115 smb2_deltree(tree1, BASEDIR);
1116 return ret;
1120 basic testing of change notify on files
1122 static bool torture_smb2_notify_file(struct torture_context *torture,
1123 struct smb2_tree *tree)
1125 NTSTATUS status;
1126 bool ret = true;
1127 union smb_open io;
1128 union smb_close cl;
1129 union smb_notify notify;
1130 struct smb2_request *req;
1131 struct smb2_handle h1;
1132 const char *fname = BASEDIR "\\file.txt";
1134 smb2_deltree(tree, BASEDIR);
1135 smb2_util_rmdir(tree, BASEDIR);
1137 torture_comment(torture, "TESTING CHANGE NOTIFY ON FILES\n");
1138 status = torture_smb2_testdir(tree, BASEDIR, &h1);
1139 CHECK_STATUS(status, NT_STATUS_OK);
1141 ZERO_STRUCT(io.smb2);
1142 io.generic.level = RAW_OPEN_SMB2;
1143 io.smb2.in.create_flags = 0;
1144 io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
1145 io.smb2.in.create_options = 0;
1146 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1147 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1148 NTCREATEX_SHARE_ACCESS_WRITE;
1149 io.smb2.in.alloc_size = 0;
1150 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1151 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1152 io.smb2.in.security_flags = 0;
1153 io.smb2.in.fname = fname;
1154 status = smb2_create(tree, torture, &(io.smb2));
1155 CHECK_STATUS(status, NT_STATUS_OK);
1156 h1 = io.smb2.out.file.handle;
1158 /* ask for a change notify,
1159 on file or directory name changes */
1160 ZERO_STRUCT(notify.smb2);
1161 notify.smb2.level = RAW_NOTIFY_SMB2;
1162 notify.smb2.in.file.handle = h1;
1163 notify.smb2.in.buffer_size = 1000;
1164 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
1165 notify.smb2.in.recursive = false;
1167 torture_comment(torture,
1168 "Testing if notifies on file handles are invalid (should be)\n");
1170 req = smb2_notify_send(tree, &(notify.smb2));
1171 status = smb2_notify_recv(req, torture, &(notify.smb2));
1172 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1174 ZERO_STRUCT(cl.smb2);
1175 cl.close.level = RAW_CLOSE_SMB2;
1176 cl.close.in.file.handle = h1;
1177 status = smb2_close(tree, &(cl.smb2));
1178 CHECK_STATUS(status, NT_STATUS_OK);
1180 status = smb2_util_unlink(tree, fname);
1181 CHECK_STATUS(status, NT_STATUS_OK);
1183 done:
1184 smb2_deltree(tree, BASEDIR);
1185 return ret;
1188 basic testing of change notifies followed by a tdis
1191 static bool torture_smb2_notify_tree_disconnect(
1192 struct torture_context *torture,
1193 struct smb2_tree *tree)
1195 bool ret = true;
1196 NTSTATUS status;
1197 union smb_notify notify;
1198 union smb_open io;
1199 struct smb2_handle h1;
1200 struct smb2_request *req;
1202 smb2_deltree(tree, BASEDIR);
1203 smb2_util_rmdir(tree, BASEDIR);
1205 torture_comment(torture, "TESTING CHANGE NOTIFY+CANCEL FOLLOWED BY "
1206 "TREE-DISCONNECT\n");
1209 get a handle on the directory
1211 ZERO_STRUCT(io.smb2);
1212 io.generic.level = RAW_OPEN_SMB2;
1213 io.smb2.in.create_flags = 0;
1214 io.smb2.in.desired_access = SEC_FILE_ALL;
1215 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1216 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1217 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1218 NTCREATEX_SHARE_ACCESS_WRITE;
1219 io.smb2.in.alloc_size = 0;
1220 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1221 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1222 io.smb2.in.security_flags = 0;
1223 io.smb2.in.fname = BASEDIR;
1225 status = smb2_create(tree, torture, &(io.smb2));
1226 CHECK_STATUS(status, NT_STATUS_OK);
1227 h1 = io.smb2.out.file.handle;
1229 /* ask for a change notify,
1230 on file or directory name changes */
1231 ZERO_STRUCT(notify.smb2);
1232 notify.smb2.level = RAW_NOTIFY_SMB2;
1233 notify.smb2.in.buffer_size = 1000;
1234 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1235 notify.smb2.in.file.handle = h1;
1236 notify.smb2.in.recursive = true;
1238 req = smb2_notify_send(tree, &(notify.smb2));
1239 smb2_cancel(req);
1240 status = smb2_notify_recv(req, torture, &(notify.smb2));
1242 status = smb2_tdis(tree);
1243 CHECK_STATUS(status, NT_STATUS_OK);
1245 req = smb2_notify_send(tree, &(notify.smb2));
1247 smb2_notify_recv(req, torture, &(notify.smb2));
1248 CHECK_STATUS(status, NT_STATUS_OK);
1249 CHECK_VAL(notify.smb2.out.num_changes, 0);
1251 done:
1252 smb2_deltree(tree, BASEDIR);
1253 return ret;
1257 testing of change notifies followed by a tdis - no cancel
1260 static bool torture_smb2_notify_tree_disconnect_1(
1261 struct torture_context *torture,
1262 struct smb2_tree *tree)
1264 bool ret = true;
1265 NTSTATUS status;
1266 union smb_notify notify;
1267 union smb_open io;
1268 struct smb2_handle h1;
1269 struct smb2_request *req;
1271 smb2_deltree(tree, BASEDIR);
1272 smb2_util_rmdir(tree, BASEDIR);
1274 torture_comment(torture, "TESTING CHANGE NOTIFY ASYNC FOLLOWED BY "
1275 "TREE-DISCONNECT\n");
1278 get a handle on the directory
1280 ZERO_STRUCT(io.smb2);
1281 io.generic.level = RAW_OPEN_SMB2;
1282 io.smb2.in.create_flags = 0;
1283 io.smb2.in.desired_access = SEC_FILE_ALL;
1284 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1285 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1286 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1287 NTCREATEX_SHARE_ACCESS_WRITE;
1288 io.smb2.in.alloc_size = 0;
1289 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1290 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1291 io.smb2.in.security_flags = 0;
1292 io.smb2.in.fname = BASEDIR;
1294 status = smb2_create(tree, torture, &(io.smb2));
1295 CHECK_STATUS(status, NT_STATUS_OK);
1296 h1 = io.smb2.out.file.handle;
1298 /* ask for a change notify,
1299 on file or directory name changes */
1300 ZERO_STRUCT(notify.smb2);
1301 notify.smb2.level = RAW_NOTIFY_SMB2;
1302 notify.smb2.in.buffer_size = 1000;
1303 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1304 notify.smb2.in.file.handle = h1;
1305 notify.smb2.in.recursive = true;
1307 req = smb2_notify_send(tree, &(notify.smb2));
1308 WAIT_FOR_ASYNC_RESPONSE(req);
1310 status = smb2_tdis(tree);
1311 CHECK_STATUS(status, NT_STATUS_OK);
1313 status = smb2_notify_recv(req, torture, &(notify.smb2));
1314 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1315 CHECK_VAL(notify.smb2.out.num_changes, 0);
1317 done:
1318 smb2_deltree(tree, BASEDIR);
1319 return ret;
1323 basic testing of change notifies followed by a close
1326 static bool torture_smb2_notify_close(struct torture_context *torture,
1327 struct smb2_tree *tree1)
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(tree1, BASEDIR);
1337 smb2_util_rmdir(tree1, BASEDIR);
1339 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1342 get a handle on the directory
1344 ZERO_STRUCT(io.smb2);
1345 io.generic.level = RAW_OPEN_SMB2;
1346 io.smb2.in.create_flags = 0;
1347 io.smb2.in.desired_access = SEC_FILE_ALL;
1348 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1349 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1350 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1351 NTCREATEX_SHARE_ACCESS_WRITE;
1352 io.smb2.in.alloc_size = 0;
1353 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1354 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1355 io.smb2.in.security_flags = 0;
1356 io.smb2.in.fname = BASEDIR;
1358 status = smb2_create(tree1, torture, &(io.smb2));
1359 CHECK_STATUS(status, NT_STATUS_OK);
1361 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1362 status = smb2_create(tree1, torture, &(io.smb2));
1363 CHECK_STATUS(status, NT_STATUS_OK);
1364 h1 = io.smb2.out.file.handle;
1366 /* ask for a change notify,
1367 on file or directory name changes */
1368 ZERO_STRUCT(notify.smb2);
1369 notify.smb2.level = RAW_NOTIFY_SMB2;
1370 notify.smb2.in.buffer_size = 1000;
1371 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1372 notify.smb2.in.file.handle = h1;
1373 notify.smb2.in.recursive = true;
1375 req = smb2_notify_send(tree1, &(notify.smb2));
1377 WAIT_FOR_ASYNC_RESPONSE(req);
1379 status = smb2_util_close(tree1, h1);
1380 CHECK_STATUS(status, NT_STATUS_OK);
1382 status = smb2_notify_recv(req, torture, &(notify.smb2));
1383 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1384 CHECK_VAL(notify.smb2.out.num_changes, 0);
1386 done:
1387 smb2_deltree(tree1, BASEDIR);
1388 return ret;
1392 basic testing of change notifies followed by a ulogoff
1395 static bool torture_smb2_notify_ulogoff(struct torture_context *torture,
1396 struct smb2_tree *tree1)
1398 bool ret = true;
1399 NTSTATUS status;
1400 union smb_notify notify;
1401 union smb_open io;
1402 struct smb2_handle h1;
1403 struct smb2_request *req;
1405 smb2_deltree(tree1, BASEDIR);
1406 smb2_util_rmdir(tree1, BASEDIR);
1408 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\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_FILE_ALL;
1417 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1418 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1419 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1420 NTCREATEX_SHARE_ACCESS_WRITE;
1421 io.smb2.in.alloc_size = 0;
1422 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1423 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1424 io.smb2.in.security_flags = 0;
1425 io.smb2.in.fname = BASEDIR;
1427 status = smb2_create(tree1, torture, &(io.smb2));
1428 CHECK_STATUS(status, NT_STATUS_OK);
1430 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1431 status = smb2_create(tree1, torture, &(io.smb2));
1432 CHECK_STATUS(status, NT_STATUS_OK);
1433 h1 = io.smb2.out.file.handle;
1435 /* ask for a change notify,
1436 on file or directory name changes */
1437 ZERO_STRUCT(notify.smb2);
1438 notify.smb2.level = RAW_NOTIFY_SMB2;
1439 notify.smb2.in.buffer_size = 1000;
1440 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1441 notify.smb2.in.file.handle = h1;
1442 notify.smb2.in.recursive = true;
1444 req = smb2_notify_send(tree1, &(notify.smb2));
1446 WAIT_FOR_ASYNC_RESPONSE(req);
1448 status = smb2_logoff(tree1->session);
1449 CHECK_STATUS(status, NT_STATUS_OK);
1451 status = smb2_notify_recv(req, torture, &(notify.smb2));
1452 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1453 CHECK_VAL(notify.smb2.out.num_changes, 0);
1455 done:
1456 smb2_deltree(tree1, BASEDIR);
1457 return ret;
1461 basic testing of change notifies followed by a session reconnect
1464 static bool torture_smb2_notify_session_reconnect(struct torture_context *torture,
1465 struct smb2_tree *tree1)
1467 bool ret = true;
1468 NTSTATUS status;
1469 union smb_notify notify;
1470 union smb_open io;
1471 struct smb2_handle h1;
1472 struct smb2_request *req;
1473 uint64_t previous_session_id = 0;
1474 struct smb2_session *session2 = NULL;
1476 smb2_deltree(tree1, BASEDIR);
1477 smb2_util_rmdir(tree1, BASEDIR);
1479 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY SESSION RECONNECT\n");
1482 get a handle on the directory
1484 ZERO_STRUCT(io.smb2);
1485 io.generic.level = RAW_OPEN_SMB2;
1486 io.smb2.in.create_flags = 0;
1487 io.smb2.in.desired_access = SEC_FILE_ALL;
1488 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1489 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1490 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1491 NTCREATEX_SHARE_ACCESS_WRITE;
1492 io.smb2.in.alloc_size = 0;
1493 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1494 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1495 io.smb2.in.security_flags = 0;
1496 io.smb2.in.fname = BASEDIR;
1498 status = smb2_create(tree1, torture, &(io.smb2));
1499 CHECK_STATUS(status, NT_STATUS_OK);
1501 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1502 status = smb2_create(tree1, torture, &(io.smb2));
1503 CHECK_STATUS(status, NT_STATUS_OK);
1504 h1 = io.smb2.out.file.handle;
1506 /* ask for a change notify,
1507 on file or directory name changes */
1508 ZERO_STRUCT(notify.smb2);
1509 notify.smb2.level = RAW_NOTIFY_SMB2;
1510 notify.smb2.in.buffer_size = 1000;
1511 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1512 notify.smb2.in.file.handle = h1;
1513 notify.smb2.in.recursive = true;
1515 req = smb2_notify_send(tree1, &(notify.smb2));
1517 WAIT_FOR_ASYNC_RESPONSE(req);
1519 previous_session_id = smb2cli_session_current_id(tree1->session->smbXcli);
1520 torture_assert(torture, torture_smb2_session_setup(torture,
1521 tree1->session->transport,
1522 previous_session_id,
1523 torture, &session2),
1524 "session setup with previous_session_id failed");
1526 status = smb2_notify_recv(req, torture, &(notify.smb2));
1527 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1528 CHECK_VAL(notify.smb2.out.num_changes, 0);
1530 status = smb2_logoff(tree1->session);
1531 CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
1533 status = smb2_logoff(session2);
1534 CHECK_STATUS(status, NT_STATUS_OK);
1535 done:
1536 smb2_deltree(tree1, BASEDIR);
1537 return ret;
1541 basic testing of change notifies followed by an invalid reauth
1544 static bool torture_smb2_notify_invalid_reauth(struct torture_context *torture,
1545 struct smb2_tree *tree1,
1546 struct smb2_tree *tree2)
1548 bool ret = true;
1549 NTSTATUS status;
1550 union smb_notify notify;
1551 union smb_open io;
1552 struct smb2_handle h1;
1553 struct smb2_request *req;
1554 struct cli_credentials *invalid_creds;
1556 smb2_deltree(tree2, BASEDIR);
1557 smb2_util_rmdir(tree2, BASEDIR);
1559 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY invalid REAUTH\n");
1562 get a handle on the directory
1564 ZERO_STRUCT(io.smb2);
1565 io.generic.level = RAW_OPEN_SMB2;
1566 io.smb2.in.create_flags = 0;
1567 io.smb2.in.desired_access = SEC_FILE_ALL;
1568 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1569 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1570 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1571 NTCREATEX_SHARE_ACCESS_WRITE;
1572 io.smb2.in.alloc_size = 0;
1573 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1574 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1575 io.smb2.in.security_flags = 0;
1576 io.smb2.in.fname = BASEDIR;
1578 status = smb2_create(tree1, torture, &(io.smb2));
1579 CHECK_STATUS(status, NT_STATUS_OK);
1581 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1582 status = smb2_create(tree1, torture, &(io.smb2));
1583 CHECK_STATUS(status, NT_STATUS_OK);
1584 h1 = io.smb2.out.file.handle;
1586 /* ask for a change notify,
1587 on file or directory name changes */
1588 ZERO_STRUCT(notify.smb2);
1589 notify.smb2.level = RAW_NOTIFY_SMB2;
1590 notify.smb2.in.buffer_size = 1000;
1591 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1592 notify.smb2.in.file.handle = h1;
1593 notify.smb2.in.recursive = true;
1595 req = smb2_notify_send(tree1, &(notify.smb2));
1597 WAIT_FOR_ASYNC_RESPONSE(req);
1599 invalid_creds = cli_credentials_init(torture);
1600 torture_assert(torture, (invalid_creds != NULL), "talloc error");
1601 cli_credentials_set_username(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1602 cli_credentials_set_domain(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1603 cli_credentials_set_password(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1604 cli_credentials_set_realm(invalid_creds, NULL, CRED_SPECIFIED);
1605 cli_credentials_set_workstation(invalid_creds, "", CRED_UNINITIALISED);
1607 status = smb2_session_setup_spnego(tree1->session,
1608 invalid_creds,
1609 0 /* previous_session_id */);
1610 CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE);
1612 status = smb2_notify_recv(req, torture, &(notify.smb2));
1613 CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1614 CHECK_VAL(notify.smb2.out.num_changes, 0);
1616 done:
1617 smb2_deltree(tree2, BASEDIR);
1618 return ret;
1621 static void tcp_dis_handler(struct smb2_transport *t, void *p)
1623 struct smb2_tree *tree = (struct smb2_tree *)p;
1624 smb2_transport_dead(tree->session->transport,
1625 NT_STATUS_LOCAL_DISCONNECT);
1626 t = NULL;
1627 tree = NULL;
1631 basic testing of change notifies followed by tcp disconnect
1634 static bool torture_smb2_notify_tcp_disconnect(
1635 struct torture_context *torture,
1636 struct smb2_tree *tree)
1638 bool ret = true;
1639 NTSTATUS status;
1640 union smb_notify notify;
1641 union smb_open io;
1642 struct smb2_handle h1;
1643 struct smb2_request *req;
1645 smb2_deltree(tree, BASEDIR);
1646 smb2_util_rmdir(tree, BASEDIR);
1648 torture_comment(torture,
1649 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1652 get a handle on the directory
1654 ZERO_STRUCT(io.smb2);
1655 io.generic.level = RAW_OPEN_SMB2;
1656 io.smb2.in.create_flags = 0;
1657 io.smb2.in.desired_access = SEC_FILE_ALL;
1658 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1659 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1660 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1661 NTCREATEX_SHARE_ACCESS_WRITE;
1662 io.smb2.in.alloc_size = 0;
1663 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1664 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1665 io.smb2.in.security_flags = 0;
1666 io.smb2.in.fname = BASEDIR;
1668 status = smb2_create(tree, torture, &(io.smb2));
1669 CHECK_STATUS(status, NT_STATUS_OK);
1670 h1 = io.smb2.out.file.handle;
1672 /* ask for a change notify,
1673 on file or directory name changes */
1674 ZERO_STRUCT(notify.smb2);
1675 notify.smb2.level = RAW_NOTIFY_SMB2;
1676 notify.smb2.in.buffer_size = 1000;
1677 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1678 notify.smb2.in.file.handle = h1;
1679 notify.smb2.in.recursive = true;
1681 req = smb2_notify_send(tree, &(notify.smb2));
1682 smb2_cancel(req);
1683 status = smb2_notify_recv(req, torture, &(notify.smb2));
1684 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1686 notify.smb2.in.recursive = true;
1687 req = smb2_notify_send(tree, &(notify.smb2));
1688 smb2_transport_idle_handler(tree->session->transport,
1689 tcp_dis_handler, 250, tree);
1690 tree = NULL;
1691 status = smb2_notify_recv(req, torture, &(notify.smb2));
1692 CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
1694 done:
1695 return ret;
1699 test setting up two change notify requests on one handle
1702 static bool torture_smb2_notify_double(struct torture_context *torture,
1703 struct smb2_tree *tree1,
1704 struct smb2_tree *tree2)
1706 bool ret = true;
1707 NTSTATUS status;
1708 union smb_notify notify;
1709 union smb_open io;
1710 struct smb2_handle h1;
1711 struct smb2_request *req1, *req2;
1713 smb2_deltree(tree1, BASEDIR);
1714 smb2_util_rmdir(tree1, BASEDIR);
1716 torture_comment(torture,
1717 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1720 get a handle on the directory
1722 ZERO_STRUCT(io.smb2);
1723 io.generic.level = RAW_OPEN_SMB2;
1724 io.smb2.in.create_flags = 0;
1725 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ|
1726 SEC_RIGHTS_FILE_WRITE|
1727 SEC_RIGHTS_FILE_ALL;
1728 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1729 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1730 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1731 NTCREATEX_SHARE_ACCESS_WRITE;
1732 io.smb2.in.alloc_size = 0;
1733 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1734 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1735 io.smb2.in.security_flags = 0;
1736 io.smb2.in.fname = BASEDIR;
1738 status = smb2_create(tree1, torture, &(io.smb2));
1739 CHECK_STATUS(status, NT_STATUS_OK);
1740 h1 = io.smb2.out.file.handle;
1742 /* ask for a change notify,
1743 on file or directory name changes */
1744 ZERO_STRUCT(notify.smb2);
1745 notify.smb2.level = RAW_NOTIFY_SMB2;
1746 notify.smb2.in.buffer_size = 1000;
1747 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1748 notify.smb2.in.file.handle = h1;
1749 notify.smb2.in.recursive = true;
1751 req1 = smb2_notify_send(tree1, &(notify.smb2));
1752 smb2_cancel(req1);
1753 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1754 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1756 req2 = smb2_notify_send(tree1, &(notify.smb2));
1757 smb2_cancel(req2);
1758 status = smb2_notify_recv(req2, torture, &(notify.smb2));
1759 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1761 smb2_util_mkdir(tree2, BASEDIR "\\subdir-name");
1762 req1 = smb2_notify_send(tree1, &(notify.smb2));
1763 req2 = smb2_notify_send(tree1, &(notify.smb2));
1765 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1766 CHECK_STATUS(status, NT_STATUS_OK);
1767 CHECK_VAL(notify.smb2.out.num_changes, 1);
1768 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1770 smb2_util_mkdir(tree2, BASEDIR "\\subdir-name2");
1772 status = smb2_notify_recv(req2, torture, &(notify.smb2));
1773 CHECK_STATUS(status, NT_STATUS_OK);
1774 CHECK_VAL(notify.smb2.out.num_changes, 1);
1775 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name2");
1777 done:
1778 smb2_deltree(tree1, BASEDIR);
1779 return ret;
1784 test multiple change notifies at different depths and with/without recursion
1787 static bool torture_smb2_notify_tree(struct torture_context *torture,
1788 struct smb2_tree *tree)
1790 bool ret = true;
1791 union smb_notify notify;
1792 union smb_open io;
1793 struct smb2_request *req;
1794 struct timeval tv;
1795 struct {
1796 const char *path;
1797 bool recursive;
1798 uint32_t filter;
1799 int expected;
1800 struct smb2_handle h1;
1801 int counted;
1802 } dirs[] = {
1803 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 30 },
1804 {BASEDIR "\\zqy", true, FILE_NOTIFY_CHANGE_NAME, 8 },
1805 {BASEDIR "\\atsy", true, FILE_NOTIFY_CHANGE_NAME, 4 },
1806 {BASEDIR "\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1807 {BASEDIR "\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME, 13 },
1808 {BASEDIR "\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME, 7 },
1809 {BASEDIR "\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1810 {BASEDIR "\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1811 {BASEDIR "\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1812 {BASEDIR "\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1813 {BASEDIR "\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1814 {BASEDIR "\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1815 {BASEDIR "\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME, 40 },
1816 {BASEDIR, true, FILE_NOTIFY_CHANGE_NAME, 40 },
1817 {BASEDIR, false,FILE_NOTIFY_CHANGE_NAME, 6 },
1818 {BASEDIR "\\atsy", false,FILE_NOTIFY_CHANGE_NAME, 4 },
1819 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1820 {BASEDIR "\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1821 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1822 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1824 int i;
1825 NTSTATUS status;
1826 bool all_done = false;
1828 smb2_deltree(tree, BASEDIR);
1829 smb2_util_rmdir(tree, BASEDIR);
1831 torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1833 ZERO_STRUCT(io.smb2);
1834 io.generic.level = RAW_OPEN_SMB2;
1835 io.smb2.in.create_flags = 0;
1836 io.smb2.in.desired_access = SEC_FILE_ALL;
1837 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1838 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1839 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1840 NTCREATEX_SHARE_ACCESS_WRITE;
1841 io.smb2.in.alloc_size = 0;
1842 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1843 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1844 io.smb2.in.security_flags = 0;
1845 io.smb2.in.fname = BASEDIR;
1846 status = smb2_create(tree, torture, &(io.smb2));
1847 CHECK_STATUS(status, NT_STATUS_OK);
1849 ZERO_STRUCT(notify.smb2);
1850 notify.smb2.level = RAW_NOTIFY_SMB2;
1851 notify.smb2.in.buffer_size = 20000;
1854 setup the directory tree, and the notify buffer on each directory
1856 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1857 io.smb2.in.fname = dirs[i].path;
1858 status = smb2_create(tree, torture, &(io.smb2));
1859 CHECK_STATUS(status, NT_STATUS_OK);
1860 dirs[i].h1 = io.smb2.out.file.handle;
1862 notify.smb2.in.completion_filter = dirs[i].filter;
1863 notify.smb2.in.file.handle = dirs[i].h1;
1864 notify.smb2.in.recursive = dirs[i].recursive;
1865 req = smb2_notify_send(tree, &(notify.smb2));
1866 smb2_cancel(req);
1867 status = smb2_notify_recv(req, torture, &(notify.smb2));
1868 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1871 /* trigger 2 events in each dir */
1872 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1873 char *path = talloc_asprintf(torture, "%s\\test.dir",
1874 dirs[i].path);
1875 smb2_util_mkdir(tree, path);
1876 smb2_util_rmdir(tree, path);
1877 talloc_free(path);
1880 /* give a bit of time for the events to propogate */
1881 tv = timeval_current();
1883 do {
1884 /* count events that have happened in each dir */
1885 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1886 notify.smb2.in.completion_filter = dirs[i].filter;
1887 notify.smb2.in.file.handle = dirs[i].h1;
1888 notify.smb2.in.recursive = dirs[i].recursive;
1889 req = smb2_notify_send(tree, &(notify.smb2));
1890 smb2_cancel(req);
1891 notify.smb2.out.num_changes = 0;
1892 status = smb2_notify_recv(req, torture,
1893 &(notify.smb2));
1894 dirs[i].counted += notify.smb2.out.num_changes;
1897 all_done = true;
1899 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1900 if (dirs[i].counted != dirs[i].expected) {
1901 all_done = false;
1904 } while (!all_done && timeval_elapsed(&tv) < 20);
1906 torture_comment(torture, "took %.4f seconds to propogate all events\n",
1907 timeval_elapsed(&tv));
1909 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1910 if (dirs[i].counted != dirs[i].expected) {
1911 torture_comment(torture,
1912 "ERROR: i=%d expected %d got %d for '%s'\n",
1913 i, dirs[i].expected, dirs[i].counted,
1914 dirs[i].path);
1915 ret = false;
1920 run from the back, closing and deleting
1922 for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1923 smb2_util_close(tree, dirs[i].h1);
1924 smb2_util_rmdir(tree, dirs[i].path);
1927 done:
1928 smb2_deltree(tree, BASEDIR);
1929 smb2_util_rmdir(tree, BASEDIR);
1930 return ret;
1934 Test response when cached server events exceed single NT NOTFIY response
1935 packet size.
1938 static bool torture_smb2_notify_overflow(struct torture_context *torture,
1939 struct smb2_tree *tree)
1941 bool ret = true;
1942 NTSTATUS status;
1943 union smb_notify notify;
1944 union smb_open io;
1945 struct smb2_handle h1, h2;
1946 int count = 100;
1947 struct smb2_request *req1;
1948 int i;
1950 smb2_deltree(tree, BASEDIR);
1951 smb2_util_rmdir(tree, BASEDIR);
1953 torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1955 /* get a handle on the directory */
1956 ZERO_STRUCT(io.smb2);
1957 io.generic.level = RAW_OPEN_SMB2;
1958 io.smb2.in.create_flags = 0;
1959 io.smb2.in.desired_access = SEC_FILE_ALL;
1960 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1961 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1962 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1963 NTCREATEX_SHARE_ACCESS_WRITE;
1964 io.smb2.in.alloc_size = 0;
1965 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1966 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1967 io.smb2.in.security_flags = 0;
1968 io.smb2.in.fname = BASEDIR;
1970 status = smb2_create(tree, torture, &(io.smb2));
1971 CHECK_STATUS(status, NT_STATUS_OK);
1972 h1 = io.smb2.out.file.handle;
1974 /* ask for a change notify, on name changes. */
1975 ZERO_STRUCT(notify.smb2);
1976 notify.smb2.level = RAW_NOTIFY_NTTRANS;
1977 notify.smb2.in.buffer_size = 1000;
1978 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1979 notify.smb2.in.file.handle = h1;
1981 notify.smb2.in.recursive = true;
1982 req1 = smb2_notify_send(tree, &(notify.smb2));
1984 /* cancel initial requests so the buffer is setup */
1985 smb2_cancel(req1);
1986 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1987 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1989 /* open a lot of files, filling up the server side notify buffer */
1990 torture_comment(torture,
1991 "Testing overflowed buffer notify on create of %d files\n",
1992 count);
1994 for (i=0;i<count;i++) {
1995 char *fname = talloc_asprintf(torture,
1996 BASEDIR "\\test%d.txt", i);
1997 union smb_open io1;
1998 ZERO_STRUCT(io1.smb2);
1999 io1.generic.level = RAW_OPEN_SMB2;
2000 io1.smb2.in.create_flags = 0;
2001 io1.smb2.in.desired_access = SEC_FILE_ALL;
2002 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2003 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2004 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2005 NTCREATEX_SHARE_ACCESS_WRITE;
2006 io1.smb2.in.alloc_size = 0;
2007 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2008 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2009 io1.smb2.in.security_flags = 0;
2010 io1.smb2.in.fname = fname;
2012 h2 = custom_smb2_create(tree, torture, &(io1.smb2));
2013 talloc_free(fname);
2014 smb2_util_close(tree, h2);
2017 req1 = smb2_notify_send(tree, &(notify.smb2));
2018 status = smb2_notify_recv(req1, torture, &(notify.smb2));
2019 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
2020 CHECK_VAL(notify.smb2.out.num_changes, 0);
2022 done:
2023 smb2_deltree(tree, BASEDIR);
2024 return ret;
2028 Test if notifications are returned for changes to the base directory.
2029 They shouldn't be.
2032 static bool torture_smb2_notify_basedir(struct torture_context *torture,
2033 struct smb2_tree *tree1,
2034 struct smb2_tree *tree2)
2036 bool ret = true;
2037 NTSTATUS status;
2038 union smb_notify notify;
2039 union smb_open io;
2040 struct smb2_handle h1;
2041 struct smb2_request *req1;
2043 smb2_deltree(tree1, BASEDIR);
2044 smb2_util_rmdir(tree1, BASEDIR);
2046 torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
2048 /* get a handle on the directory */
2049 ZERO_STRUCT(io.smb2);
2050 io.generic.level = RAW_OPEN_SMB2;
2051 io.smb2.in.create_flags = 0;
2052 io.smb2.in.desired_access = SEC_FILE_ALL;
2053 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2054 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2055 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2056 NTCREATEX_SHARE_ACCESS_WRITE;
2057 io.smb2.in.alloc_size = 0;
2058 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2059 io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
2060 io.smb2.in.security_flags = 0;
2061 io.smb2.in.fname = BASEDIR;
2063 status = smb2_create(tree1, torture, &(io.smb2));
2064 CHECK_STATUS(status, NT_STATUS_OK);
2065 h1 = io.smb2.out.file.handle;
2067 /* create a test file that will also be modified */
2068 io.smb2.in.fname = BASEDIR "\\tname1";
2069 io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
2070 status = smb2_create(tree2, torture, &(io.smb2));
2071 CHECK_STATUS(status,NT_STATUS_OK);
2072 smb2_util_close(tree2, io.smb2.out.file.handle);
2074 /* ask for a change notify, on attribute changes. */
2075 ZERO_STRUCT(notify.smb2);
2076 notify.smb2.level = RAW_NOTIFY_SMB2;
2077 notify.smb2.in.buffer_size = 1000;
2078 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
2079 notify.smb2.in.file.handle = h1;
2080 notify.smb2.in.recursive = true;
2082 req1 = smb2_notify_send(tree1, &(notify.smb2));
2084 /* set attribute on the base dir */
2085 smb2_util_setatr(tree2, BASEDIR, FILE_ATTRIBUTE_HIDDEN);
2087 /* set attribute on a file to assure we receive a notification */
2088 smb2_util_setatr(tree2, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN);
2089 smb_msleep(200);
2091 /* check how many responses were given, expect only 1 for the file */
2092 status = smb2_notify_recv(req1, torture, &(notify.smb2));
2093 CHECK_STATUS(status, NT_STATUS_OK);
2094 CHECK_VAL(notify.smb2.out.num_changes, 1);
2095 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
2096 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
2098 done:
2099 smb2_deltree(tree1, BASEDIR);
2100 return ret;
2104 very simple change notify test
2106 static bool torture_smb2_notify_tcon(struct torture_context *torture,
2107 struct smb2_tree *tree)
2109 bool ret = true;
2110 NTSTATUS status;
2111 union smb_notify notify;
2112 union smb_open io;
2113 struct smb2_handle h1;
2114 struct smb2_request *req = NULL;
2115 struct smb2_tree *tree1 = NULL;
2116 const char *fname = BASEDIR "\\subdir-name";
2118 smb2_deltree(tree, BASEDIR);
2119 smb2_util_rmdir(tree, BASEDIR);
2121 torture_comment(torture, "TESTING SIMPLE CHANGE NOTIFY\n");
2124 get a handle on the directory
2127 ZERO_STRUCT(io.smb2);
2128 io.generic.level = RAW_OPEN_SMB2;
2129 io.smb2.in.create_flags = 0;
2130 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2131 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2132 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL |
2133 FILE_ATTRIBUTE_DIRECTORY;
2134 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2135 NTCREATEX_SHARE_ACCESS_WRITE;
2136 io.smb2.in.alloc_size = 0;
2137 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2138 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2139 io.smb2.in.security_flags = 0;
2140 io.smb2.in.fname = BASEDIR;
2142 status = smb2_create(tree, torture, &(io.smb2));
2143 CHECK_STATUS(status, NT_STATUS_OK);
2144 h1 = io.smb2.out.file.handle;
2146 /* ask for a change notify,
2147 on file or directory name changes */
2148 ZERO_STRUCT(notify.smb2);
2149 notify.smb2.level = RAW_NOTIFY_SMB2;
2150 notify.smb2.in.buffer_size = 1000;
2151 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2152 notify.smb2.in.file.handle = h1;
2153 notify.smb2.in.recursive = true;
2155 torture_comment(torture, "Testing notify mkdir\n");
2156 req = smb2_notify_send(tree, &(notify.smb2));
2157 smb2_cancel(req);
2158 status = smb2_notify_recv(req, torture, &(notify.smb2));
2159 CHECK_STATUS(status, NT_STATUS_CANCELLED);
2161 notify.smb2.in.recursive = true;
2162 req = smb2_notify_send(tree, &(notify.smb2));
2163 status = smb2_util_mkdir(tree, fname);
2164 CHECK_STATUS(status, NT_STATUS_OK);
2166 status = smb2_notify_recv(req, torture, &(notify.smb2));
2167 CHECK_STATUS(status, NT_STATUS_OK);
2169 CHECK_VAL(notify.smb2.out.num_changes, 1);
2170 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2171 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2173 torture_comment(torture, "Testing notify rmdir\n");
2174 req = smb2_notify_send(tree, &(notify.smb2));
2175 status = smb2_util_rmdir(tree, fname);
2176 CHECK_STATUS(status, NT_STATUS_OK);
2178 status = smb2_notify_recv(req, torture, &(notify.smb2));
2179 CHECK_STATUS(status, NT_STATUS_OK);
2180 CHECK_VAL(notify.smb2.out.num_changes, 1);
2181 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2182 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2184 torture_comment(torture, "SIMPLE CHANGE NOTIFY OK\n");
2186 torture_comment(torture, "TESTING WITH SECONDARY TCON\n");
2187 if (!torture_smb2_tree_connect(torture, tree->session, tree, &tree1)) {
2188 torture_warning(torture, "couldn't reconnect to share, bailing\n");
2189 ret = false;
2190 goto done;
2193 torture_comment(torture, "tid1=%d tid2=%d\n",
2194 smb2cli_tcon_current_id(tree->smbXcli),
2195 smb2cli_tcon_current_id(tree1->smbXcli));
2197 torture_comment(torture, "Testing notify mkdir\n");
2198 req = smb2_notify_send(tree, &(notify.smb2));
2199 smb2_util_mkdir(tree1, fname);
2201 status = smb2_notify_recv(req, torture, &(notify.smb2));
2202 CHECK_STATUS(status, NT_STATUS_OK);
2204 CHECK_VAL(notify.smb2.out.num_changes, 1);
2205 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2206 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2208 torture_comment(torture, "Testing notify rmdir\n");
2209 req = smb2_notify_send(tree, &(notify.smb2));
2210 smb2_util_rmdir(tree, fname);
2212 status = smb2_notify_recv(req, torture, &(notify.smb2));
2213 CHECK_STATUS(status, NT_STATUS_OK);
2214 CHECK_VAL(notify.smb2.out.num_changes, 1);
2215 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2216 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2218 torture_comment(torture, "CHANGE NOTIFY WITH TCON OK\n");
2220 torture_comment(torture, "Disconnecting secondary tree\n");
2221 status = smb2_tdis(tree1);
2222 CHECK_STATUS(status, NT_STATUS_OK);
2223 talloc_free(tree1);
2225 torture_comment(torture, "Testing notify mkdir\n");
2226 req = smb2_notify_send(tree, &(notify.smb2));
2227 smb2_util_mkdir(tree, fname);
2229 status = smb2_notify_recv(req, torture, &(notify.smb2));
2230 CHECK_STATUS(status, NT_STATUS_OK);
2232 CHECK_VAL(notify.smb2.out.num_changes, 1);
2233 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2234 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2236 torture_comment(torture, "Testing notify rmdir\n");
2237 req = smb2_notify_send(tree, &(notify.smb2));
2238 smb2_util_rmdir(tree, fname);
2240 status = smb2_notify_recv(req, torture, &(notify.smb2));
2241 CHECK_STATUS(status, NT_STATUS_OK);
2242 CHECK_VAL(notify.smb2.out.num_changes, 1);
2243 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2244 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2246 torture_comment(torture, "CHANGE NOTIFY WITH TDIS OK\n");
2247 done:
2248 smb2_util_close(tree, h1);
2249 smb2_deltree(tree, BASEDIR);
2251 return ret;
2254 static bool torture_smb2_notify_rmdir(struct torture_context *torture,
2255 struct smb2_tree *tree1,
2256 struct smb2_tree *tree2,
2257 bool initial_delete_on_close)
2259 bool ret = true;
2260 NTSTATUS status;
2261 union smb_notify notify = {};
2262 union smb_setfileinfo sfinfo = {};
2263 union smb_open io = {};
2264 struct smb2_handle h = {};
2265 struct smb2_request *req;
2267 torture_comment(torture, "TESTING NOTIFY CANCEL FOR DELETED DIR\n");
2269 smb2_deltree(tree1, BASEDIR);
2270 smb2_util_rmdir(tree1, BASEDIR);
2272 ZERO_STRUCT(io.smb2);
2273 io.generic.level = RAW_OPEN_SMB2;
2274 io.smb2.in.create_flags = 0;
2275 io.smb2.in.desired_access = SEC_FILE_ALL;
2276 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2277 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2278 io.smb2.in.share_access =
2279 NTCREATEX_SHARE_ACCESS_READ |
2280 NTCREATEX_SHARE_ACCESS_WRITE |
2281 NTCREATEX_SHARE_ACCESS_DELETE ;
2282 io.smb2.in.alloc_size = 0;
2283 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2284 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2285 io.smb2.in.security_flags = 0;
2286 io.smb2.in.fname = BASEDIR;
2288 status = smb2_create(tree1, torture, &(io.smb2));
2289 CHECK_STATUS(status, NT_STATUS_OK);
2290 h = io.smb2.out.file.handle;
2292 ZERO_STRUCT(notify.smb2);
2293 notify.smb2.level = RAW_NOTIFY_SMB2;
2294 notify.smb2.in.buffer_size = 1000;
2295 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2296 notify.smb2.in.file.handle = h;
2297 notify.smb2.in.recursive = false;
2299 io.smb2.in.desired_access |= SEC_STD_DELETE;
2300 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
2301 req = smb2_notify_send(tree1, &(notify.smb2));
2303 if (initial_delete_on_close) {
2304 status = smb2_util_rmdir(tree2, BASEDIR);
2305 CHECK_STATUS(status, NT_STATUS_OK);
2306 } else {
2307 status = smb2_create(tree2, torture, &(io.smb2));
2308 CHECK_STATUS(status, NT_STATUS_OK);
2310 sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
2311 sfinfo.generic.in.file.handle = io.smb2.out.file.handle;
2312 sfinfo.disposition_info.in.delete_on_close = 1;
2313 status = smb2_setinfo_file(tree2, &sfinfo);
2314 CHECK_STATUS(status, NT_STATUS_OK);
2316 smb2_util_close(tree2, io.smb2.out.file.handle);
2319 status = smb2_notify_recv(req, torture, &(notify.smb2));
2320 CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
2322 done:
2324 smb2_util_close(tree1, h);
2325 smb2_deltree(tree1, BASEDIR);
2327 return ret;
2330 static bool torture_smb2_notify_rmdir1(struct torture_context *torture,
2331 struct smb2_tree *tree)
2333 return torture_smb2_notify_rmdir(torture, tree, tree, false);
2336 static bool torture_smb2_notify_rmdir2(struct torture_context *torture,
2337 struct smb2_tree *tree)
2339 return torture_smb2_notify_rmdir(torture, tree, tree, true);
2342 static bool torture_smb2_notify_rmdir3(struct torture_context *torture,
2343 struct smb2_tree *tree1,
2344 struct smb2_tree *tree2)
2346 return torture_smb2_notify_rmdir(torture, tree1, tree2, false);
2349 static bool torture_smb2_notify_rmdir4(struct torture_context *torture,
2350 struct smb2_tree *tree1,
2351 struct smb2_tree *tree2)
2353 return torture_smb2_notify_rmdir(torture, tree1, tree2, true);
2357 basic testing of SMB2 change notify
2359 struct torture_suite *torture_smb2_notify_init(void)
2361 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "notify");
2363 torture_suite_add_1smb2_test(suite, "valid-req", test_valid_request);
2364 torture_suite_add_1smb2_test(suite, "tcon", torture_smb2_notify_tcon);
2365 torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir);
2366 torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask);
2367 torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
2368 torture_suite_add_1smb2_test(suite, "tdis1", torture_smb2_notify_tree_disconnect_1);
2369 torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
2370 torture_suite_add_1smb2_test(suite, "close", torture_smb2_notify_close);
2371 torture_suite_add_1smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
2372 torture_suite_add_1smb2_test(suite, "session-reconnect", torture_smb2_notify_session_reconnect);
2373 torture_suite_add_2smb2_test(suite, "invalid-reauth", torture_smb2_notify_invalid_reauth);
2374 torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
2375 torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
2376 torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
2377 torture_suite_add_1smb2_test(suite, "file", torture_smb2_notify_file);
2378 torture_suite_add_1smb2_test(suite, "tcp", torture_smb2_notify_tcp_disconnect);
2379 torture_suite_add_2smb2_test(suite, "rec", torture_smb2_notify_recursive);
2380 torture_suite_add_1smb2_test(suite, "overflow", torture_smb2_notify_overflow);
2381 torture_suite_add_1smb2_test(suite, "rmdir1",
2382 torture_smb2_notify_rmdir1);
2383 torture_suite_add_1smb2_test(suite, "rmdir2",
2384 torture_smb2_notify_rmdir2);
2385 torture_suite_add_2smb2_test(suite, "rmdir3",
2386 torture_smb2_notify_rmdir3);
2387 torture_suite_add_2smb2_test(suite, "rmdir4",
2388 torture_smb2_notify_rmdir4);
2390 suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");
2392 return suite;