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