s4:torture:smb2:notify: remove an unused variable
[tridge/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 (tevent_loop_once(torture->ev) != 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 (tevent_loop_once(torture->ev) != 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 (tevent_loop_once(torture->ev) != 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 (tevent_loop_once(torture->ev) != 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 (tevent_loop_once(torture->ev) != 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         union smb_setfileinfo sinfo;
850
851         smb2_deltree(tree1, BASEDIR);
852         smb2_util_rmdir(tree1, BASEDIR);
853
854         torture_comment(torture, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
855
856         tv = timeval_current_ofs(1000, 0);
857
858         /*
859           get a handle on the directory
860         */
861         ZERO_STRUCT(io.smb2);
862         io.generic.level = RAW_OPEN_SMB2;
863         io.smb2.in.create_flags = 0;
864         io.smb2.in.desired_access = SEC_FILE_ALL;
865         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
866         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
867         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
868                                 NTCREATEX_SHARE_ACCESS_WRITE;
869         io.smb2.in.alloc_size = 0;
870         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
871         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
872         io.smb2.in.security_flags = 0;
873         io.smb2.in.fname = BASEDIR;
874
875         ZERO_STRUCT(notify.smb2);
876         notify.smb2.level = RAW_NOTIFY_SMB2;
877         notify.smb2.in.buffer_size = 1000;
878         notify.smb2.in.recursive = true;
879
880 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
881                          expected, nchanges) \
882         do { \
883         do { for (mask=i=0;i<32;i++) { \
884                 struct smb2_request *req; \
885                 status = smb2_create(tree1, torture, &(io.smb2)); \
886                 CHECK_STATUS(status, NT_STATUS_OK); \
887                 h1 = io.smb2.out.file.handle; \
888                 setup \
889                 notify.smb2.in.file.handle = h1;        \
890                 notify.smb2.in.completion_filter = (1<<i); \
891                 /* cancel initial requests so the buffer is setup */    \
892                 req = smb2_notify_send(tree1, &(notify.smb2)); \
893                 smb2_cancel(req); \
894                 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
895                 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
896                 /* send the change notify request */ \
897                 req = smb2_notify_send(tree1, &(notify.smb2)); \
898                 op \
899                 smb_msleep(200); smb2_cancel(req); \
900                 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
901                 cleanup \
902                 smb2_util_close(tree1, h1); \
903                 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
904                 CHECK_STATUS(status, NT_STATUS_OK); \
905                 /* special case to cope with file rename behaviour */ \
906                 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
907                     notify.smb2.out.changes[0].action == \
908                         NOTIFY_ACTION_MODIFIED && \
909                     ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
910                     Action == NOTIFY_ACTION_OLD_NAME) { \
911                         torture_comment(torture, \
912                                 "(rename file special handling OK)\n"); \
913                 } else if (nchanges != notify.smb2.out.num_changes) { \
914                         torture_result(torture, TORTURE_FAIL, \
915                                "ERROR: nchanges=%d expected=%d "\
916                                "action=%d filter=0x%08x\n", \
917                                notify.smb2.out.num_changes, \
918                                nchanges, \
919                                notify.smb2.out.changes[0].action, \
920                                notify.smb2.in.completion_filter); \
921                         ret = false; \
922                 } else if (notify.smb2.out.changes[0].action != Action) { \
923                         torture_result(torture, TORTURE_FAIL, \
924                                "ERROR: nchanges=%d action=%d " \
925                                "expectedAction=%d filter=0x%08x\n", \
926                                notify.smb2.out.num_changes, \
927                                notify.smb2.out.changes[0].action, \
928                                Action, \
929                                notify.smb2.in.completion_filter); \
930                         ret = false; \
931                 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
932                            "tname1") != 0) { \
933                         torture_result(torture, TORTURE_FAIL, \
934                                "ERROR: nchanges=%d action=%d " \
935                                "filter=0x%08x name=%s\n", \
936                                notify.smb2.out.num_changes, \
937                                notify.smb2.out.changes[0].action, \
938                                notify.smb2.in.completion_filter, \
939                                notify.smb2.out.changes[0].name.s);      \
940                         ret = false; \
941                 } \
942                 mask |= (1<<i); \
943         } \
944         } while (0); \
945         } while (0);
946
947         torture_comment(torture, "Testing mkdir\n");
948         NOTIFY_MASK_TEST("Testing mkdir",;,
949                          smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
950                          smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
951                          NOTIFY_ACTION_ADDED,
952                          FILE_NOTIFY_CHANGE_DIR_NAME, 1);
953
954         torture_comment(torture, "Testing create file\n");
955         ZERO_STRUCT(io1.smb2);
956         io1.generic.level = RAW_OPEN_SMB2;
957         io1.smb2.in.create_flags = 0;
958         io1.smb2.in.desired_access = SEC_FILE_ALL;
959         io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
960         io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
961                                 NTCREATEX_SHARE_ACCESS_WRITE;
962         io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
963         io1.smb2.in.security_flags = 0;
964         io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
965         io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
966         io1.smb2.in.fname = BASEDIR "\\tname1";
967
968         NOTIFY_MASK_TEST("Testing create file",;,
969                          smb2_util_close(tree2, custom_smb2_create(tree2,
970                                                 torture, &(io1.smb2)));,
971                          smb2_util_unlink(tree2, BASEDIR "\\tname1");,
972                          NOTIFY_ACTION_ADDED,
973                          FILE_NOTIFY_CHANGE_FILE_NAME, 1);
974
975         torture_comment(torture, "Testing unlink\n");
976         NOTIFY_MASK_TEST("Testing unlink",
977                          smb2_util_close(tree2, custom_smb2_create(tree2,
978                                                 torture, &(io1.smb2)));,
979                          smb2_util_unlink(tree2, BASEDIR "\\tname1");,
980                          ;,
981                          NOTIFY_ACTION_REMOVED,
982                          FILE_NOTIFY_CHANGE_FILE_NAME, 1);
983
984         torture_comment(torture, "Testing rmdir\n");
985         NOTIFY_MASK_TEST("Testing rmdir",
986                          smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
987                          smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
988                          ;,
989                          NOTIFY_ACTION_REMOVED,
990                          FILE_NOTIFY_CHANGE_DIR_NAME, 1);
991
992         torture_comment(torture, "Testing rename file\n");
993         ZERO_STRUCT(sinfo);
994         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
995         sinfo.rename_information.in.file.handle = h1;
996         sinfo.rename_information.in.overwrite = true;
997         sinfo.rename_information.in.root_fid = 0;
998         sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
999         NOTIFY_MASK_TEST("Testing rename file",
1000                          smb2_util_close(tree2, custom_smb2_create(tree2,
1001                                                 torture, &(io1.smb2)));,
1002                          smb2_setinfo_file(tree2, &sinfo);,
1003                          smb2_util_unlink(tree2, BASEDIR "\\tname2");,
1004                          NOTIFY_ACTION_OLD_NAME,
1005                          FILE_NOTIFY_CHANGE_FILE_NAME, 2);
1006
1007         torture_comment(torture, "Testing rename dir\n");
1008         ZERO_STRUCT(sinfo);
1009         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1010         sinfo.rename_information.in.file.handle = h1;
1011         sinfo.rename_information.in.overwrite = true;
1012         sinfo.rename_information.in.root_fid = 0;
1013         sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
1014         NOTIFY_MASK_TEST("Testing rename dir",
1015                 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
1016                 smb2_setinfo_file(tree2, &sinfo);,
1017                 smb2_util_rmdir(tree2, BASEDIR "\\tname2");,
1018                 NOTIFY_ACTION_OLD_NAME,
1019                 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
1020
1021         torture_comment(torture, "Testing set path attribute\n");
1022         NOTIFY_MASK_TEST("Testing set path attribute",
1023                 smb2_util_close(tree2, custom_smb2_create(tree2,
1024                                        torture, &(io.smb2)));,
1025                 smb2_util_setatr(tree2, BASEDIR "\\tname1",
1026                                  FILE_ATTRIBUTE_HIDDEN);,
1027                 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1028                 NOTIFY_ACTION_MODIFIED,
1029                 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
1030
1031         torture_comment(torture, "Testing set path write time\n");
1032         ZERO_STRUCT(sinfo);
1033         sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1034         sinfo.generic.in.file.handle = h1;
1035         sinfo.basic_info.in.write_time = 1000;
1036         NOTIFY_MASK_TEST("Testing set path write time",
1037                 smb2_util_close(tree2, custom_smb2_create(tree2,
1038                                        torture, &(io1.smb2)));,
1039                 smb2_setinfo_file(tree2, &sinfo);,
1040                 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1041                 NOTIFY_ACTION_MODIFIED,
1042                 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
1043
1044         if (torture_setting_bool(torture, "samba3", false)) {
1045                 torture_comment(torture,
1046                        "Samba3 does not yet support create times "
1047                        "everywhere\n");
1048         }
1049         else {
1050                 ZERO_STRUCT(sinfo);
1051                 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1052                 sinfo.generic.in.file.handle = h1;
1053                 sinfo.basic_info.in.create_time = 0;
1054                 torture_comment(torture, "Testing set file create time\n");
1055                 NOTIFY_MASK_TEST("Testing set file create time",
1056                         smb2_create_complex_file(tree2,
1057                         BASEDIR "\\tname1", &h2);,
1058                         smb2_setinfo_file(tree2, &sinfo);,
1059                         (smb2_util_close(tree2, h2),
1060                          smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1061                         NOTIFY_ACTION_MODIFIED,
1062                         FILE_NOTIFY_CHANGE_CREATION, 1);
1063         }
1064
1065         ZERO_STRUCT(sinfo);
1066         sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1067         sinfo.generic.in.file.handle = h1;
1068         sinfo.basic_info.in.access_time = 0;
1069         torture_comment(torture, "Testing set file access time\n");
1070         NOTIFY_MASK_TEST("Testing set file access time",
1071                 smb2_create_complex_file(tree2, 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_LAST_ACCESS, 1);
1077
1078         ZERO_STRUCT(sinfo);
1079         sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1080         sinfo.generic.in.file.handle = h1;
1081         sinfo.basic_info.in.change_time = 0;
1082         torture_comment(torture, "Testing set file change time\n");
1083         NOTIFY_MASK_TEST("Testing set file change time",
1084                 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1085                 smb2_setinfo_file(tree2, &sinfo);,
1086                 (smb2_util_close(tree2, h2),
1087                 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1088                 NOTIFY_ACTION_MODIFIED,
1089                 0, 1);
1090
1091
1092         torture_comment(torture, "Testing write\n");
1093         NOTIFY_MASK_TEST("Testing write",
1094                 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1095                 smb2_util_write(tree2, h2, &c, 10000, 1);,
1096                 (smb2_util_close(tree2, h2),
1097                 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1098                 NOTIFY_ACTION_MODIFIED,
1099                 0, 1);
1100
1101 done:
1102         smb2_deltree(tree1, BASEDIR);
1103         return ret;
1104 }
1105
1106 /*
1107   basic testing of change notify on files
1108 */
1109 static bool torture_smb2_notify_file(struct torture_context *torture,
1110                                 struct smb2_tree *tree)
1111 {
1112         NTSTATUS status;
1113         bool ret = true;
1114         union smb_open io;
1115         union smb_close cl;
1116         union smb_notify notify;
1117         struct smb2_request *req;
1118         struct smb2_handle h1;
1119         const char *fname = BASEDIR "\\file.txt";
1120
1121         smb2_deltree(tree, BASEDIR);
1122         smb2_util_rmdir(tree, BASEDIR);
1123
1124         torture_comment(torture, "TESTING CHANGE NOTIFY ON FILES\n");
1125         status = torture_smb2_testdir(tree, BASEDIR, &h1);
1126         CHECK_STATUS(status, NT_STATUS_OK);
1127
1128         ZERO_STRUCT(io.smb2);
1129         io.generic.level = RAW_OPEN_SMB2;
1130         io.smb2.in.create_flags = 0;
1131         io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
1132         io.smb2.in.create_options = 0;
1133         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1134         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1135                                 NTCREATEX_SHARE_ACCESS_WRITE;
1136         io.smb2.in.alloc_size = 0;
1137         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1138         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1139         io.smb2.in.security_flags = 0;
1140         io.smb2.in.fname = fname;
1141         status = smb2_create(tree, torture, &(io.smb2));
1142         CHECK_STATUS(status, NT_STATUS_OK);
1143         h1 = io.smb2.out.file.handle;
1144
1145         /* ask for a change notify,
1146            on file or directory name changes */
1147         ZERO_STRUCT(notify.smb2);
1148         notify.smb2.level = RAW_NOTIFY_SMB2;
1149         notify.smb2.in.file.handle = h1;
1150         notify.smb2.in.buffer_size = 1000;
1151         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
1152         notify.smb2.in.recursive = false;
1153
1154         torture_comment(torture,
1155         "Testing if notifies on file handles are invalid (should be)\n");
1156
1157         req = smb2_notify_send(tree, &(notify.smb2));
1158         status = smb2_notify_recv(req, torture, &(notify.smb2));
1159         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1160
1161         ZERO_STRUCT(cl.smb2);
1162         cl.close.level = RAW_CLOSE_SMB2;
1163         cl.close.in.file.handle = h1;
1164         status = smb2_close(tree, &(cl.smb2));
1165         CHECK_STATUS(status, NT_STATUS_OK);
1166
1167         status = smb2_util_unlink(tree, fname);
1168         CHECK_STATUS(status, NT_STATUS_OK);
1169
1170 done:
1171         smb2_deltree(tree, BASEDIR);
1172         return ret;
1173 }
1174 /*
1175   basic testing of change notifies followed by a tdis
1176 */
1177
1178 static bool torture_smb2_notify_tree_disconnect(
1179                 struct torture_context *torture,
1180                 struct smb2_tree *tree)
1181 {
1182         bool ret = true;
1183         NTSTATUS status;
1184         union smb_notify notify;
1185         union smb_open io;
1186         struct smb2_handle h1;
1187         struct smb2_request *req;
1188
1189         smb2_deltree(tree, BASEDIR);
1190         smb2_util_rmdir(tree, BASEDIR);
1191
1192         torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY "
1193                         "TREE-DISCONNECT\n");
1194
1195         /*
1196           get a handle on the directory
1197         */
1198         ZERO_STRUCT(io.smb2);
1199         io.generic.level = RAW_OPEN_SMB2;
1200         io.smb2.in.create_flags = 0;
1201         io.smb2.in.desired_access = SEC_FILE_ALL;
1202         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1203         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1204         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1205                                 NTCREATEX_SHARE_ACCESS_WRITE;
1206         io.smb2.in.alloc_size = 0;
1207         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1208         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1209         io.smb2.in.security_flags = 0;
1210         io.smb2.in.fname = BASEDIR;
1211
1212         status = smb2_create(tree, torture, &(io.smb2));
1213         CHECK_STATUS(status, NT_STATUS_OK);
1214         h1 = io.smb2.out.file.handle;
1215
1216         /* ask for a change notify,
1217            on file or directory name changes */
1218         ZERO_STRUCT(notify.smb2);
1219         notify.smb2.level = RAW_NOTIFY_SMB2;
1220         notify.smb2.in.buffer_size = 1000;
1221         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1222         notify.smb2.in.file.handle = h1;
1223         notify.smb2.in.recursive = true;
1224
1225         req = smb2_notify_send(tree, &(notify.smb2));
1226         smb2_cancel(req);
1227         status = smb2_notify_recv(req, torture, &(notify.smb2));
1228
1229         status = smb2_tdis(tree);
1230         CHECK_STATUS(status, NT_STATUS_OK);
1231
1232         req = smb2_notify_send(tree, &(notify.smb2));
1233
1234         smb2_notify_recv(req, torture, &(notify.smb2));
1235         CHECK_STATUS(status, NT_STATUS_OK);
1236         CHECK_VAL(notify.smb2.out.num_changes, 0);
1237
1238 done:
1239         smb2_deltree(tree, BASEDIR);
1240         return ret;
1241 }
1242
1243 /*
1244   basic testing of change notifies followed by a ulogoff
1245 */
1246
1247 static bool torture_smb2_notify_ulogoff(struct torture_context *torture,
1248                                 struct smb2_tree *tree1,
1249                                 struct smb2_tree *tree2)
1250 {
1251         bool ret = true;
1252         NTSTATUS status;
1253         union smb_notify notify;
1254         union smb_open io;
1255         struct smb2_handle h1;
1256         struct smb2_request *req;
1257
1258         smb2_deltree(tree1, BASEDIR);
1259         smb2_util_rmdir(tree1, BASEDIR);
1260
1261         torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1262
1263         /*
1264           get a handle on the directory
1265         */
1266         ZERO_STRUCT(io.smb2);
1267         io.generic.level = RAW_OPEN_SMB2;
1268         io.smb2.in.create_flags = 0;
1269         io.smb2.in.desired_access = SEC_FILE_ALL;
1270         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1271         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1272         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1273                                 NTCREATEX_SHARE_ACCESS_WRITE;
1274         io.smb2.in.alloc_size = 0;
1275         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1276         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1277         io.smb2.in.security_flags = 0;
1278         io.smb2.in.fname = BASEDIR;
1279
1280         status = smb2_create(tree2, torture, &(io.smb2));
1281         CHECK_STATUS(status, NT_STATUS_OK);
1282
1283         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1284         status = smb2_create(tree2, torture, &(io.smb2));
1285         CHECK_STATUS(status, NT_STATUS_OK);
1286         h1 = io.smb2.out.file.handle;
1287
1288         /* ask for a change notify,
1289            on file or directory name changes */
1290         ZERO_STRUCT(notify.smb2);
1291         notify.smb2.level = RAW_NOTIFY_SMB2;
1292         notify.smb2.in.buffer_size = 1000;
1293         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1294         notify.smb2.in.file.handle = h1;
1295         notify.smb2.in.recursive = true;
1296
1297         req = smb2_notify_send(tree1, &(notify.smb2));
1298
1299         status = smb2_logoff(tree2->session);
1300         CHECK_STATUS(status, NT_STATUS_OK);
1301
1302         status = smb2_notify_recv(req, torture, &(notify.smb2));
1303         CHECK_VAL(notify.smb2.out.num_changes, 0);
1304
1305 done:
1306         smb2_deltree(tree1, BASEDIR);
1307         return ret;
1308 }
1309
1310 static void tcp_dis_handler(struct smb2_transport *t, void *p)
1311 {
1312         struct smb2_tree *tree = (struct smb2_tree *)p;
1313         smb2_transport_dead(tree->session->transport,
1314                         NT_STATUS_LOCAL_DISCONNECT);
1315         t = NULL;
1316         tree = NULL;
1317 }
1318
1319 /*
1320   basic testing of change notifies followed by tcp disconnect
1321 */
1322
1323 static bool torture_smb2_notify_tcp_disconnect(
1324                 struct torture_context *torture,
1325                 struct smb2_tree *tree)
1326 {
1327         bool ret = true;
1328         NTSTATUS status;
1329         union smb_notify notify;
1330         union smb_open io;
1331         struct smb2_handle h1;
1332         struct smb2_request *req;
1333
1334         smb2_deltree(tree, BASEDIR);
1335         smb2_util_rmdir(tree, BASEDIR);
1336
1337         torture_comment(torture,
1338                 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1339
1340         /*
1341           get a handle on the directory
1342         */
1343         ZERO_STRUCT(io.smb2);
1344         io.generic.level = RAW_OPEN_SMB2;
1345         io.smb2.in.create_flags = 0;
1346         io.smb2.in.desired_access = SEC_FILE_ALL;
1347         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1348         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1349         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1350                                 NTCREATEX_SHARE_ACCESS_WRITE;
1351         io.smb2.in.alloc_size = 0;
1352         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1353         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1354         io.smb2.in.security_flags = 0;
1355         io.smb2.in.fname = BASEDIR;
1356
1357         status = smb2_create(tree, torture, &(io.smb2));
1358         CHECK_STATUS(status, NT_STATUS_OK);
1359         h1 = io.smb2.out.file.handle;
1360
1361         /* ask for a change notify,
1362            on file or directory name changes */
1363         ZERO_STRUCT(notify.smb2);
1364         notify.smb2.level = RAW_NOTIFY_SMB2;
1365         notify.smb2.in.buffer_size = 1000;
1366         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1367         notify.smb2.in.file.handle = h1;
1368         notify.smb2.in.recursive = true;
1369
1370         req = smb2_notify_send(tree, &(notify.smb2));
1371         smb2_cancel(req);
1372         status = smb2_notify_recv(req, torture, &(notify.smb2));
1373         CHECK_STATUS(status, NT_STATUS_CANCELLED);
1374
1375         notify.smb2.in.recursive = true;
1376         req = smb2_notify_send(tree, &(notify.smb2));
1377         smb2_transport_idle_handler(tree->session->transport,
1378                                 tcp_dis_handler, 250, tree);
1379         tree = NULL;
1380         status = smb2_notify_recv(req, torture, &(notify.smb2));
1381         CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
1382
1383 done:
1384         return ret;
1385 }
1386
1387 /*
1388    test setting up two change notify requests on one handle
1389 */
1390
1391 static bool torture_smb2_notify_double(struct torture_context *torture,
1392                         struct smb2_tree *tree1,
1393                         struct smb2_tree *tree2)
1394 {
1395         bool ret = true;
1396         NTSTATUS status;
1397         union smb_notify notify;
1398         union smb_open io;
1399         struct smb2_handle h1;
1400         struct smb2_request *req1, *req2;
1401
1402         smb2_deltree(tree1, BASEDIR);
1403         smb2_util_rmdir(tree1, BASEDIR);
1404
1405         torture_comment(torture,
1406                 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1407
1408         /*
1409           get a handle on the directory
1410         */
1411         ZERO_STRUCT(io.smb2);
1412         io.generic.level = RAW_OPEN_SMB2;
1413         io.smb2.in.create_flags = 0;
1414         io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ|
1415                                 SEC_RIGHTS_FILE_WRITE|
1416                                 SEC_RIGHTS_FILE_ALL;
1417         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1418         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1419         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1420                                 NTCREATEX_SHARE_ACCESS_WRITE;
1421         io.smb2.in.alloc_size = 0;
1422         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1423         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1424         io.smb2.in.security_flags = 0;
1425         io.smb2.in.fname = BASEDIR;
1426
1427         status = smb2_create(tree1, torture, &(io.smb2));
1428         CHECK_STATUS(status, NT_STATUS_OK);
1429         h1 = io.smb2.out.file.handle;
1430
1431         /* ask for a change notify,
1432            on file or directory name changes */
1433         ZERO_STRUCT(notify.smb2);
1434         notify.smb2.level = RAW_NOTIFY_SMB2;
1435         notify.smb2.in.buffer_size = 1000;
1436         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1437         notify.smb2.in.file.handle = h1;
1438         notify.smb2.in.recursive = true;
1439
1440         req1 = smb2_notify_send(tree1, &(notify.smb2));
1441         smb2_cancel(req1);
1442         status = smb2_notify_recv(req1, torture, &(notify.smb2));
1443         CHECK_STATUS(status, NT_STATUS_CANCELLED);
1444
1445         req2 = smb2_notify_send(tree1, &(notify.smb2));
1446         smb2_cancel(req2);
1447         status = smb2_notify_recv(req2, torture, &(notify.smb2));
1448         CHECK_STATUS(status, NT_STATUS_CANCELLED);
1449
1450         smb2_util_mkdir(tree2, BASEDIR "\\subdir-name");
1451         req1 = smb2_notify_send(tree1, &(notify.smb2));
1452         req2 = smb2_notify_send(tree1, &(notify.smb2));
1453
1454         status = smb2_notify_recv(req1, torture, &(notify.smb2));
1455         CHECK_STATUS(status, NT_STATUS_OK);
1456         CHECK_VAL(notify.smb2.out.num_changes, 1);
1457         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1458
1459         smb2_util_mkdir(tree2, BASEDIR "\\subdir-name2");
1460
1461         status = smb2_notify_recv(req2, torture, &(notify.smb2));
1462         CHECK_STATUS(status, NT_STATUS_OK);
1463         CHECK_VAL(notify.smb2.out.num_changes, 1);
1464         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name2");
1465
1466 done:
1467         smb2_deltree(tree1, BASEDIR);
1468         return ret;
1469 }
1470
1471
1472 /*
1473    test multiple change notifies at different depths and with/without recursion
1474 */
1475
1476 static bool torture_smb2_notify_tree(struct torture_context *torture,
1477                              struct smb2_tree *tree)
1478 {
1479         bool ret = true;
1480         union smb_notify notify;
1481         union smb_open io;
1482         struct smb2_request *req;
1483         struct timeval tv;
1484         struct {
1485                 const char *path;
1486                 bool recursive;
1487                 uint32_t filter;
1488                 int expected;
1489                 struct smb2_handle h1;
1490                 int counted;
1491         } dirs[] = {
1492                 {BASEDIR "\\abc",               true, FILE_NOTIFY_CHANGE_NAME, 30 },
1493                 {BASEDIR "\\zqy",               true, FILE_NOTIFY_CHANGE_NAME, 8 },
1494                 {BASEDIR "\\atsy",              true, FILE_NOTIFY_CHANGE_NAME, 4 },
1495                 {BASEDIR "\\abc\\foo",          true,  FILE_NOTIFY_CHANGE_NAME, 2 },
1496                 {BASEDIR "\\abc\\blah",         true,  FILE_NOTIFY_CHANGE_NAME, 13 },
1497                 {BASEDIR "\\abc\\blah",         false, FILE_NOTIFY_CHANGE_NAME, 7 },
1498                 {BASEDIR "\\abc\\blah\\a",      true, FILE_NOTIFY_CHANGE_NAME, 2 },
1499                 {BASEDIR "\\abc\\blah\\b",      true, FILE_NOTIFY_CHANGE_NAME, 2 },
1500                 {BASEDIR "\\abc\\blah\\c",      true, FILE_NOTIFY_CHANGE_NAME, 2 },
1501                 {BASEDIR "\\abc\\fooblah",      true, FILE_NOTIFY_CHANGE_NAME, 2 },
1502                 {BASEDIR "\\zqy\\xx",           true, FILE_NOTIFY_CHANGE_NAME, 2 },
1503                 {BASEDIR "\\zqy\\yyy",          true, FILE_NOTIFY_CHANGE_NAME, 2 },
1504                 {BASEDIR "\\zqy\\..",           true, FILE_NOTIFY_CHANGE_NAME, 40 },
1505                 {BASEDIR,                       true, FILE_NOTIFY_CHANGE_NAME, 40 },
1506                 {BASEDIR,                       false,FILE_NOTIFY_CHANGE_NAME, 6 },
1507                 {BASEDIR "\\atsy",              false,FILE_NOTIFY_CHANGE_NAME, 4 },
1508                 {BASEDIR "\\abc",               true, FILE_NOTIFY_CHANGE_NAME, 24 },
1509                 {BASEDIR "\\abc",               false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1510                 {BASEDIR "\\abc",               true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1511                 {BASEDIR "\\abc",               true, FILE_NOTIFY_CHANGE_NAME, 24 },
1512         };
1513         int i;
1514         NTSTATUS status;
1515         bool all_done = false;
1516
1517         smb2_deltree(tree, BASEDIR);
1518         smb2_util_rmdir(tree, BASEDIR);
1519
1520         torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1521
1522         ZERO_STRUCT(io.smb2);
1523         io.generic.level = RAW_OPEN_SMB2;
1524         io.smb2.in.create_flags = 0;
1525         io.smb2.in.desired_access = SEC_FILE_ALL;
1526         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1527         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1528         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1529                                 NTCREATEX_SHARE_ACCESS_WRITE;
1530         io.smb2.in.alloc_size = 0;
1531         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1532         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1533         io.smb2.in.security_flags = 0;
1534         io.smb2.in.fname = BASEDIR;
1535         status = smb2_create(tree, torture, &(io.smb2));
1536         CHECK_STATUS(status, NT_STATUS_OK);
1537
1538         ZERO_STRUCT(notify.smb2);
1539         notify.smb2.level = RAW_NOTIFY_SMB2;
1540         notify.smb2.in.buffer_size = 20000;
1541
1542         /*
1543           setup the directory tree, and the notify buffer on each directory
1544         */
1545         for (i=0;i<ARRAY_SIZE(dirs);i++) {
1546                 io.smb2.in.fname = dirs[i].path;
1547                 status = smb2_create(tree, torture, &(io.smb2));
1548                 CHECK_STATUS(status, NT_STATUS_OK);
1549                 dirs[i].h1 = io.smb2.out.file.handle;
1550
1551                 notify.smb2.in.completion_filter = dirs[i].filter;
1552                 notify.smb2.in.file.handle = dirs[i].h1;
1553                 notify.smb2.in.recursive = dirs[i].recursive;
1554                 req = smb2_notify_send(tree, &(notify.smb2));
1555                 smb2_cancel(req);
1556                 status = smb2_notify_recv(req, torture, &(notify.smb2));
1557                 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1558         }
1559
1560         /* trigger 2 events in each dir */
1561         for (i=0;i<ARRAY_SIZE(dirs);i++) {
1562                 char *path = talloc_asprintf(torture, "%s\\test.dir",
1563                                              dirs[i].path);
1564                 smb2_util_mkdir(tree, path);
1565                 smb2_util_rmdir(tree, path);
1566                 talloc_free(path);
1567         }
1568
1569         /* give a bit of time for the events to propogate */
1570         tv = timeval_current();
1571
1572         do {
1573                 /* count events that have happened in each dir */
1574                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1575                         notify.smb2.in.file.handle = dirs[i].h1;
1576                         req = smb2_notify_send(tree, &(notify.smb2));
1577                         smb2_cancel(req);
1578                         notify.smb2.out.num_changes = 0;
1579                         status = smb2_notify_recv(req, torture,
1580                                  &(notify.smb2));
1581                         dirs[i].counted += notify.smb2.out.num_changes;
1582                 }
1583
1584                 all_done = true;
1585
1586                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1587                         if (dirs[i].counted != dirs[i].expected) {
1588                                 all_done = false;
1589                         }
1590                 }
1591         } while (!all_done && timeval_elapsed(&tv) < 20);
1592
1593         torture_comment(torture, "took %.4f seconds to propogate all events\n",
1594                         timeval_elapsed(&tv));
1595
1596         for (i=0;i<ARRAY_SIZE(dirs);i++) {
1597                 if (dirs[i].counted != dirs[i].expected) {
1598                         torture_comment(torture,
1599                                 "ERROR: i=%d expected %d got %d for '%s'\n",
1600                                 i, dirs[i].expected, dirs[i].counted,
1601                                 dirs[i].path);
1602                         ret = false;
1603                 }
1604         }
1605
1606         /*
1607           run from the back, closing and deleting
1608         */
1609         for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1610                 smb2_util_close(tree, dirs[i].h1);
1611                 smb2_util_rmdir(tree, dirs[i].path);
1612         }
1613
1614 done:
1615         smb2_deltree(tree, BASEDIR);
1616         smb2_util_rmdir(tree, BASEDIR);
1617         return ret;
1618 }
1619
1620 /*
1621    Test response when cached server events exceed single NT NOTFIY response
1622    packet size.
1623 */
1624
1625 static bool torture_smb2_notify_overflow(struct torture_context *torture,
1626                                 struct smb2_tree *tree)
1627 {
1628         bool ret = true;
1629         NTSTATUS status;
1630         union smb_notify notify;
1631         union smb_open io;
1632         struct smb2_handle h1, h2;
1633         int count = 100;
1634         struct smb2_request *req1;
1635         int i;
1636
1637         smb2_deltree(tree, BASEDIR);
1638         smb2_util_rmdir(tree, BASEDIR);
1639
1640         torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1641
1642         /* get a handle on the directory */
1643         ZERO_STRUCT(io.smb2);
1644         io.generic.level = RAW_OPEN_SMB2;
1645         io.smb2.in.create_flags = 0;
1646         io.smb2.in.desired_access = SEC_FILE_ALL;
1647         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1648         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1649         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1650                             NTCREATEX_SHARE_ACCESS_WRITE;
1651         io.smb2.in.alloc_size = 0;
1652         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1653         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1654         io.smb2.in.security_flags = 0;
1655         io.smb2.in.fname = BASEDIR;
1656
1657         status = smb2_create(tree, torture, &(io.smb2));
1658         CHECK_STATUS(status, NT_STATUS_OK);
1659         h1 = io.smb2.out.file.handle;
1660
1661         /* ask for a change notify, on name changes. */
1662         ZERO_STRUCT(notify.smb2);
1663         notify.smb2.level = RAW_NOTIFY_NTTRANS;
1664         notify.smb2.in.buffer_size = 1000;
1665         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1666         notify.smb2.in.file.handle = h1;
1667
1668         notify.smb2.in.recursive = true;
1669         req1 = smb2_notify_send(tree, &(notify.smb2));
1670
1671         /* cancel initial requests so the buffer is setup */
1672         smb2_cancel(req1);
1673         status = smb2_notify_recv(req1, torture, &(notify.smb2));
1674         CHECK_STATUS(status, NT_STATUS_CANCELLED);
1675
1676         /* open a lot of files, filling up the server side notify buffer */
1677         torture_comment(torture,
1678                 "Testing overflowed buffer notify on create of %d files\n",
1679                 count);
1680
1681         for (i=0;i<count;i++) {
1682                 char *fname = talloc_asprintf(torture,
1683                               BASEDIR "\\test%d.txt", i);
1684                 union smb_open io1;
1685                 ZERO_STRUCT(io1.smb2);
1686                 io1.generic.level = RAW_OPEN_SMB2;
1687                 io1.smb2.in.create_flags = 0;
1688                 io1.smb2.in.desired_access = SEC_FILE_ALL;
1689                 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1690                 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1691                 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1692                                     NTCREATEX_SHARE_ACCESS_WRITE;
1693                 io1.smb2.in.alloc_size = 0;
1694                 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1695                 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1696                 io1.smb2.in.security_flags = 0;
1697                 io1.smb2.in.fname = fname;
1698
1699                 h2 = custom_smb2_create(tree, torture, &(io1.smb2));
1700                 talloc_free(fname);
1701                 smb2_util_close(tree, h2);
1702         }
1703
1704         req1 = smb2_notify_send(tree, &(notify.smb2));
1705         status = smb2_notify_recv(req1, torture, &(notify.smb2));
1706         CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
1707         CHECK_VAL(notify.smb2.out.num_changes, 0);
1708
1709 done:
1710         smb2_deltree(tree, BASEDIR);
1711         return ret;
1712 }
1713
1714 /*
1715    Test if notifications are returned for changes to the base directory.
1716    They shouldn't be.
1717 */
1718
1719 static bool torture_smb2_notify_basedir(struct torture_context *torture,
1720                                 struct smb2_tree *tree1,
1721                                 struct smb2_tree *tree2)
1722 {
1723         bool ret = true;
1724         NTSTATUS status;
1725         union smb_notify notify;
1726         union smb_open io;
1727         struct smb2_handle h1;
1728         struct smb2_request *req1;
1729
1730         smb2_deltree(tree1, BASEDIR);
1731         smb2_util_rmdir(tree1, BASEDIR);
1732
1733         torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1734
1735         /* get a handle on the directory */
1736         ZERO_STRUCT(io.smb2);
1737         io.generic.level = RAW_OPEN_SMB2;
1738         io.smb2.in.create_flags = 0;
1739         io.smb2.in.desired_access = SEC_FILE_ALL;
1740         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1741         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1742         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1743             NTCREATEX_SHARE_ACCESS_WRITE;
1744         io.smb2.in.alloc_size = 0;
1745         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1746         io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
1747         io.smb2.in.security_flags = 0;
1748         io.smb2.in.fname = BASEDIR;
1749
1750         status = smb2_create(tree1, torture, &(io.smb2));
1751         CHECK_STATUS(status, NT_STATUS_OK);
1752         h1 = io.smb2.out.file.handle;
1753
1754         /* create a test file that will also be modified */
1755         io.smb2.in.fname = BASEDIR "\\tname1";
1756         io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
1757         status =  smb2_create(tree2, torture, &(io.smb2));
1758         CHECK_STATUS(status,NT_STATUS_OK);
1759         smb2_util_close(tree2, io.smb2.out.file.handle);
1760
1761         /* ask for a change notify, on attribute changes. */
1762         ZERO_STRUCT(notify.smb2);
1763         notify.smb2.level = RAW_NOTIFY_SMB2;
1764         notify.smb2.in.buffer_size = 1000;
1765         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
1766         notify.smb2.in.file.handle = h1;
1767         notify.smb2.in.recursive = true;
1768
1769         req1 = smb2_notify_send(tree1, &(notify.smb2));
1770
1771         /* set attribute on the base dir */
1772         smb2_util_setatr(tree2, BASEDIR, FILE_ATTRIBUTE_HIDDEN);
1773
1774         /* set attribute on a file to assure we receive a notification */
1775         smb2_util_setatr(tree2, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN);
1776         smb_msleep(200);
1777
1778         /* check how many responses were given, expect only 1 for the file */
1779         status = smb2_notify_recv(req1, torture, &(notify.smb2));
1780         CHECK_STATUS(status, NT_STATUS_OK);
1781         CHECK_VAL(notify.smb2.out.num_changes, 1);
1782         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
1783         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
1784
1785 done:
1786         smb2_deltree(tree1, BASEDIR);
1787         return ret;
1788 }
1789
1790
1791 /*
1792   create a secondary tree connect - used to test for a bug in Samba3 messaging
1793   with change notify
1794 */
1795 static struct smb2_tree *secondary_tcon(struct smb2_tree *tree,
1796                                         struct torture_context *tctx)
1797 {
1798         NTSTATUS status;
1799         const char *share, *host;
1800         struct smb2_tree *tree1;
1801         union smb_tcon tcon;
1802
1803         share = torture_setting_string(tctx, "share", NULL);
1804         host  = torture_setting_string(tctx, "host", NULL);
1805
1806         torture_comment(tctx,
1807                 "create a second tree context on the same session\n");
1808         tree1 = smb2_tree_init(tree->session, tctx, false);
1809
1810         ZERO_STRUCT(tcon.smb2);
1811         tcon.generic.level = RAW_TCON_SMB2;
1812         tcon.smb2.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
1813         status = smb2_tree_connect(tree, &(tcon.smb2));
1814         if (!NT_STATUS_IS_OK(status)) {
1815                 talloc_free(tree);
1816                 torture_comment(tctx,"Failed to create secondary tree\n");
1817                 return NULL;
1818         }
1819
1820         tree1->tid = tcon.smb2.out.tid;
1821         torture_comment(tctx,"tid1=%d tid2=%d\n", tree->tid, tree1->tid);
1822
1823         return tree1;
1824 }
1825
1826
1827 /*
1828    very simple change notify test
1829 */
1830 static bool torture_smb2_notify_tcon(struct torture_context *torture,
1831                                   struct smb2_tree *tree)
1832 {
1833         bool ret = true;
1834         NTSTATUS status;
1835         union smb_notify notify;
1836         union smb_open io;
1837         struct smb2_handle h1;
1838         struct smb2_request *req = NULL;
1839         struct smb2_tree *tree1 = NULL;
1840         const char *fname = BASEDIR "\\subdir-name";
1841
1842         smb2_deltree(tree, BASEDIR);
1843         smb2_util_rmdir(tree, BASEDIR);
1844
1845         torture_comment(torture, "TESTING SIMPLE CHANGE NOTIFY\n");
1846
1847         /*
1848           get a handle on the directory
1849         */
1850
1851         ZERO_STRUCT(io.smb2);
1852         io.generic.level = RAW_OPEN_SMB2;
1853         io.smb2.in.create_flags = 0;
1854         io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1855         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1856         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL |
1857                                 FILE_ATTRIBUTE_DIRECTORY;
1858         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1859                                 NTCREATEX_SHARE_ACCESS_WRITE;
1860         io.smb2.in.alloc_size = 0;
1861         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1862         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1863         io.smb2.in.security_flags = 0;
1864         io.smb2.in.fname = BASEDIR;
1865
1866         status = smb2_create(tree, torture, &(io.smb2));
1867         CHECK_STATUS(status, NT_STATUS_OK);
1868         h1 = io.smb2.out.file.handle;
1869
1870         /* ask for a change notify,
1871            on file or directory name changes */
1872         ZERO_STRUCT(notify.smb2);
1873         notify.smb2.level = RAW_NOTIFY_SMB2;
1874         notify.smb2.in.buffer_size = 1000;
1875         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1876         notify.smb2.in.file.handle = h1;
1877         notify.smb2.in.recursive = true;
1878
1879         torture_comment(torture, "Testing notify mkdir\n");
1880         req = smb2_notify_send(tree, &(notify.smb2));
1881         smb2_cancel(req);
1882         status = smb2_notify_recv(req, torture, &(notify.smb2));
1883         CHECK_STATUS(status, NT_STATUS_CANCELLED);
1884
1885         notify.smb2.in.recursive = true;
1886         req = smb2_notify_send(tree, &(notify.smb2));
1887         status = smb2_util_mkdir(tree, fname);
1888         CHECK_STATUS(status, NT_STATUS_OK);
1889
1890         status = smb2_notify_recv(req, torture, &(notify.smb2));
1891         CHECK_STATUS(status, NT_STATUS_OK);
1892
1893         CHECK_VAL(notify.smb2.out.num_changes, 1);
1894         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
1895         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1896
1897         torture_comment(torture, "Testing notify rmdir\n");
1898         req = smb2_notify_send(tree, &(notify.smb2));
1899         status = smb2_util_rmdir(tree, fname);
1900         CHECK_STATUS(status, NT_STATUS_OK);
1901
1902         status = smb2_notify_recv(req, torture, &(notify.smb2));
1903         CHECK_STATUS(status, NT_STATUS_OK);
1904         CHECK_VAL(notify.smb2.out.num_changes, 1);
1905         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
1906         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1907
1908         torture_comment(torture, "SIMPLE CHANGE NOTIFY OK\n");
1909
1910         torture_comment(torture, "TESTING WITH SECONDARY TCON\n");
1911         tree1 = secondary_tcon(tree, torture);
1912
1913         torture_comment(torture, "Testing notify mkdir\n");
1914         req = smb2_notify_send(tree, &(notify.smb2));
1915         smb2_util_mkdir(tree1, fname);
1916
1917         status = smb2_notify_recv(req, torture, &(notify.smb2));
1918         CHECK_STATUS(status, NT_STATUS_OK);
1919
1920         CHECK_VAL(notify.smb2.out.num_changes, 1);
1921         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
1922         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1923
1924         torture_comment(torture, "Testing notify rmdir\n");
1925         req = smb2_notify_send(tree, &(notify.smb2));
1926         smb2_util_rmdir(tree, fname);
1927
1928         status = smb2_notify_recv(req, torture, &(notify.smb2));
1929         CHECK_STATUS(status, NT_STATUS_OK);
1930         CHECK_VAL(notify.smb2.out.num_changes, 1);
1931         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
1932         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1933
1934         torture_comment(torture, "CHANGE NOTIFY WITH TCON OK\n");
1935
1936         torture_comment(torture, "Disconnecting secondary tree\n");
1937         status = smb2_tdis(tree1);
1938         CHECK_STATUS(status, NT_STATUS_OK);
1939         talloc_free(tree1);
1940
1941         torture_comment(torture, "Testing notify mkdir\n");
1942         req = smb2_notify_send(tree, &(notify.smb2));
1943         smb2_util_mkdir(tree, fname);
1944
1945         status = smb2_notify_recv(req, torture, &(notify.smb2));
1946         CHECK_STATUS(status, NT_STATUS_OK);
1947
1948         CHECK_VAL(notify.smb2.out.num_changes, 1);
1949         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
1950         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1951
1952         torture_comment(torture, "Testing notify rmdir\n");
1953         req = smb2_notify_send(tree, &(notify.smb2));
1954         smb2_util_rmdir(tree, fname);
1955
1956         status = smb2_notify_recv(req, torture, &(notify.smb2));
1957         CHECK_STATUS(status, NT_STATUS_OK);
1958         CHECK_VAL(notify.smb2.out.num_changes, 1);
1959         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
1960         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1961
1962         torture_comment(torture, "CHANGE NOTIFY WITH TDIS OK\n");
1963 done:
1964         smb2_util_close(tree, h1);
1965         smb2_deltree(tree, BASEDIR);
1966
1967         return ret;
1968 }
1969
1970 /*
1971    basic testing of SMB2 change notify
1972 */
1973 struct torture_suite *torture_smb2_notify_init(void)
1974 {
1975         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "notify");
1976
1977         torture_suite_add_1smb2_test(suite, "valid-req", test_valid_request);
1978         torture_suite_add_1smb2_test(suite, "tcon", torture_smb2_notify_tcon);
1979         torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir);
1980         torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask);
1981         torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
1982         torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
1983         torture_suite_add_2smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
1984         torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
1985         torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
1986         torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
1987         torture_suite_add_1smb2_test(suite, "file", torture_smb2_notify_file);
1988         torture_suite_add_1smb2_test(suite, "tcp", torture_smb2_notify_tcp_disconnect);
1989         torture_suite_add_2smb2_test(suite, "rec", torture_smb2_notify_recursive);
1990         torture_suite_add_1smb2_test(suite, "overflow", torture_smb2_notify_overflow);
1991
1992         suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");
1993
1994         return suite;
1995 }
1996