6ef24fe889e57a117cff32738c688a1dbd96a1f0
[garming/samba-autobuild/.git] / source4 / torture / smb2 / notify.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    SMB2 notify test suite
5
6    Copyright (C) Stefan Metzmacher 2006
7    Copyright (C) Andrew Tridgell 2009
8
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.
13
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.
18
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/>.
21 */
22
23 #include "includes.h"
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "../libcli/smb/smbXcli_base.h"
27
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"
33
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"
38
39 #include "lib/events/events.h"
40
41 #include "libcli/raw/libcliraw.h"
42 #include "libcli/raw/raw_proto.h"
43 #include "libcli/libcli.h"
44
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)
53
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)
62
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)
71
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                 } \
77         }
78
79 #define BASEDIR "test_notify"
80 #define FNAME "smb2-notify01.dat"
81
82 static bool test_valid_request(struct torture_context *torture,
83                                struct smb2_tree *tree)
84 {
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;
91
92         torture_comment(torture, "TESTING VALIDITY OF CHANGE NOTIFY REQUEST\n");
93
94         smb2_util_unlink(tree, FNAME);
95
96         status = smb2_util_roothandle(tree, &dh);
97         CHECK_STATUS(status, NT_STATUS_OK);
98
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);
103
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);
110
111         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
112                 if (tevent_loop_once(torture->ev) != 0) {
113                         break;
114                 }
115         }
116
117         status = torture_setup_complex_file(torture, tree, FNAME);
118         CHECK_STATUS(status, NT_STATUS_OK);
119
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);
125
126         /*
127          * if the change response doesn't fit in the buffer
128          * NOTIFY_ENUM_DIR is returned.
129          */
130         n.in.buffer_size        = 0x00000000;
131         req = smb2_notify_send(tree, &n);
132
133         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
134                 if (tevent_loop_once(torture->ev) != 0) {
135                         break;
136                 }
137         }
138
139         status = torture_setup_complex_file(torture, tree, FNAME);
140         CHECK_STATUS(status, NT_STATUS_OK);
141
142         status = smb2_notify_recv(req, torture, &n);
143         CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
144
145         /*
146          * if the change response fits in the buffer we get
147          * NT_STATUS_OK again
148          */
149         n.in.buffer_size        = max_buffer_size;
150         req = smb2_notify_send(tree, &n);
151
152         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
153                 if (tevent_loop_once(torture->ev) != 0) {
154                         break;
155                 }
156         }
157
158         status = torture_setup_complex_file(torture, tree, FNAME);
159         CHECK_STATUS(status, NT_STATUS_OK);
160
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);
170
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);
176
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);
183
184         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
185                 if (tevent_loop_once(torture->ev) != 0) {
186                         break;
187                 }
188         }
189
190         status = torture_setup_complex_file(torture, tree, FNAME);
191         CHECK_STATUS(status, NT_STATUS_OK);
192
193         status = smb2_notify_recv(req, torture, &n);
194         CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
195
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;
201                 }
202         }
203
204         status = torture_setup_complex_file(torture, tree, FNAME);
205         CHECK_STATUS(status, NT_STATUS_OK);
206
207         status = smb2_notify_recv(req, torture, &n);
208         CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
209
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);
219
220 done:
221         return ret;
222 }
223
224 /*
225    basic testing of change notify on directories
226 */
227 static bool torture_smb2_notify_dir(struct torture_context *torture,
228                               struct smb2_tree *tree1,
229                               struct smb2_tree *tree2)
230 {
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 = {{0}};
238         struct smb2_handle h2 = {{0}};
239         struct smb2_request *req, *req2;
240         const char *fname = BASEDIR "\\subdir-name";
241         extern int torture_numops;
242
243         torture_comment(torture, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
244
245         smb2_deltree(tree1, BASEDIR);
246         smb2_util_rmdir(tree1, BASEDIR);
247         /*
248           get a handle on the directory
249         */
250         ZERO_STRUCT(io.smb2);
251         io.generic.level = RAW_OPEN_SMB2;
252         io.smb2.in.create_flags = 0;
253         io.smb2.in.desired_access = SEC_FILE_ALL;
254         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
255         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
256         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
257                                 NTCREATEX_SHARE_ACCESS_WRITE;
258         io.smb2.in.alloc_size = 0;
259         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
260         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
261         io.smb2.in.security_flags = 0;
262         io.smb2.in.fname = BASEDIR;
263
264         status = smb2_create(tree1, torture, &(io.smb2));
265         CHECK_STATUS(status, NT_STATUS_OK);
266         h1 = io.smb2.out.file.handle;
267
268         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
269         io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ;
270         status = smb2_create(tree1, torture, &(io.smb2));
271         CHECK_STATUS(status, NT_STATUS_OK);
272         h2 = io.smb2.out.file.handle;
273
274         /* ask for a change notify,
275            on file or directory name changes */
276         ZERO_STRUCT(notify.smb2);
277         notify.smb2.level = RAW_NOTIFY_SMB2;
278         notify.smb2.in.buffer_size = 1000;
279         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
280         notify.smb2.in.file.handle = h1;
281         notify.smb2.in.recursive = true;
282
283         torture_comment(torture, "Testing notify cancel\n");
284
285         req = smb2_notify_send(tree1, &(notify.smb2));
286         smb2_cancel(req);
287         status = smb2_notify_recv(req, torture, &(notify.smb2));
288         CHECK_STATUS(status, NT_STATUS_CANCELLED);
289
290         torture_comment(torture, "Testing notify mkdir\n");
291
292         req = smb2_notify_send(tree1, &(notify.smb2));
293         smb2_util_mkdir(tree2, fname);
294
295         status = smb2_notify_recv(req, torture, &(notify.smb2));
296         CHECK_STATUS(status, NT_STATUS_OK);
297
298         CHECK_VAL(notify.smb2.out.num_changes, 1);
299         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
300         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
301
302         torture_comment(torture, "Testing notify rmdir\n");
303
304         req = smb2_notify_send(tree1, &(notify.smb2));
305         smb2_util_rmdir(tree2, fname);
306
307         status = smb2_notify_recv(req, torture, &(notify.smb2));
308         CHECK_STATUS(status, NT_STATUS_OK);
309         CHECK_VAL(notify.smb2.out.num_changes, 1);
310         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
311         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
312
313         torture_comment(torture,
314                 "Testing notify mkdir - rmdir - mkdir - rmdir\n");
315
316         smb2_util_mkdir(tree2, fname);
317         smb2_util_rmdir(tree2, fname);
318         smb2_util_mkdir(tree2, fname);
319         smb2_util_rmdir(tree2, fname);
320         smb_msleep(200);
321         req = smb2_notify_send(tree1, &(notify.smb2));
322         status = smb2_notify_recv(req, torture, &(notify.smb2));
323         CHECK_STATUS(status, NT_STATUS_OK);
324         CHECK_VAL(notify.smb2.out.num_changes, 4);
325         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
326         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
327         CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_REMOVED);
328         CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name");
329         CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_ADDED);
330         CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name");
331         CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_REMOVED);
332         CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name");
333
334         count = torture_numops;
335         torture_comment(torture,
336                 "Testing buffered notify on create of %d files\n", count);
337         for (i=0;i<count;i++) {
338                 struct smb2_handle h12;
339                 char *fname2 = talloc_asprintf(torture, BASEDIR "\\test%d.txt",
340                                               i);
341
342                 ZERO_STRUCT(io.smb2);
343                 io.generic.level = RAW_OPEN_SMB2;
344                 io.smb2.in.create_flags = 0;
345                 io.smb2.in.desired_access = SEC_FILE_ALL;
346                 io.smb2.in.create_options =
347                     NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
348                 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
349                 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
350                                         NTCREATEX_SHARE_ACCESS_WRITE;
351                 io.smb2.in.alloc_size = 0;
352                 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
353                 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
354                 io.smb2.in.security_flags = 0;
355                 io.smb2.in.fname = fname2;
356
357                 status = smb2_create(tree1, torture, &(io.smb2));
358                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
359                         torture_comment(torture, "Failed to create %s \n",
360                                fname);
361                         ret = false;
362                         goto done;
363                 }
364                 h12 = io.smb2.out.file.handle;
365                 talloc_free(fname2);
366                 smb2_util_close(tree1, h12);
367         }
368
369         /* (1st notify) setup a new notify on a different directory handle.
370            This new notify won't see the events above. */
371         notify.smb2.in.file.handle = h2;
372         req2 = smb2_notify_send(tree1, &(notify.smb2));
373
374         /* (2nd notify) whereas this notify will see the above buffered events,
375            and it directly returns the buffered events */
376         notify.smb2.in.file.handle = h1;
377         req = smb2_notify_send(tree1, &(notify.smb2));
378
379         status = smb2_util_unlink(tree1, BASEDIR "\\nonexistent.txt");
380         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
381
382         /* (1st unlink) as the 2nd notify directly returns,
383            this unlink is only seen by the 1st notify and
384            the 3rd notify (later) */
385         torture_comment(torture,
386                 "Testing notify on unlink for the first file\n");
387         status = smb2_util_unlink(tree2, BASEDIR "\\test0.txt");
388         CHECK_STATUS(status, NT_STATUS_OK);
389
390         /* receive the reply from the 2nd notify */
391         status = smb2_notify_recv(req, torture, &(notify.smb2));
392         CHECK_STATUS(status, NT_STATUS_OK);
393
394         CHECK_VAL(notify.smb2.out.num_changes, count);
395         for (i=1;i<count;i++) {
396                 CHECK_VAL(notify.smb2.out.changes[i].action,
397                           NOTIFY_ACTION_ADDED);
398         }
399         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
400
401         torture_comment(torture, "and now from the 1st notify\n");
402         status = smb2_notify_recv(req2, torture, &(notify.smb2));
403         CHECK_STATUS(status, NT_STATUS_OK);
404         CHECK_VAL(notify.smb2.out.num_changes, 1);
405         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
406         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
407
408         torture_comment(torture,
409                 "(3rd notify) this notify will only see the 1st unlink\n");
410         req = smb2_notify_send(tree1, &(notify.smb2));
411
412         status = smb2_util_unlink(tree1, BASEDIR "\\nonexistent.txt");
413         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
414
415         for (i=1;i<count;i++) {
416                 char *fname2 = talloc_asprintf(torture,
417                               BASEDIR "\\test%d.txt", i);
418                 status = smb2_util_unlink(tree2, fname2);
419                 CHECK_STATUS(status, NT_STATUS_OK);
420                 talloc_free(fname2);
421         }
422
423         /* receive the 3rd notify */
424         status = smb2_notify_recv(req, torture, &(notify.smb2));
425         CHECK_STATUS(status, NT_STATUS_OK);
426         CHECK_VAL(notify.smb2.out.num_changes, 1);
427         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
428         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
429
430         /* and we now see the rest of the unlink calls on both
431          * directory handles */
432         notify.smb2.in.file.handle = h1;
433         sleep(3);
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);
441         }
442         notify.smb2.in.file.handle = h2;
443         req = smb2_notify_send(tree1, &(notify.smb2));
444         status = smb2_notify_recv(req, torture, &(notify.smb2));
445         CHECK_STATUS(status, NT_STATUS_OK);
446         CHECK_VAL(notify.smb2.out.num_changes, count-1);
447         for (i=0;i<notify.smb2.out.num_changes;i++) {
448                 CHECK_VAL(notify.smb2.out.changes[i].action,
449                           NOTIFY_ACTION_REMOVED);
450         }
451
452         torture_comment(torture,
453         "Testing if a close() on the dir handle triggers the notify reply\n");
454
455         notify.smb2.in.file.handle = h1;
456         req = smb2_notify_send(tree1, &(notify.smb2));
457
458         ZERO_STRUCT(cl.smb2);
459         cl.smb2.level = RAW_CLOSE_SMB2;
460         cl.smb2.in.file.handle = h1;
461         status = smb2_close(tree1, &(cl.smb2));
462         CHECK_STATUS(status, NT_STATUS_OK);
463
464         status = smb2_notify_recv(req, torture, &(notify.smb2));
465         CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
466         CHECK_VAL(notify.smb2.out.num_changes, 9);
467
468 done:
469         smb2_util_close(tree1, h1);
470         smb2_util_close(tree1, h2);
471         smb2_deltree(tree1, BASEDIR);
472         return ret;
473 }
474
475 static struct smb2_handle custom_smb2_create(struct smb2_tree *tree,
476                                                 struct torture_context *torture,
477                                                 struct smb2_create *smb2)
478 {
479         struct smb2_handle h1;
480         bool ret = true;
481         NTSTATUS status;
482         smb2_deltree(tree, smb2->in.fname);
483         status = smb2_create(tree, torture, smb2);
484         CHECK_STATUS(status, NT_STATUS_OK);
485         h1 = smb2->out.file.handle;
486 done:
487         if (!ret) {
488                 h1 = (struct smb2_handle) {
489                         .data = { 0 , 0},
490                 };
491         }
492         return h1;
493 }
494
495 /*
496    testing of recursive change notify
497 */
498
499 static bool torture_smb2_notify_recursive(struct torture_context *torture,
500                                 struct smb2_tree *tree1,
501                                 struct smb2_tree *tree2)
502 {
503         bool ret = true;
504         NTSTATUS status;
505         union smb_notify notify;
506         union smb_open io, io1;
507         union smb_setfileinfo sinfo;
508         struct smb2_handle h1;
509         struct smb2_request *req1, *req2;
510
511         smb2_deltree(tree1, BASEDIR);
512         smb2_util_rmdir(tree1, BASEDIR);
513
514         torture_comment(torture, "TESTING CHANGE NOTIFY WITH RECURSION\n");
515
516         /*
517           get a handle on the directory
518         */
519         ZERO_STRUCT(io.smb2);
520         io.generic.level = RAW_OPEN_SMB2;
521         io.smb2.in.create_flags = 0;
522         io.smb2.in.desired_access = SEC_FILE_ALL;
523         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
524         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
525         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
526                                 NTCREATEX_SHARE_ACCESS_WRITE;
527         io.smb2.in.alloc_size = 0;
528         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
529         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
530         io.smb2.in.security_flags = 0;
531         io.smb2.in.fname = BASEDIR;
532
533         status = smb2_create(tree1, torture, &(io.smb2));
534         CHECK_STATUS(status, NT_STATUS_OK);
535         h1 = io.smb2.out.file.handle;
536
537         /* ask for a change notify, on file or directory name
538            changes. Setup both with and without recursion */
539         ZERO_STRUCT(notify.smb2);
540         notify.smb2.level = RAW_NOTIFY_SMB2;
541         notify.smb2.in.buffer_size = 1000;
542         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
543                                 FILE_NOTIFY_CHANGE_ATTRIBUTES |
544                                 FILE_NOTIFY_CHANGE_CREATION;
545         notify.smb2.in.file.handle = h1;
546
547         notify.smb2.in.recursive = true;
548         req1 = smb2_notify_send(tree1, &(notify.smb2));
549         smb2_cancel(req1);
550         status = smb2_notify_recv(req1, torture, &(notify.smb2));
551         CHECK_STATUS(status, NT_STATUS_CANCELLED);
552
553         notify.smb2.in.recursive = false;
554         req2 = smb2_notify_send(tree1, &(notify.smb2));
555         smb2_cancel(req2);
556         status = smb2_notify_recv(req2, torture, &(notify.smb2));
557         CHECK_STATUS(status, NT_STATUS_CANCELLED);
558
559         ZERO_STRUCT(io1.smb2);
560         io1.generic.level = RAW_OPEN_SMB2;
561         io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
562         io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
563                                 SEC_RIGHTS_FILE_WRITE|
564                                 SEC_RIGHTS_FILE_ALL;
565         io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
566         io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
567         io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
568                                 NTCREATEX_SHARE_ACCESS_WRITE |
569                                 NTCREATEX_SHARE_ACCESS_DELETE;
570         io1.smb2.in.alloc_size = 0;
571         io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
572         io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
573         io1.smb2.in.security_flags = 0;
574         io1.smb2.in.fname = BASEDIR "\\subdir-name";
575         status = smb2_create(tree2, torture, &(io1.smb2));
576         CHECK_STATUS(status, NT_STATUS_OK);
577         smb2_util_close(tree2, io1.smb2.out.file.handle);
578
579         io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname1";
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 = 0;
586         sinfo.rename_information.in.root_fid = 0;
587         sinfo.rename_information.in.new_name =
588                                 BASEDIR "\\subdir-name\\subname1-r";
589         status = smb2_setinfo_file(tree2, &sinfo);
590         CHECK_STATUS(status, NT_STATUS_OK);
591
592         io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
593         io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname2";
594         status = smb2_create(tree2, torture, &(io1.smb2));
595         CHECK_STATUS(status, NT_STATUS_OK);
596         ZERO_STRUCT(sinfo);
597         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
598         sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
599         sinfo.rename_information.in.overwrite = true;
600         sinfo.rename_information.in.root_fid = 0;
601         sinfo.rename_information.in.new_name = BASEDIR "\\subname2-r";
602         status = smb2_setinfo_file(tree2, &sinfo);
603         CHECK_STATUS(status, NT_STATUS_OK);
604
605         io1.smb2.in.fname = BASEDIR "\\subname2-r";
606         io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
607         status = smb2_create(tree2, torture, &(io1.smb2));
608         CHECK_STATUS(status, NT_STATUS_OK);
609         ZERO_STRUCT(sinfo);
610         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
611         sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
612         sinfo.rename_information.in.overwrite = true;
613         sinfo.rename_information.in.root_fid = 0;
614         sinfo.rename_information.in.new_name = BASEDIR "\\subname3-r";
615         status = smb2_setinfo_file(tree2, &sinfo);
616         CHECK_STATUS(status, NT_STATUS_OK);
617
618         notify.smb2.in.completion_filter = 0;
619         notify.smb2.in.recursive = true;
620         smb_msleep(200);
621         req1 = smb2_notify_send(tree1, &(notify.smb2));
622
623         status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name\\subname1-r");
624         CHECK_STATUS(status, NT_STATUS_OK);
625         status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name");
626         CHECK_STATUS(status, NT_STATUS_OK);
627         status = smb2_util_unlink(tree2, BASEDIR "\\subname3-r");
628         CHECK_STATUS(status, NT_STATUS_OK);
629
630         notify.smb2.in.recursive = false;
631         req2 = smb2_notify_send(tree1, &(notify.smb2));
632
633         status = smb2_notify_recv(req1, torture, &(notify.smb2));
634         CHECK_STATUS(status, NT_STATUS_OK);
635
636         CHECK_VAL(notify.smb2.out.num_changes, 9);
637         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
638         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
639         CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_ADDED);
640         CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name\\subname1");
641         CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_OLD_NAME);
642         CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name\\subname1");
643         CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_NEW_NAME);
644         CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name\\subname1-r");
645         CHECK_VAL(notify.smb2.out.changes[4].action, NOTIFY_ACTION_ADDED);
646         CHECK_WIRE_STR(notify.smb2.out.changes[4].name, "subdir-name\\subname2");
647         CHECK_VAL(notify.smb2.out.changes[5].action, NOTIFY_ACTION_REMOVED);
648         CHECK_WIRE_STR(notify.smb2.out.changes[5].name, "subdir-name\\subname2");
649         CHECK_VAL(notify.smb2.out.changes[6].action, NOTIFY_ACTION_ADDED);
650         CHECK_WIRE_STR(notify.smb2.out.changes[6].name, "subname2-r");
651         CHECK_VAL(notify.smb2.out.changes[7].action, NOTIFY_ACTION_OLD_NAME);
652         CHECK_WIRE_STR(notify.smb2.out.changes[7].name, "subname2-r");
653         CHECK_VAL(notify.smb2.out.changes[8].action, NOTIFY_ACTION_NEW_NAME);
654         CHECK_WIRE_STR(notify.smb2.out.changes[8].name, "subname3-r");
655
656 done:
657         smb2_deltree(tree1, BASEDIR);
658         return ret;
659 }
660
661 /*
662    testing of change notify mask change
663 */
664
665 static bool torture_smb2_notify_mask_change(struct torture_context *torture,
666                                             struct smb2_tree *tree1,
667                                             struct smb2_tree *tree2)
668 {
669         bool ret = true;
670         NTSTATUS status;
671         union smb_notify notify;
672         union smb_open io, io1;
673         struct smb2_handle h1;
674         struct smb2_request *req1, *req2;
675         union smb_setfileinfo sinfo;
676
677         smb2_deltree(tree1, BASEDIR);
678         smb2_util_rmdir(tree1, BASEDIR);
679
680         torture_comment(torture, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
681
682         /*
683           get a handle on the directory
684         */
685         ZERO_STRUCT(io.smb2);
686         io.generic.level = RAW_OPEN_SMB2;
687         io.smb2.in.create_flags = 0;
688         io.smb2.in.desired_access = SEC_FILE_ALL;
689         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
690         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
691         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
692                                 NTCREATEX_SHARE_ACCESS_WRITE;
693         io.smb2.in.alloc_size = 0;
694         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
695         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
696         io.smb2.in.security_flags = 0;
697         io.smb2.in.fname = BASEDIR;
698
699         status = smb2_create(tree1, torture, &(io.smb2));
700         CHECK_STATUS(status, NT_STATUS_OK);
701         h1 = io.smb2.out.file.handle;
702
703         /* ask for a change notify, on file or directory name
704            changes. Setup both with and without recursion */
705         ZERO_STRUCT(notify.smb2);
706         notify.smb2.level = RAW_NOTIFY_SMB2;
707         notify.smb2.in.buffer_size = 1000;
708         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
709         notify.smb2.in.file.handle = h1;
710
711         notify.smb2.in.recursive = true;
712         req1 = smb2_notify_send(tree1, &(notify.smb2));
713
714         smb2_cancel(req1);
715         status = smb2_notify_recv(req1, torture, &(notify.smb2));
716         CHECK_STATUS(status, NT_STATUS_CANCELLED);
717
718
719         notify.smb2.in.recursive = false;
720         req2 = smb2_notify_send(tree1, &(notify.smb2));
721
722         smb2_cancel(req2);
723         status = smb2_notify_recv(req2, torture, &(notify.smb2));
724         CHECK_STATUS(status, NT_STATUS_CANCELLED);
725
726         notify.smb2.in.recursive = true;
727         req1 = smb2_notify_send(tree1, &(notify.smb2));
728
729         /* Set to hidden then back again. */
730         ZERO_STRUCT(io1.smb2);
731         io1.generic.level = RAW_OPEN_SMB2;
732         io1.smb2.in.create_flags = 0;
733         io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
734                                 SEC_RIGHTS_FILE_WRITE|
735                                 SEC_RIGHTS_FILE_ALL;
736         io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
737         io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
738                                 NTCREATEX_SHARE_ACCESS_WRITE |
739                                 NTCREATEX_SHARE_ACCESS_DELETE;
740         io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
741         io1.smb2.in.security_flags = 0;
742         io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
743         io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
744         io1.smb2.in.fname = BASEDIR "\\tname1";
745
746         smb2_util_close(tree1,
747                 custom_smb2_create(tree1, torture, &(io1.smb2)));
748         status = smb2_util_setatr(tree1, BASEDIR "\\tname1",
749                                 FILE_ATTRIBUTE_HIDDEN);
750         CHECK_STATUS(status, NT_STATUS_OK);
751         smb2_util_unlink(tree1, BASEDIR "\\tname1");
752
753         status = smb2_notify_recv(req1, torture, &(notify.smb2));
754         CHECK_STATUS(status, NT_STATUS_OK);
755
756         CHECK_VAL(notify.smb2.out.num_changes, 1);
757         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
758         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
759
760         /* Now try and change the mask to include other events.
761          * This should not work - once the mask is set on a directory
762          * h1 it seems to be fixed until the fnum is closed. */
763
764         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
765                                         FILE_NOTIFY_CHANGE_ATTRIBUTES |
766                                         FILE_NOTIFY_CHANGE_CREATION;
767         notify.smb2.in.recursive = true;
768         req1 = smb2_notify_send(tree1, &(notify.smb2));
769
770         notify.smb2.in.recursive = false;
771         req2 = smb2_notify_send(tree1, &(notify.smb2));
772
773         io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
774         io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
775         io1.smb2.in.fname = BASEDIR "\\subdir-name";
776         status = smb2_create(tree2, torture, &(io1.smb2));
777         CHECK_STATUS(status, NT_STATUS_OK);
778         smb2_util_close(tree2, io1.smb2.out.file.handle);
779
780         ZERO_STRUCT(sinfo);
781         io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname1";
782         io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
783         io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
784         status = smb2_create(tree2, torture, &(io1.smb2));
785         CHECK_STATUS(status, NT_STATUS_OK);
786         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
787         sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
788         sinfo.rename_information.in.overwrite = true;
789         sinfo.rename_information.in.root_fid = 0;
790         sinfo.rename_information.in.new_name =
791                                 BASEDIR "\\subdir-name\\subname1-r";
792         status = smb2_setinfo_file(tree2, &sinfo);
793         CHECK_STATUS(status, NT_STATUS_OK);
794
795         io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname2";
796         io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
797         io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
798         status = smb2_create(tree2, torture, &(io1.smb2));
799         CHECK_STATUS(status, NT_STATUS_OK);
800         sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
801         sinfo.rename_information.in.new_name = BASEDIR "\\subname2-r";
802         status = smb2_setinfo_file(tree2, &sinfo);
803         CHECK_STATUS(status, NT_STATUS_OK);
804         smb2_util_close(tree2, io1.smb2.out.file.handle);
805
806         io1.smb2.in.fname = BASEDIR "\\subname2-r";
807         io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
808         status = smb2_create(tree2, torture, &(io1.smb2));
809         CHECK_STATUS(status, NT_STATUS_OK);
810         sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
811         sinfo.rename_information.in.new_name = BASEDIR "\\subname3-r";
812         status = smb2_setinfo_file(tree2, &sinfo);
813         CHECK_STATUS(status, NT_STATUS_OK);
814         smb2_util_close(tree2, io1.smb2.out.file.handle);
815
816         status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name\\subname1-r");
817         CHECK_STATUS(status, NT_STATUS_OK);
818         status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name");
819         CHECK_STATUS(status, NT_STATUS_OK);
820         status = smb2_util_unlink(tree2, BASEDIR "\\subname3-r");
821         CHECK_STATUS(status, NT_STATUS_OK);
822
823         status = smb2_notify_recv(req1, torture, &(notify.smb2));
824         CHECK_STATUS(status, NT_STATUS_OK);
825
826         CHECK_VAL(notify.smb2.out.num_changes, 1);
827         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
828         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname2-r");
829
830         status = smb2_notify_recv(req2, torture, &(notify.smb2));
831         CHECK_STATUS(status, NT_STATUS_OK);
832
833         CHECK_VAL(notify.smb2.out.num_changes, 1);
834         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
835         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname3-r");
836
837         if (!ret) {
838                 goto done;
839         }
840
841 done:
842         smb2_deltree(tree1, BASEDIR);
843         return ret;
844 }
845
846 /*
847    testing of mask bits for change notify
848 */
849
850 static bool torture_smb2_notify_mask(struct torture_context *torture,
851                                      struct smb2_tree *tree1,
852                                      struct smb2_tree *tree2)
853 {
854         bool ret = true;
855         NTSTATUS status;
856         union smb_notify notify;
857         union smb_open io, io1;
858         struct smb2_handle h1, h2;
859         uint32_t mask;
860         int i;
861         char c = 1;
862         union smb_setfileinfo sinfo;
863
864         smb2_deltree(tree1, BASEDIR);
865         smb2_util_rmdir(tree1, BASEDIR);
866
867         torture_comment(torture, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
868
869
870         ZERO_STRUCT(h1);
871         ZERO_STRUCT(h2);
872         /*
873           get a handle on the directory
874         */
875         ZERO_STRUCT(io.smb2);
876         io.generic.level = RAW_OPEN_SMB2;
877         io.smb2.in.create_flags = 0;
878         io.smb2.in.desired_access = SEC_FILE_ALL;
879         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
880         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
881         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
882                                 NTCREATEX_SHARE_ACCESS_WRITE;
883         io.smb2.in.alloc_size = 0;
884         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
885         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
886         io.smb2.in.security_flags = 0;
887         io.smb2.in.fname = BASEDIR;
888
889         ZERO_STRUCT(notify.smb2);
890         notify.smb2.level = RAW_NOTIFY_SMB2;
891         notify.smb2.in.buffer_size = 1000;
892         notify.smb2.in.recursive = true;
893
894 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
895                          expected, nchanges) \
896         do { \
897         do { for (mask=i=0;i<32;i++) { \
898                 struct smb2_request *req; \
899                 status = smb2_create(tree1, torture, &(io.smb2)); \
900                 CHECK_STATUS(status, NT_STATUS_OK); \
901                 h1 = io.smb2.out.file.handle; \
902                 setup \
903                 notify.smb2.in.file.handle = h1;        \
904                 notify.smb2.in.completion_filter = (1<<i); \
905                 /* cancel initial requests so the buffer is setup */    \
906                 req = smb2_notify_send(tree1, &(notify.smb2)); \
907                 smb2_cancel(req); \
908                 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
909                 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
910                 /* send the change notify request */ \
911                 req = smb2_notify_send(tree1, &(notify.smb2)); \
912                 op \
913                 smb_msleep(200); smb2_cancel(req); \
914                 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
915                 cleanup \
916                 smb2_util_close(tree1, h1); \
917                 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
918                 CHECK_STATUS(status, NT_STATUS_OK); \
919                 /* special case to cope with file rename behaviour */ \
920                 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
921                     notify.smb2.out.changes[0].action == \
922                         NOTIFY_ACTION_MODIFIED && \
923                     ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
924                     Action == NOTIFY_ACTION_OLD_NAME) { \
925                         torture_comment(torture, \
926                                 "(rename file special handling OK)\n"); \
927                 } else if (nchanges != notify.smb2.out.num_changes) { \
928                         torture_result(torture, TORTURE_FAIL, \
929                                "ERROR: nchanges=%d expected=%d "\
930                                "action=%d filter=0x%08x\n", \
931                                notify.smb2.out.num_changes, \
932                                nchanges, \
933                                notify.smb2.out.changes[0].action, \
934                                notify.smb2.in.completion_filter); \
935                         ret = false; \
936                 } else if (notify.smb2.out.changes[0].action != Action) { \
937                         torture_result(torture, TORTURE_FAIL, \
938                                "ERROR: nchanges=%d action=%d " \
939                                "expectedAction=%d filter=0x%08x\n", \
940                                notify.smb2.out.num_changes, \
941                                notify.smb2.out.changes[0].action, \
942                                Action, \
943                                notify.smb2.in.completion_filter); \
944                         ret = false; \
945                 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
946                            "tname1") != 0) { \
947                         torture_result(torture, TORTURE_FAIL, \
948                                "ERROR: nchanges=%d action=%d " \
949                                "filter=0x%08x name=%s\n", \
950                                notify.smb2.out.num_changes, \
951                                notify.smb2.out.changes[0].action, \
952                                notify.smb2.in.completion_filter, \
953                                notify.smb2.out.changes[0].name.s);      \
954                         ret = false; \
955                 } \
956                 mask |= (1<<i); \
957         } \
958         } while (0); \
959         } while (0);
960
961         torture_comment(torture, "Testing mkdir\n");
962         NOTIFY_MASK_TEST("Testing mkdir",;,
963                          smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
964                          smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
965                          NOTIFY_ACTION_ADDED,
966                          FILE_NOTIFY_CHANGE_DIR_NAME, 1);
967
968         torture_comment(torture, "Testing create file\n");
969         ZERO_STRUCT(io1.smb2);
970         io1.generic.level = RAW_OPEN_SMB2;
971         io1.smb2.in.create_flags = 0;
972         io1.smb2.in.desired_access = SEC_FILE_ALL;
973         io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
974         io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
975                                 NTCREATEX_SHARE_ACCESS_WRITE;
976         io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
977         io1.smb2.in.security_flags = 0;
978         io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
979         io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
980         io1.smb2.in.fname = BASEDIR "\\tname1";
981
982         NOTIFY_MASK_TEST("Testing create file",;,
983                          smb2_util_close(tree2, custom_smb2_create(tree2,
984                                                 torture, &(io1.smb2)));,
985                          smb2_util_unlink(tree2, BASEDIR "\\tname1");,
986                          NOTIFY_ACTION_ADDED,
987                          FILE_NOTIFY_CHANGE_FILE_NAME, 1);
988
989         torture_comment(torture, "Testing unlink\n");
990         NOTIFY_MASK_TEST("Testing unlink",
991                          smb2_util_close(tree2, custom_smb2_create(tree2,
992                                                 torture, &(io1.smb2)));,
993                          smb2_util_unlink(tree2, BASEDIR "\\tname1");,
994                          ;,
995                          NOTIFY_ACTION_REMOVED,
996                          FILE_NOTIFY_CHANGE_FILE_NAME, 1);
997
998         torture_comment(torture, "Testing rmdir\n");
999         NOTIFY_MASK_TEST("Testing rmdir",
1000                          smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
1001                          smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
1002                          ;,
1003                          NOTIFY_ACTION_REMOVED,
1004                          FILE_NOTIFY_CHANGE_DIR_NAME, 1);
1005
1006         torture_comment(torture, "Testing rename file\n");
1007         ZERO_STRUCT(sinfo);
1008         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1009         sinfo.rename_information.in.file.handle = h1;
1010         sinfo.rename_information.in.overwrite = true;
1011         sinfo.rename_information.in.root_fid = 0;
1012         sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
1013         NOTIFY_MASK_TEST("Testing rename file",
1014                          smb2_util_close(tree2, custom_smb2_create(tree2,
1015                                                 torture, &(io1.smb2)));,
1016                          smb2_setinfo_file(tree2, &sinfo);,
1017                          smb2_util_unlink(tree2, BASEDIR "\\tname2");,
1018                          NOTIFY_ACTION_OLD_NAME,
1019                          FILE_NOTIFY_CHANGE_FILE_NAME, 2);
1020
1021         torture_comment(torture, "Testing rename dir\n");
1022         ZERO_STRUCT(sinfo);
1023         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1024         sinfo.rename_information.in.file.handle = h1;
1025         sinfo.rename_information.in.overwrite = true;
1026         sinfo.rename_information.in.root_fid = 0;
1027         sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
1028         NOTIFY_MASK_TEST("Testing rename dir",
1029                 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
1030                 smb2_setinfo_file(tree2, &sinfo);,
1031                 smb2_util_rmdir(tree2, BASEDIR "\\tname2");,
1032                 NOTIFY_ACTION_OLD_NAME,
1033                 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
1034
1035         torture_comment(torture, "Testing set path attribute\n");
1036         NOTIFY_MASK_TEST("Testing set path attribute",
1037                 smb2_util_close(tree2, custom_smb2_create(tree2,
1038                                        torture, &(io.smb2)));,
1039                 smb2_util_setatr(tree2, BASEDIR "\\tname1",
1040                                  FILE_ATTRIBUTE_HIDDEN);,
1041                 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1042                 NOTIFY_ACTION_MODIFIED,
1043                 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
1044
1045         torture_comment(torture, "Testing set path write time\n");
1046         ZERO_STRUCT(sinfo);
1047         sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1048         sinfo.generic.in.file.handle = h1;
1049         sinfo.basic_info.in.write_time = 1000;
1050         NOTIFY_MASK_TEST("Testing set path write time",
1051                 smb2_util_close(tree2, custom_smb2_create(tree2,
1052                                        torture, &(io1.smb2)));,
1053                 smb2_setinfo_file(tree2, &sinfo);,
1054                 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1055                 NOTIFY_ACTION_MODIFIED,
1056                 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
1057
1058         if (torture_setting_bool(torture, "samba3", false)) {
1059                 torture_comment(torture,
1060                        "Samba3 does not yet support create times "
1061                        "everywhere\n");
1062         }
1063         else {
1064                 ZERO_STRUCT(sinfo);
1065                 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1066                 sinfo.generic.in.file.handle = h1;
1067                 sinfo.basic_info.in.create_time = 0;
1068                 torture_comment(torture, "Testing set file create time\n");
1069                 NOTIFY_MASK_TEST("Testing set file create time",
1070                         smb2_create_complex_file(torture, tree2,
1071                         BASEDIR "\\tname1", &h2);,
1072                         smb2_setinfo_file(tree2, &sinfo);,
1073                         (smb2_util_close(tree2, h2),
1074                          smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1075                         NOTIFY_ACTION_MODIFIED,
1076                         FILE_NOTIFY_CHANGE_CREATION, 1);
1077         }
1078
1079         ZERO_STRUCT(sinfo);
1080         sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1081         sinfo.generic.in.file.handle = h1;
1082         sinfo.basic_info.in.access_time = 0;
1083         torture_comment(torture, "Testing set file access time\n");
1084         NOTIFY_MASK_TEST("Testing set file access time",
1085                 smb2_create_complex_file(torture, tree2, BASEDIR "\\tname1", &h2);,
1086                 smb2_setinfo_file(tree2, &sinfo);,
1087                 (smb2_util_close(tree2, h2),
1088                 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1089                 NOTIFY_ACTION_MODIFIED,
1090                 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
1091
1092         ZERO_STRUCT(sinfo);
1093         sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1094         sinfo.generic.in.file.handle = h1;
1095         sinfo.basic_info.in.change_time = 0;
1096         torture_comment(torture, "Testing set file change time\n");
1097         NOTIFY_MASK_TEST("Testing set file change time",
1098                 smb2_create_complex_file(torture, tree2, BASEDIR "\\tname1", &h2);,
1099                 smb2_setinfo_file(tree2, &sinfo);,
1100                 (smb2_util_close(tree2, h2),
1101                 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1102                 NOTIFY_ACTION_MODIFIED,
1103                 0, 1);
1104
1105
1106         torture_comment(torture, "Testing write\n");
1107         NOTIFY_MASK_TEST("Testing write",
1108                 smb2_create_complex_file(torture, tree2, BASEDIR "\\tname1", &h2);,
1109                 smb2_util_write(tree2, h2, &c, 10000, 1);,
1110                 (smb2_util_close(tree2, h2),
1111                 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1112                 NOTIFY_ACTION_MODIFIED,
1113                 0, 1);
1114
1115 done:
1116         smb2_deltree(tree1, BASEDIR);
1117         return ret;
1118 }
1119
1120 /*
1121   basic testing of change notify on files
1122 */
1123 static bool torture_smb2_notify_file(struct torture_context *torture,
1124                                 struct smb2_tree *tree)
1125 {
1126         NTSTATUS status;
1127         bool ret = true;
1128         union smb_open io;
1129         union smb_close cl;
1130         union smb_notify notify;
1131         struct smb2_request *req;
1132         struct smb2_handle h1;
1133         const char *fname = BASEDIR "\\file.txt";
1134
1135         smb2_deltree(tree, BASEDIR);
1136         smb2_util_rmdir(tree, BASEDIR);
1137
1138         torture_comment(torture, "TESTING CHANGE NOTIFY ON FILES\n");
1139         status = torture_smb2_testdir(tree, BASEDIR, &h1);
1140         CHECK_STATUS(status, NT_STATUS_OK);
1141
1142         ZERO_STRUCT(io.smb2);
1143         io.generic.level = RAW_OPEN_SMB2;
1144         io.smb2.in.create_flags = 0;
1145         io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
1146         io.smb2.in.create_options = 0;
1147         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1148         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1149                                 NTCREATEX_SHARE_ACCESS_WRITE;
1150         io.smb2.in.alloc_size = 0;
1151         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1152         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1153         io.smb2.in.security_flags = 0;
1154         io.smb2.in.fname = fname;
1155         status = smb2_create(tree, torture, &(io.smb2));
1156         CHECK_STATUS(status, NT_STATUS_OK);
1157         h1 = io.smb2.out.file.handle;
1158
1159         /* ask for a change notify,
1160            on file or directory name changes */
1161         ZERO_STRUCT(notify.smb2);
1162         notify.smb2.level = RAW_NOTIFY_SMB2;
1163         notify.smb2.in.file.handle = h1;
1164         notify.smb2.in.buffer_size = 1000;
1165         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
1166         notify.smb2.in.recursive = false;
1167
1168         torture_comment(torture,
1169         "Testing if notifies on file handles are invalid (should be)\n");
1170
1171         req = smb2_notify_send(tree, &(notify.smb2));
1172         status = smb2_notify_recv(req, torture, &(notify.smb2));
1173         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1174
1175         ZERO_STRUCT(cl.smb2);
1176         cl.close.level = RAW_CLOSE_SMB2;
1177         cl.close.in.file.handle = h1;
1178         status = smb2_close(tree, &(cl.smb2));
1179         CHECK_STATUS(status, NT_STATUS_OK);
1180
1181         status = smb2_util_unlink(tree, fname);
1182         CHECK_STATUS(status, NT_STATUS_OK);
1183
1184 done:
1185         smb2_deltree(tree, BASEDIR);
1186         return ret;
1187 }
1188 /*
1189   basic testing of change notifies followed by a tdis
1190 */
1191
1192 static bool torture_smb2_notify_tree_disconnect(
1193                 struct torture_context *torture,
1194                 struct smb2_tree *tree)
1195 {
1196         bool ret = true;
1197         NTSTATUS status;
1198         union smb_notify notify;
1199         union smb_open io;
1200         struct smb2_handle h1;
1201         struct smb2_request *req;
1202
1203         smb2_deltree(tree, BASEDIR);
1204         smb2_util_rmdir(tree, BASEDIR);
1205
1206         torture_comment(torture, "TESTING CHANGE NOTIFY+CANCEL FOLLOWED BY "
1207                         "TREE-DISCONNECT\n");
1208
1209         /*
1210           get a handle on the directory
1211         */
1212         ZERO_STRUCT(io.smb2);
1213         io.generic.level = RAW_OPEN_SMB2;
1214         io.smb2.in.create_flags = 0;
1215         io.smb2.in.desired_access = SEC_FILE_ALL;
1216         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1217         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1218         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1219                                 NTCREATEX_SHARE_ACCESS_WRITE;
1220         io.smb2.in.alloc_size = 0;
1221         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1222         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1223         io.smb2.in.security_flags = 0;
1224         io.smb2.in.fname = BASEDIR;
1225
1226         status = smb2_create(tree, torture, &(io.smb2));
1227         CHECK_STATUS(status, NT_STATUS_OK);
1228         h1 = io.smb2.out.file.handle;
1229
1230         /* ask for a change notify,
1231            on file or directory name changes */
1232         ZERO_STRUCT(notify.smb2);
1233         notify.smb2.level = RAW_NOTIFY_SMB2;
1234         notify.smb2.in.buffer_size = 1000;
1235         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1236         notify.smb2.in.file.handle = h1;
1237         notify.smb2.in.recursive = true;
1238
1239         req = smb2_notify_send(tree, &(notify.smb2));
1240         smb2_cancel(req);
1241         status = smb2_notify_recv(req, torture, &(notify.smb2));
1242
1243         status = smb2_tdis(tree);
1244         CHECK_STATUS(status, NT_STATUS_OK);
1245
1246         req = smb2_notify_send(tree, &(notify.smb2));
1247
1248         smb2_notify_recv(req, torture, &(notify.smb2));
1249         CHECK_STATUS(status, NT_STATUS_OK);
1250         CHECK_VAL(notify.smb2.out.num_changes, 0);
1251
1252 done:
1253         smb2_deltree(tree, BASEDIR);
1254         return ret;
1255 }
1256
1257 /*
1258   testing of change notifies followed by a tdis - no cancel
1259 */
1260
1261 static bool torture_smb2_notify_tree_disconnect_1(
1262                 struct torture_context *torture,
1263                 struct smb2_tree *tree)
1264 {
1265         bool ret = true;
1266         NTSTATUS status;
1267         union smb_notify notify;
1268         union smb_open io;
1269         struct smb2_handle h1;
1270         struct smb2_request *req;
1271
1272         smb2_deltree(tree, BASEDIR);
1273         smb2_util_rmdir(tree, BASEDIR);
1274
1275         torture_comment(torture, "TESTING CHANGE NOTIFY ASYNC FOLLOWED BY "
1276                         "TREE-DISCONNECT\n");
1277
1278         /*
1279           get a handle on the directory
1280         */
1281         ZERO_STRUCT(io.smb2);
1282         io.generic.level = RAW_OPEN_SMB2;
1283         io.smb2.in.create_flags = 0;
1284         io.smb2.in.desired_access = SEC_FILE_ALL;
1285         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1286         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1287         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1288                                 NTCREATEX_SHARE_ACCESS_WRITE;
1289         io.smb2.in.alloc_size = 0;
1290         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1291         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1292         io.smb2.in.security_flags = 0;
1293         io.smb2.in.fname = BASEDIR;
1294
1295         status = smb2_create(tree, torture, &(io.smb2));
1296         CHECK_STATUS(status, NT_STATUS_OK);
1297         h1 = io.smb2.out.file.handle;
1298
1299         /* ask for a change notify,
1300            on file or directory name changes */
1301         ZERO_STRUCT(notify.smb2);
1302         notify.smb2.level = RAW_NOTIFY_SMB2;
1303         notify.smb2.in.buffer_size = 1000;
1304         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1305         notify.smb2.in.file.handle = h1;
1306         notify.smb2.in.recursive = true;
1307
1308         req = smb2_notify_send(tree, &(notify.smb2));
1309         WAIT_FOR_ASYNC_RESPONSE(req);
1310
1311         status = smb2_tdis(tree);
1312         CHECK_STATUS(status, NT_STATUS_OK);
1313
1314         status = smb2_notify_recv(req, torture, &(notify.smb2));
1315         CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1316         CHECK_VAL(notify.smb2.out.num_changes, 0);
1317
1318 done:
1319         smb2_deltree(tree, BASEDIR);
1320         return ret;
1321 }
1322
1323 /*
1324   basic testing of change notifies followed by a close
1325 */
1326
1327 static bool torture_smb2_notify_close(struct torture_context *torture,
1328                                 struct smb2_tree *tree1)
1329 {
1330         bool ret = true;
1331         NTSTATUS status;
1332         union smb_notify notify;
1333         union smb_open io;
1334         struct smb2_handle h1;
1335         struct smb2_request *req;
1336
1337         smb2_deltree(tree1, BASEDIR);
1338         smb2_util_rmdir(tree1, BASEDIR);
1339
1340         torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1341
1342         /*
1343           get a handle on the directory
1344         */
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_CREATE;
1355         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1356         io.smb2.in.security_flags = 0;
1357         io.smb2.in.fname = BASEDIR;
1358
1359         status = smb2_create(tree1, torture, &(io.smb2));
1360         CHECK_STATUS(status, NT_STATUS_OK);
1361
1362         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1363         status = smb2_create(tree1, torture, &(io.smb2));
1364         CHECK_STATUS(status, NT_STATUS_OK);
1365         h1 = io.smb2.out.file.handle;
1366
1367         /* ask for a change notify,
1368            on file or directory name changes */
1369         ZERO_STRUCT(notify.smb2);
1370         notify.smb2.level = RAW_NOTIFY_SMB2;
1371         notify.smb2.in.buffer_size = 1000;
1372         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1373         notify.smb2.in.file.handle = h1;
1374         notify.smb2.in.recursive = true;
1375
1376         req = smb2_notify_send(tree1, &(notify.smb2));
1377
1378         WAIT_FOR_ASYNC_RESPONSE(req);
1379
1380         status = smb2_util_close(tree1, h1);
1381         CHECK_STATUS(status, NT_STATUS_OK);
1382
1383         status = smb2_notify_recv(req, torture, &(notify.smb2));
1384         CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1385         CHECK_VAL(notify.smb2.out.num_changes, 0);
1386
1387 done:
1388         smb2_deltree(tree1, BASEDIR);
1389         return ret;
1390 }
1391
1392 /*
1393   basic testing of change notifies followed by a ulogoff
1394 */
1395
1396 static bool torture_smb2_notify_ulogoff(struct torture_context *torture,
1397                                 struct smb2_tree *tree1)
1398 {
1399         bool ret = true;
1400         NTSTATUS status;
1401         union smb_notify notify;
1402         union smb_open io;
1403         struct smb2_handle h1;
1404         struct smb2_request *req;
1405
1406         smb2_deltree(tree1, BASEDIR);
1407         smb2_util_rmdir(tree1, BASEDIR);
1408
1409         torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1410
1411         /*
1412           get a handle on the directory
1413         */
1414         ZERO_STRUCT(io.smb2);
1415         io.generic.level = RAW_OPEN_SMB2;
1416         io.smb2.in.create_flags = 0;
1417         io.smb2.in.desired_access = SEC_FILE_ALL;
1418         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1419         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1420         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1421                                 NTCREATEX_SHARE_ACCESS_WRITE;
1422         io.smb2.in.alloc_size = 0;
1423         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1424         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1425         io.smb2.in.security_flags = 0;
1426         io.smb2.in.fname = BASEDIR;
1427
1428         status = smb2_create(tree1, torture, &(io.smb2));
1429         CHECK_STATUS(status, NT_STATUS_OK);
1430
1431         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1432         status = smb2_create(tree1, torture, &(io.smb2));
1433         CHECK_STATUS(status, NT_STATUS_OK);
1434         h1 = io.smb2.out.file.handle;
1435
1436         /* ask for a change notify,
1437            on file or directory name changes */
1438         ZERO_STRUCT(notify.smb2);
1439         notify.smb2.level = RAW_NOTIFY_SMB2;
1440         notify.smb2.in.buffer_size = 1000;
1441         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1442         notify.smb2.in.file.handle = h1;
1443         notify.smb2.in.recursive = true;
1444
1445         req = smb2_notify_send(tree1, &(notify.smb2));
1446
1447         WAIT_FOR_ASYNC_RESPONSE(req);
1448
1449         status = smb2_logoff(tree1->session);
1450         CHECK_STATUS(status, NT_STATUS_OK);
1451
1452         status = smb2_notify_recv(req, torture, &(notify.smb2));
1453         CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1454         CHECK_VAL(notify.smb2.out.num_changes, 0);
1455
1456 done:
1457         smb2_deltree(tree1, BASEDIR);
1458         return ret;
1459 }
1460
1461 /*
1462   basic testing of change notifies followed by a session reconnect
1463 */
1464
1465 static bool torture_smb2_notify_session_reconnect(struct torture_context *torture,
1466                                 struct smb2_tree *tree1)
1467 {
1468         bool ret = true;
1469         NTSTATUS status;
1470         union smb_notify notify;
1471         union smb_open io;
1472         struct smb2_handle h1;
1473         struct smb2_request *req;
1474         uint64_t previous_session_id = 0;
1475         struct smb2_session *session2 = NULL;
1476
1477         smb2_deltree(tree1, BASEDIR);
1478         smb2_util_rmdir(tree1, BASEDIR);
1479
1480         torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY SESSION RECONNECT\n");
1481
1482         /*
1483           get a handle on the directory
1484         */
1485         ZERO_STRUCT(io.smb2);
1486         io.generic.level = RAW_OPEN_SMB2;
1487         io.smb2.in.create_flags = 0;
1488         io.smb2.in.desired_access = SEC_FILE_ALL;
1489         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1490         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1491         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1492                                 NTCREATEX_SHARE_ACCESS_WRITE;
1493         io.smb2.in.alloc_size = 0;
1494         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1495         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1496         io.smb2.in.security_flags = 0;
1497         io.smb2.in.fname = BASEDIR;
1498
1499         status = smb2_create(tree1, torture, &(io.smb2));
1500         CHECK_STATUS(status, NT_STATUS_OK);
1501
1502         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1503         status = smb2_create(tree1, torture, &(io.smb2));
1504         CHECK_STATUS(status, NT_STATUS_OK);
1505         h1 = io.smb2.out.file.handle;
1506
1507         /* ask for a change notify,
1508            on file or directory name changes */
1509         ZERO_STRUCT(notify.smb2);
1510         notify.smb2.level = RAW_NOTIFY_SMB2;
1511         notify.smb2.in.buffer_size = 1000;
1512         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1513         notify.smb2.in.file.handle = h1;
1514         notify.smb2.in.recursive = true;
1515
1516         req = smb2_notify_send(tree1, &(notify.smb2));
1517
1518         WAIT_FOR_ASYNC_RESPONSE(req);
1519
1520         previous_session_id = smb2cli_session_current_id(tree1->session->smbXcli);
1521         torture_assert(torture, torture_smb2_session_setup(torture,
1522                        tree1->session->transport,
1523                        previous_session_id,
1524                        torture, &session2),
1525                        "session setup with previous_session_id failed");
1526
1527         status = smb2_notify_recv(req, torture, &(notify.smb2));
1528         CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1529         CHECK_VAL(notify.smb2.out.num_changes, 0);
1530
1531         status = smb2_logoff(tree1->session);
1532         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
1533
1534         status = smb2_logoff(session2);
1535         CHECK_STATUS(status, NT_STATUS_OK);
1536 done:
1537         smb2_deltree(tree1, BASEDIR);
1538         return ret;
1539 }
1540
1541 /*
1542   basic testing of change notifies followed by an invalid reauth
1543 */
1544
1545 static bool torture_smb2_notify_invalid_reauth(struct torture_context *torture,
1546                                                struct smb2_tree *tree1,
1547                                                struct smb2_tree *tree2)
1548 {
1549         bool ret = true;
1550         NTSTATUS status;
1551         union smb_notify notify;
1552         union smb_open io;
1553         struct smb2_handle h1;
1554         struct smb2_request *req;
1555         struct cli_credentials *invalid_creds;
1556
1557         smb2_deltree(tree2, BASEDIR);
1558         smb2_util_rmdir(tree2, BASEDIR);
1559
1560         torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY invalid REAUTH\n");
1561
1562         /*
1563           get a handle on the directory
1564         */
1565         ZERO_STRUCT(io.smb2);
1566         io.generic.level = RAW_OPEN_SMB2;
1567         io.smb2.in.create_flags = 0;
1568         io.smb2.in.desired_access = SEC_FILE_ALL;
1569         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1570         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1571         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1572                                 NTCREATEX_SHARE_ACCESS_WRITE;
1573         io.smb2.in.alloc_size = 0;
1574         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1575         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1576         io.smb2.in.security_flags = 0;
1577         io.smb2.in.fname = BASEDIR;
1578
1579         status = smb2_create(tree1, torture, &(io.smb2));
1580         CHECK_STATUS(status, NT_STATUS_OK);
1581
1582         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1583         status = smb2_create(tree1, torture, &(io.smb2));
1584         CHECK_STATUS(status, NT_STATUS_OK);
1585         h1 = io.smb2.out.file.handle;
1586
1587         /* ask for a change notify,
1588            on file or directory name changes */
1589         ZERO_STRUCT(notify.smb2);
1590         notify.smb2.level = RAW_NOTIFY_SMB2;
1591         notify.smb2.in.buffer_size = 1000;
1592         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1593         notify.smb2.in.file.handle = h1;
1594         notify.smb2.in.recursive = true;
1595
1596         req = smb2_notify_send(tree1, &(notify.smb2));
1597
1598         WAIT_FOR_ASYNC_RESPONSE(req);
1599
1600         invalid_creds = cli_credentials_init(torture);
1601         torture_assert(torture, (invalid_creds != NULL), "talloc error");
1602         cli_credentials_set_username(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1603         cli_credentials_set_domain(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1604         cli_credentials_set_password(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
1605         cli_credentials_set_realm(invalid_creds, NULL, CRED_SPECIFIED);
1606         cli_credentials_set_workstation(invalid_creds, "", CRED_UNINITIALISED);
1607
1608         status = smb2_session_setup_spnego(tree1->session,
1609                                            invalid_creds,
1610                                            0 /* previous_session_id */);
1611         CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE);
1612
1613         status = smb2_notify_recv(req, torture, &(notify.smb2));
1614         CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
1615         CHECK_VAL(notify.smb2.out.num_changes, 0);
1616
1617 done:
1618         smb2_deltree(tree2, BASEDIR);
1619         return ret;
1620 }
1621
1622 static void tcp_dis_handler(struct smb2_transport *t, void *p)
1623 {
1624         struct smb2_tree *tree = (struct smb2_tree *)p;
1625         smb2_transport_dead(tree->session->transport,
1626                         NT_STATUS_LOCAL_DISCONNECT);
1627         t = NULL;
1628         tree = NULL;
1629 }
1630
1631 /*
1632   basic testing of change notifies followed by tcp disconnect
1633 */
1634
1635 static bool torture_smb2_notify_tcp_disconnect(
1636                 struct torture_context *torture,
1637                 struct smb2_tree *tree)
1638 {
1639         bool ret = true;
1640         NTSTATUS status;
1641         union smb_notify notify;
1642         union smb_open io;
1643         struct smb2_handle h1;
1644         struct smb2_request *req;
1645
1646         smb2_deltree(tree, BASEDIR);
1647         smb2_util_rmdir(tree, BASEDIR);
1648
1649         torture_comment(torture,
1650                 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1651
1652         /*
1653           get a handle on the directory
1654         */
1655         ZERO_STRUCT(io.smb2);
1656         io.generic.level = RAW_OPEN_SMB2;
1657         io.smb2.in.create_flags = 0;
1658         io.smb2.in.desired_access = SEC_FILE_ALL;
1659         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1660         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1661         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1662                                 NTCREATEX_SHARE_ACCESS_WRITE;
1663         io.smb2.in.alloc_size = 0;
1664         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1665         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1666         io.smb2.in.security_flags = 0;
1667         io.smb2.in.fname = BASEDIR;
1668
1669         status = smb2_create(tree, torture, &(io.smb2));
1670         CHECK_STATUS(status, NT_STATUS_OK);
1671         h1 = io.smb2.out.file.handle;
1672
1673         /* ask for a change notify,
1674            on file or directory name changes */
1675         ZERO_STRUCT(notify.smb2);
1676         notify.smb2.level = RAW_NOTIFY_SMB2;
1677         notify.smb2.in.buffer_size = 1000;
1678         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1679         notify.smb2.in.file.handle = h1;
1680         notify.smb2.in.recursive = true;
1681
1682         req = smb2_notify_send(tree, &(notify.smb2));
1683         smb2_cancel(req);
1684         status = smb2_notify_recv(req, torture, &(notify.smb2));
1685         CHECK_STATUS(status, NT_STATUS_CANCELLED);
1686
1687         notify.smb2.in.recursive = true;
1688         req = smb2_notify_send(tree, &(notify.smb2));
1689         smb2_transport_idle_handler(tree->session->transport,
1690                                 tcp_dis_handler, 250, tree);
1691         tree = NULL;
1692         status = smb2_notify_recv(req, torture, &(notify.smb2));
1693         CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
1694
1695 done:
1696         return ret;
1697 }
1698
1699 /*
1700    test setting up two change notify requests on one handle
1701 */
1702
1703 static bool torture_smb2_notify_double(struct torture_context *torture,
1704                         struct smb2_tree *tree1,
1705                         struct smb2_tree *tree2)
1706 {
1707         bool ret = true;
1708         NTSTATUS status;
1709         union smb_notify notify;
1710         union smb_open io;
1711         struct smb2_handle h1;
1712         struct smb2_request *req1, *req2;
1713
1714         smb2_deltree(tree1, BASEDIR);
1715         smb2_util_rmdir(tree1, BASEDIR);
1716
1717         torture_comment(torture,
1718                 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1719
1720         /*
1721           get a handle on the directory
1722         */
1723         ZERO_STRUCT(io.smb2);
1724         io.generic.level = RAW_OPEN_SMB2;
1725         io.smb2.in.create_flags = 0;
1726         io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ|
1727                                 SEC_RIGHTS_FILE_WRITE|
1728                                 SEC_RIGHTS_FILE_ALL;
1729         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1730         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1731         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1732                                 NTCREATEX_SHARE_ACCESS_WRITE;
1733         io.smb2.in.alloc_size = 0;
1734         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1735         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1736         io.smb2.in.security_flags = 0;
1737         io.smb2.in.fname = BASEDIR;
1738
1739         status = smb2_create(tree1, torture, &(io.smb2));
1740         CHECK_STATUS(status, NT_STATUS_OK);
1741         h1 = io.smb2.out.file.handle;
1742
1743         /* ask for a change notify,
1744            on file or directory name changes */
1745         ZERO_STRUCT(notify.smb2);
1746         notify.smb2.level = RAW_NOTIFY_SMB2;
1747         notify.smb2.in.buffer_size = 1000;
1748         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1749         notify.smb2.in.file.handle = h1;
1750         notify.smb2.in.recursive = true;
1751
1752         req1 = smb2_notify_send(tree1, &(notify.smb2));
1753         smb2_cancel(req1);
1754         status = smb2_notify_recv(req1, torture, &(notify.smb2));
1755         CHECK_STATUS(status, NT_STATUS_CANCELLED);
1756
1757         req2 = smb2_notify_send(tree1, &(notify.smb2));
1758         smb2_cancel(req2);
1759         status = smb2_notify_recv(req2, torture, &(notify.smb2));
1760         CHECK_STATUS(status, NT_STATUS_CANCELLED);
1761
1762         smb2_util_mkdir(tree2, BASEDIR "\\subdir-name");
1763         req1 = smb2_notify_send(tree1, &(notify.smb2));
1764         req2 = smb2_notify_send(tree1, &(notify.smb2));
1765
1766         status = smb2_notify_recv(req1, torture, &(notify.smb2));
1767         CHECK_STATUS(status, NT_STATUS_OK);
1768         CHECK_VAL(notify.smb2.out.num_changes, 1);
1769         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1770
1771         smb2_util_mkdir(tree2, BASEDIR "\\subdir-name2");
1772
1773         status = smb2_notify_recv(req2, torture, &(notify.smb2));
1774         CHECK_STATUS(status, NT_STATUS_OK);
1775         CHECK_VAL(notify.smb2.out.num_changes, 1);
1776         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name2");
1777
1778 done:
1779         smb2_deltree(tree1, BASEDIR);
1780         return ret;
1781 }
1782
1783
1784 /*
1785    test multiple change notifies at different depths and with/without recursion
1786 */
1787
1788 static bool torture_smb2_notify_tree(struct torture_context *torture,
1789                              struct smb2_tree *tree)
1790 {
1791         bool ret = true;
1792         union smb_notify notify;
1793         union smb_open io;
1794         struct smb2_request *req;
1795         struct timeval tv;
1796         struct {
1797                 const char *path;
1798                 bool recursive;
1799                 uint32_t filter;
1800                 int expected;
1801                 struct smb2_handle h1;
1802                 int counted;
1803         } dirs[] = {
1804                 {BASEDIR "\\abc",               true, FILE_NOTIFY_CHANGE_NAME, 30 },
1805                 {BASEDIR "\\zqy",               true, FILE_NOTIFY_CHANGE_NAME, 8 },
1806                 {BASEDIR "\\atsy",              true, FILE_NOTIFY_CHANGE_NAME, 4 },
1807                 {BASEDIR "\\abc\\foo",          true,  FILE_NOTIFY_CHANGE_NAME, 2 },
1808                 {BASEDIR "\\abc\\blah",         true,  FILE_NOTIFY_CHANGE_NAME, 13 },
1809                 {BASEDIR "\\abc\\blah",         false, FILE_NOTIFY_CHANGE_NAME, 7 },
1810                 {BASEDIR "\\abc\\blah\\a",      true, FILE_NOTIFY_CHANGE_NAME, 2 },
1811                 {BASEDIR "\\abc\\blah\\b",      true, FILE_NOTIFY_CHANGE_NAME, 2 },
1812                 {BASEDIR "\\abc\\blah\\c",      true, FILE_NOTIFY_CHANGE_NAME, 2 },
1813                 {BASEDIR "\\abc\\fooblah",      true, FILE_NOTIFY_CHANGE_NAME, 2 },
1814                 {BASEDIR "\\zqy\\xx",           true, FILE_NOTIFY_CHANGE_NAME, 2 },
1815                 {BASEDIR "\\zqy\\yyy",          true, FILE_NOTIFY_CHANGE_NAME, 2 },
1816                 {BASEDIR "\\zqy\\..",           true, FILE_NOTIFY_CHANGE_NAME, 40 },
1817                 {BASEDIR,                       true, FILE_NOTIFY_CHANGE_NAME, 40 },
1818                 {BASEDIR,                       false,FILE_NOTIFY_CHANGE_NAME, 6 },
1819                 {BASEDIR "\\atsy",              false,FILE_NOTIFY_CHANGE_NAME, 4 },
1820                 {BASEDIR "\\abc",               true, FILE_NOTIFY_CHANGE_NAME, 24 },
1821                 {BASEDIR "\\abc",               false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1822                 {BASEDIR "\\abc",               true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1823                 {BASEDIR "\\abc",               true, FILE_NOTIFY_CHANGE_NAME, 24 },
1824         };
1825         int i;
1826         NTSTATUS status;
1827         bool all_done = false;
1828
1829         smb2_deltree(tree, BASEDIR);
1830         smb2_util_rmdir(tree, BASEDIR);
1831
1832         torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1833
1834         ZERO_STRUCT(io.smb2);
1835         io.generic.level = RAW_OPEN_SMB2;
1836         io.smb2.in.create_flags = 0;
1837         io.smb2.in.desired_access = SEC_FILE_ALL;
1838         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1839         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1840         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1841                                 NTCREATEX_SHARE_ACCESS_WRITE;
1842         io.smb2.in.alloc_size = 0;
1843         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1844         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1845         io.smb2.in.security_flags = 0;
1846         io.smb2.in.fname = BASEDIR;
1847         status = smb2_create(tree, torture, &(io.smb2));
1848         CHECK_STATUS(status, NT_STATUS_OK);
1849
1850         ZERO_STRUCT(notify.smb2);
1851         notify.smb2.level = RAW_NOTIFY_SMB2;
1852         notify.smb2.in.buffer_size = 20000;
1853
1854         /*
1855           setup the directory tree, and the notify buffer on each directory
1856         */
1857         for (i=0;i<ARRAY_SIZE(dirs);i++) {
1858                 io.smb2.in.fname = dirs[i].path;
1859                 status = smb2_create(tree, torture, &(io.smb2));
1860                 CHECK_STATUS(status, NT_STATUS_OK);
1861                 dirs[i].h1 = io.smb2.out.file.handle;
1862
1863                 notify.smb2.in.completion_filter = dirs[i].filter;
1864                 notify.smb2.in.file.handle = dirs[i].h1;
1865                 notify.smb2.in.recursive = dirs[i].recursive;
1866                 req = smb2_notify_send(tree, &(notify.smb2));
1867                 smb2_cancel(req);
1868                 status = smb2_notify_recv(req, torture, &(notify.smb2));
1869                 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1870         }
1871
1872         /* trigger 2 events in each dir */
1873         for (i=0;i<ARRAY_SIZE(dirs);i++) {
1874                 char *path = talloc_asprintf(torture, "%s\\test.dir",
1875                                              dirs[i].path);
1876                 smb2_util_mkdir(tree, path);
1877                 smb2_util_rmdir(tree, path);
1878                 talloc_free(path);
1879         }
1880
1881         /* give a bit of time for the events to propogate */
1882         tv = timeval_current();
1883
1884         do {
1885                 /* count events that have happened in each dir */
1886                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1887                         notify.smb2.in.completion_filter = dirs[i].filter;
1888                         notify.smb2.in.file.handle = dirs[i].h1;
1889                         notify.smb2.in.recursive = dirs[i].recursive;
1890                         req = smb2_notify_send(tree, &(notify.smb2));
1891                         smb2_cancel(req);
1892                         notify.smb2.out.num_changes = 0;
1893                         status = smb2_notify_recv(req, torture,
1894                                  &(notify.smb2));
1895                         dirs[i].counted += notify.smb2.out.num_changes;
1896                 }
1897
1898                 all_done = true;
1899
1900                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1901                         if (dirs[i].counted != dirs[i].expected) {
1902                                 all_done = false;
1903                         }
1904                 }
1905         } while (!all_done && timeval_elapsed(&tv) < 20);
1906
1907         torture_comment(torture, "took %.4f seconds to propogate all events\n",
1908                         timeval_elapsed(&tv));
1909
1910         for (i=0;i<ARRAY_SIZE(dirs);i++) {
1911                 if (dirs[i].counted != dirs[i].expected) {
1912                         torture_comment(torture,
1913                                 "ERROR: i=%d expected %d got %d for '%s'\n",
1914                                 i, dirs[i].expected, dirs[i].counted,
1915                                 dirs[i].path);
1916                         ret = false;
1917                 }
1918         }
1919
1920         /*
1921           run from the back, closing and deleting
1922         */
1923         for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1924                 smb2_util_close(tree, dirs[i].h1);
1925                 smb2_util_rmdir(tree, dirs[i].path);
1926         }
1927
1928 done:
1929         smb2_deltree(tree, BASEDIR);
1930         smb2_util_rmdir(tree, BASEDIR);
1931         return ret;
1932 }
1933
1934 /*
1935    Test response when cached server events exceed single NT NOTFIY response
1936    packet size.
1937 */
1938
1939 static bool torture_smb2_notify_overflow(struct torture_context *torture,
1940                                 struct smb2_tree *tree)
1941 {
1942         bool ret = true;
1943         NTSTATUS status;
1944         union smb_notify notify;
1945         union smb_open io;
1946         struct smb2_handle h1, h2;
1947         int count = 100;
1948         struct smb2_request *req1;
1949         int i;
1950
1951         smb2_deltree(tree, BASEDIR);
1952         smb2_util_rmdir(tree, BASEDIR);
1953
1954         torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1955
1956         /* get a handle on the directory */
1957         ZERO_STRUCT(io.smb2);
1958         io.generic.level = RAW_OPEN_SMB2;
1959         io.smb2.in.create_flags = 0;
1960         io.smb2.in.desired_access = SEC_FILE_ALL;
1961         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1962         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1963         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1964                             NTCREATEX_SHARE_ACCESS_WRITE;
1965         io.smb2.in.alloc_size = 0;
1966         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1967         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1968         io.smb2.in.security_flags = 0;
1969         io.smb2.in.fname = BASEDIR;
1970
1971         status = smb2_create(tree, torture, &(io.smb2));
1972         CHECK_STATUS(status, NT_STATUS_OK);
1973         h1 = io.smb2.out.file.handle;
1974
1975         /* ask for a change notify, on name changes. */
1976         ZERO_STRUCT(notify.smb2);
1977         notify.smb2.level = RAW_NOTIFY_NTTRANS;
1978         notify.smb2.in.buffer_size = 1000;
1979         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1980         notify.smb2.in.file.handle = h1;
1981
1982         notify.smb2.in.recursive = true;
1983         req1 = smb2_notify_send(tree, &(notify.smb2));
1984
1985         /* cancel initial requests so the buffer is setup */
1986         smb2_cancel(req1);
1987         status = smb2_notify_recv(req1, torture, &(notify.smb2));
1988         CHECK_STATUS(status, NT_STATUS_CANCELLED);
1989
1990         /* open a lot of files, filling up the server side notify buffer */
1991         torture_comment(torture,
1992                 "Testing overflowed buffer notify on create of %d files\n",
1993                 count);
1994
1995         for (i=0;i<count;i++) {
1996                 char *fname = talloc_asprintf(torture,
1997                               BASEDIR "\\test%d.txt", i);
1998                 union smb_open io1;
1999                 ZERO_STRUCT(io1.smb2);
2000                 io1.generic.level = RAW_OPEN_SMB2;
2001                 io1.smb2.in.create_flags = 0;
2002                 io1.smb2.in.desired_access = SEC_FILE_ALL;
2003                 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2004                 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2005                 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2006                                     NTCREATEX_SHARE_ACCESS_WRITE;
2007                 io1.smb2.in.alloc_size = 0;
2008                 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2009                 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2010                 io1.smb2.in.security_flags = 0;
2011                 io1.smb2.in.fname = fname;
2012
2013                 h2 = custom_smb2_create(tree, torture, &(io1.smb2));
2014                 talloc_free(fname);
2015                 smb2_util_close(tree, h2);
2016         }
2017
2018         req1 = smb2_notify_send(tree, &(notify.smb2));
2019         status = smb2_notify_recv(req1, torture, &(notify.smb2));
2020         CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
2021         CHECK_VAL(notify.smb2.out.num_changes, 0);
2022
2023 done:
2024         smb2_deltree(tree, BASEDIR);
2025         return ret;
2026 }
2027
2028 /*
2029    Test if notifications are returned for changes to the base directory.
2030    They shouldn't be.
2031 */
2032
2033 static bool torture_smb2_notify_basedir(struct torture_context *torture,
2034                                 struct smb2_tree *tree1,
2035                                 struct smb2_tree *tree2)
2036 {
2037         bool ret = true;
2038         NTSTATUS status;
2039         union smb_notify notify;
2040         union smb_open io;
2041         struct smb2_handle h1;
2042         struct smb2_request *req1;
2043
2044         smb2_deltree(tree1, BASEDIR);
2045         smb2_util_rmdir(tree1, BASEDIR);
2046
2047         torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
2048
2049         /* get a handle on the directory */
2050         ZERO_STRUCT(io.smb2);
2051         io.generic.level = RAW_OPEN_SMB2;
2052         io.smb2.in.create_flags = 0;
2053         io.smb2.in.desired_access = SEC_FILE_ALL;
2054         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2055         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2056         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2057             NTCREATEX_SHARE_ACCESS_WRITE;
2058         io.smb2.in.alloc_size = 0;
2059         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2060         io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
2061         io.smb2.in.security_flags = 0;
2062         io.smb2.in.fname = BASEDIR;
2063
2064         status = smb2_create(tree1, torture, &(io.smb2));
2065         CHECK_STATUS(status, NT_STATUS_OK);
2066         h1 = io.smb2.out.file.handle;
2067
2068         /* create a test file that will also be modified */
2069         io.smb2.in.fname = BASEDIR "\\tname1";
2070         io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
2071         status =  smb2_create(tree2, torture, &(io.smb2));
2072         CHECK_STATUS(status,NT_STATUS_OK);
2073         smb2_util_close(tree2, io.smb2.out.file.handle);
2074
2075         /* ask for a change notify, on attribute changes. */
2076         ZERO_STRUCT(notify.smb2);
2077         notify.smb2.level = RAW_NOTIFY_SMB2;
2078         notify.smb2.in.buffer_size = 1000;
2079         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
2080         notify.smb2.in.file.handle = h1;
2081         notify.smb2.in.recursive = true;
2082
2083         req1 = smb2_notify_send(tree1, &(notify.smb2));
2084
2085         /* set attribute on the base dir */
2086         smb2_util_setatr(tree2, BASEDIR, FILE_ATTRIBUTE_HIDDEN);
2087
2088         /* set attribute on a file to assure we receive a notification */
2089         smb2_util_setatr(tree2, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN);
2090         smb_msleep(200);
2091
2092         /* check how many responses were given, expect only 1 for the file */
2093         status = smb2_notify_recv(req1, torture, &(notify.smb2));
2094         CHECK_STATUS(status, NT_STATUS_OK);
2095         CHECK_VAL(notify.smb2.out.num_changes, 1);
2096         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
2097         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
2098
2099 done:
2100         smb2_deltree(tree1, BASEDIR);
2101         return ret;
2102 }
2103
2104 /*
2105    very simple change notify test
2106 */
2107 static bool torture_smb2_notify_tcon(struct torture_context *torture,
2108                                   struct smb2_tree *tree)
2109 {
2110         bool ret = true;
2111         NTSTATUS status;
2112         union smb_notify notify;
2113         union smb_open io;
2114         struct smb2_handle h1 = {{0}};
2115         struct smb2_request *req = NULL;
2116         struct smb2_tree *tree1 = NULL;
2117         const char *fname = BASEDIR "\\subdir-name";
2118
2119         smb2_deltree(tree, BASEDIR);
2120         smb2_util_rmdir(tree, BASEDIR);
2121
2122         torture_comment(torture, "TESTING SIMPLE CHANGE NOTIFY\n");
2123
2124         /*
2125           get a handle on the directory
2126         */
2127
2128         ZERO_STRUCT(io.smb2);
2129         io.generic.level = RAW_OPEN_SMB2;
2130         io.smb2.in.create_flags = 0;
2131         io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2132         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2133         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL |
2134                                 FILE_ATTRIBUTE_DIRECTORY;
2135         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2136                                 NTCREATEX_SHARE_ACCESS_WRITE;
2137         io.smb2.in.alloc_size = 0;
2138         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2139         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2140         io.smb2.in.security_flags = 0;
2141         io.smb2.in.fname = BASEDIR;
2142
2143         status = smb2_create(tree, torture, &(io.smb2));
2144         CHECK_STATUS(status, NT_STATUS_OK);
2145         h1 = io.smb2.out.file.handle;
2146
2147         /* ask for a change notify,
2148            on file or directory name changes */
2149         ZERO_STRUCT(notify.smb2);
2150         notify.smb2.level = RAW_NOTIFY_SMB2;
2151         notify.smb2.in.buffer_size = 1000;
2152         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2153         notify.smb2.in.file.handle = h1;
2154         notify.smb2.in.recursive = true;
2155
2156         torture_comment(torture, "Testing notify mkdir\n");
2157         req = smb2_notify_send(tree, &(notify.smb2));
2158         smb2_cancel(req);
2159         status = smb2_notify_recv(req, torture, &(notify.smb2));
2160         CHECK_STATUS(status, NT_STATUS_CANCELLED);
2161
2162         notify.smb2.in.recursive = true;
2163         req = smb2_notify_send(tree, &(notify.smb2));
2164         status = smb2_util_mkdir(tree, fname);
2165         CHECK_STATUS(status, NT_STATUS_OK);
2166
2167         status = smb2_notify_recv(req, torture, &(notify.smb2));
2168         CHECK_STATUS(status, NT_STATUS_OK);
2169
2170         CHECK_VAL(notify.smb2.out.num_changes, 1);
2171         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2172         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2173
2174         torture_comment(torture, "Testing notify rmdir\n");
2175         req = smb2_notify_send(tree, &(notify.smb2));
2176         status = smb2_util_rmdir(tree, fname);
2177         CHECK_STATUS(status, NT_STATUS_OK);
2178
2179         status = smb2_notify_recv(req, torture, &(notify.smb2));
2180         CHECK_STATUS(status, NT_STATUS_OK);
2181         CHECK_VAL(notify.smb2.out.num_changes, 1);
2182         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2183         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2184
2185         torture_comment(torture, "SIMPLE CHANGE NOTIFY OK\n");
2186
2187         torture_comment(torture, "TESTING WITH SECONDARY TCON\n");
2188         if (!torture_smb2_tree_connect(torture, tree->session, tree, &tree1)) {
2189                 torture_warning(torture, "couldn't reconnect to share, bailing\n");
2190                 ret = false;
2191                 goto done;
2192         }
2193
2194         torture_comment(torture, "tid1=%d tid2=%d\n",
2195                         smb2cli_tcon_current_id(tree->smbXcli),
2196                         smb2cli_tcon_current_id(tree1->smbXcli));
2197
2198         torture_comment(torture, "Testing notify mkdir\n");
2199         req = smb2_notify_send(tree, &(notify.smb2));
2200         smb2_util_mkdir(tree1, fname);
2201
2202         status = smb2_notify_recv(req, torture, &(notify.smb2));
2203         CHECK_STATUS(status, NT_STATUS_OK);
2204
2205         CHECK_VAL(notify.smb2.out.num_changes, 1);
2206         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2207         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2208
2209         torture_comment(torture, "Testing notify rmdir\n");
2210         req = smb2_notify_send(tree, &(notify.smb2));
2211         smb2_util_rmdir(tree, fname);
2212
2213         status = smb2_notify_recv(req, torture, &(notify.smb2));
2214         CHECK_STATUS(status, NT_STATUS_OK);
2215         CHECK_VAL(notify.smb2.out.num_changes, 1);
2216         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2217         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2218
2219         torture_comment(torture, "CHANGE NOTIFY WITH TCON OK\n");
2220
2221         torture_comment(torture, "Disconnecting secondary tree\n");
2222         status = smb2_tdis(tree1);
2223         CHECK_STATUS(status, NT_STATUS_OK);
2224         talloc_free(tree1);
2225
2226         torture_comment(torture, "Testing notify mkdir\n");
2227         req = smb2_notify_send(tree, &(notify.smb2));
2228         smb2_util_mkdir(tree, fname);
2229
2230         status = smb2_notify_recv(req, torture, &(notify.smb2));
2231         CHECK_STATUS(status, NT_STATUS_OK);
2232
2233         CHECK_VAL(notify.smb2.out.num_changes, 1);
2234         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2235         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2236
2237         torture_comment(torture, "Testing notify rmdir\n");
2238         req = smb2_notify_send(tree, &(notify.smb2));
2239         smb2_util_rmdir(tree, fname);
2240
2241         status = smb2_notify_recv(req, torture, &(notify.smb2));
2242         CHECK_STATUS(status, NT_STATUS_OK);
2243         CHECK_VAL(notify.smb2.out.num_changes, 1);
2244         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2245         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2246
2247         torture_comment(torture, "CHANGE NOTIFY WITH TDIS OK\n");
2248 done:
2249         smb2_util_close(tree, h1);
2250         smb2_deltree(tree, BASEDIR);
2251
2252         return ret;
2253 }
2254
2255 static bool torture_smb2_notify_rmdir(struct torture_context *torture,
2256                                       struct smb2_tree *tree1,
2257                                       struct smb2_tree *tree2,
2258                                       bool initial_delete_on_close)
2259 {
2260         bool ret = true;
2261         NTSTATUS status;
2262         union smb_notify notify = {};
2263         union smb_setfileinfo sfinfo = {};
2264         union smb_open io = {};
2265         struct smb2_handle h = {};
2266         struct smb2_request *req;
2267
2268         torture_comment(torture, "TESTING NOTIFY CANCEL FOR DELETED DIR\n");
2269
2270         smb2_deltree(tree1, BASEDIR);
2271         smb2_util_rmdir(tree1, BASEDIR);
2272
2273         ZERO_STRUCT(io.smb2);
2274         io.generic.level = RAW_OPEN_SMB2;
2275         io.smb2.in.create_flags = 0;
2276         io.smb2.in.desired_access = SEC_FILE_ALL;
2277         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2278         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2279         io.smb2.in.share_access =
2280                 NTCREATEX_SHARE_ACCESS_READ |
2281                 NTCREATEX_SHARE_ACCESS_WRITE |
2282                 NTCREATEX_SHARE_ACCESS_DELETE ;
2283         io.smb2.in.alloc_size = 0;
2284         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2285         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2286         io.smb2.in.security_flags = 0;
2287         io.smb2.in.fname = BASEDIR;
2288
2289         status = smb2_create(tree1, torture, &(io.smb2));
2290         CHECK_STATUS(status, NT_STATUS_OK);
2291         h = io.smb2.out.file.handle;
2292
2293         ZERO_STRUCT(notify.smb2);
2294         notify.smb2.level = RAW_NOTIFY_SMB2;
2295         notify.smb2.in.buffer_size = 1000;
2296         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2297         notify.smb2.in.file.handle = h;
2298         notify.smb2.in.recursive = false;
2299
2300         io.smb2.in.desired_access |= SEC_STD_DELETE;
2301         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
2302         req = smb2_notify_send(tree1, &(notify.smb2));
2303
2304         if (initial_delete_on_close) {
2305                 status = smb2_util_rmdir(tree2, BASEDIR);
2306                 CHECK_STATUS(status, NT_STATUS_OK);
2307         } else {
2308                 status = smb2_create(tree2, torture, &(io.smb2));
2309                 CHECK_STATUS(status, NT_STATUS_OK);
2310
2311                 sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
2312                 sfinfo.generic.in.file.handle = io.smb2.out.file.handle;
2313                 sfinfo.disposition_info.in.delete_on_close = 1;
2314                 status = smb2_setinfo_file(tree2, &sfinfo);
2315                 CHECK_STATUS(status, NT_STATUS_OK);
2316
2317                 smb2_util_close(tree2, io.smb2.out.file.handle);
2318         }
2319
2320         status = smb2_notify_recv(req, torture, &(notify.smb2));
2321         CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
2322
2323 done:
2324
2325         smb2_util_close(tree1, h);
2326         smb2_deltree(tree1, BASEDIR);
2327
2328         return ret;
2329 }
2330
2331 static bool torture_smb2_notify_rmdir1(struct torture_context *torture,
2332                                        struct smb2_tree *tree)
2333 {
2334         return torture_smb2_notify_rmdir(torture, tree, tree, false);
2335 }
2336
2337 static bool torture_smb2_notify_rmdir2(struct torture_context *torture,
2338                                        struct smb2_tree *tree)
2339 {
2340         return torture_smb2_notify_rmdir(torture, tree, tree, true);
2341 }
2342
2343 static bool torture_smb2_notify_rmdir3(struct torture_context *torture,
2344                                        struct smb2_tree *tree1,
2345                                        struct smb2_tree *tree2)
2346 {
2347         return torture_smb2_notify_rmdir(torture, tree1, tree2, false);
2348 }
2349
2350 static bool torture_smb2_notify_rmdir4(struct torture_context *torture,
2351                                        struct smb2_tree *tree1,
2352                                        struct smb2_tree *tree2)
2353 {
2354         return torture_smb2_notify_rmdir(torture, tree1, tree2, true);
2355 }
2356
2357 static void notify_timeout(struct tevent_context *ev,
2358                            struct tevent_timer *te,
2359                            struct timeval current_time,
2360                            void *private_data)
2361 {
2362         struct smb2_request *req = talloc_get_type_abort(
2363                 private_data, struct smb2_request);
2364
2365         smb2_cancel(req);
2366 }
2367
2368 static bool torture_smb2_inotify_rename(struct torture_context *torture,
2369                                         struct smb2_tree *tree1,
2370                                         struct smb2_tree *tree2)
2371 {
2372         NTSTATUS status;
2373         struct smb2_notify notify;
2374         struct notify_changes change1 = {0};
2375         struct notify_changes change2 = {0};
2376         struct smb2_create create;
2377         union smb_setfileinfo sinfo;
2378         struct smb2_handle h1 = {{0}};
2379         struct smb2_handle h2 = {{0}};
2380         struct smb2_request *req;
2381         struct tevent_timer *te = NULL;
2382         bool ok = false;
2383
2384         smb2_deltree(tree1, BASEDIR);
2385
2386         torture_comment(torture, "Testing change notify of a rename with inotify\n");
2387
2388         status = torture_smb2_testdir(tree1, BASEDIR, &h1);
2389         torture_assert_ntstatus_ok_goto(torture, status, ok, done, "torture_smb2_testdir failed");
2390
2391         ZERO_STRUCT(create);
2392         create.in.desired_access = SEC_RIGHTS_FILE_READ |
2393                 SEC_RIGHTS_FILE_WRITE|
2394                 SEC_RIGHTS_FILE_ALL;
2395         create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2396         create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2397         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2398                 NTCREATEX_SHARE_ACCESS_WRITE |
2399                 NTCREATEX_SHARE_ACCESS_DELETE;
2400         create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2401         create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2402         create.in.fname = BASEDIR "\\subdir-name";
2403
2404         status = smb2_create(tree2, torture, &create);
2405         torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_create failed\n");
2406         h2 = create.out.file.handle;
2407
2408         ZERO_STRUCT(notify);
2409         notify.level = RAW_NOTIFY_SMB2;
2410         notify.in.buffer_size = 4096;
2411         notify.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2412         notify.in.file.handle = h1;
2413         notify.in.recursive = true;
2414         req = smb2_notify_send(tree1, &notify);
2415         torture_assert_not_null_goto(torture, req, ok, done, "smb2_notify_send failed\n");
2416
2417         while (!NT_STATUS_EQUAL(req->status, STATUS_PENDING)) {
2418                 if (tevent_loop_once(torture->ev) != 0) {
2419                         return false;
2420                 }
2421         }
2422
2423         ZERO_STRUCT(sinfo);
2424         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
2425         sinfo.rename_information.in.file.handle = h2;
2426         sinfo.rename_information.in.new_name = BASEDIR "\\subdir-name-r";
2427
2428         status = smb2_setinfo_file(tree2, &sinfo);
2429         torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_setinfo_file failed\n");
2430
2431         smb2_util_close(tree2, h2);
2432
2433         te = tevent_add_timer(torture->ev,
2434                               tree1,
2435                               tevent_timeval_current_ofs(1, 0),
2436                               notify_timeout,
2437                               req);
2438         torture_assert_not_null_goto(torture, te, ok, done, "tevent_add_timer failed\n");
2439
2440         status = smb2_notify_recv(req, torture, &notify);
2441         torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_notify_recv failed\n");
2442
2443         torture_assert_goto(torture, notify.out.num_changes == 1 || notify.out.num_changes == 2,
2444                             ok, done, "bad notify\n");
2445
2446         change1 = notify.out.changes[0];
2447         if (notify.out.num_changes == 2) {
2448                 change2 = notify.out.changes[1];
2449         } else {
2450                 /*
2451                  * We may only get one event at a time, so check for the
2452                  * matching second event for the oldname/newname or
2453                  * removed/added pair.
2454                  */
2455                 ZERO_STRUCT(notify);
2456                 notify.level = RAW_NOTIFY_SMB2;
2457                 notify.in.buffer_size = 4096;
2458                 notify.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2459                 notify.in.file.handle = h1;
2460                 notify.in.recursive = true;
2461                 req = smb2_notify_send(tree1, &notify);
2462                 torture_assert_not_null_goto(torture, req, ok, done, "smb2_notify_send failed\n");
2463
2464                 status = smb2_notify_recv(req, torture, &notify);
2465                 torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_notify_recv failed\n");
2466
2467                 torture_assert_goto(torture, notify.out.num_changes == 1, ok, done,
2468                                     "bad notify\n");
2469
2470                 change2 = notify.out.changes[0];
2471         }
2472
2473         if ((change1.action != NOTIFY_ACTION_OLD_NAME) &&
2474             (change1.action != NOTIFY_ACTION_REMOVED))
2475         {
2476                 torture_fail_goto(torture, done, "bad change notification\n");
2477         }
2478         torture_assert_str_equal_goto(torture, change1.name.s, "subdir-name",
2479                             ok, done, "bad change notification\n");
2480
2481         if ((change2.action != NOTIFY_ACTION_NEW_NAME) &&
2482             (change2.action != NOTIFY_ACTION_ADDED))
2483         {
2484                 torture_fail_goto(torture, done, "bad change notification\n");
2485         }
2486         torture_assert_str_equal_goto(torture, change2.name.s, "subdir-name-r",
2487                             ok, done, "bad change notification\n");
2488
2489         ok = true;
2490 done:
2491         if (!smb2_util_handle_empty(h1)) {
2492                 smb2_util_close(tree2, h1);
2493         }
2494         if (!smb2_util_handle_empty(h2)) {
2495                 smb2_util_close(tree2, h2);
2496         }
2497
2498         smb2_deltree(tree1, BASEDIR);
2499         return ok;
2500 }
2501
2502 /*
2503    basic testing of SMB2 change notify
2504 */
2505 struct torture_suite *torture_smb2_notify_init(TALLOC_CTX *ctx)
2506 {
2507         struct torture_suite *suite = torture_suite_create(ctx, "notify");
2508
2509         torture_suite_add_1smb2_test(suite, "valid-req", test_valid_request);
2510         torture_suite_add_1smb2_test(suite, "tcon", torture_smb2_notify_tcon);
2511         torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir);
2512         torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask);
2513         torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
2514         torture_suite_add_1smb2_test(suite, "tdis1", torture_smb2_notify_tree_disconnect_1);
2515         torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
2516         torture_suite_add_1smb2_test(suite, "close", torture_smb2_notify_close);
2517         torture_suite_add_1smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
2518         torture_suite_add_1smb2_test(suite, "session-reconnect", torture_smb2_notify_session_reconnect);
2519         torture_suite_add_2smb2_test(suite, "invalid-reauth", torture_smb2_notify_invalid_reauth);
2520         torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
2521         torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
2522         torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
2523         torture_suite_add_1smb2_test(suite, "file", torture_smb2_notify_file);
2524         torture_suite_add_1smb2_test(suite, "tcp", torture_smb2_notify_tcp_disconnect);
2525         torture_suite_add_2smb2_test(suite, "rec", torture_smb2_notify_recursive);
2526         torture_suite_add_1smb2_test(suite, "overflow", torture_smb2_notify_overflow);
2527         torture_suite_add_1smb2_test(suite, "rmdir1",
2528                                      torture_smb2_notify_rmdir1);
2529         torture_suite_add_1smb2_test(suite, "rmdir2",
2530                                      torture_smb2_notify_rmdir2);
2531         torture_suite_add_2smb2_test(suite, "rmdir3",
2532                                      torture_smb2_notify_rmdir3);
2533         torture_suite_add_2smb2_test(suite, "rmdir4",
2534                                      torture_smb2_notify_rmdir4);
2535
2536         suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");
2537
2538         return suite;
2539 }
2540
2541 /*
2542    basic testing of SMB2 change notify
2543 */
2544 struct torture_suite *torture_smb2_notify_inotify_init(TALLOC_CTX *ctx)
2545 {
2546         struct torture_suite *suite = torture_suite_create(ctx, "notify-inotify");
2547
2548         suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests that use inotify");
2549
2550         torture_suite_add_2smb2_test(suite, "inotify-rename", torture_smb2_inotify_rename);
2551
2552         return suite;
2553 }