80c560be0073672ef6c21f188e0f73b578c2559d
[kai/samba.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
27 #include "torture/torture.h"
28 #include "torture/smb2/proto.h"
29 #include "librpc/gen_ndr/ndr_security.h"
30 #include "libcli/security/security.h"
31 #include "torture/util.h"
32
33 #include "system/filesys.h"
34 #include "auth/credentials/credentials.h"
35 #include "lib/cmdline/popt_common.h"
36 #include "librpc/gen_ndr/security.h"
37
38 #include "lib/events/events.h"
39
40 #include "libcli/raw/libcliraw.h"
41 #include "libcli/raw/raw_proto.h"
42 #include "libcli/libcli.h"
43
44 #define CHECK_STATUS(status, correct) do { \
45         if (!NT_STATUS_EQUAL(status, correct)) { \
46                 torture_result(torture, TORTURE_FAIL, \
47                        "(%s) Incorrect status %s - should be %s\n", \
48                        __location__, nt_errstr(status), nt_errstr(correct)); \
49                 ret = false; \
50                 goto done; \
51         }} while (0)
52
53 #define CHECK_VAL(v, correct) do { \
54         if ((v) != (correct)) { \
55                 torture_result(torture, TORTURE_FAIL, \
56                        "(%s) wrong value for %s  0x%x should be 0x%x\n", \
57                        __location__, #v, (int)v, (int)correct); \
58                 ret = false; \
59                 goto done; \
60         }} while (0)
61
62 #define CHECK_WIRE_STR(field, value) do { \
63         if (!field.s || strcmp(field.s, value)) { \
64                 torture_result(torture, TORTURE_FAIL, \
65                         "(%s) %s [%s] != %s\n",  __location__, #field, \
66                         field.s, value); \
67                 ret = false; \
68                 goto done; \
69         }} while (0)
70
71 #define BASEDIR "test_notify"
72 #define FNAME "smb2-notify01.dat"
73
74 static bool test_valid_request(struct torture_context *torture,
75                                struct smb2_tree *tree)
76 {
77         bool ret = true;
78         NTSTATUS status;
79         struct smb2_handle dh;
80         struct smb2_notify n;
81         struct smb2_request *req;
82         uint32_t max_buffer_size;
83
84         torture_comment(torture, "TESTING VALIDITY OF CHANGE NOTIFY REQUEST\n");
85
86         smb2_util_unlink(tree, FNAME);
87
88         status = smb2_util_roothandle(tree, &dh);
89         CHECK_STATUS(status, NT_STATUS_OK);
90
91         /* 0x00080000 is the default max buffer size for Windows servers
92          * pre-Win7 */
93         max_buffer_size = torture_setting_ulong(torture, "cn_max_buffer_size",
94                                                 0x00080000);
95
96         n.in.recursive          = 0x0000;
97         n.in.buffer_size        = max_buffer_size;
98         n.in.file.handle        = dh;
99         n.in.completion_filter  = FILE_NOTIFY_CHANGE_ALL;
100         n.in.unknown            = 0x00000000;
101         req = smb2_notify_send(tree, &n);
102
103         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
104                 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
105                         break;
106                 }
107         }
108
109         status = torture_setup_complex_file(tree, FNAME);
110         CHECK_STATUS(status, NT_STATUS_OK);
111
112         status = smb2_notify_recv(req, torture, &n);
113         CHECK_STATUS(status, NT_STATUS_OK);
114         CHECK_VAL(n.out.num_changes, 1);
115         CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_ADDED);
116         CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
117
118         /*
119          * if the change response doesn't fit in the buffer
120          * NOTIFY_ENUM_DIR is returned.
121          */
122         n.in.buffer_size        = 0x00000000;
123         req = smb2_notify_send(tree, &n);
124
125         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
126                 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
127                         break;
128                 }
129         }
130
131         status = torture_setup_complex_file(tree, FNAME);
132         CHECK_STATUS(status, NT_STATUS_OK);
133
134         status = smb2_notify_recv(req, torture, &n);
135         CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
136
137         /*
138          * if the change response fits in the buffer we get
139          * NT_STATUS_OK again
140          */
141         n.in.buffer_size        = max_buffer_size;
142         req = smb2_notify_send(tree, &n);
143
144         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
145                 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
146                         break;
147                 }
148         }
149
150         status = torture_setup_complex_file(tree, FNAME);
151         CHECK_STATUS(status, NT_STATUS_OK);
152
153         status = smb2_notify_recv(req, torture, &n);
154         CHECK_STATUS(status, NT_STATUS_OK);
155         CHECK_VAL(n.out.num_changes, 3);
156         CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_REMOVED);
157         CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
158         CHECK_VAL(n.out.changes[1].action, NOTIFY_ACTION_ADDED);
159         CHECK_WIRE_STR(n.out.changes[1].name, FNAME);
160         CHECK_VAL(n.out.changes[2].action, NOTIFY_ACTION_MODIFIED);
161         CHECK_WIRE_STR(n.out.changes[2].name, FNAME);
162
163         /* if the first notify returns NOTIFY_ENUM_DIR, all do */
164         status = smb2_util_close(tree, dh);
165         CHECK_STATUS(status, NT_STATUS_OK);
166         status = smb2_util_roothandle(tree, &dh);
167         CHECK_STATUS(status, NT_STATUS_OK);
168
169         n.in.recursive          = 0x0000;
170         n.in.buffer_size        = 0x00000001;
171         n.in.file.handle        = dh;
172         n.in.completion_filter  = FILE_NOTIFY_CHANGE_ALL;
173         n.in.unknown            = 0x00000000;
174         req = smb2_notify_send(tree, &n);
175
176         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
177                 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
178                         break;
179                 }
180         }
181
182         status = torture_setup_complex_file(tree, FNAME);
183         CHECK_STATUS(status, NT_STATUS_OK);
184
185         status = smb2_notify_recv(req, torture, &n);
186         CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
187
188         n.in.buffer_size        = max_buffer_size;
189         req = smb2_notify_send(tree, &n);
190         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
191                 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
192                         break;
193                 }
194         }
195
196         status = torture_setup_complex_file(tree, FNAME);
197         CHECK_STATUS(status, NT_STATUS_OK);
198
199         status = smb2_notify_recv(req, torture, &n);
200         CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
201
202         /* if the buffer size is too large, we get invalid parameter */
203         n.in.recursive          = 0x0000;
204         n.in.buffer_size        = max_buffer_size + 1;
205         n.in.file.handle        = dh;
206         n.in.completion_filter  = FILE_NOTIFY_CHANGE_ALL;
207         n.in.unknown            = 0x00000000;
208         req = smb2_notify_send(tree, &n);
209         status = smb2_notify_recv(req, torture, &n);
210         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
211
212 done:
213         return ret;
214 }
215
216 /*
217    basic testing of change notify on directories
218 */
219 static bool torture_smb2_notify_dir(struct torture_context *torture,
220                               struct smb2_tree *tree1,
221                               struct smb2_tree *tree2)
222 {
223         bool ret = true;
224         NTSTATUS status;
225         union smb_notify notify;
226         union smb_open io;
227         union smb_close cl;
228         int i, count;
229         struct smb2_handle h1, h2;
230         struct smb2_request *req, *req2;
231         const char *fname = BASEDIR "\\subdir-name";
232         extern int torture_numops;
233
234         torture_comment(torture, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
235
236         smb2_deltree(tree1, BASEDIR);
237         smb2_util_rmdir(tree1, BASEDIR);
238         /*
239           get a handle on the directory
240         */
241         ZERO_STRUCT(io.smb2);
242         io.generic.level = RAW_OPEN_SMB2;
243         io.smb2.in.create_flags = 0;
244         io.smb2.in.desired_access = SEC_FILE_ALL;
245         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
246         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
247         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
248                                 NTCREATEX_SHARE_ACCESS_WRITE;
249         io.smb2.in.alloc_size = 0;
250         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
251         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
252         io.smb2.in.security_flags = 0;
253         io.smb2.in.fname = BASEDIR;
254
255         status = smb2_create(tree1, torture, &(io.smb2));
256         CHECK_STATUS(status, NT_STATUS_OK);
257         h1 = io.smb2.out.file.handle;
258
259         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
260         io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ;
261         status = smb2_create(tree1, torture, &(io.smb2));
262         CHECK_STATUS(status, NT_STATUS_OK);
263         h2 = io.smb2.out.file.handle;
264
265         /* ask for a change notify,
266            on file or directory name changes */
267         ZERO_STRUCT(notify.smb2);
268         notify.smb2.level = RAW_NOTIFY_SMB2;
269         notify.smb2.in.buffer_size = 1000;
270         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
271         notify.smb2.in.file.handle = h1;
272         notify.smb2.in.recursive = true;
273
274         torture_comment(torture, "Testing notify cancel\n");
275
276         req = smb2_notify_send(tree1, &(notify.smb2));
277         smb2_cancel(req);
278         status = smb2_notify_recv(req, torture, &(notify.smb2));
279         CHECK_STATUS(status, NT_STATUS_CANCELLED);
280
281         torture_comment(torture, "Testing notify mkdir\n");
282
283         req = smb2_notify_send(tree1, &(notify.smb2));
284         smb2_util_mkdir(tree2, fname);
285
286         status = smb2_notify_recv(req, torture, &(notify.smb2));
287         CHECK_STATUS(status, NT_STATUS_OK);
288
289         CHECK_VAL(notify.smb2.out.num_changes, 1);
290         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
291         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
292
293         torture_comment(torture, "Testing notify rmdir\n");
294
295         req = smb2_notify_send(tree1, &(notify.smb2));
296         smb2_util_rmdir(tree2, fname);
297
298         status = smb2_notify_recv(req, torture, &(notify.smb2));
299         CHECK_STATUS(status, NT_STATUS_OK);
300         CHECK_VAL(notify.smb2.out.num_changes, 1);
301         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
302         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
303
304         torture_comment(torture,
305                 "Testing notify mkdir - rmdir - mkdir - rmdir\n");
306
307         smb2_util_mkdir(tree2, fname);
308         smb2_util_rmdir(tree2, fname);
309         smb2_util_mkdir(tree2, fname);
310         smb2_util_rmdir(tree2, fname);
311         smb_msleep(200);
312         req = smb2_notify_send(tree1, &(notify.smb2));
313         status = smb2_notify_recv(req, torture, &(notify.smb2));
314         CHECK_STATUS(status, NT_STATUS_OK);
315         CHECK_VAL(notify.smb2.out.num_changes, 4);
316         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
317         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
318         CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_REMOVED);
319         CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name");
320         CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_ADDED);
321         CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name");
322         CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_REMOVED);
323         CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name");
324
325         count = torture_numops;
326         torture_comment(torture,
327                 "Testing buffered notify on create of %d files\n", count);
328         for (i=0;i<count;i++) {
329                 struct smb2_handle h12;
330                 char *fname2 = talloc_asprintf(torture, BASEDIR "\\test%d.txt",
331                                               i);
332
333                 ZERO_STRUCT(io.smb2);
334                 io.generic.level = RAW_OPEN_SMB2;
335                 io.smb2.in.create_flags = 0;
336                 io.smb2.in.desired_access = SEC_FILE_ALL;
337                 io.smb2.in.create_options =
338                     NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
339                 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
340                 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
341                                         NTCREATEX_SHARE_ACCESS_WRITE;
342                 io.smb2.in.alloc_size = 0;
343                 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
344                 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
345                 io.smb2.in.security_flags = 0;
346                 io.smb2.in.fname = fname2;
347
348                 status = smb2_create(tree1, torture, &(io.smb2));
349                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
350                         torture_comment(torture, "Failed to create %s \n",
351                                fname);
352                         ret = false;
353                         goto done;
354                 }
355                 h12 = io.smb2.out.file.handle;
356                 talloc_free(fname2);
357                 smb2_util_close(tree1, h12);
358         }
359
360         /* (1st notify) setup a new notify on a different directory handle.
361            This new notify won't see the events above. */
362         notify.smb2.in.file.handle = h2;
363         req2 = smb2_notify_send(tree1, &(notify.smb2));
364
365         /* (2nd notify) whereas this notify will see the above buffered events,
366            and it directly returns the buffered events */
367         notify.smb2.in.file.handle = h1;
368         req = smb2_notify_send(tree1, &(notify.smb2));
369
370         status = smb2_util_unlink(tree1, BASEDIR "\\nonexistant.txt");
371         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
372
373         /* (1st unlink) as the 2nd notify directly returns,
374            this unlink is only seen by the 1st notify and
375            the 3rd notify (later) */
376         torture_comment(torture,
377                 "Testing notify on unlink for the first file\n");
378         status = smb2_util_unlink(tree2, BASEDIR "\\test0.txt");
379         CHECK_STATUS(status, NT_STATUS_OK);
380
381         /* receive the reply from the 2nd notify */
382         status = smb2_notify_recv(req, torture, &(notify.smb2));
383         CHECK_STATUS(status, NT_STATUS_OK);
384
385         CHECK_VAL(notify.smb2.out.num_changes, count);
386         for (i=1;i<count;i++) {
387                 CHECK_VAL(notify.smb2.out.changes[i].action,
388                           NOTIFY_ACTION_ADDED);
389         }
390         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
391
392         torture_comment(torture, "and now from the 1st notify\n");
393         status = smb2_notify_recv(req2, torture, &(notify.smb2));
394         CHECK_STATUS(status, NT_STATUS_OK);
395         CHECK_VAL(notify.smb2.out.num_changes, 1);
396         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
397         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
398
399         torture_comment(torture,
400                 "(3rd notify) this notify will only see the 1st unlink\n");
401         req = smb2_notify_send(tree1, &(notify.smb2));
402
403         status = smb2_util_unlink(tree1, BASEDIR "\\nonexistant.txt");
404         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
405
406         for (i=1;i<count;i++) {
407                 char *fname2 = talloc_asprintf(torture,
408                               BASEDIR "\\test%d.txt", i);
409                 status = smb2_util_unlink(tree2, fname2);
410                 CHECK_STATUS(status, NT_STATUS_OK);
411                 talloc_free(fname2);
412         }
413
414         /* receive the 3rd notify */
415         status = smb2_notify_recv(req, torture, &(notify.smb2));
416         CHECK_STATUS(status, NT_STATUS_OK);
417         CHECK_VAL(notify.smb2.out.num_changes, 1);
418         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
419         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
420
421         /* and we now see the rest of the unlink calls on both
422          * directory handles */
423         notify.smb2.in.file.handle = h1;
424         sleep(3);
425         req = smb2_notify_send(tree1, &(notify.smb2));
426         status = smb2_notify_recv(req, torture, &(notify.smb2));
427         CHECK_STATUS(status, NT_STATUS_OK);
428         CHECK_VAL(notify.smb2.out.num_changes, count-1);
429         for (i=0;i<notify.smb2.out.num_changes;i++) {
430                 CHECK_VAL(notify.smb2.out.changes[i].action,
431                           NOTIFY_ACTION_REMOVED);
432         }
433         notify.smb2.in.file.handle = h2;
434         req = smb2_notify_send(tree1, &(notify.smb2));
435         status = smb2_notify_recv(req, torture, &(notify.smb2));
436         CHECK_STATUS(status, NT_STATUS_OK);
437         CHECK_VAL(notify.smb2.out.num_changes, count-1);
438         for (i=0;i<notify.smb2.out.num_changes;i++) {
439                 CHECK_VAL(notify.smb2.out.changes[i].action,
440                           NOTIFY_ACTION_REMOVED);
441         }
442
443         torture_comment(torture,
444         "Testing if a close() on the dir handle triggers the notify reply\n");
445
446         notify.smb2.in.file.handle = h1;
447         req = smb2_notify_send(tree1, &(notify.smb2));
448
449         ZERO_STRUCT(cl.smb2);
450         cl.smb2.level = RAW_CLOSE_SMB2;
451         cl.smb2.in.file.handle = h1;
452         status = smb2_close(tree1, &(cl.smb2));
453         CHECK_STATUS(status, NT_STATUS_OK);
454
455         status = smb2_notify_recv(req, torture, &(notify.smb2));
456         CHECK_STATUS(status, STATUS_NOTIFY_CLEANUP);
457         CHECK_VAL(notify.smb2.out.num_changes, 9);
458
459 done:
460         smb2_util_close(tree1, h1);
461         smb2_util_close(tree1, h2);
462         smb2_deltree(tree1, BASEDIR);
463         return ret;
464 }
465
466 static struct smb2_handle custom_smb2_create(struct smb2_tree *tree,
467                                                 struct torture_context *torture,
468                                                 struct smb2_create *smb2)
469 {
470         struct smb2_handle h1;
471         bool ret = true;
472         NTSTATUS status;
473         smb2_deltree(tree, smb2->in.fname);
474         status = smb2_create(tree, torture, smb2);
475         CHECK_STATUS(status, NT_STATUS_OK);
476         h1 = smb2->out.file.handle;
477 done:
478         return h1;
479 }
480
481 /*
482    testing of recursive change notify
483 */
484
485 static bool torture_smb2_notify_recursive(struct torture_context *torture,
486                                 struct smb2_tree *tree1,
487                                 struct smb2_tree *tree2)
488 {
489         bool ret = true;
490         NTSTATUS status;
491         union smb_notify notify;
492         union smb_open io, io1;
493         union smb_setfileinfo sinfo;
494         struct smb2_handle h1;
495         struct smb2_request *req1, *req2;
496
497         smb2_deltree(tree1, BASEDIR);
498         smb2_util_rmdir(tree1, BASEDIR);
499
500         torture_comment(torture, "TESTING CHANGE NOTIFY WITH RECURSION\n");
501
502         /*
503           get a handle on the directory
504         */
505         ZERO_STRUCT(io.smb2);
506         io.generic.level = RAW_OPEN_SMB2;
507         io.smb2.in.create_flags = 0;
508         io.smb2.in.desired_access = SEC_FILE_ALL;
509         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
510         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
511         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
512                                 NTCREATEX_SHARE_ACCESS_WRITE;
513         io.smb2.in.alloc_size = 0;
514         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
515         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
516         io.smb2.in.security_flags = 0;
517         io.smb2.in.fname = BASEDIR;
518
519         status = smb2_create(tree1, torture, &(io.smb2));
520         CHECK_STATUS(status, NT_STATUS_OK);
521         h1 = io.smb2.out.file.handle;
522
523         /* ask for a change notify, on file or directory name
524            changes. Setup both with and without recursion */
525         ZERO_STRUCT(notify.smb2);
526         notify.smb2.level = RAW_NOTIFY_SMB2;
527         notify.smb2.in.buffer_size = 1000;
528         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
529                                 FILE_NOTIFY_CHANGE_ATTRIBUTES |
530                                 FILE_NOTIFY_CHANGE_CREATION;
531         notify.smb2.in.file.handle = h1;
532
533         notify.smb2.in.recursive = true;
534         req1 = smb2_notify_send(tree1, &(notify.smb2));
535         smb2_cancel(req1);
536         status = smb2_notify_recv(req1, torture, &(notify.smb2));
537         CHECK_STATUS(status, NT_STATUS_CANCELLED);
538
539         notify.smb2.in.recursive = false;
540         req2 = smb2_notify_send(tree1, &(notify.smb2));
541         smb2_cancel(req2);
542         status = smb2_notify_recv(req2, torture, &(notify.smb2));
543         CHECK_STATUS(status, NT_STATUS_CANCELLED);
544
545         ZERO_STRUCT(io1.smb2);
546         io1.generic.level = RAW_OPEN_SMB2;
547         io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
548         io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
549                                 SEC_RIGHTS_FILE_WRITE|
550                                 SEC_RIGHTS_FILE_ALL;
551         io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
552         io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
553         io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
554                                 NTCREATEX_SHARE_ACCESS_WRITE |
555                                 NTCREATEX_SHARE_ACCESS_DELETE;
556         io1.smb2.in.alloc_size = 0;
557         io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
558         io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
559         io1.smb2.in.security_flags = 0;
560         io1.smb2.in.fname = BASEDIR "\\subdir-name";
561         status = smb2_create(tree2, torture, &(io1.smb2));
562         CHECK_STATUS(status, NT_STATUS_OK);
563         smb2_util_close(tree2, io1.smb2.out.file.handle);
564
565         io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname1";
566         status = smb2_create(tree2, torture, &(io1.smb2));
567         CHECK_STATUS(status, NT_STATUS_OK);
568         ZERO_STRUCT(sinfo);
569         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
570         sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
571         sinfo.rename_information.in.overwrite = 0;
572         sinfo.rename_information.in.root_fid = 0;
573         sinfo.rename_information.in.new_name =
574                                 BASEDIR "\\subdir-name\\subname1-r";
575         status = smb2_setinfo_file(tree2, &sinfo);
576         CHECK_STATUS(status, NT_STATUS_OK);
577
578         io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
579         io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname2";
580         status = smb2_create(tree2, torture, &(io1.smb2));
581         CHECK_STATUS(status, NT_STATUS_OK);
582         ZERO_STRUCT(sinfo);
583         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
584         sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
585         sinfo.rename_information.in.overwrite = true;
586         sinfo.rename_information.in.root_fid = 0;
587         sinfo.rename_information.in.new_name = BASEDIR "\\subname2-r";
588         status = smb2_setinfo_file(tree2, &sinfo);
589         CHECK_STATUS(status, NT_STATUS_OK);
590
591         io1.smb2.in.fname = BASEDIR "\\subname2-r";
592         io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
593         status = smb2_create(tree2, torture, &(io1.smb2));
594         CHECK_STATUS(status, NT_STATUS_OK);
595         ZERO_STRUCT(sinfo);
596         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
597         sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
598         sinfo.rename_information.in.overwrite = true;
599         sinfo.rename_information.in.root_fid = 0;
600         sinfo.rename_information.in.new_name = BASEDIR "\\subname3-r";
601         status = smb2_setinfo_file(tree2, &sinfo);
602         CHECK_STATUS(status, NT_STATUS_OK);
603
604         notify.smb2.in.completion_filter = 0;
605         notify.smb2.in.recursive = true;
606         smb_msleep(200);
607         req1 = smb2_notify_send(tree1, &(notify.smb2));
608
609         status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name\\subname1-r");
610         CHECK_STATUS(status, NT_STATUS_OK);
611         status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name");
612         CHECK_STATUS(status, NT_STATUS_OK);
613         status = smb2_util_unlink(tree2, BASEDIR "\\subname3-r");
614         CHECK_STATUS(status, NT_STATUS_OK);
615
616         notify.smb2.in.recursive = false;
617         req2 = smb2_notify_send(tree1, &(notify.smb2));
618
619         status = smb2_notify_recv(req1, torture, &(notify.smb2));
620         CHECK_STATUS(status, NT_STATUS_OK);
621
622         CHECK_VAL(notify.smb2.out.num_changes, 9);
623         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
624         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
625         CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_ADDED);
626         CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name\\subname1");
627         CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_OLD_NAME);
628         CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name\\subname1");
629         CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_NEW_NAME);
630         CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name\\subname1-r");
631         CHECK_VAL(notify.smb2.out.changes[4].action, NOTIFY_ACTION_ADDED);
632         CHECK_WIRE_STR(notify.smb2.out.changes[4].name, "subdir-name\\subname2");
633         CHECK_VAL(notify.smb2.out.changes[5].action, NOTIFY_ACTION_REMOVED);
634         CHECK_WIRE_STR(notify.smb2.out.changes[5].name, "subdir-name\\subname2");
635         CHECK_VAL(notify.smb2.out.changes[6].action, NOTIFY_ACTION_ADDED);
636         CHECK_WIRE_STR(notify.smb2.out.changes[6].name, "subname2-r");
637         CHECK_VAL(notify.smb2.out.changes[7].action, NOTIFY_ACTION_OLD_NAME);
638         CHECK_WIRE_STR(notify.smb2.out.changes[7].name, "subname2-r");
639         CHECK_VAL(notify.smb2.out.changes[8].action, NOTIFY_ACTION_NEW_NAME);
640         CHECK_WIRE_STR(notify.smb2.out.changes[8].name, "subname3-r");
641
642 done:
643         smb2_deltree(tree1, BASEDIR);
644         return ret;
645 }
646
647 /*
648    testing of change notify mask change
649 */
650
651 static bool torture_smb2_notify_mask_change(struct torture_context *torture,
652                                             struct smb2_tree *tree1,
653                                             struct smb2_tree *tree2)
654 {
655         bool ret = true;
656         NTSTATUS status;
657         union smb_notify notify;
658         union smb_open io, io1;
659         struct smb2_handle h1;
660         struct smb2_request *req1, *req2;
661         union smb_setfileinfo sinfo;
662
663         smb2_deltree(tree1, BASEDIR);
664         smb2_util_rmdir(tree1, BASEDIR);
665
666         torture_comment(torture, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
667
668         /*
669           get a handle on the directory
670         */
671         ZERO_STRUCT(io.smb2);
672         io.generic.level = RAW_OPEN_SMB2;
673         io.smb2.in.create_flags = 0;
674         io.smb2.in.desired_access = SEC_FILE_ALL;
675         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
676         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
677         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
678                                 NTCREATEX_SHARE_ACCESS_WRITE;
679         io.smb2.in.alloc_size = 0;
680         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
681         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
682         io.smb2.in.security_flags = 0;
683         io.smb2.in.fname = BASEDIR;
684
685         status = smb2_create(tree1, torture, &(io.smb2));
686         CHECK_STATUS(status, NT_STATUS_OK);
687         h1 = io.smb2.out.file.handle;
688
689         /* ask for a change notify, on file or directory name
690            changes. Setup both with and without recursion */
691         ZERO_STRUCT(notify.smb2);
692         notify.smb2.level = RAW_NOTIFY_SMB2;
693         notify.smb2.in.buffer_size = 1000;
694         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
695         notify.smb2.in.file.handle = h1;
696
697         notify.smb2.in.recursive = true;
698         req1 = smb2_notify_send(tree1, &(notify.smb2));
699
700         smb2_cancel(req1);
701         status = smb2_notify_recv(req1, torture, &(notify.smb2));
702         CHECK_STATUS(status, NT_STATUS_CANCELLED);
703
704
705         notify.smb2.in.recursive = false;
706         req2 = smb2_notify_send(tree1, &(notify.smb2));
707
708         smb2_cancel(req2);
709         status = smb2_notify_recv(req2, torture, &(notify.smb2));
710         CHECK_STATUS(status, NT_STATUS_CANCELLED);
711
712         notify.smb2.in.recursive = true;
713         req1 = smb2_notify_send(tree1, &(notify.smb2));
714
715         /* Set to hidden then back again. */
716         ZERO_STRUCT(io1.smb2);
717         io1.generic.level = RAW_OPEN_SMB2;
718         io1.smb2.in.create_flags = 0;
719         io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
720                                 SEC_RIGHTS_FILE_WRITE|
721                                 SEC_RIGHTS_FILE_ALL;
722         io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
723         io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
724                                 NTCREATEX_SHARE_ACCESS_WRITE |
725                                 NTCREATEX_SHARE_ACCESS_DELETE;
726         io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
727         io1.smb2.in.security_flags = 0;
728         io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
729         io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
730         io1.smb2.in.fname = BASEDIR "\\tname1";
731
732         smb2_util_close(tree1,
733                 custom_smb2_create(tree1, torture, &(io1.smb2)));
734         status = smb2_util_setatr(tree1, BASEDIR "\\tname1",
735                                 FILE_ATTRIBUTE_HIDDEN);
736         CHECK_STATUS(status, NT_STATUS_OK);
737         smb2_util_unlink(tree1, BASEDIR "\\tname1");
738
739         status = smb2_notify_recv(req1, torture, &(notify.smb2));
740         CHECK_STATUS(status, NT_STATUS_OK);
741
742         CHECK_VAL(notify.smb2.out.num_changes, 1);
743         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
744         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
745
746         /* Now try and change the mask to include other events.
747          * This should not work - once the mask is set on a directory
748          * h1 it seems to be fixed until the fnum is closed. */
749
750         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
751                                         FILE_NOTIFY_CHANGE_ATTRIBUTES |
752                                         FILE_NOTIFY_CHANGE_CREATION;
753         notify.smb2.in.recursive = true;
754         req1 = smb2_notify_send(tree1, &(notify.smb2));
755
756         notify.smb2.in.recursive = false;
757         req2 = smb2_notify_send(tree1, &(notify.smb2));
758
759         io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
760         io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
761         io1.smb2.in.fname = BASEDIR "\\subdir-name";
762         status = smb2_create(tree2, torture, &(io1.smb2));
763         CHECK_STATUS(status, NT_STATUS_OK);
764         smb2_util_close(tree2, io1.smb2.out.file.handle);
765
766         ZERO_STRUCT(sinfo);
767         io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname1";
768         io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
769         io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
770         status = smb2_create(tree2, torture, &(io1.smb2));
771         CHECK_STATUS(status, NT_STATUS_OK);
772         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
773         sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
774         sinfo.rename_information.in.overwrite = true;
775         sinfo.rename_information.in.root_fid = 0;
776         sinfo.rename_information.in.new_name =
777                                 BASEDIR "\\subdir-name\\subname1-r";
778         status = smb2_setinfo_file(tree2, &sinfo);
779         CHECK_STATUS(status, NT_STATUS_OK);
780
781         io1.smb2.in.fname = BASEDIR "\\subdir-name\\subname2";
782         io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
783         io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
784         status = smb2_create(tree2, torture, &(io1.smb2));
785         CHECK_STATUS(status, NT_STATUS_OK);
786         sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
787         sinfo.rename_information.in.new_name = BASEDIR "\\subname2-r";
788         status = smb2_setinfo_file(tree2, &sinfo);
789         CHECK_STATUS(status, NT_STATUS_OK);
790         smb2_util_close(tree2, io1.smb2.out.file.handle);
791
792         io1.smb2.in.fname = BASEDIR "\\subname2-r";
793         io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
794         status = smb2_create(tree2, torture, &(io1.smb2));
795         CHECK_STATUS(status, NT_STATUS_OK);
796         sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
797         sinfo.rename_information.in.new_name = BASEDIR "\\subname3-r";
798         status = smb2_setinfo_file(tree2, &sinfo);
799         CHECK_STATUS(status, NT_STATUS_OK);
800         smb2_util_close(tree2, io1.smb2.out.file.handle);
801
802         status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name\\subname1-r");
803         CHECK_STATUS(status, NT_STATUS_OK);
804         status = smb2_util_rmdir(tree2, BASEDIR "\\subdir-name");
805         CHECK_STATUS(status, NT_STATUS_OK);
806         status = smb2_util_unlink(tree2, BASEDIR "\\subname3-r");
807         CHECK_STATUS(status, NT_STATUS_OK);
808
809         status = smb2_notify_recv(req1, torture, &(notify.smb2));
810         CHECK_STATUS(status, NT_STATUS_OK);
811
812         CHECK_VAL(notify.smb2.out.num_changes, 1);
813         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
814         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname2-r");
815
816         status = smb2_notify_recv(req2, torture, &(notify.smb2));
817         CHECK_STATUS(status, NT_STATUS_OK);
818
819         CHECK_VAL(notify.smb2.out.num_changes, 1);
820         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
821         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname3-r");
822
823         if (!ret) {
824                 goto done;
825         }
826
827 done:
828         smb2_deltree(tree1, BASEDIR);
829         return ret;
830 }
831
832 /*
833    testing of mask bits for change notify
834 */
835
836 static bool torture_smb2_notify_mask(struct torture_context *torture,
837                                      struct smb2_tree *tree1,
838                                      struct smb2_tree *tree2)
839 {
840         bool ret = true;
841         NTSTATUS status;
842         union smb_notify notify;
843         union smb_open io, io1;
844         struct smb2_handle h1, h2;
845         uint32_t mask;
846         int i;
847         char c = 1;
848         struct timeval tv;
849         NTTIME t;
850         union smb_setfileinfo sinfo;
851
852         smb2_deltree(tree1, BASEDIR);
853         smb2_util_rmdir(tree1, BASEDIR);
854
855         torture_comment(torture, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
856
857         tv = timeval_current_ofs(1000, 0);
858         t = timeval_to_nttime(&tv);
859
860         /*
861           get a handle on the directory
862         */
863         ZERO_STRUCT(io.smb2);
864         io.generic.level = RAW_OPEN_SMB2;
865         io.smb2.in.create_flags = 0;
866         io.smb2.in.desired_access = SEC_FILE_ALL;
867         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
868         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
869         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
870                                 NTCREATEX_SHARE_ACCESS_WRITE;
871         io.smb2.in.alloc_size = 0;
872         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
873         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
874         io.smb2.in.security_flags = 0;
875         io.smb2.in.fname = BASEDIR;
876
877         ZERO_STRUCT(notify.smb2);
878         notify.smb2.level = RAW_NOTIFY_SMB2;
879         notify.smb2.in.buffer_size = 1000;
880         notify.smb2.in.recursive = true;
881
882 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
883                          expected, nchanges) \
884         do { \
885         do { for (mask=i=0;i<32;i++) { \
886                 struct smb2_request *req; \
887                 status = smb2_create(tree1, torture, &(io.smb2)); \
888                 CHECK_STATUS(status, NT_STATUS_OK); \
889                 h1 = io.smb2.out.file.handle; \
890                 setup \
891                 notify.smb2.in.file.handle = h1;        \
892                 notify.smb2.in.completion_filter = (1<<i); \
893                 /* cancel initial requests so the buffer is setup */    \
894                 req = smb2_notify_send(tree1, &(notify.smb2)); \
895                 smb2_cancel(req); \
896                 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
897                 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
898                 /* send the change notify request */ \
899                 req = smb2_notify_send(tree1, &(notify.smb2)); \
900                 op \
901                 smb_msleep(200); smb2_cancel(req); \
902                 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
903                 cleanup \
904                 smb2_util_close(tree1, h1); \
905                 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
906                 CHECK_STATUS(status, NT_STATUS_OK); \
907                 /* special case to cope with file rename behaviour */ \
908                 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
909                     notify.smb2.out.changes[0].action == \
910                         NOTIFY_ACTION_MODIFIED && \
911                     ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
912                     Action == NOTIFY_ACTION_OLD_NAME) { \
913                         torture_comment(torture, \
914                                 "(rename file special handling OK)\n"); \
915                 } else if (nchanges != notify.smb2.out.num_changes) { \
916                         torture_result(torture, TORTURE_FAIL, \
917                                "ERROR: nchanges=%d expected=%d "\
918                                "action=%d filter=0x%08x\n", \
919                                notify.smb2.out.num_changes, \
920                                nchanges, \
921                                notify.smb2.out.changes[0].action, \
922                                notify.smb2.in.completion_filter); \
923                         ret = false; \
924                 } else if (notify.smb2.out.changes[0].action != Action) { \
925                         torture_result(torture, TORTURE_FAIL, \
926                                "ERROR: nchanges=%d action=%d " \
927                                "expectedAction=%d filter=0x%08x\n", \
928                                notify.smb2.out.num_changes, \
929                                notify.smb2.out.changes[0].action, \
930                                Action, \
931                                notify.smb2.in.completion_filter); \
932                         ret = false; \
933                 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
934                            "tname1") != 0) { \
935                         torture_result(torture, TORTURE_FAIL, \
936                                "ERROR: nchanges=%d action=%d " \
937                                "filter=0x%08x name=%s\n", \
938                                notify.smb2.out.num_changes, \
939                                notify.smb2.out.changes[0].action, \
940                                notify.smb2.in.completion_filter, \
941                                notify.smb2.out.changes[0].name.s);      \
942                         ret = false; \
943                 } \
944                 mask |= (1<<i); \
945         } \
946         } while (0); \
947         } while (0);
948
949         torture_comment(torture, "Testing mkdir\n");
950         NOTIFY_MASK_TEST("Testing mkdir",;,
951                          smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
952                          smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
953                          NOTIFY_ACTION_ADDED,
954                          FILE_NOTIFY_CHANGE_DIR_NAME, 1);
955
956         torture_comment(torture, "Testing create file\n");
957         ZERO_STRUCT(io1.smb2);
958         io1.generic.level = RAW_OPEN_SMB2;
959         io1.smb2.in.create_flags = 0;
960         io1.smb2.in.desired_access = SEC_FILE_ALL;
961         io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
962         io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
963                                 NTCREATEX_SHARE_ACCESS_WRITE;
964         io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
965         io1.smb2.in.security_flags = 0;
966         io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
967         io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
968         io1.smb2.in.fname = BASEDIR "\\tname1";
969
970         NOTIFY_MASK_TEST("Testing create file",;,
971                          smb2_util_close(tree2, custom_smb2_create(tree2,
972                                                 torture, &(io1.smb2)));,
973                          smb2_util_unlink(tree2, BASEDIR "\\tname1");,
974                          NOTIFY_ACTION_ADDED,
975                          FILE_NOTIFY_CHANGE_FILE_NAME, 1);
976
977         torture_comment(torture, "Testing unlink\n");
978         NOTIFY_MASK_TEST("Testing unlink",
979                          smb2_util_close(tree2, custom_smb2_create(tree2,
980                                                 torture, &(io1.smb2)));,
981                          smb2_util_unlink(tree2, BASEDIR "\\tname1");,
982                          ;,
983                          NOTIFY_ACTION_REMOVED,
984                          FILE_NOTIFY_CHANGE_FILE_NAME, 1);
985
986         torture_comment(torture, "Testing rmdir\n");
987         NOTIFY_MASK_TEST("Testing rmdir",
988                          smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
989                          smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
990                          ;,
991                          NOTIFY_ACTION_REMOVED,
992                          FILE_NOTIFY_CHANGE_DIR_NAME, 1);
993
994         torture_comment(torture, "Testing rename file\n");
995         ZERO_STRUCT(sinfo);
996         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
997         sinfo.rename_information.in.file.handle = h1;
998         sinfo.rename_information.in.overwrite = true;
999         sinfo.rename_information.in.root_fid = 0;
1000         sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
1001         NOTIFY_MASK_TEST("Testing rename file",
1002                          smb2_util_close(tree2, custom_smb2_create(tree2,
1003                                                 torture, &(io1.smb2)));,
1004                          smb2_setinfo_file(tree2, &sinfo);,
1005                          smb2_util_unlink(tree2, BASEDIR "\\tname2");,
1006                          NOTIFY_ACTION_OLD_NAME,
1007                          FILE_NOTIFY_CHANGE_FILE_NAME, 2);
1008
1009         torture_comment(torture, "Testing rename dir\n");
1010         ZERO_STRUCT(sinfo);
1011         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1012         sinfo.rename_information.in.file.handle = h1;
1013         sinfo.rename_information.in.overwrite = true;
1014         sinfo.rename_information.in.root_fid = 0;
1015         sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
1016         NOTIFY_MASK_TEST("Testing rename dir",
1017                 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
1018                 smb2_setinfo_file(tree2, &sinfo);,
1019                 smb2_util_rmdir(tree2, BASEDIR "\\tname2");,
1020                 NOTIFY_ACTION_OLD_NAME,
1021                 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
1022
1023         torture_comment(torture, "Testing set path attribute\n");
1024         NOTIFY_MASK_TEST("Testing set path attribute",
1025                 smb2_util_close(tree2, custom_smb2_create(tree2,
1026                                        torture, &(io.smb2)));,
1027                 smb2_util_setatr(tree2, BASEDIR "\\tname1",
1028                                  FILE_ATTRIBUTE_HIDDEN);,
1029                 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1030                 NOTIFY_ACTION_MODIFIED,
1031                 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
1032
1033         torture_comment(torture, "Testing set path write time\n");
1034         ZERO_STRUCT(sinfo);
1035         sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1036         sinfo.generic.in.file.handle = h1;
1037         sinfo.basic_info.in.write_time = 1000;
1038         NOTIFY_MASK_TEST("Testing set path write time",
1039                 smb2_util_close(tree2, custom_smb2_create(tree2,
1040                                        torture, &(io1.smb2)));,
1041                 smb2_setinfo_file(tree2, &sinfo);,
1042                 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1043                 NOTIFY_ACTION_MODIFIED,
1044                 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
1045
1046         if (torture_setting_bool(torture, "samba3", false)) {
1047                 torture_comment(torture,
1048                        "Samba3 does not yet support create times "
1049                        "everywhere\n");
1050         }
1051         else {
1052                 ZERO_STRUCT(sinfo);
1053                 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1054                 sinfo.generic.in.file.handle = h1;
1055                 sinfo.basic_info.in.create_time = 0;
1056                 torture_comment(torture, "Testing set file create time\n");
1057                 NOTIFY_MASK_TEST("Testing set file create time",
1058                         smb2_create_complex_file(tree2,
1059                         BASEDIR "\\tname1", &h2);,
1060                         smb2_setinfo_file(tree2, &sinfo);,
1061                         (smb2_util_close(tree2, h2),
1062                          smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1063                         NOTIFY_ACTION_MODIFIED,
1064                         FILE_NOTIFY_CHANGE_CREATION, 1);
1065         }
1066
1067         ZERO_STRUCT(sinfo);
1068         sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1069         sinfo.generic.in.file.handle = h1;
1070         sinfo.basic_info.in.access_time = 0;
1071         torture_comment(torture, "Testing set file access time\n");
1072         NOTIFY_MASK_TEST("Testing set file access time",
1073                 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1074                 smb2_setinfo_file(tree2, &sinfo);,
1075                 (smb2_util_close(tree2, h2),
1076                 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1077                 NOTIFY_ACTION_MODIFIED,
1078                 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
1079
1080         ZERO_STRUCT(sinfo);
1081         sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1082         sinfo.generic.in.file.handle = h1;
1083         sinfo.basic_info.in.change_time = 0;
1084         torture_comment(torture, "Testing set file change time\n");
1085         NOTIFY_MASK_TEST("Testing set file change time",
1086                 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1087                 smb2_setinfo_file(tree2, &sinfo);,
1088                 (smb2_util_close(tree2, h2),
1089                 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1090                 NOTIFY_ACTION_MODIFIED,
1091                 0, 1);
1092
1093
1094         torture_comment(torture, "Testing write\n");
1095         NOTIFY_MASK_TEST("Testing write",
1096                 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1097                 smb2_util_write(tree2, h2, &c, 10000, 1);,
1098                 (smb2_util_close(tree2, h2),
1099                 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1100                 NOTIFY_ACTION_MODIFIED,
1101                 0, 1);
1102
1103 done:
1104         smb2_deltree(tree1, BASEDIR);
1105         return ret;
1106 }
1107
1108 /*
1109   basic testing of change notify on files
1110 */
1111 static bool torture_smb2_notify_file(struct torture_context *torture,
1112                                 struct smb2_tree *tree)
1113 {
1114         NTSTATUS status;
1115         bool ret = true;
1116         union smb_open io;
1117         union smb_close cl;
1118         union smb_notify notify;
1119         struct smb2_request *req;
1120         struct smb2_handle h1;
1121         const char *fname = BASEDIR "\\file.txt";
1122
1123         smb2_deltree(tree, BASEDIR);
1124         smb2_util_rmdir(tree, BASEDIR);
1125
1126         torture_comment(torture, "TESTING CHANGE NOTIFY ON FILES\n");
1127         status = torture_smb2_testdir(tree, BASEDIR, &h1);
1128         CHECK_STATUS(status, NT_STATUS_OK);
1129
1130         ZERO_STRUCT(io.smb2);
1131         io.generic.level = RAW_OPEN_SMB2;
1132         io.smb2.in.create_flags = 0;
1133         io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
1134         io.smb2.in.create_options = 0;
1135         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1136         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1137                                 NTCREATEX_SHARE_ACCESS_WRITE;
1138         io.smb2.in.alloc_size = 0;
1139         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1140         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1141         io.smb2.in.security_flags = 0;
1142         io.smb2.in.fname = fname;
1143         status = smb2_create(tree, torture, &(io.smb2));
1144         CHECK_STATUS(status, NT_STATUS_OK);
1145         h1 = io.smb2.out.file.handle;
1146
1147         /* ask for a change notify,
1148            on file or directory name changes */
1149         ZERO_STRUCT(notify.smb2);
1150         notify.smb2.level = RAW_NOTIFY_SMB2;
1151         notify.smb2.in.file.handle = h1;
1152         notify.smb2.in.buffer_size = 1000;
1153         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
1154         notify.smb2.in.recursive = false;
1155
1156         torture_comment(torture,
1157         "Testing if notifies on file handles are invalid (should be)\n");
1158
1159         req = smb2_notify_send(tree, &(notify.smb2));
1160         status = smb2_notify_recv(req, torture, &(notify.smb2));
1161         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1162
1163         ZERO_STRUCT(cl.smb2);
1164         cl.close.level = RAW_CLOSE_SMB2;
1165         cl.close.in.file.handle = h1;
1166         status = smb2_close(tree, &(cl.smb2));
1167         CHECK_STATUS(status, NT_STATUS_OK);
1168
1169         status = smb2_util_unlink(tree, fname);
1170         CHECK_STATUS(status, NT_STATUS_OK);
1171
1172 done:
1173         smb2_deltree(tree, BASEDIR);
1174         return ret;
1175 }
1176 /*
1177   basic testing of change notifies followed by a tdis
1178 */
1179
1180 static bool torture_smb2_notify_tree_disconnect(
1181                 struct torture_context *torture,
1182                 struct smb2_tree *tree)
1183 {
1184         bool ret = true;
1185         NTSTATUS status;
1186         union smb_notify notify;
1187         union smb_open io;
1188         struct smb2_handle h1;
1189         struct smb2_request *req;
1190
1191         smb2_deltree(tree, BASEDIR);
1192         smb2_util_rmdir(tree, BASEDIR);
1193
1194         torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY "
1195                         "TREE-DISCONNECT\n");
1196
1197         /*
1198           get a handle on the directory
1199         */
1200         ZERO_STRUCT(io.smb2);
1201         io.generic.level = RAW_OPEN_SMB2;
1202         io.smb2.in.create_flags = 0;
1203         io.smb2.in.desired_access = SEC_FILE_ALL;
1204         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1205         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1206         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1207                                 NTCREATEX_SHARE_ACCESS_WRITE;
1208         io.smb2.in.alloc_size = 0;
1209         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1210         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1211         io.smb2.in.security_flags = 0;
1212         io.smb2.in.fname = BASEDIR;
1213
1214         status = smb2_create(tree, torture, &(io.smb2));
1215         CHECK_STATUS(status, NT_STATUS_OK);
1216         h1 = io.smb2.out.file.handle;
1217
1218         /* ask for a change notify,
1219            on file or directory name changes */
1220         ZERO_STRUCT(notify.smb2);
1221         notify.smb2.level = RAW_NOTIFY_SMB2;
1222         notify.smb2.in.buffer_size = 1000;
1223         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1224         notify.smb2.in.file.handle = h1;
1225         notify.smb2.in.recursive = true;
1226
1227         req = smb2_notify_send(tree, &(notify.smb2));
1228         smb2_cancel(req);
1229         status = smb2_notify_recv(req, torture, &(notify.smb2));
1230
1231         status = smb2_tdis(tree);
1232         CHECK_STATUS(status, NT_STATUS_OK);
1233
1234         req = smb2_notify_send(tree, &(notify.smb2));
1235
1236         smb2_notify_recv(req, torture, &(notify.smb2));
1237         CHECK_STATUS(status, NT_STATUS_OK);
1238         CHECK_VAL(notify.smb2.out.num_changes, 0);
1239
1240 done:
1241         smb2_deltree(tree, BASEDIR);
1242         return ret;
1243 }
1244
1245 /*
1246   basic testing of change notifies followed by a ulogoff
1247 */
1248
1249 static bool torture_smb2_notify_ulogoff(struct torture_context *torture,
1250                                 struct smb2_tree *tree1,
1251                                 struct smb2_tree *tree2)
1252 {
1253         bool ret = true;
1254         NTSTATUS status;
1255         union smb_notify notify;
1256         union smb_open io;
1257         struct smb2_handle h1;
1258         struct smb2_request *req;
1259
1260         smb2_deltree(tree1, BASEDIR);
1261         smb2_util_rmdir(tree1, BASEDIR);
1262
1263         torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1264
1265         /*
1266           get a handle on the directory
1267         */
1268         ZERO_STRUCT(io.smb2);
1269         io.generic.level = RAW_OPEN_SMB2;
1270         io.smb2.in.create_flags = 0;
1271         io.smb2.in.desired_access = SEC_FILE_ALL;
1272         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1273         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1274         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1275                                 NTCREATEX_SHARE_ACCESS_WRITE;
1276         io.smb2.in.alloc_size = 0;
1277         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1278         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1279         io.smb2.in.security_flags = 0;
1280         io.smb2.in.fname = BASEDIR;
1281
1282         status = smb2_create(tree2, torture, &(io.smb2));
1283         CHECK_STATUS(status, NT_STATUS_OK);
1284
1285         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1286         status = smb2_create(tree2, torture, &(io.smb2));
1287         CHECK_STATUS(status, NT_STATUS_OK);
1288         h1 = io.smb2.out.file.handle;
1289
1290         /* ask for a change notify,
1291            on file or directory name changes */
1292         ZERO_STRUCT(notify.smb2);
1293         notify.smb2.level = RAW_NOTIFY_SMB2;
1294         notify.smb2.in.buffer_size = 1000;
1295         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1296         notify.smb2.in.file.handle = h1;
1297         notify.smb2.in.recursive = true;
1298
1299         req = smb2_notify_send(tree1, &(notify.smb2));
1300
1301         status = smb2_logoff(tree2->session);
1302         CHECK_STATUS(status, NT_STATUS_OK);
1303
1304         status = smb2_notify_recv(req, torture, &(notify.smb2));
1305         CHECK_VAL(notify.smb2.out.num_changes, 0);
1306
1307 done:
1308         smb2_deltree(tree1, BASEDIR);
1309         return ret;
1310 }
1311
1312 static void tcp_dis_handler(struct smb2_transport *t, void *p)
1313 {
1314         struct smb2_tree *tree = (struct smb2_tree *)p;
1315         smb2_transport_dead(tree->session->transport,
1316                         NT_STATUS_LOCAL_DISCONNECT);
1317         t = NULL;
1318         tree = NULL;
1319 }
1320
1321 /*
1322   basic testing of change notifies followed by tcp disconnect
1323 */
1324
1325 static bool torture_smb2_notify_tcp_disconnect(
1326                 struct torture_context *torture,
1327                 struct smb2_tree *tree)
1328 {
1329         bool ret = true;
1330         NTSTATUS status;
1331         union smb_notify notify;
1332         union smb_open io;
1333         struct smb2_handle h1;
1334         struct smb2_request *req;
1335
1336         smb2_deltree(tree, BASEDIR);
1337         smb2_util_rmdir(tree, BASEDIR);
1338
1339         torture_comment(torture,
1340                 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\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_OPEN_IF;
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(tree, torture, &(io.smb2));
1360         CHECK_STATUS(status, NT_STATUS_OK);
1361         h1 = io.smb2.out.file.handle;
1362
1363         /* ask for a change notify,
1364            on file or directory name changes */
1365         ZERO_STRUCT(notify.smb2);
1366         notify.smb2.level = RAW_NOTIFY_SMB2;
1367         notify.smb2.in.buffer_size = 1000;
1368         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1369         notify.smb2.in.file.handle = h1;
1370         notify.smb2.in.recursive = true;
1371
1372         req = smb2_notify_send(tree, &(notify.smb2));
1373         smb2_cancel(req);
1374         status = smb2_notify_recv(req, torture, &(notify.smb2));
1375         CHECK_STATUS(status, NT_STATUS_CANCELLED);
1376
1377         notify.smb2.in.recursive = true;
1378         req = smb2_notify_send(tree, &(notify.smb2));
1379         smb2_transport_idle_handler(tree->session->transport,
1380                                 tcp_dis_handler, 250, tree);
1381         tree = NULL;
1382         status = smb2_notify_recv(req, torture, &(notify.smb2));
1383         CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
1384
1385 done:
1386         return ret;
1387 }
1388
1389 /*
1390    test setting up two change notify requests on one handle
1391 */
1392
1393 static bool torture_smb2_notify_double(struct torture_context *torture,
1394                         struct smb2_tree *tree1,
1395                         struct smb2_tree *tree2)
1396 {
1397         bool ret = true;
1398         NTSTATUS status;
1399         union smb_notify notify;
1400         union smb_open io;
1401         struct smb2_handle h1;
1402         struct smb2_request *req1, *req2;
1403
1404         smb2_deltree(tree1, BASEDIR);
1405         smb2_util_rmdir(tree1, BASEDIR);
1406
1407         torture_comment(torture,
1408                 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1409
1410         /*
1411           get a handle on the directory
1412         */
1413         ZERO_STRUCT(io.smb2);
1414         io.generic.level = RAW_OPEN_SMB2;
1415         io.smb2.in.create_flags = 0;
1416         io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ|
1417                                 SEC_RIGHTS_FILE_WRITE|
1418                                 SEC_RIGHTS_FILE_ALL;
1419         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1420         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1421         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1422                                 NTCREATEX_SHARE_ACCESS_WRITE;
1423         io.smb2.in.alloc_size = 0;
1424         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1425         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1426         io.smb2.in.security_flags = 0;
1427         io.smb2.in.fname = BASEDIR;
1428
1429         status = smb2_create(tree1, torture, &(io.smb2));
1430         CHECK_STATUS(status, NT_STATUS_OK);
1431         h1 = io.smb2.out.file.handle;
1432
1433         /* ask for a change notify,
1434            on file or directory name changes */
1435         ZERO_STRUCT(notify.smb2);
1436         notify.smb2.level = RAW_NOTIFY_SMB2;
1437         notify.smb2.in.buffer_size = 1000;
1438         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1439         notify.smb2.in.file.handle = h1;
1440         notify.smb2.in.recursive = true;
1441
1442         req1 = smb2_notify_send(tree1, &(notify.smb2));
1443         smb2_cancel(req1);
1444         status = smb2_notify_recv(req1, torture, &(notify.smb2));
1445         CHECK_STATUS(status, NT_STATUS_CANCELLED);
1446
1447         req2 = smb2_notify_send(tree1, &(notify.smb2));
1448         smb2_cancel(req2);
1449         status = smb2_notify_recv(req2, torture, &(notify.smb2));
1450         CHECK_STATUS(status, NT_STATUS_CANCELLED);
1451
1452         smb2_util_mkdir(tree2, BASEDIR "\\subdir-name");
1453         req1 = smb2_notify_send(tree1, &(notify.smb2));
1454         req2 = smb2_notify_send(tree1, &(notify.smb2));
1455
1456         status = smb2_notify_recv(req1, torture, &(notify.smb2));
1457         CHECK_STATUS(status, NT_STATUS_OK);
1458         CHECK_VAL(notify.smb2.out.num_changes, 1);
1459         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1460
1461         smb2_util_mkdir(tree2, BASEDIR "\\subdir-name2");
1462
1463         status = smb2_notify_recv(req2, torture, &(notify.smb2));
1464         CHECK_STATUS(status, NT_STATUS_OK);
1465         CHECK_VAL(notify.smb2.out.num_changes, 1);
1466         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name2");
1467
1468 done:
1469         smb2_deltree(tree1, BASEDIR);
1470         return ret;
1471 }
1472
1473
1474 /*
1475    test multiple change notifies at different depths and with/without recursion
1476 */
1477
1478 static bool torture_smb2_notify_tree(struct torture_context *torture,
1479                              struct smb2_tree *tree)
1480 {
1481         bool ret = true;
1482         union smb_notify notify;
1483         union smb_open io;
1484         struct smb2_request *req;
1485         struct timeval tv;
1486         struct {
1487                 const char *path;
1488                 bool recursive;
1489                 uint32_t filter;
1490                 int expected;
1491                 struct smb2_handle h1;
1492                 int counted;
1493         } dirs[] = {
1494                 {BASEDIR "\\abc",               true, FILE_NOTIFY_CHANGE_NAME, 30 },
1495                 {BASEDIR "\\zqy",               true, FILE_NOTIFY_CHANGE_NAME, 8 },
1496                 {BASEDIR "\\atsy",              true, FILE_NOTIFY_CHANGE_NAME, 4 },
1497                 {BASEDIR "\\abc\\foo",          true,  FILE_NOTIFY_CHANGE_NAME, 2 },
1498                 {BASEDIR "\\abc\\blah",         true,  FILE_NOTIFY_CHANGE_NAME, 13 },
1499                 {BASEDIR "\\abc\\blah",         false, FILE_NOTIFY_CHANGE_NAME, 7 },
1500                 {BASEDIR "\\abc\\blah\\a",      true, FILE_NOTIFY_CHANGE_NAME, 2 },
1501                 {BASEDIR "\\abc\\blah\\b",      true, FILE_NOTIFY_CHANGE_NAME, 2 },
1502                 {BASEDIR "\\abc\\blah\\c",      true, FILE_NOTIFY_CHANGE_NAME, 2 },
1503                 {BASEDIR "\\abc\\fooblah",      true, FILE_NOTIFY_CHANGE_NAME, 2 },
1504                 {BASEDIR "\\zqy\\xx",           true, FILE_NOTIFY_CHANGE_NAME, 2 },
1505                 {BASEDIR "\\zqy\\yyy",          true, FILE_NOTIFY_CHANGE_NAME, 2 },
1506                 {BASEDIR "\\zqy\\..",           true, FILE_NOTIFY_CHANGE_NAME, 40 },
1507                 {BASEDIR,                       true, FILE_NOTIFY_CHANGE_NAME, 40 },
1508                 {BASEDIR,                       false,FILE_NOTIFY_CHANGE_NAME, 6 },
1509                 {BASEDIR "\\atsy",              false,FILE_NOTIFY_CHANGE_NAME, 4 },
1510                 {BASEDIR "\\abc",               true, FILE_NOTIFY_CHANGE_NAME, 24 },
1511                 {BASEDIR "\\abc",               false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1512                 {BASEDIR "\\abc",               true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1513                 {BASEDIR "\\abc",               true, FILE_NOTIFY_CHANGE_NAME, 24 },
1514         };
1515         int i;
1516         NTSTATUS status;
1517         bool all_done = false;
1518
1519         smb2_deltree(tree, BASEDIR);
1520         smb2_util_rmdir(tree, BASEDIR);
1521
1522         torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1523
1524         ZERO_STRUCT(io.smb2);
1525         io.generic.level = RAW_OPEN_SMB2;
1526         io.smb2.in.create_flags = 0;
1527         io.smb2.in.desired_access = SEC_FILE_ALL;
1528         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1529         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1530         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1531                                 NTCREATEX_SHARE_ACCESS_WRITE;
1532         io.smb2.in.alloc_size = 0;
1533         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1534         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1535         io.smb2.in.security_flags = 0;
1536         io.smb2.in.fname = BASEDIR;
1537         status = smb2_create(tree, torture, &(io.smb2));
1538         CHECK_STATUS(status, NT_STATUS_OK);
1539
1540         ZERO_STRUCT(notify.smb2);
1541         notify.smb2.level = RAW_NOTIFY_SMB2;
1542         notify.smb2.in.buffer_size = 20000;
1543
1544         /*
1545           setup the directory tree, and the notify buffer on each directory
1546         */
1547         for (i=0;i<ARRAY_SIZE(dirs);i++) {
1548                 io.smb2.in.fname = dirs[i].path;
1549                 status = smb2_create(tree, torture, &(io.smb2));
1550                 CHECK_STATUS(status, NT_STATUS_OK);
1551                 dirs[i].h1 = io.smb2.out.file.handle;
1552
1553                 notify.smb2.in.completion_filter = dirs[i].filter;
1554                 notify.smb2.in.file.handle = dirs[i].h1;
1555                 notify.smb2.in.recursive = dirs[i].recursive;
1556                 req = smb2_notify_send(tree, &(notify.smb2));
1557                 smb2_cancel(req);
1558                 status = smb2_notify_recv(req, torture, &(notify.smb2));
1559                 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1560         }
1561
1562         /* trigger 2 events in each dir */
1563         for (i=0;i<ARRAY_SIZE(dirs);i++) {
1564                 char *path = talloc_asprintf(torture, "%s\\test.dir",
1565                                              dirs[i].path);
1566                 smb2_util_mkdir(tree, path);
1567                 smb2_util_rmdir(tree, path);
1568                 talloc_free(path);
1569         }
1570
1571         /* give a bit of time for the events to propogate */
1572         tv = timeval_current();
1573
1574         do {
1575                 /* count events that have happened in each dir */
1576                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1577                         notify.smb2.in.file.handle = dirs[i].h1;
1578                         req = smb2_notify_send(tree, &(notify.smb2));
1579                         smb2_cancel(req);
1580                         notify.smb2.out.num_changes = 0;
1581                         status = smb2_notify_recv(req, torture,
1582                                  &(notify.smb2));
1583                         dirs[i].counted += notify.smb2.out.num_changes;
1584                 }
1585
1586                 all_done = true;
1587
1588                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1589                         if (dirs[i].counted != dirs[i].expected) {
1590                                 all_done = false;
1591                         }
1592                 }
1593         } while (!all_done && timeval_elapsed(&tv) < 20);
1594
1595         torture_comment(torture, "took %.4f seconds to propogate all events\n",
1596                         timeval_elapsed(&tv));
1597
1598         for (i=0;i<ARRAY_SIZE(dirs);i++) {
1599                 if (dirs[i].counted != dirs[i].expected) {
1600                         torture_comment(torture,
1601                                 "ERROR: i=%d expected %d got %d for '%s'\n",
1602                                 i, dirs[i].expected, dirs[i].counted,
1603                                 dirs[i].path);
1604                         ret = false;
1605                 }
1606         }
1607
1608         /*
1609           run from the back, closing and deleting
1610         */
1611         for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1612                 smb2_util_close(tree, dirs[i].h1);
1613                 smb2_util_rmdir(tree, dirs[i].path);
1614         }
1615
1616 done:
1617         smb2_deltree(tree, BASEDIR);
1618         smb2_util_rmdir(tree, BASEDIR);
1619         return ret;
1620 }
1621
1622 /*
1623    Test response when cached server events exceed single NT NOTFIY response
1624    packet size.
1625 */
1626
1627 static bool torture_smb2_notify_overflow(struct torture_context *torture,
1628                                 struct smb2_tree *tree)
1629 {
1630         bool ret = true;
1631         NTSTATUS status;
1632         union smb_notify notify;
1633         union smb_open io;
1634         struct smb2_handle h1, h2;
1635         int count = 100;
1636         struct smb2_request *req1;
1637         int i;
1638
1639         smb2_deltree(tree, BASEDIR);
1640         smb2_util_rmdir(tree, BASEDIR);
1641
1642         torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1643
1644         /* get a handle on the directory */
1645         ZERO_STRUCT(io.smb2);
1646         io.generic.level = RAW_OPEN_SMB2;
1647         io.smb2.in.create_flags = 0;
1648         io.smb2.in.desired_access = SEC_FILE_ALL;
1649         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1650         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1651         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1652                             NTCREATEX_SHARE_ACCESS_WRITE;
1653         io.smb2.in.alloc_size = 0;
1654         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1655         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1656         io.smb2.in.security_flags = 0;
1657         io.smb2.in.fname = BASEDIR;
1658
1659         status = smb2_create(tree, torture, &(io.smb2));
1660         CHECK_STATUS(status, NT_STATUS_OK);
1661         h1 = io.smb2.out.file.handle;
1662
1663         /* ask for a change notify, on name changes. */
1664         ZERO_STRUCT(notify.smb2);
1665         notify.smb2.level = RAW_NOTIFY_NTTRANS;
1666         notify.smb2.in.buffer_size = 1000;
1667         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1668         notify.smb2.in.file.handle = h1;
1669
1670         notify.smb2.in.recursive = true;
1671         req1 = smb2_notify_send(tree, &(notify.smb2));
1672
1673         /* cancel initial requests so the buffer is setup */
1674         smb2_cancel(req1);
1675         status = smb2_notify_recv(req1, torture, &(notify.smb2));
1676         CHECK_STATUS(status, NT_STATUS_CANCELLED);
1677
1678         /* open a lot of files, filling up the server side notify buffer */
1679         torture_comment(torture,
1680                 "Testing overflowed buffer notify on create of %d files\n",
1681                 count);
1682
1683         for (i=0;i<count;i++) {
1684                 char *fname = talloc_asprintf(torture,
1685                               BASEDIR "\\test%d.txt", i);
1686                 union smb_open io1;
1687                 ZERO_STRUCT(io1.smb2);
1688                 io1.generic.level = RAW_OPEN_SMB2;
1689                 io1.smb2.in.create_flags = 0;
1690                 io1.smb2.in.desired_access = SEC_FILE_ALL;
1691                 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1692                 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1693                 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1694                                     NTCREATEX_SHARE_ACCESS_WRITE;
1695                 io1.smb2.in.alloc_size = 0;
1696                 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1697                 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1698                 io1.smb2.in.security_flags = 0;
1699                 io1.smb2.in.fname = fname;
1700
1701                 h2 = custom_smb2_create(tree, torture, &(io1.smb2));
1702                 talloc_free(fname);
1703                 smb2_util_close(tree, h2);
1704         }
1705
1706         req1 = smb2_notify_send(tree, &(notify.smb2));
1707         status = smb2_notify_recv(req1, torture, &(notify.smb2));
1708         CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
1709         CHECK_VAL(notify.smb2.out.num_changes, 0);
1710
1711 done:
1712         smb2_deltree(tree, BASEDIR);
1713         return ret;
1714 }
1715
1716 /*
1717    Test if notifications are returned for changes to the base directory.
1718    They shouldn't be.
1719 */
1720
1721 static bool torture_smb2_notify_basedir(struct torture_context *torture,
1722                                 struct smb2_tree *tree1,
1723                                 struct smb2_tree *tree2)
1724 {
1725         bool ret = true;
1726         NTSTATUS status;
1727         union smb_notify notify;
1728         union smb_open io;
1729         struct smb2_handle h1;
1730         struct smb2_request *req1;
1731
1732         smb2_deltree(tree1, BASEDIR);
1733         smb2_util_rmdir(tree1, BASEDIR);
1734
1735         torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1736
1737         /* get a handle on the directory */
1738         ZERO_STRUCT(io.smb2);
1739         io.generic.level = RAW_OPEN_SMB2;
1740         io.smb2.in.create_flags = 0;
1741         io.smb2.in.desired_access = SEC_FILE_ALL;
1742         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1743         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1744         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1745             NTCREATEX_SHARE_ACCESS_WRITE;
1746         io.smb2.in.alloc_size = 0;
1747         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1748         io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
1749         io.smb2.in.security_flags = 0;
1750         io.smb2.in.fname = BASEDIR;
1751
1752         status = smb2_create(tree1, torture, &(io.smb2));
1753         CHECK_STATUS(status, NT_STATUS_OK);
1754         h1 = io.smb2.out.file.handle;
1755
1756         /* create a test file that will also be modified */
1757         io.smb2.in.fname = BASEDIR "\\tname1";
1758         io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
1759         status =  smb2_create(tree2, torture, &(io.smb2));
1760         CHECK_STATUS(status,NT_STATUS_OK);
1761         smb2_util_close(tree2, io.smb2.out.file.handle);
1762
1763         /* ask for a change notify, on attribute changes. */
1764         ZERO_STRUCT(notify.smb2);
1765         notify.smb2.level = RAW_NOTIFY_SMB2;
1766         notify.smb2.in.buffer_size = 1000;
1767         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
1768         notify.smb2.in.file.handle = h1;
1769         notify.smb2.in.recursive = true;
1770
1771         req1 = smb2_notify_send(tree1, &(notify.smb2));
1772
1773         /* set attribute on the base dir */
1774         smb2_util_setatr(tree2, BASEDIR, FILE_ATTRIBUTE_HIDDEN);
1775
1776         /* set attribute on a file to assure we receive a notification */
1777         smb2_util_setatr(tree2, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN);
1778         smb_msleep(200);
1779
1780         /* check how many responses were given, expect only 1 for the file */
1781         status = smb2_notify_recv(req1, torture, &(notify.smb2));
1782         CHECK_STATUS(status, NT_STATUS_OK);
1783         CHECK_VAL(notify.smb2.out.num_changes, 1);
1784         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
1785         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
1786
1787 done:
1788         smb2_deltree(tree1, BASEDIR);
1789         return ret;
1790 }
1791
1792
1793 /*
1794   create a secondary tree connect - used to test for a bug in Samba3 messaging
1795   with change notify
1796 */
1797 static struct smb2_tree *secondary_tcon(struct smb2_tree *tree,
1798                                         struct torture_context *tctx)
1799 {
1800         NTSTATUS status;
1801         const char *share, *host;
1802         struct smb2_tree *tree1;
1803         union smb_tcon tcon;
1804
1805         share = torture_setting_string(tctx, "share", NULL);
1806         host  = torture_setting_string(tctx, "host", NULL);
1807
1808         torture_comment(tctx,
1809                 "create a second tree context on the same session\n");
1810         tree1 = smb2_tree_init(tree->session, tctx, false);
1811
1812         ZERO_STRUCT(tcon.smb2);
1813         tcon.generic.level = RAW_TCON_SMB2;
1814         tcon.smb2.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
1815         status = smb2_tree_connect(tree, &(tcon.smb2));
1816         if (!NT_STATUS_IS_OK(status)) {
1817                 talloc_free(tree);
1818                 torture_comment(tctx,"Failed to create secondary tree\n");
1819                 return NULL;
1820         }
1821
1822         tree1->tid = tcon.smb2.out.tid;
1823         torture_comment(tctx,"tid1=%d tid2=%d\n", tree->tid, tree1->tid);
1824
1825         return tree1;
1826 }
1827
1828
1829 /*
1830    very simple change notify test
1831 */
1832 static bool torture_smb2_notify_tcon(struct torture_context *torture,
1833                                   struct smb2_tree *tree)
1834 {
1835         bool ret = true;
1836         NTSTATUS status;
1837         union smb_notify notify;
1838         union smb_open io;
1839         struct smb2_handle h1;
1840         struct smb2_request *req = NULL;
1841         struct smb2_tree *tree1 = NULL;
1842         const char *fname = BASEDIR "\\subdir-name";
1843
1844         smb2_deltree(tree, BASEDIR);
1845         smb2_util_rmdir(tree, BASEDIR);
1846
1847         torture_comment(torture, "TESTING SIMPLE CHANGE NOTIFY\n");
1848
1849         /*
1850           get a handle on the directory
1851         */
1852
1853         ZERO_STRUCT(io.smb2);
1854         io.generic.level = RAW_OPEN_SMB2;
1855         io.smb2.in.create_flags = 0;
1856         io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1857         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1858         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL |
1859                                 FILE_ATTRIBUTE_DIRECTORY;
1860         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1861                                 NTCREATEX_SHARE_ACCESS_WRITE;
1862         io.smb2.in.alloc_size = 0;
1863         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1864         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1865         io.smb2.in.security_flags = 0;
1866         io.smb2.in.fname = BASEDIR;
1867
1868         status = smb2_create(tree, torture, &(io.smb2));
1869         CHECK_STATUS(status, NT_STATUS_OK);
1870         h1 = io.smb2.out.file.handle;
1871
1872         /* ask for a change notify,
1873            on file or directory name changes */
1874         ZERO_STRUCT(notify.smb2);
1875         notify.smb2.level = RAW_NOTIFY_SMB2;
1876         notify.smb2.in.buffer_size = 1000;
1877         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1878         notify.smb2.in.file.handle = h1;
1879         notify.smb2.in.recursive = true;
1880
1881         torture_comment(torture, "Testing notify mkdir\n");
1882         req = smb2_notify_send(tree, &(notify.smb2));
1883         smb2_cancel(req);
1884         status = smb2_notify_recv(req, torture, &(notify.smb2));
1885         CHECK_STATUS(status, NT_STATUS_CANCELLED);
1886
1887         notify.smb2.in.recursive = true;
1888         req = smb2_notify_send(tree, &(notify.smb2));
1889         status = smb2_util_mkdir(tree, fname);
1890         CHECK_STATUS(status, NT_STATUS_OK);
1891
1892         status = smb2_notify_recv(req, torture, &(notify.smb2));
1893         CHECK_STATUS(status, NT_STATUS_OK);
1894
1895         CHECK_VAL(notify.smb2.out.num_changes, 1);
1896         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
1897         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1898
1899         torture_comment(torture, "Testing notify rmdir\n");
1900         req = smb2_notify_send(tree, &(notify.smb2));
1901         status = smb2_util_rmdir(tree, fname);
1902         CHECK_STATUS(status, NT_STATUS_OK);
1903
1904         status = smb2_notify_recv(req, torture, &(notify.smb2));
1905         CHECK_STATUS(status, NT_STATUS_OK);
1906         CHECK_VAL(notify.smb2.out.num_changes, 1);
1907         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
1908         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1909
1910         torture_comment(torture, "SIMPLE CHANGE NOTIFY OK\n");
1911
1912         torture_comment(torture, "TESTING WITH SECONDARY TCON\n");
1913         tree1 = secondary_tcon(tree, torture);
1914
1915         torture_comment(torture, "Testing notify mkdir\n");
1916         req = smb2_notify_send(tree, &(notify.smb2));
1917         smb2_util_mkdir(tree1, fname);
1918
1919         status = smb2_notify_recv(req, torture, &(notify.smb2));
1920         CHECK_STATUS(status, NT_STATUS_OK);
1921
1922         CHECK_VAL(notify.smb2.out.num_changes, 1);
1923         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
1924         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1925
1926         torture_comment(torture, "Testing notify rmdir\n");
1927         req = smb2_notify_send(tree, &(notify.smb2));
1928         smb2_util_rmdir(tree, fname);
1929
1930         status = smb2_notify_recv(req, torture, &(notify.smb2));
1931         CHECK_STATUS(status, NT_STATUS_OK);
1932         CHECK_VAL(notify.smb2.out.num_changes, 1);
1933         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
1934         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1935
1936         torture_comment(torture, "CHANGE NOTIFY WITH TCON OK\n");
1937
1938         torture_comment(torture, "Disconnecting secondary tree\n");
1939         status = smb2_tdis(tree1);
1940         CHECK_STATUS(status, NT_STATUS_OK);
1941         talloc_free(tree1);
1942
1943         torture_comment(torture, "Testing notify mkdir\n");
1944         req = smb2_notify_send(tree, &(notify.smb2));
1945         smb2_util_mkdir(tree, fname);
1946
1947         status = smb2_notify_recv(req, torture, &(notify.smb2));
1948         CHECK_STATUS(status, NT_STATUS_OK);
1949
1950         CHECK_VAL(notify.smb2.out.num_changes, 1);
1951         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
1952         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1953
1954         torture_comment(torture, "Testing notify rmdir\n");
1955         req = smb2_notify_send(tree, &(notify.smb2));
1956         smb2_util_rmdir(tree, fname);
1957
1958         status = smb2_notify_recv(req, torture, &(notify.smb2));
1959         CHECK_STATUS(status, NT_STATUS_OK);
1960         CHECK_VAL(notify.smb2.out.num_changes, 1);
1961         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
1962         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1963
1964         torture_comment(torture, "CHANGE NOTIFY WITH TDIS OK\n");
1965 done:
1966         smb2_util_close(tree, h1);
1967         smb2_deltree(tree, BASEDIR);
1968
1969         return ret;
1970 }
1971
1972 /*
1973    basic testing of SMB2 change notify
1974 */
1975 struct torture_suite *torture_smb2_notify_init(void)
1976 {
1977         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "notify");
1978
1979         torture_suite_add_1smb2_test(suite, "valid-req", test_valid_request);
1980         torture_suite_add_1smb2_test(suite, "tcon", torture_smb2_notify_tcon);
1981         torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir);
1982         torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask);
1983         torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
1984         torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
1985         torture_suite_add_2smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
1986         torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
1987         torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
1988         torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
1989         torture_suite_add_1smb2_test(suite, "file", torture_smb2_notify_file);
1990         torture_suite_add_1smb2_test(suite, "tcp", torture_smb2_notify_tcp_disconnect);
1991         torture_suite_add_2smb2_test(suite, "rec", torture_smb2_notify_recursive);
1992         torture_suite_add_1smb2_test(suite, "overflow", torture_smb2_notify_overflow);
1993
1994         suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");
1995
1996         return suite;
1997 }
1998