s4:torture/smb2: test_notify_tcp_dis trigger idle event every 0.25s
[vlendec/samba-autobuild/.git] / source4 / torture / smb2 / notify.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    SMB2 notify test suite
5
6    Copyright (C) Stefan Metzmacher 2006
7    Copyright (C) Andrew Tridgell 2009
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "../libcli/smb/smbXcli_base.h"
27
28 #include "torture/torture.h"
29 #include "torture/smb2/proto.h"
30 #include "librpc/gen_ndr/ndr_security.h"
31 #include "libcli/security/security.h"
32 #include "torture/util.h"
33
34 #include "system/filesys.h"
35 #include "auth/credentials/credentials.h"
36 #include "lib/cmdline/popt_common.h"
37 #include "librpc/gen_ndr/security.h"
38
39 #include "lib/events/events.h"
40
41 #include "libcli/raw/libcliraw.h"
42 #include "libcli/raw/raw_proto.h"
43 #include "libcli/libcli.h"
44
45 #define CHECK_STATUS(status, correct) do { \
46         if (!NT_STATUS_EQUAL(status, correct)) { \
47                 torture_result(torture, TORTURE_FAIL, \
48                        "(%s) Incorrect status %s - should be %s\n", \
49                        __location__, nt_errstr(status), nt_errstr(correct)); \
50                 ret = false; \
51                 goto done; \
52         }} while (0)
53
54 #define CHECK_VAL(v, correct) do { \
55         if ((v) != (correct)) { \
56                 torture_result(torture, TORTURE_FAIL, \
57                        "(%s) wrong value for %s  0x%x should be 0x%x\n", \
58                        __location__, #v, (int)v, (int)correct); \
59                 ret = false; \
60                 goto done; \
61         }} while (0)
62
63 #define CHECK_WIRE_STR(field, value) do { \
64         if (!field.s || strcmp(field.s, value)) { \
65                 torture_result(torture, TORTURE_FAIL, \
66                         "(%s) %s [%s] != %s\n",  __location__, #field, \
67                         field.s, value); \
68                 ret = false; \
69                 goto done; \
70         }} while (0)
71
72 #define WAIT_FOR_ASYNC_RESPONSE(req) \
73         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \
74                 if (tevent_loop_once(torture->ev) != 0) { \
75                         break; \
76                 } \
77         }
78
79 #define BASEDIR "test_notify"
80 #define FNAME "smb2-notify01.dat"
81
82 static bool test_valid_request(struct torture_context *torture,
83                                struct smb2_tree *tree)
84 {
85         bool ret = true;
86         NTSTATUS status;
87         struct smb2_handle dh;
88         struct smb2_notify n;
89         struct smb2_request *req;
90         uint32_t max_buffer_size;
91
92         torture_comment(torture, "TESTING VALIDITY OF CHANGE NOTIFY REQUEST\n");
93
94         smb2_util_unlink(tree, FNAME);
95
96         status = smb2_util_roothandle(tree, &dh);
97         CHECK_STATUS(status, NT_STATUS_OK);
98
99         /* 0x00080000 is the default max buffer size for Windows servers
100          * pre-Win7 */
101         max_buffer_size = torture_setting_ulong(torture, "cn_max_buffer_size",
102                                                 0x00080000);
103
104         n.in.recursive          = 0x0000;
105         n.in.buffer_size        = max_buffer_size;
106         n.in.file.handle        = dh;
107         n.in.completion_filter  = FILE_NOTIFY_CHANGE_ALL;
108         n.in.unknown            = 0x00000000;
109         req = smb2_notify_send(tree, &n);
110
111         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
112                 if (tevent_loop_once(torture->ev) != 0) {
113                         break;
114                 }
115         }
116
117         status = torture_setup_complex_file(torture, tree, FNAME);
118         CHECK_STATUS(status, NT_STATUS_OK);
119
120         status = smb2_notify_recv(req, torture, &n);
121         CHECK_STATUS(status, NT_STATUS_OK);
122         CHECK_VAL(n.out.num_changes, 1);
123         CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_ADDED);
124         CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
125
126         /*
127          * if the change response doesn't fit in the buffer
128          * NOTIFY_ENUM_DIR is returned.
129          */
130         n.in.buffer_size        = 0x00000000;
131         req = smb2_notify_send(tree, &n);
132
133         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
134                 if (tevent_loop_once(torture->ev) != 0) {
135                         break;
136                 }
137         }
138
139         status = torture_setup_complex_file(torture, tree, FNAME);
140         CHECK_STATUS(status, NT_STATUS_OK);
141
142         status = smb2_notify_recv(req, torture, &n);
143         CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
144
145         /*
146          * if the change response fits in the buffer we get
147          * NT_STATUS_OK again
148          */
149         n.in.buffer_size        = max_buffer_size;
150         req = smb2_notify_send(tree, &n);
151
152         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
153                 if (tevent_loop_once(torture->ev) != 0) {
154                         break;
155                 }
156         }
157
158         status = torture_setup_complex_file(torture, tree, FNAME);
159         CHECK_STATUS(status, NT_STATUS_OK);
160
161         status = smb2_notify_recv(req, torture, &n);
162         CHECK_STATUS(status, NT_STATUS_OK);
163         CHECK_VAL(n.out.num_changes, 3);
164         CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_REMOVED);
165         CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
166         CHECK_VAL(n.out.changes[1].action, NOTIFY_ACTION_ADDED);
167         CHECK_WIRE_STR(n.out.changes[1].name, FNAME);
168         CHECK_VAL(n.out.changes[2].action, NOTIFY_ACTION_MODIFIED);
169         CHECK_WIRE_STR(n.out.changes[2].name, FNAME);
170
171         /* if the first notify returns NOTIFY_ENUM_DIR, all do */
172         status = smb2_util_close(tree, dh);
173         CHECK_STATUS(status, NT_STATUS_OK);
174         status = smb2_util_roothandle(tree, &dh);
175         CHECK_STATUS(status, NT_STATUS_OK);
176
177         n.in.recursive          = 0x0000;
178         n.in.buffer_size        = 0x00000001;
179         n.in.file.handle        = dh;
180         n.in.completion_filter  = FILE_NOTIFY_CHANGE_ALL;
181         n.in.unknown            = 0x00000000;
182         req = smb2_notify_send(tree, &n);
183
184         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
185                 if (tevent_loop_once(torture->ev) != 0) {
186                         break;
187                 }
188         }
189
190         status = torture_setup_complex_file(torture, tree, FNAME);
191         CHECK_STATUS(status, NT_STATUS_OK);
192
193         status = smb2_notify_recv(req, torture, &n);
194         CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
195
196         n.in.buffer_size        = max_buffer_size;
197         req = smb2_notify_send(tree, &n);
198         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
199                 if (tevent_loop_once(torture->ev) != 0) {
200                         break;
201                 }
202         }
203
204         status = torture_setup_complex_file(torture, tree, FNAME);
205         CHECK_STATUS(status, NT_STATUS_OK);
206
207         status = smb2_notify_recv(req, torture, &n);
208         CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
209
210         /* if the buffer size is too large, we get invalid parameter */
211         n.in.recursive          = 0x0000;
212         n.in.buffer_size        = max_buffer_size + 1;
213         n.in.file.handle        = dh;
214         n.in.completion_filter  = FILE_NOTIFY_CHANGE_ALL;
215         n.in.unknown            = 0x00000000;
216         req = smb2_notify_send(tree, &n);
217         status = smb2_notify_recv(req, torture, &n);
218         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
219
220 done:
221         return ret;
222 }
223
224 /*
225    basic testing of change notify on directories
226 */
227
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, 250000, 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                 {
1844                         .path      = BASEDIR_TREE "\\abc",
1845                         .recursive = true,
1846                         .filter    = FILE_NOTIFY_CHANGE_NAME,
1847                         .expected  = 30,
1848                 },
1849                 {
1850                         .path      = BASEDIR_TREE "\\zqy",
1851                         .recursive = true,
1852                         .filter    = FILE_NOTIFY_CHANGE_NAME,
1853                         .expected  = 8,
1854                 },
1855                 {
1856                         .path      = BASEDIR_TREE "\\atsy",
1857                         .recursive = true,
1858                         .filter    = FILE_NOTIFY_CHANGE_NAME,
1859                         .expected  = 4,
1860                 },
1861                 {
1862                         .path      = BASEDIR_TREE "\\abc\\foo",
1863                         .recursive = true,
1864                         .filter    = FILE_NOTIFY_CHANGE_NAME,
1865                         .expected  = 2,
1866                 },
1867                 {
1868                         .path      = BASEDIR_TREE "\\abc\\blah",
1869                         .recursive = true,
1870                         .filter    =  FILE_NOTIFY_CHANGE_NAME,
1871                         .expected  = 13,
1872                 },
1873                 {
1874                         .path      = BASEDIR_TREE "\\abc\\blah",
1875                         .recursive = false,
1876                         .filter    = FILE_NOTIFY_CHANGE_NAME,
1877                         .expected  = 7,
1878                 },
1879                 {
1880                         .path      = BASEDIR_TREE "\\abc\\blah\\a",
1881                         .recursive = true,
1882                         .filter    = FILE_NOTIFY_CHANGE_NAME,
1883                         .expected  = 2,
1884                 },
1885                 {
1886                         .path      = BASEDIR_TREE "\\abc\\blah\\b",
1887                         .recursive = true,
1888                         .filter    = FILE_NOTIFY_CHANGE_NAME,
1889                         .expected  = 2,
1890                 },
1891                 {
1892                         .path      = BASEDIR_TREE "\\abc\\blah\\c",
1893                         .recursive = true,
1894                         .filter    = FILE_NOTIFY_CHANGE_NAME,
1895                         .expected  = 2,
1896                 },
1897                 {
1898                         .path      = BASEDIR_TREE "\\abc\\fooblah",
1899                         .recursive = true,
1900                         .filter    = FILE_NOTIFY_CHANGE_NAME,
1901                         .expected  = 2,
1902                 },
1903                 {
1904                         .path      = BASEDIR_TREE "\\zqy\\xx",
1905                         .recursive = true,
1906                         .filter    = FILE_NOTIFY_CHANGE_NAME,
1907                         .expected  = 2,
1908                 },
1909                 {
1910                         .path      = BASEDIR_TREE "\\zqy\\yyy",
1911                         .recursive = true,
1912                         .filter    = FILE_NOTIFY_CHANGE_NAME,
1913                         .expected  = 2,
1914                 },
1915                 {
1916                         .path      = BASEDIR_TREE "\\zqy\\..",
1917                         .recursive = true,
1918                         .filter    = FILE_NOTIFY_CHANGE_NAME,
1919                         .expected  = 40,
1920                 },
1921                 {
1922                         .path      = BASEDIR_TREE,
1923                         .recursive = true,
1924                         .filter    = FILE_NOTIFY_CHANGE_NAME,
1925                         .expected  = 40,
1926                 },
1927                 {
1928                         .path      = BASEDIR_TREE,
1929                         .recursive = false,
1930                         .filter    = FILE_NOTIFY_CHANGE_NAME,
1931                         .expected  = 6,
1932                 },
1933                 {
1934                         .path      = BASEDIR_TREE "\\atsy",
1935                         .recursive = false,
1936                         .filter    = FILE_NOTIFY_CHANGE_NAME,
1937                         .expected  = 4,
1938                 },
1939                 {
1940                         .path      = BASEDIR_TREE "\\abc",
1941                         .recursive = true,
1942                         .filter    = FILE_NOTIFY_CHANGE_NAME,
1943                         .expected  = 24,
1944                 },
1945                 {
1946                         .path      = BASEDIR_TREE "\\abc",
1947                         .recursive = false,
1948                         .filter    = FILE_NOTIFY_CHANGE_FILE_NAME,
1949                         .expected  = 0,
1950                 },
1951                 {
1952                         .path      = BASEDIR_TREE "\\abc",
1953                         .recursive = true,
1954                         .filter    = FILE_NOTIFY_CHANGE_FILE_NAME,
1955                         .expected  = 0,
1956                 },
1957                 {
1958                         .path      = BASEDIR_TREE "\\abc",
1959                         .recursive = true,
1960                         .filter    = FILE_NOTIFY_CHANGE_NAME,
1961                         .expected  = 24,
1962                 },
1963         };
1964         int i;
1965         NTSTATUS status;
1966         bool all_done = false;
1967
1968         smb2_deltree(tree, BASEDIR_TREE);
1969         smb2_util_rmdir(tree, BASEDIR_TREE);
1970
1971         torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1972
1973         ZERO_STRUCT(io.smb2);
1974         io.generic.level = RAW_OPEN_SMB2;
1975         io.smb2.in.create_flags = 0;
1976         io.smb2.in.desired_access = SEC_FILE_ALL;
1977         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1978         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1979         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1980                                 NTCREATEX_SHARE_ACCESS_WRITE;
1981         io.smb2.in.alloc_size = 0;
1982         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1983         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1984         io.smb2.in.security_flags = 0;
1985         io.smb2.in.fname = BASEDIR_TREE;
1986         status = smb2_create(tree, torture, &(io.smb2));
1987         CHECK_STATUS(status, NT_STATUS_OK);
1988
1989         ZERO_STRUCT(notify.smb2);
1990         notify.smb2.level = RAW_NOTIFY_SMB2;
1991         notify.smb2.in.buffer_size = 20000;
1992
1993         /*
1994           setup the directory tree, and the notify buffer on each directory
1995         */
1996         for (i=0;i<ARRAY_SIZE(dirs);i++) {
1997                 io.smb2.in.fname = dirs[i].path;
1998                 status = smb2_create(tree, torture, &(io.smb2));
1999                 CHECK_STATUS(status, NT_STATUS_OK);
2000                 dirs[i].h1 = io.smb2.out.file.handle;
2001
2002                 notify.smb2.in.completion_filter = dirs[i].filter;
2003                 notify.smb2.in.file.handle = dirs[i].h1;
2004                 notify.smb2.in.recursive = dirs[i].recursive;
2005                 req = smb2_notify_send(tree, &(notify.smb2));
2006                 smb2_cancel(req);
2007                 status = smb2_notify_recv(req, torture, &(notify.smb2));
2008                 CHECK_STATUS(status, NT_STATUS_CANCELLED);
2009         }
2010
2011         /* trigger 2 events in each dir */
2012         for (i=0;i<ARRAY_SIZE(dirs);i++) {
2013                 char *path = talloc_asprintf(torture, "%s\\test.dir",
2014                                              dirs[i].path);
2015                 smb2_util_mkdir(tree, path);
2016                 smb2_util_rmdir(tree, path);
2017                 talloc_free(path);
2018         }
2019
2020         /* give a bit of time for the events to propagate */
2021         tv = timeval_current();
2022
2023         do {
2024                 /* count events that have happened in each dir */
2025                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
2026                         notify.smb2.in.completion_filter = dirs[i].filter;
2027                         notify.smb2.in.file.handle = dirs[i].h1;
2028                         notify.smb2.in.recursive = dirs[i].recursive;
2029                         req = smb2_notify_send(tree, &(notify.smb2));
2030                         smb2_cancel(req);
2031                         notify.smb2.out.num_changes = 0;
2032                         status = smb2_notify_recv(req, torture,
2033                                  &(notify.smb2));
2034                         dirs[i].counted += notify.smb2.out.num_changes;
2035                 }
2036
2037                 all_done = true;
2038
2039                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
2040                         if (dirs[i].counted != dirs[i].expected) {
2041                                 all_done = false;
2042                         }
2043                 }
2044         } while (!all_done && timeval_elapsed(&tv) < 20);
2045
2046         torture_comment(torture, "took %.4f seconds to propagate all events\n",
2047                         timeval_elapsed(&tv));
2048
2049         for (i=0;i<ARRAY_SIZE(dirs);i++) {
2050                 if (dirs[i].counted != dirs[i].expected) {
2051                         torture_comment(torture,
2052                                 "ERROR: i=%d expected %d got %d for '%s'\n",
2053                                 i, dirs[i].expected, dirs[i].counted,
2054                                 dirs[i].path);
2055                         ret = false;
2056                 }
2057         }
2058
2059         /*
2060           run from the back, closing and deleting
2061         */
2062         for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
2063                 smb2_util_close(tree, dirs[i].h1);
2064                 smb2_util_rmdir(tree, dirs[i].path);
2065         }
2066
2067 done:
2068         smb2_deltree(tree, BASEDIR_TREE);
2069         smb2_util_rmdir(tree, BASEDIR_TREE);
2070         return ret;
2071 }
2072
2073 /*
2074    Test response when cached server events exceed single NT NOTFIY response
2075    packet size.
2076 */
2077
2078 #define BASEDIR_OVF BASEDIR "_OVF"
2079
2080 static bool torture_smb2_notify_overflow(struct torture_context *torture,
2081                                 struct smb2_tree *tree)
2082 {
2083         bool ret = true;
2084         NTSTATUS status;
2085         union smb_notify notify;
2086         union smb_open io;
2087         struct smb2_handle h1, h2;
2088         int count = 100;
2089         struct smb2_request *req1;
2090         int i;
2091
2092         smb2_deltree(tree, BASEDIR_OVF);
2093         smb2_util_rmdir(tree, BASEDIR_OVF);
2094
2095         torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
2096
2097         /* get a handle on the directory */
2098         ZERO_STRUCT(io.smb2);
2099         io.generic.level = RAW_OPEN_SMB2;
2100         io.smb2.in.create_flags = 0;
2101         io.smb2.in.desired_access = SEC_FILE_ALL;
2102         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2103         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2104         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2105                             NTCREATEX_SHARE_ACCESS_WRITE;
2106         io.smb2.in.alloc_size = 0;
2107         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2108         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2109         io.smb2.in.security_flags = 0;
2110         io.smb2.in.fname = BASEDIR_OVF;
2111
2112         status = smb2_create(tree, torture, &(io.smb2));
2113         CHECK_STATUS(status, NT_STATUS_OK);
2114         h1 = io.smb2.out.file.handle;
2115
2116         /* ask for a change notify, on name changes. */
2117         ZERO_STRUCT(notify.smb2);
2118         notify.smb2.level = RAW_NOTIFY_NTTRANS;
2119         notify.smb2.in.buffer_size = 1000;
2120         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2121         notify.smb2.in.file.handle = h1;
2122
2123         notify.smb2.in.recursive = true;
2124         req1 = smb2_notify_send(tree, &(notify.smb2));
2125
2126         /* cancel initial requests so the buffer is setup */
2127         smb2_cancel(req1);
2128         status = smb2_notify_recv(req1, torture, &(notify.smb2));
2129         CHECK_STATUS(status, NT_STATUS_CANCELLED);
2130
2131         /* open a lot of files, filling up the server side notify buffer */
2132         torture_comment(torture,
2133                 "Testing overflowed buffer notify on create of %d files\n",
2134                 count);
2135
2136         for (i=0;i<count;i++) {
2137                 char *fname = talloc_asprintf(torture,
2138                               BASEDIR_OVF "\\test%d.txt", i);
2139                 union smb_open io1;
2140                 ZERO_STRUCT(io1.smb2);
2141                 io1.generic.level = RAW_OPEN_SMB2;
2142                 io1.smb2.in.create_flags = 0;
2143                 io1.smb2.in.desired_access = SEC_FILE_ALL;
2144                 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2145                 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2146                 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2147                                     NTCREATEX_SHARE_ACCESS_WRITE;
2148                 io1.smb2.in.alloc_size = 0;
2149                 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2150                 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2151                 io1.smb2.in.security_flags = 0;
2152                 io1.smb2.in.fname = fname;
2153
2154                 h2 = custom_smb2_create(tree, torture, &(io1.smb2));
2155                 talloc_free(fname);
2156                 smb2_util_close(tree, h2);
2157         }
2158
2159         req1 = smb2_notify_send(tree, &(notify.smb2));
2160         status = smb2_notify_recv(req1, torture, &(notify.smb2));
2161         CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
2162         CHECK_VAL(notify.smb2.out.num_changes, 0);
2163
2164 done:
2165         smb2_deltree(tree, BASEDIR_OVF);
2166         return ret;
2167 }
2168
2169 /*
2170    Test if notifications are returned for changes to the base directory.
2171    They shouldn't be.
2172 */
2173
2174 #define BASEDIR_BAS BASEDIR "_BAS"
2175
2176 static bool torture_smb2_notify_basedir(struct torture_context *torture,
2177                                 struct smb2_tree *tree1,
2178                                 struct smb2_tree *tree2)
2179 {
2180         bool ret = true;
2181         NTSTATUS status;
2182         union smb_notify notify;
2183         union smb_open io;
2184         struct smb2_handle h1;
2185         struct smb2_request *req1;
2186
2187         smb2_deltree(tree1, BASEDIR_BAS);
2188         smb2_util_rmdir(tree1, BASEDIR_BAS);
2189
2190         torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
2191
2192         /* get a handle on the directory */
2193         ZERO_STRUCT(io.smb2);
2194         io.generic.level = RAW_OPEN_SMB2;
2195         io.smb2.in.create_flags = 0;
2196         io.smb2.in.desired_access = SEC_FILE_ALL;
2197         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2198         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2199         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2200             NTCREATEX_SHARE_ACCESS_WRITE;
2201         io.smb2.in.alloc_size = 0;
2202         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2203         io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
2204         io.smb2.in.security_flags = 0;
2205         io.smb2.in.fname = BASEDIR_BAS;
2206
2207         status = smb2_create(tree1, torture, &(io.smb2));
2208         CHECK_STATUS(status, NT_STATUS_OK);
2209         h1 = io.smb2.out.file.handle;
2210
2211         /* create a test file that will also be modified */
2212         io.smb2.in.fname = BASEDIR_BAS "\\tname1";
2213         io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
2214         status =  smb2_create(tree2, torture, &(io.smb2));
2215         CHECK_STATUS(status,NT_STATUS_OK);
2216         smb2_util_close(tree2, io.smb2.out.file.handle);
2217
2218         /* ask for a change notify, on attribute changes. */
2219         ZERO_STRUCT(notify.smb2);
2220         notify.smb2.level = RAW_NOTIFY_SMB2;
2221         notify.smb2.in.buffer_size = 1000;
2222         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
2223         notify.smb2.in.file.handle = h1;
2224         notify.smb2.in.recursive = true;
2225
2226         req1 = smb2_notify_send(tree1, &(notify.smb2));
2227
2228         /* set attribute on the base dir */
2229         smb2_util_setatr(tree2, BASEDIR_BAS, FILE_ATTRIBUTE_HIDDEN);
2230
2231         /* set attribute on a file to assure we receive a notification */
2232         smb2_util_setatr(tree2, BASEDIR_BAS "\\tname1", FILE_ATTRIBUTE_HIDDEN);
2233         smb_msleep(200);
2234
2235         /* check how many responses were given, expect only 1 for the file */
2236         status = smb2_notify_recv(req1, torture, &(notify.smb2));
2237         CHECK_STATUS(status, NT_STATUS_OK);
2238         CHECK_VAL(notify.smb2.out.num_changes, 1);
2239         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
2240         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
2241
2242 done:
2243         smb2_deltree(tree1, BASEDIR_BAS);
2244         return ret;
2245 }
2246
2247 /*
2248    very simple change notify test
2249 */
2250
2251 #define BASEDIR_TCON BASEDIR "_TCON"
2252
2253 static bool torture_smb2_notify_tcon(struct torture_context *torture,
2254                                   struct smb2_tree *tree)
2255 {
2256         bool ret = true;
2257         NTSTATUS status;
2258         union smb_notify notify;
2259         union smb_open io;
2260         struct smb2_handle h1 = {{0}};
2261         struct smb2_request *req = NULL;
2262         struct smb2_tree *tree1 = NULL;
2263         const char *fname = BASEDIR_TCON "\\subdir-name";
2264
2265         smb2_deltree(tree, BASEDIR_TCON);
2266         smb2_util_rmdir(tree, BASEDIR_TCON);
2267
2268         torture_comment(torture, "TESTING SIMPLE CHANGE NOTIFY\n");
2269
2270         /*
2271           get a handle on the directory
2272         */
2273
2274         ZERO_STRUCT(io.smb2);
2275         io.generic.level = RAW_OPEN_SMB2;
2276         io.smb2.in.create_flags = 0;
2277         io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2278         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2279         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL |
2280                                 FILE_ATTRIBUTE_DIRECTORY;
2281         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2282                                 NTCREATEX_SHARE_ACCESS_WRITE;
2283         io.smb2.in.alloc_size = 0;
2284         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2285         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2286         io.smb2.in.security_flags = 0;
2287         io.smb2.in.fname = BASEDIR_TCON;
2288
2289         status = smb2_create(tree, torture, &(io.smb2));
2290         CHECK_STATUS(status, NT_STATUS_OK);
2291         h1 = io.smb2.out.file.handle;
2292
2293         /* ask for a change notify,
2294            on file or directory name changes */
2295         ZERO_STRUCT(notify.smb2);
2296         notify.smb2.level = RAW_NOTIFY_SMB2;
2297         notify.smb2.in.buffer_size = 1000;
2298         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2299         notify.smb2.in.file.handle = h1;
2300         notify.smb2.in.recursive = true;
2301
2302         torture_comment(torture, "Testing notify mkdir\n");
2303         req = smb2_notify_send(tree, &(notify.smb2));
2304         smb2_cancel(req);
2305         status = smb2_notify_recv(req, torture, &(notify.smb2));
2306         CHECK_STATUS(status, NT_STATUS_CANCELLED);
2307
2308         notify.smb2.in.recursive = true;
2309         req = smb2_notify_send(tree, &(notify.smb2));
2310         status = smb2_util_mkdir(tree, fname);
2311         CHECK_STATUS(status, NT_STATUS_OK);
2312
2313         status = smb2_notify_recv(req, torture, &(notify.smb2));
2314         CHECK_STATUS(status, NT_STATUS_OK);
2315
2316         CHECK_VAL(notify.smb2.out.num_changes, 1);
2317         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2318         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2319
2320         torture_comment(torture, "Testing notify rmdir\n");
2321         req = smb2_notify_send(tree, &(notify.smb2));
2322         status = smb2_util_rmdir(tree, fname);
2323         CHECK_STATUS(status, NT_STATUS_OK);
2324
2325         status = smb2_notify_recv(req, torture, &(notify.smb2));
2326         CHECK_STATUS(status, NT_STATUS_OK);
2327         CHECK_VAL(notify.smb2.out.num_changes, 1);
2328         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2329         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2330
2331         torture_comment(torture, "SIMPLE CHANGE NOTIFY OK\n");
2332
2333         torture_comment(torture, "TESTING WITH SECONDARY TCON\n");
2334         if (!torture_smb2_tree_connect(torture, tree->session, tree, &tree1)) {
2335                 torture_warning(torture, "couldn't reconnect to share, bailing\n");
2336                 ret = false;
2337                 goto done;
2338         }
2339
2340         torture_comment(torture, "tid1=%d tid2=%d\n",
2341                         smb2cli_tcon_current_id(tree->smbXcli),
2342                         smb2cli_tcon_current_id(tree1->smbXcli));
2343
2344         torture_comment(torture, "Testing notify mkdir\n");
2345         req = smb2_notify_send(tree, &(notify.smb2));
2346         smb2_util_mkdir(tree1, fname);
2347
2348         status = smb2_notify_recv(req, torture, &(notify.smb2));
2349         CHECK_STATUS(status, NT_STATUS_OK);
2350
2351         CHECK_VAL(notify.smb2.out.num_changes, 1);
2352         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2353         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2354
2355         torture_comment(torture, "Testing notify rmdir\n");
2356         req = smb2_notify_send(tree, &(notify.smb2));
2357         smb2_util_rmdir(tree, fname);
2358
2359         status = smb2_notify_recv(req, torture, &(notify.smb2));
2360         CHECK_STATUS(status, NT_STATUS_OK);
2361         CHECK_VAL(notify.smb2.out.num_changes, 1);
2362         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2363         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2364
2365         torture_comment(torture, "CHANGE NOTIFY WITH TCON OK\n");
2366
2367         torture_comment(torture, "Disconnecting secondary tree\n");
2368         status = smb2_tdis(tree1);
2369         CHECK_STATUS(status, NT_STATUS_OK);
2370         talloc_free(tree1);
2371
2372         torture_comment(torture, "Testing notify mkdir\n");
2373         req = smb2_notify_send(tree, &(notify.smb2));
2374         smb2_util_mkdir(tree, fname);
2375
2376         status = smb2_notify_recv(req, torture, &(notify.smb2));
2377         CHECK_STATUS(status, NT_STATUS_OK);
2378
2379         CHECK_VAL(notify.smb2.out.num_changes, 1);
2380         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
2381         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2382
2383         torture_comment(torture, "Testing notify rmdir\n");
2384         req = smb2_notify_send(tree, &(notify.smb2));
2385         smb2_util_rmdir(tree, fname);
2386
2387         status = smb2_notify_recv(req, torture, &(notify.smb2));
2388         CHECK_STATUS(status, NT_STATUS_OK);
2389         CHECK_VAL(notify.smb2.out.num_changes, 1);
2390         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
2391         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
2392
2393         torture_comment(torture, "CHANGE NOTIFY WITH TDIS OK\n");
2394 done:
2395         smb2_util_close(tree, h1);
2396         smb2_deltree(tree, BASEDIR_TCON);
2397
2398         return ret;
2399 }
2400
2401 #define BASEDIR_RMD BASEDIR "_RMD"
2402
2403 static bool torture_smb2_notify_rmdir(struct torture_context *torture,
2404                                       struct smb2_tree *tree1,
2405                                       struct smb2_tree *tree2,
2406                                       bool initial_delete_on_close)
2407 {
2408         bool ret = true;
2409         NTSTATUS status;
2410         union smb_notify notify = {};
2411         union smb_setfileinfo sfinfo = {};
2412         union smb_open io = {};
2413         struct smb2_handle h = {};
2414         struct smb2_request *req;
2415
2416         torture_comment(torture, "TESTING NOTIFY CANCEL FOR DELETED DIR\n");
2417
2418         smb2_deltree(tree1, BASEDIR_RMD);
2419         smb2_util_rmdir(tree1, BASEDIR_RMD);
2420
2421         ZERO_STRUCT(io.smb2);
2422         io.generic.level = RAW_OPEN_SMB2;
2423         io.smb2.in.create_flags = 0;
2424         io.smb2.in.desired_access = SEC_FILE_ALL;
2425         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2426         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2427         io.smb2.in.share_access =
2428                 NTCREATEX_SHARE_ACCESS_READ |
2429                 NTCREATEX_SHARE_ACCESS_WRITE |
2430                 NTCREATEX_SHARE_ACCESS_DELETE ;
2431         io.smb2.in.alloc_size = 0;
2432         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2433         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2434         io.smb2.in.security_flags = 0;
2435         io.smb2.in.fname = BASEDIR_RMD;
2436
2437         status = smb2_create(tree1, torture, &(io.smb2));
2438         CHECK_STATUS(status, NT_STATUS_OK);
2439         h = io.smb2.out.file.handle;
2440
2441         ZERO_STRUCT(notify.smb2);
2442         notify.smb2.level = RAW_NOTIFY_SMB2;
2443         notify.smb2.in.buffer_size = 1000;
2444         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2445         notify.smb2.in.file.handle = h;
2446         notify.smb2.in.recursive = false;
2447
2448         io.smb2.in.desired_access |= SEC_STD_DELETE;
2449         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
2450         req = smb2_notify_send(tree1, &(notify.smb2));
2451
2452         if (initial_delete_on_close) {
2453                 status = smb2_util_rmdir(tree2, BASEDIR_RMD);
2454                 CHECK_STATUS(status, NT_STATUS_OK);
2455         } else {
2456                 status = smb2_create(tree2, torture, &(io.smb2));
2457                 CHECK_STATUS(status, NT_STATUS_OK);
2458
2459                 sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
2460                 sfinfo.generic.in.file.handle = io.smb2.out.file.handle;
2461                 sfinfo.disposition_info.in.delete_on_close = 1;
2462                 status = smb2_setinfo_file(tree2, &sfinfo);
2463                 CHECK_STATUS(status, NT_STATUS_OK);
2464
2465                 smb2_util_close(tree2, io.smb2.out.file.handle);
2466         }
2467
2468         status = smb2_notify_recv(req, torture, &(notify.smb2));
2469         CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
2470
2471 done:
2472
2473         smb2_util_close(tree1, h);
2474         smb2_deltree(tree1, BASEDIR_RMD);
2475
2476         return ret;
2477 }
2478
2479 static bool torture_smb2_notify_rmdir1(struct torture_context *torture,
2480                                        struct smb2_tree *tree)
2481 {
2482         return torture_smb2_notify_rmdir(torture, tree, tree, false);
2483 }
2484
2485 static bool torture_smb2_notify_rmdir2(struct torture_context *torture,
2486                                        struct smb2_tree *tree)
2487 {
2488         return torture_smb2_notify_rmdir(torture, tree, tree, true);
2489 }
2490
2491 static bool torture_smb2_notify_rmdir3(struct torture_context *torture,
2492                                        struct smb2_tree *tree1,
2493                                        struct smb2_tree *tree2)
2494 {
2495         return torture_smb2_notify_rmdir(torture, tree1, tree2, false);
2496 }
2497
2498 static bool torture_smb2_notify_rmdir4(struct torture_context *torture,
2499                                        struct smb2_tree *tree1,
2500                                        struct smb2_tree *tree2)
2501 {
2502         return torture_smb2_notify_rmdir(torture, tree1, tree2, true);
2503 }
2504
2505 static void notify_timeout(struct tevent_context *ev,
2506                            struct tevent_timer *te,
2507                            struct timeval current_time,
2508                            void *private_data)
2509 {
2510         struct smb2_request *req = talloc_get_type_abort(
2511                 private_data, struct smb2_request);
2512
2513         smb2_cancel(req);
2514 }
2515
2516 #define BASEDIR_INR BASEDIR "_INR"
2517
2518 static bool torture_smb2_inotify_rename(struct torture_context *torture,
2519                                         struct smb2_tree *tree1,
2520                                         struct smb2_tree *tree2)
2521 {
2522         NTSTATUS status;
2523         struct smb2_notify notify;
2524         struct notify_changes change1 = {0};
2525         struct notify_changes change2 = {0};
2526         struct smb2_create create;
2527         union smb_setfileinfo sinfo;
2528         struct smb2_handle h1 = {{0}};
2529         struct smb2_handle h2 = {{0}};
2530         struct smb2_request *req;
2531         struct tevent_timer *te = NULL;
2532         bool ok = false;
2533
2534         smb2_deltree(tree1, BASEDIR_INR);
2535
2536         torture_comment(torture, "Testing change notify of a rename with inotify\n");
2537
2538         status = torture_smb2_testdir(tree1, BASEDIR_INR, &h1);
2539         torture_assert_ntstatus_ok_goto(torture, status, ok, done, "torture_smb2_testdir failed");
2540
2541         ZERO_STRUCT(create);
2542         create.in.desired_access = SEC_RIGHTS_FILE_READ |
2543                 SEC_RIGHTS_FILE_WRITE|
2544                 SEC_RIGHTS_FILE_ALL;
2545         create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2546         create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2547         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2548                 NTCREATEX_SHARE_ACCESS_WRITE |
2549                 NTCREATEX_SHARE_ACCESS_DELETE;
2550         create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2551         create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2552         create.in.fname = BASEDIR_INR "\\subdir-name";
2553
2554         status = smb2_create(tree2, torture, &create);
2555         torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_create failed\n");
2556         h2 = create.out.file.handle;
2557
2558         ZERO_STRUCT(notify);
2559         notify.level = RAW_NOTIFY_SMB2;
2560         notify.in.buffer_size = 4096;
2561         notify.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2562         notify.in.file.handle = h1;
2563         notify.in.recursive = true;
2564         req = smb2_notify_send(tree1, &notify);
2565         torture_assert_not_null_goto(torture, req, ok, done, "smb2_notify_send failed\n");
2566
2567         while (!NT_STATUS_EQUAL(req->status, STATUS_PENDING)) {
2568                 if (tevent_loop_once(torture->ev) != 0) {
2569                         goto done;
2570                 }
2571         }
2572
2573         ZERO_STRUCT(sinfo);
2574         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
2575         sinfo.rename_information.in.file.handle = h2;
2576         sinfo.rename_information.in.new_name = BASEDIR_INR "\\subdir-name-r";
2577
2578         status = smb2_setinfo_file(tree2, &sinfo);
2579         torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_setinfo_file failed\n");
2580
2581         smb2_util_close(tree2, h2);
2582
2583         te = tevent_add_timer(torture->ev,
2584                               tree1,
2585                               tevent_timeval_current_ofs(1, 0),
2586                               notify_timeout,
2587                               req);
2588         torture_assert_not_null_goto(torture, te, ok, done, "tevent_add_timer failed\n");
2589
2590         status = smb2_notify_recv(req, torture, &notify);
2591         torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_notify_recv failed\n");
2592
2593         torture_assert_goto(torture, notify.out.num_changes == 1 || notify.out.num_changes == 2,
2594                             ok, done, "bad notify\n");
2595
2596         change1 = notify.out.changes[0];
2597         if (notify.out.num_changes == 2) {
2598                 change2 = notify.out.changes[1];
2599         } else {
2600                 /*
2601                  * We may only get one event at a time, so check for the
2602                  * matching second event for the oldname/newname or
2603                  * removed/added pair.
2604                  */
2605                 ZERO_STRUCT(notify);
2606                 notify.level = RAW_NOTIFY_SMB2;
2607                 notify.in.buffer_size = 4096;
2608                 notify.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
2609                 notify.in.file.handle = h1;
2610                 notify.in.recursive = true;
2611                 req = smb2_notify_send(tree1, &notify);
2612                 torture_assert_not_null_goto(torture, req, ok, done, "smb2_notify_send failed\n");
2613
2614                 status = smb2_notify_recv(req, torture, &notify);
2615                 torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_notify_recv failed\n");
2616
2617                 torture_assert_goto(torture, notify.out.num_changes == 1, ok, done,
2618                                     "bad notify\n");
2619
2620                 change2 = notify.out.changes[0];
2621         }
2622
2623         if ((change1.action != NOTIFY_ACTION_OLD_NAME) &&
2624             (change1.action != NOTIFY_ACTION_REMOVED))
2625         {
2626                 torture_fail_goto(torture, done, "bad change notification\n");
2627         }
2628         torture_assert_str_equal_goto(torture, change1.name.s, "subdir-name",
2629                             ok, done, "bad change notification\n");
2630
2631         if ((change2.action != NOTIFY_ACTION_NEW_NAME) &&
2632             (change2.action != NOTIFY_ACTION_ADDED))
2633         {
2634                 torture_fail_goto(torture, done, "bad change notification\n");
2635         }
2636         torture_assert_str_equal_goto(torture, change2.name.s, "subdir-name-r",
2637                             ok, done, "bad change notification\n");
2638
2639         ok = true;
2640 done:
2641         if (!smb2_util_handle_empty(h1)) {
2642                 smb2_util_close(tree1, h1);
2643         }
2644         if (!smb2_util_handle_empty(h2)) {
2645                 smb2_util_close(tree2, h2);
2646         }
2647
2648         smb2_deltree(tree1, BASEDIR_INR);
2649         return ok;
2650 }
2651
2652 /*
2653    basic testing of SMB2 change notify
2654 */
2655 struct torture_suite *torture_smb2_notify_init(TALLOC_CTX *ctx)
2656 {
2657         struct torture_suite *suite = torture_suite_create(ctx, "notify");
2658
2659         torture_suite_add_1smb2_test(suite, "valid-req", test_valid_request);
2660         torture_suite_add_1smb2_test(suite, "tcon", torture_smb2_notify_tcon);
2661         torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir);
2662         torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask);
2663         torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
2664         torture_suite_add_1smb2_test(suite, "tdis1", torture_smb2_notify_tree_disconnect_1);
2665         torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
2666         torture_suite_add_1smb2_test(suite, "close", torture_smb2_notify_close);
2667         torture_suite_add_1smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
2668         torture_suite_add_1smb2_test(suite, "session-reconnect", torture_smb2_notify_session_reconnect);
2669         torture_suite_add_2smb2_test(suite, "invalid-reauth", torture_smb2_notify_invalid_reauth);
2670         torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
2671         torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
2672         torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
2673         torture_suite_add_1smb2_test(suite, "file", torture_smb2_notify_file);
2674         torture_suite_add_1smb2_test(suite, "tcp", torture_smb2_notify_tcp_disconnect);
2675         torture_suite_add_2smb2_test(suite, "rec", torture_smb2_notify_recursive);
2676         torture_suite_add_1smb2_test(suite, "overflow", torture_smb2_notify_overflow);
2677         torture_suite_add_1smb2_test(suite, "rmdir1",
2678                                      torture_smb2_notify_rmdir1);
2679         torture_suite_add_1smb2_test(suite, "rmdir2",
2680                                      torture_smb2_notify_rmdir2);
2681         torture_suite_add_2smb2_test(suite, "rmdir3",
2682                                      torture_smb2_notify_rmdir3);
2683         torture_suite_add_2smb2_test(suite, "rmdir4",
2684                                      torture_smb2_notify_rmdir4);
2685
2686         suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");
2687
2688         return suite;
2689 }
2690
2691 /*
2692    basic testing of SMB2 change notify
2693 */
2694 struct torture_suite *torture_smb2_notify_inotify_init(TALLOC_CTX *ctx)
2695 {
2696         struct torture_suite *suite = torture_suite_create(ctx, "notify-inotify");
2697
2698         suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests that use inotify");
2699
2700         torture_suite_add_2smb2_test(suite, "inotify-rename", torture_smb2_inotify_rename);
2701
2702         return suite;
2703 }