2 Unix SMB/CIFS implementation.
6 Copyright (C) Stefan Metzmacher 2006
7 Copyright (C) Andrew Tridgell 2009
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.
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.
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/>.
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "../libcli/smb/smbXcli_base.h"
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"
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"
39 #include "lib/events/events.h"
41 #include "libcli/raw/libcliraw.h"
42 #include "libcli/raw/raw_proto.h"
43 #include "libcli/libcli.h"
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)); \
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); \
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, \
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) { \
79 #define BASEDIR "test_notify"
80 #define FNAME "smb2-notify01.dat"
82 static bool test_valid_request(struct torture_context
*torture
,
83 struct smb2_tree
*tree
)
87 struct smb2_handle dh
;
89 struct smb2_request
*req
;
90 uint32_t max_buffer_size
;
92 torture_comment(torture
, "TESTING VALIDITY OF CHANGE NOTIFY REQUEST\n");
94 smb2_util_unlink(tree
, FNAME
);
96 status
= smb2_util_roothandle(tree
, &dh
);
97 CHECK_STATUS(status
, NT_STATUS_OK
);
99 /* 0x00080000 is the default max buffer size for Windows servers
101 max_buffer_size
= torture_setting_ulong(torture
, "cn_max_buffer_size",
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
);
111 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
112 if (tevent_loop_once(torture
->ev
) != 0) {
117 status
= torture_setup_complex_file(torture
, tree
, FNAME
);
118 CHECK_STATUS(status
, NT_STATUS_OK
);
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
);
127 * if the change response doesn't fit in the buffer
128 * NOTIFY_ENUM_DIR is returned.
130 n
.in
.buffer_size
= 0x00000000;
131 req
= smb2_notify_send(tree
, &n
);
133 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
134 if (tevent_loop_once(torture
->ev
) != 0) {
139 status
= torture_setup_complex_file(torture
, tree
, FNAME
);
140 CHECK_STATUS(status
, NT_STATUS_OK
);
142 status
= smb2_notify_recv(req
, torture
, &n
);
143 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
146 * if the change response fits in the buffer we get
149 n
.in
.buffer_size
= max_buffer_size
;
150 req
= smb2_notify_send(tree
, &n
);
152 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
153 if (tevent_loop_once(torture
->ev
) != 0) {
158 status
= torture_setup_complex_file(torture
, tree
, FNAME
);
159 CHECK_STATUS(status
, NT_STATUS_OK
);
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
);
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
);
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
);
184 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
185 if (tevent_loop_once(torture
->ev
) != 0) {
190 status
= torture_setup_complex_file(torture
, tree
, FNAME
);
191 CHECK_STATUS(status
, NT_STATUS_OK
);
193 status
= smb2_notify_recv(req
, torture
, &n
);
194 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
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) {
204 status
= torture_setup_complex_file(torture
, tree
, FNAME
);
205 CHECK_STATUS(status
, NT_STATUS_OK
);
207 status
= smb2_notify_recv(req
, torture
, &n
);
208 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
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
);
225 basic testing of change notify on directories
227 static bool torture_smb2_notify_dir(struct torture_context
*torture
,
228 struct smb2_tree
*tree1
,
229 struct smb2_tree
*tree2
)
233 union smb_notify notify
;
237 struct smb2_handle h1
= {{0}};
238 struct smb2_handle h2
= {{0}};
239 struct smb2_request
*req
, *req2
;
240 const char *fname
= BASEDIR
"\\subdir-name";
241 extern int torture_numops
;
243 torture_comment(torture
, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
245 smb2_deltree(tree1
, BASEDIR
);
246 smb2_util_rmdir(tree1
, BASEDIR
);
248 get a handle on the directory
250 ZERO_STRUCT(io
.smb2
);
251 io
.generic
.level
= RAW_OPEN_SMB2
;
252 io
.smb2
.in
.create_flags
= 0;
253 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
254 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
255 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
256 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
257 NTCREATEX_SHARE_ACCESS_WRITE
;
258 io
.smb2
.in
.alloc_size
= 0;
259 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
260 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
261 io
.smb2
.in
.security_flags
= 0;
262 io
.smb2
.in
.fname
= BASEDIR
;
264 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
265 CHECK_STATUS(status
, NT_STATUS_OK
);
266 h1
= io
.smb2
.out
.file
.handle
;
268 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
269 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
;
270 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
271 CHECK_STATUS(status
, NT_STATUS_OK
);
272 h2
= io
.smb2
.out
.file
.handle
;
274 /* ask for a change notify,
275 on file or directory name changes */
276 ZERO_STRUCT(notify
.smb2
);
277 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
278 notify
.smb2
.in
.buffer_size
= 1000;
279 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
280 notify
.smb2
.in
.file
.handle
= h1
;
281 notify
.smb2
.in
.recursive
= true;
283 torture_comment(torture
, "Testing notify cancel\n");
285 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
287 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
288 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
290 torture_comment(torture
, "Testing notify mkdir\n");
292 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
293 smb2_util_mkdir(tree2
, fname
);
295 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
296 CHECK_STATUS(status
, NT_STATUS_OK
);
298 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
299 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
300 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
302 torture_comment(torture
, "Testing notify rmdir\n");
304 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
305 smb2_util_rmdir(tree2
, fname
);
307 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
308 CHECK_STATUS(status
, NT_STATUS_OK
);
309 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
310 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
311 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
313 torture_comment(torture
,
314 "Testing notify mkdir - rmdir - mkdir - rmdir\n");
316 smb2_util_mkdir(tree2
, fname
);
317 smb2_util_rmdir(tree2
, fname
);
318 smb2_util_mkdir(tree2
, fname
);
319 smb2_util_rmdir(tree2
, fname
);
321 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
322 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
323 CHECK_STATUS(status
, NT_STATUS_OK
);
324 CHECK_VAL(notify
.smb2
.out
.num_changes
, 4);
325 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
326 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
327 CHECK_VAL(notify
.smb2
.out
.changes
[1].action
, NOTIFY_ACTION_REMOVED
);
328 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[1].name
, "subdir-name");
329 CHECK_VAL(notify
.smb2
.out
.changes
[2].action
, NOTIFY_ACTION_ADDED
);
330 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[2].name
, "subdir-name");
331 CHECK_VAL(notify
.smb2
.out
.changes
[3].action
, NOTIFY_ACTION_REMOVED
);
332 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[3].name
, "subdir-name");
334 count
= torture_numops
;
335 torture_comment(torture
,
336 "Testing buffered notify on create of %d files\n", count
);
337 for (i
=0;i
<count
;i
++) {
338 struct smb2_handle h12
;
339 char *fname2
= talloc_asprintf(torture
, BASEDIR
"\\test%d.txt",
342 ZERO_STRUCT(io
.smb2
);
343 io
.generic
.level
= RAW_OPEN_SMB2
;
344 io
.smb2
.in
.create_flags
= 0;
345 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
346 io
.smb2
.in
.create_options
=
347 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
348 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
349 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
350 NTCREATEX_SHARE_ACCESS_WRITE
;
351 io
.smb2
.in
.alloc_size
= 0;
352 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
353 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
354 io
.smb2
.in
.security_flags
= 0;
355 io
.smb2
.in
.fname
= fname2
;
357 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
358 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OK
)) {
359 torture_comment(torture
, "Failed to create %s \n",
364 h12
= io
.smb2
.out
.file
.handle
;
366 smb2_util_close(tree1
, h12
);
369 /* (1st notify) setup a new notify on a different directory handle.
370 This new notify won't see the events above. */
371 notify
.smb2
.in
.file
.handle
= h2
;
372 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
374 /* (2nd notify) whereas this notify will see the above buffered events,
375 and it directly returns the buffered events */
376 notify
.smb2
.in
.file
.handle
= h1
;
377 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
379 status
= smb2_util_unlink(tree1
, BASEDIR
"\\nonexistent.txt");
380 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
382 /* (1st unlink) as the 2nd notify directly returns,
383 this unlink is only seen by the 1st notify and
384 the 3rd notify (later) */
385 torture_comment(torture
,
386 "Testing notify on unlink for the first file\n");
387 status
= smb2_util_unlink(tree2
, BASEDIR
"\\test0.txt");
388 CHECK_STATUS(status
, NT_STATUS_OK
);
390 /* receive the reply from the 2nd notify */
391 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
392 CHECK_STATUS(status
, NT_STATUS_OK
);
394 CHECK_VAL(notify
.smb2
.out
.num_changes
, count
);
395 for (i
=1;i
<count
;i
++) {
396 CHECK_VAL(notify
.smb2
.out
.changes
[i
].action
,
397 NOTIFY_ACTION_ADDED
);
399 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "test0.txt");
401 torture_comment(torture
, "and now from the 1st notify\n");
402 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
403 CHECK_STATUS(status
, NT_STATUS_OK
);
404 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
405 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
406 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "test0.txt");
408 torture_comment(torture
,
409 "(3rd notify) this notify will only see the 1st unlink\n");
410 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
412 status
= smb2_util_unlink(tree1
, BASEDIR
"\\nonexistent.txt");
413 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
415 for (i
=1;i
<count
;i
++) {
416 char *fname2
= talloc_asprintf(torture
,
417 BASEDIR
"\\test%d.txt", i
);
418 status
= smb2_util_unlink(tree2
, fname2
);
419 CHECK_STATUS(status
, NT_STATUS_OK
);
423 /* receive the 3rd notify */
424 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
425 CHECK_STATUS(status
, NT_STATUS_OK
);
426 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
427 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
428 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "test0.txt");
430 /* and we now see the rest of the unlink calls on both
431 * directory handles */
432 notify
.smb2
.in
.file
.handle
= h1
;
434 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
435 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
436 CHECK_STATUS(status
, NT_STATUS_OK
);
437 CHECK_VAL(notify
.smb2
.out
.num_changes
, count
-1);
438 for (i
=0;i
<notify
.smb2
.out
.num_changes
;i
++) {
439 CHECK_VAL(notify
.smb2
.out
.changes
[i
].action
,
440 NOTIFY_ACTION_REMOVED
);
442 notify
.smb2
.in
.file
.handle
= h2
;
443 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
444 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
445 CHECK_STATUS(status
, NT_STATUS_OK
);
446 CHECK_VAL(notify
.smb2
.out
.num_changes
, count
-1);
447 for (i
=0;i
<notify
.smb2
.out
.num_changes
;i
++) {
448 CHECK_VAL(notify
.smb2
.out
.changes
[i
].action
,
449 NOTIFY_ACTION_REMOVED
);
452 torture_comment(torture
,
453 "Testing if a close() on the dir handle triggers the notify reply\n");
455 notify
.smb2
.in
.file
.handle
= h1
;
456 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
458 ZERO_STRUCT(cl
.smb2
);
459 cl
.smb2
.level
= RAW_CLOSE_SMB2
;
460 cl
.smb2
.in
.file
.handle
= h1
;
461 status
= smb2_close(tree1
, &(cl
.smb2
));
462 CHECK_STATUS(status
, NT_STATUS_OK
);
464 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
465 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
466 CHECK_VAL(notify
.smb2
.out
.num_changes
, 9);
469 smb2_util_close(tree1
, h1
);
470 smb2_util_close(tree1
, h2
);
471 smb2_deltree(tree1
, BASEDIR
);
475 static struct smb2_handle
custom_smb2_create(struct smb2_tree
*tree
,
476 struct torture_context
*torture
,
477 struct smb2_create
*smb2
)
479 struct smb2_handle h1
;
482 smb2_deltree(tree
, smb2
->in
.fname
);
483 status
= smb2_create(tree
, torture
, smb2
);
484 CHECK_STATUS(status
, NT_STATUS_OK
);
485 h1
= smb2
->out
.file
.handle
;
488 h1
= (struct smb2_handle
) {
496 testing of recursive change notify
499 static bool torture_smb2_notify_recursive(struct torture_context
*torture
,
500 struct smb2_tree
*tree1
,
501 struct smb2_tree
*tree2
)
505 union smb_notify notify
;
506 union smb_open io
, io1
;
507 union smb_setfileinfo sinfo
;
508 struct smb2_handle h1
;
509 struct smb2_request
*req1
, *req2
;
511 smb2_deltree(tree1
, BASEDIR
);
512 smb2_util_rmdir(tree1
, BASEDIR
);
514 torture_comment(torture
, "TESTING CHANGE NOTIFY WITH RECURSION\n");
517 get a handle on the directory
519 ZERO_STRUCT(io
.smb2
);
520 io
.generic
.level
= RAW_OPEN_SMB2
;
521 io
.smb2
.in
.create_flags
= 0;
522 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
523 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
524 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
525 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
526 NTCREATEX_SHARE_ACCESS_WRITE
;
527 io
.smb2
.in
.alloc_size
= 0;
528 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
529 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
530 io
.smb2
.in
.security_flags
= 0;
531 io
.smb2
.in
.fname
= BASEDIR
;
533 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
534 CHECK_STATUS(status
, NT_STATUS_OK
);
535 h1
= io
.smb2
.out
.file
.handle
;
537 /* ask for a change notify, on file or directory name
538 changes. Setup both with and without recursion */
539 ZERO_STRUCT(notify
.smb2
);
540 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
541 notify
.smb2
.in
.buffer_size
= 1000;
542 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
|
543 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
544 FILE_NOTIFY_CHANGE_CREATION
;
545 notify
.smb2
.in
.file
.handle
= h1
;
547 notify
.smb2
.in
.recursive
= true;
548 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
550 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
551 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
553 notify
.smb2
.in
.recursive
= false;
554 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
556 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
557 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
559 ZERO_STRUCT(io1
.smb2
);
560 io1
.generic
.level
= RAW_OPEN_SMB2
;
561 io1
.smb2
.in
.create_flags
= NTCREATEX_FLAGS_EXTENDED
;
562 io1
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
563 SEC_RIGHTS_FILE_WRITE
|
565 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
566 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
567 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
568 NTCREATEX_SHARE_ACCESS_WRITE
|
569 NTCREATEX_SHARE_ACCESS_DELETE
;
570 io1
.smb2
.in
.alloc_size
= 0;
571 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
572 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
573 io1
.smb2
.in
.security_flags
= 0;
574 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name";
575 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
576 CHECK_STATUS(status
, NT_STATUS_OK
);
577 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
579 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname1";
580 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
581 CHECK_STATUS(status
, NT_STATUS_OK
);
583 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
584 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
585 sinfo
.rename_information
.in
.overwrite
= 0;
586 sinfo
.rename_information
.in
.root_fid
= 0;
587 sinfo
.rename_information
.in
.new_name
=
588 BASEDIR
"\\subdir-name\\subname1-r";
589 status
= smb2_setinfo_file(tree2
, &sinfo
);
590 CHECK_STATUS(status
, NT_STATUS_OK
);
592 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
593 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname2";
594 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
595 CHECK_STATUS(status
, NT_STATUS_OK
);
597 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
598 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
599 sinfo
.rename_information
.in
.overwrite
= true;
600 sinfo
.rename_information
.in
.root_fid
= 0;
601 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname2-r";
602 status
= smb2_setinfo_file(tree2
, &sinfo
);
603 CHECK_STATUS(status
, NT_STATUS_OK
);
605 io1
.smb2
.in
.fname
= BASEDIR
"\\subname2-r";
606 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
607 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
608 CHECK_STATUS(status
, NT_STATUS_OK
);
610 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
611 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
612 sinfo
.rename_information
.in
.overwrite
= true;
613 sinfo
.rename_information
.in
.root_fid
= 0;
614 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname3-r";
615 status
= smb2_setinfo_file(tree2
, &sinfo
);
616 CHECK_STATUS(status
, NT_STATUS_OK
);
618 notify
.smb2
.in
.completion_filter
= 0;
619 notify
.smb2
.in
.recursive
= true;
621 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
623 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name\\subname1-r");
624 CHECK_STATUS(status
, NT_STATUS_OK
);
625 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name");
626 CHECK_STATUS(status
, NT_STATUS_OK
);
627 status
= smb2_util_unlink(tree2
, BASEDIR
"\\subname3-r");
628 CHECK_STATUS(status
, NT_STATUS_OK
);
630 notify
.smb2
.in
.recursive
= false;
631 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
633 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
634 CHECK_STATUS(status
, NT_STATUS_OK
);
636 CHECK_VAL(notify
.smb2
.out
.num_changes
, 9);
637 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
638 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
639 CHECK_VAL(notify
.smb2
.out
.changes
[1].action
, NOTIFY_ACTION_ADDED
);
640 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[1].name
, "subdir-name\\subname1");
641 CHECK_VAL(notify
.smb2
.out
.changes
[2].action
, NOTIFY_ACTION_OLD_NAME
);
642 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[2].name
, "subdir-name\\subname1");
643 CHECK_VAL(notify
.smb2
.out
.changes
[3].action
, NOTIFY_ACTION_NEW_NAME
);
644 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[3].name
, "subdir-name\\subname1-r");
645 CHECK_VAL(notify
.smb2
.out
.changes
[4].action
, NOTIFY_ACTION_ADDED
);
646 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[4].name
, "subdir-name\\subname2");
647 CHECK_VAL(notify
.smb2
.out
.changes
[5].action
, NOTIFY_ACTION_REMOVED
);
648 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[5].name
, "subdir-name\\subname2");
649 CHECK_VAL(notify
.smb2
.out
.changes
[6].action
, NOTIFY_ACTION_ADDED
);
650 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[6].name
, "subname2-r");
651 CHECK_VAL(notify
.smb2
.out
.changes
[7].action
, NOTIFY_ACTION_OLD_NAME
);
652 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[7].name
, "subname2-r");
653 CHECK_VAL(notify
.smb2
.out
.changes
[8].action
, NOTIFY_ACTION_NEW_NAME
);
654 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[8].name
, "subname3-r");
657 smb2_deltree(tree1
, BASEDIR
);
662 testing of change notify mask change
665 static bool torture_smb2_notify_mask_change(struct torture_context
*torture
,
666 struct smb2_tree
*tree1
,
667 struct smb2_tree
*tree2
)
671 union smb_notify notify
;
672 union smb_open io
, io1
;
673 struct smb2_handle h1
;
674 struct smb2_request
*req1
, *req2
;
675 union smb_setfileinfo sinfo
;
677 smb2_deltree(tree1
, BASEDIR
);
678 smb2_util_rmdir(tree1
, BASEDIR
);
680 torture_comment(torture
, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
683 get a handle on the directory
685 ZERO_STRUCT(io
.smb2
);
686 io
.generic
.level
= RAW_OPEN_SMB2
;
687 io
.smb2
.in
.create_flags
= 0;
688 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
689 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
690 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
691 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
692 NTCREATEX_SHARE_ACCESS_WRITE
;
693 io
.smb2
.in
.alloc_size
= 0;
694 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
695 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
696 io
.smb2
.in
.security_flags
= 0;
697 io
.smb2
.in
.fname
= BASEDIR
;
699 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
700 CHECK_STATUS(status
, NT_STATUS_OK
);
701 h1
= io
.smb2
.out
.file
.handle
;
703 /* ask for a change notify, on file or directory name
704 changes. Setup both with and without recursion */
705 ZERO_STRUCT(notify
.smb2
);
706 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
707 notify
.smb2
.in
.buffer_size
= 1000;
708 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
709 notify
.smb2
.in
.file
.handle
= h1
;
711 notify
.smb2
.in
.recursive
= true;
712 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
715 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
716 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
719 notify
.smb2
.in
.recursive
= false;
720 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
723 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
724 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
726 notify
.smb2
.in
.recursive
= true;
727 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
729 /* Set to hidden then back again. */
730 ZERO_STRUCT(io1
.smb2
);
731 io1
.generic
.level
= RAW_OPEN_SMB2
;
732 io1
.smb2
.in
.create_flags
= 0;
733 io1
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
734 SEC_RIGHTS_FILE_WRITE
|
736 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
737 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
738 NTCREATEX_SHARE_ACCESS_WRITE
|
739 NTCREATEX_SHARE_ACCESS_DELETE
;
740 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
741 io1
.smb2
.in
.security_flags
= 0;
742 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
743 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
744 io1
.smb2
.in
.fname
= BASEDIR
"\\tname1";
746 smb2_util_close(tree1
,
747 custom_smb2_create(tree1
, torture
, &(io1
.smb2
)));
748 status
= smb2_util_setatr(tree1
, BASEDIR
"\\tname1",
749 FILE_ATTRIBUTE_HIDDEN
);
750 CHECK_STATUS(status
, NT_STATUS_OK
);
751 smb2_util_unlink(tree1
, BASEDIR
"\\tname1");
753 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
754 CHECK_STATUS(status
, NT_STATUS_OK
);
756 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
757 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
758 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "tname1");
760 /* Now try and change the mask to include other events.
761 * This should not work - once the mask is set on a directory
762 * h1 it seems to be fixed until the fnum is closed. */
764 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
|
765 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
766 FILE_NOTIFY_CHANGE_CREATION
;
767 notify
.smb2
.in
.recursive
= true;
768 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
770 notify
.smb2
.in
.recursive
= false;
771 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
773 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
774 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
775 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name";
776 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
777 CHECK_STATUS(status
, NT_STATUS_OK
);
778 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
781 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname1";
782 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
783 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
784 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
785 CHECK_STATUS(status
, NT_STATUS_OK
);
786 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
787 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
788 sinfo
.rename_information
.in
.overwrite
= true;
789 sinfo
.rename_information
.in
.root_fid
= 0;
790 sinfo
.rename_information
.in
.new_name
=
791 BASEDIR
"\\subdir-name\\subname1-r";
792 status
= smb2_setinfo_file(tree2
, &sinfo
);
793 CHECK_STATUS(status
, NT_STATUS_OK
);
795 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname2";
796 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
797 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
798 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
799 CHECK_STATUS(status
, NT_STATUS_OK
);
800 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
801 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname2-r";
802 status
= smb2_setinfo_file(tree2
, &sinfo
);
803 CHECK_STATUS(status
, NT_STATUS_OK
);
804 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
806 io1
.smb2
.in
.fname
= BASEDIR
"\\subname2-r";
807 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
808 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
809 CHECK_STATUS(status
, NT_STATUS_OK
);
810 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
811 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname3-r";
812 status
= smb2_setinfo_file(tree2
, &sinfo
);
813 CHECK_STATUS(status
, NT_STATUS_OK
);
814 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
816 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name\\subname1-r");
817 CHECK_STATUS(status
, NT_STATUS_OK
);
818 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name");
819 CHECK_STATUS(status
, NT_STATUS_OK
);
820 status
= smb2_util_unlink(tree2
, BASEDIR
"\\subname3-r");
821 CHECK_STATUS(status
, NT_STATUS_OK
);
823 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
824 CHECK_STATUS(status
, NT_STATUS_OK
);
826 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
827 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
828 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subname2-r");
830 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
831 CHECK_STATUS(status
, NT_STATUS_OK
);
833 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
834 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
835 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subname3-r");
842 smb2_deltree(tree1
, BASEDIR
);
847 testing of mask bits for change notify
850 static bool torture_smb2_notify_mask(struct torture_context
*torture
,
851 struct smb2_tree
*tree1
,
852 struct smb2_tree
*tree2
)
856 union smb_notify notify
;
857 union smb_open io
, io1
;
858 struct smb2_handle h1
, h2
;
862 union smb_setfileinfo sinfo
;
864 smb2_deltree(tree1
, BASEDIR
);
865 smb2_util_rmdir(tree1
, BASEDIR
);
867 torture_comment(torture
, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
873 get a handle on the directory
875 ZERO_STRUCT(io
.smb2
);
876 io
.generic
.level
= RAW_OPEN_SMB2
;
877 io
.smb2
.in
.create_flags
= 0;
878 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
879 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
880 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
881 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
882 NTCREATEX_SHARE_ACCESS_WRITE
;
883 io
.smb2
.in
.alloc_size
= 0;
884 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
885 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
886 io
.smb2
.in
.security_flags
= 0;
887 io
.smb2
.in
.fname
= BASEDIR
;
889 ZERO_STRUCT(notify
.smb2
);
890 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
891 notify
.smb2
.in
.buffer_size
= 1000;
892 notify
.smb2
.in
.recursive
= true;
894 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
895 expected, nchanges) \
897 do { for (mask=i=0;i<32;i++) { \
898 struct smb2_request *req; \
899 status = smb2_create(tree1, torture, &(io.smb2)); \
900 CHECK_STATUS(status, NT_STATUS_OK); \
901 h1 = io.smb2.out.file.handle; \
903 notify.smb2.in.file.handle = h1; \
904 notify.smb2.in.completion_filter = (1<<i); \
905 /* cancel initial requests so the buffer is setup */ \
906 req = smb2_notify_send(tree1, &(notify.smb2)); \
908 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
909 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
910 /* send the change notify request */ \
911 req = smb2_notify_send(tree1, &(notify.smb2)); \
913 smb_msleep(200); smb2_cancel(req); \
914 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
916 smb2_util_close(tree1, h1); \
917 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
918 CHECK_STATUS(status, NT_STATUS_OK); \
919 /* special case to cope with file rename behaviour */ \
920 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
921 notify.smb2.out.changes[0].action == \
922 NOTIFY_ACTION_MODIFIED && \
923 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
924 Action == NOTIFY_ACTION_OLD_NAME) { \
925 torture_comment(torture, \
926 "(rename file special handling OK)\n"); \
927 } else if (nchanges != notify.smb2.out.num_changes) { \
928 torture_result(torture, TORTURE_FAIL, \
929 "ERROR: nchanges=%d expected=%d "\
930 "action=%d filter=0x%08x\n", \
931 notify.smb2.out.num_changes, \
933 notify.smb2.out.changes[0].action, \
934 notify.smb2.in.completion_filter); \
936 } else if (notify.smb2.out.changes[0].action != Action) { \
937 torture_result(torture, TORTURE_FAIL, \
938 "ERROR: nchanges=%d action=%d " \
939 "expectedAction=%d filter=0x%08x\n", \
940 notify.smb2.out.num_changes, \
941 notify.smb2.out.changes[0].action, \
943 notify.smb2.in.completion_filter); \
945 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
947 torture_result(torture, TORTURE_FAIL, \
948 "ERROR: nchanges=%d action=%d " \
949 "filter=0x%08x name=%s\n", \
950 notify.smb2.out.num_changes, \
951 notify.smb2.out.changes[0].action, \
952 notify.smb2.in.completion_filter, \
953 notify.smb2.out.changes[0].name.s); \
961 torture_comment(torture
, "Testing mkdir\n");
962 NOTIFY_MASK_TEST("Testing mkdir",;,
963 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
964 smb2_util_rmdir(tree2
, BASEDIR
"\\tname1");,
966 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
968 torture_comment(torture
, "Testing create file\n");
969 ZERO_STRUCT(io1
.smb2
);
970 io1
.generic
.level
= RAW_OPEN_SMB2
;
971 io1
.smb2
.in
.create_flags
= 0;
972 io1
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
973 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
974 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
975 NTCREATEX_SHARE_ACCESS_WRITE
;
976 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
977 io1
.smb2
.in
.security_flags
= 0;
978 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
979 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
980 io1
.smb2
.in
.fname
= BASEDIR
"\\tname1";
982 NOTIFY_MASK_TEST("Testing create file",;,
983 smb2_util_close(tree2
, custom_smb2_create(tree2
,
984 torture
, &(io1
.smb2
)));,
985 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
987 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
989 torture_comment(torture
, "Testing unlink\n");
990 NOTIFY_MASK_TEST("Testing unlink",
991 smb2_util_close(tree2
, custom_smb2_create(tree2
,
992 torture
, &(io1
.smb2
)));,
993 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
995 NOTIFY_ACTION_REMOVED
,
996 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
998 torture_comment(torture
, "Testing rmdir\n");
999 NOTIFY_MASK_TEST("Testing rmdir",
1000 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
1001 smb2_util_rmdir(tree2
, BASEDIR
"\\tname1");,
1003 NOTIFY_ACTION_REMOVED
,
1004 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
1006 torture_comment(torture
, "Testing rename file\n");
1008 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1009 sinfo
.rename_information
.in
.file
.handle
= h1
;
1010 sinfo
.rename_information
.in
.overwrite
= true;
1011 sinfo
.rename_information
.in
.root_fid
= 0;
1012 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\tname2";
1013 NOTIFY_MASK_TEST("Testing rename file",
1014 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1015 torture
, &(io1
.smb2
)));,
1016 smb2_setinfo_file(tree2
, &sinfo
);,
1017 smb2_util_unlink(tree2
, BASEDIR
"\\tname2");,
1018 NOTIFY_ACTION_OLD_NAME
,
1019 FILE_NOTIFY_CHANGE_FILE_NAME
, 2);
1021 torture_comment(torture
, "Testing rename dir\n");
1023 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1024 sinfo
.rename_information
.in
.file
.handle
= h1
;
1025 sinfo
.rename_information
.in
.overwrite
= true;
1026 sinfo
.rename_information
.in
.root_fid
= 0;
1027 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\tname2";
1028 NOTIFY_MASK_TEST("Testing rename dir",
1029 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
1030 smb2_setinfo_file(tree2
, &sinfo
);,
1031 smb2_util_rmdir(tree2
, BASEDIR
"\\tname2");,
1032 NOTIFY_ACTION_OLD_NAME
,
1033 FILE_NOTIFY_CHANGE_DIR_NAME
, 2);
1035 torture_comment(torture
, "Testing set path attribute\n");
1036 NOTIFY_MASK_TEST("Testing set path attribute",
1037 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1038 torture
, &(io
.smb2
)));,
1039 smb2_util_setatr(tree2
, BASEDIR
"\\tname1",
1040 FILE_ATTRIBUTE_HIDDEN
);,
1041 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
1042 NOTIFY_ACTION_MODIFIED
,
1043 FILE_NOTIFY_CHANGE_ATTRIBUTES
, 1);
1045 torture_comment(torture
, "Testing set path write time\n");
1047 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1048 sinfo
.generic
.in
.file
.handle
= h1
;
1049 sinfo
.basic_info
.in
.write_time
= 1000;
1050 NOTIFY_MASK_TEST("Testing set path write time",
1051 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1052 torture
, &(io1
.smb2
)));,
1053 smb2_setinfo_file(tree2
, &sinfo
);,
1054 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
1055 NOTIFY_ACTION_MODIFIED
,
1056 FILE_NOTIFY_CHANGE_LAST_WRITE
, 1);
1058 if (torture_setting_bool(torture
, "samba3", false)) {
1059 torture_comment(torture
,
1060 "Samba3 does not yet support create times "
1065 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1066 sinfo
.generic
.in
.file
.handle
= h1
;
1067 sinfo
.basic_info
.in
.create_time
= 0;
1068 torture_comment(torture
, "Testing set file create time\n");
1069 NOTIFY_MASK_TEST("Testing set file create time",
1070 smb2_create_complex_file(torture
, tree2
,
1071 BASEDIR
"\\tname1", &h2
);,
1072 smb2_setinfo_file(tree2
, &sinfo
);,
1073 (smb2_util_close(tree2
, h2
),
1074 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1075 NOTIFY_ACTION_MODIFIED
,
1076 FILE_NOTIFY_CHANGE_CREATION
, 1);
1080 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1081 sinfo
.generic
.in
.file
.handle
= h1
;
1082 sinfo
.basic_info
.in
.access_time
= 0;
1083 torture_comment(torture
, "Testing set file access time\n");
1084 NOTIFY_MASK_TEST("Testing set file access time",
1085 smb2_create_complex_file(torture
, tree2
, BASEDIR
"\\tname1", &h2
);,
1086 smb2_setinfo_file(tree2
, &sinfo
);,
1087 (smb2_util_close(tree2
, h2
),
1088 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1089 NOTIFY_ACTION_MODIFIED
,
1090 FILE_NOTIFY_CHANGE_LAST_ACCESS
, 1);
1093 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1094 sinfo
.generic
.in
.file
.handle
= h1
;
1095 sinfo
.basic_info
.in
.change_time
= 0;
1096 torture_comment(torture
, "Testing set file change time\n");
1097 NOTIFY_MASK_TEST("Testing set file change time",
1098 smb2_create_complex_file(torture
, tree2
, BASEDIR
"\\tname1", &h2
);,
1099 smb2_setinfo_file(tree2
, &sinfo
);,
1100 (smb2_util_close(tree2
, h2
),
1101 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1102 NOTIFY_ACTION_MODIFIED
,
1106 torture_comment(torture
, "Testing write\n");
1107 NOTIFY_MASK_TEST("Testing write",
1108 smb2_create_complex_file(torture
, tree2
, BASEDIR
"\\tname1", &h2
);,
1109 smb2_util_write(tree2
, h2
, &c
, 10000, 1);,
1110 (smb2_util_close(tree2
, h2
),
1111 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1112 NOTIFY_ACTION_MODIFIED
,
1116 smb2_deltree(tree1
, BASEDIR
);
1121 basic testing of change notify on files
1123 static bool torture_smb2_notify_file(struct torture_context
*torture
,
1124 struct smb2_tree
*tree
)
1130 union smb_notify notify
;
1131 struct smb2_request
*req
;
1132 struct smb2_handle h1
;
1133 const char *fname
= BASEDIR
"\\file.txt";
1135 smb2_deltree(tree
, BASEDIR
);
1136 smb2_util_rmdir(tree
, BASEDIR
);
1138 torture_comment(torture
, "TESTING CHANGE NOTIFY ON FILES\n");
1139 status
= torture_smb2_testdir(tree
, BASEDIR
, &h1
);
1140 CHECK_STATUS(status
, NT_STATUS_OK
);
1142 ZERO_STRUCT(io
.smb2
);
1143 io
.generic
.level
= RAW_OPEN_SMB2
;
1144 io
.smb2
.in
.create_flags
= 0;
1145 io
.smb2
.in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
;
1146 io
.smb2
.in
.create_options
= 0;
1147 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1148 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1149 NTCREATEX_SHARE_ACCESS_WRITE
;
1150 io
.smb2
.in
.alloc_size
= 0;
1151 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1152 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1153 io
.smb2
.in
.security_flags
= 0;
1154 io
.smb2
.in
.fname
= fname
;
1155 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1156 CHECK_STATUS(status
, NT_STATUS_OK
);
1157 h1
= io
.smb2
.out
.file
.handle
;
1159 /* ask for a change notify,
1160 on file or directory name changes */
1161 ZERO_STRUCT(notify
.smb2
);
1162 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1163 notify
.smb2
.in
.file
.handle
= h1
;
1164 notify
.smb2
.in
.buffer_size
= 1000;
1165 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_STREAM_NAME
;
1166 notify
.smb2
.in
.recursive
= false;
1168 torture_comment(torture
,
1169 "Testing if notifies on file handles are invalid (should be)\n");
1171 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1172 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1173 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1175 ZERO_STRUCT(cl
.smb2
);
1176 cl
.close
.level
= RAW_CLOSE_SMB2
;
1177 cl
.close
.in
.file
.handle
= h1
;
1178 status
= smb2_close(tree
, &(cl
.smb2
));
1179 CHECK_STATUS(status
, NT_STATUS_OK
);
1181 status
= smb2_util_unlink(tree
, fname
);
1182 CHECK_STATUS(status
, NT_STATUS_OK
);
1185 smb2_deltree(tree
, BASEDIR
);
1189 basic testing of change notifies followed by a tdis
1192 static bool torture_smb2_notify_tree_disconnect(
1193 struct torture_context
*torture
,
1194 struct smb2_tree
*tree
)
1198 union smb_notify notify
;
1200 struct smb2_handle h1
;
1201 struct smb2_request
*req
;
1203 smb2_deltree(tree
, BASEDIR
);
1204 smb2_util_rmdir(tree
, BASEDIR
);
1206 torture_comment(torture
, "TESTING CHANGE NOTIFY+CANCEL FOLLOWED BY "
1207 "TREE-DISCONNECT\n");
1210 get a handle on the directory
1212 ZERO_STRUCT(io
.smb2
);
1213 io
.generic
.level
= RAW_OPEN_SMB2
;
1214 io
.smb2
.in
.create_flags
= 0;
1215 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1216 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1217 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1218 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1219 NTCREATEX_SHARE_ACCESS_WRITE
;
1220 io
.smb2
.in
.alloc_size
= 0;
1221 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1222 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1223 io
.smb2
.in
.security_flags
= 0;
1224 io
.smb2
.in
.fname
= BASEDIR
;
1226 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1227 CHECK_STATUS(status
, NT_STATUS_OK
);
1228 h1
= io
.smb2
.out
.file
.handle
;
1230 /* ask for a change notify,
1231 on file or directory name changes */
1232 ZERO_STRUCT(notify
.smb2
);
1233 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1234 notify
.smb2
.in
.buffer_size
= 1000;
1235 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1236 notify
.smb2
.in
.file
.handle
= h1
;
1237 notify
.smb2
.in
.recursive
= true;
1239 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1241 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1243 status
= smb2_tdis(tree
);
1244 CHECK_STATUS(status
, NT_STATUS_OK
);
1246 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1248 smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1249 CHECK_STATUS(status
, NT_STATUS_OK
);
1250 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1253 smb2_deltree(tree
, BASEDIR
);
1258 testing of change notifies followed by a tdis - no cancel
1261 static bool torture_smb2_notify_tree_disconnect_1(
1262 struct torture_context
*torture
,
1263 struct smb2_tree
*tree
)
1267 union smb_notify notify
;
1269 struct smb2_handle h1
;
1270 struct smb2_request
*req
;
1272 smb2_deltree(tree
, BASEDIR
);
1273 smb2_util_rmdir(tree
, BASEDIR
);
1275 torture_comment(torture
, "TESTING CHANGE NOTIFY ASYNC FOLLOWED BY "
1276 "TREE-DISCONNECT\n");
1279 get a handle on the directory
1281 ZERO_STRUCT(io
.smb2
);
1282 io
.generic
.level
= RAW_OPEN_SMB2
;
1283 io
.smb2
.in
.create_flags
= 0;
1284 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1285 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1286 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1287 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1288 NTCREATEX_SHARE_ACCESS_WRITE
;
1289 io
.smb2
.in
.alloc_size
= 0;
1290 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1291 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1292 io
.smb2
.in
.security_flags
= 0;
1293 io
.smb2
.in
.fname
= BASEDIR
;
1295 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1296 CHECK_STATUS(status
, NT_STATUS_OK
);
1297 h1
= io
.smb2
.out
.file
.handle
;
1299 /* ask for a change notify,
1300 on file or directory name changes */
1301 ZERO_STRUCT(notify
.smb2
);
1302 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1303 notify
.smb2
.in
.buffer_size
= 1000;
1304 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1305 notify
.smb2
.in
.file
.handle
= h1
;
1306 notify
.smb2
.in
.recursive
= true;
1308 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1309 WAIT_FOR_ASYNC_RESPONSE(req
);
1311 status
= smb2_tdis(tree
);
1312 CHECK_STATUS(status
, NT_STATUS_OK
);
1314 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1315 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
1316 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1319 smb2_deltree(tree
, BASEDIR
);
1324 basic testing of change notifies followed by a close
1327 static bool torture_smb2_notify_close(struct torture_context
*torture
,
1328 struct smb2_tree
*tree1
)
1332 union smb_notify notify
;
1334 struct smb2_handle h1
;
1335 struct smb2_request
*req
;
1337 smb2_deltree(tree1
, BASEDIR
);
1338 smb2_util_rmdir(tree1
, BASEDIR
);
1340 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1343 get a handle on the directory
1345 ZERO_STRUCT(io
.smb2
);
1346 io
.generic
.level
= RAW_OPEN_SMB2
;
1347 io
.smb2
.in
.create_flags
= 0;
1348 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1349 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1350 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1351 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1352 NTCREATEX_SHARE_ACCESS_WRITE
;
1353 io
.smb2
.in
.alloc_size
= 0;
1354 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1355 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1356 io
.smb2
.in
.security_flags
= 0;
1357 io
.smb2
.in
.fname
= BASEDIR
;
1359 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1360 CHECK_STATUS(status
, NT_STATUS_OK
);
1362 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1363 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1364 CHECK_STATUS(status
, NT_STATUS_OK
);
1365 h1
= io
.smb2
.out
.file
.handle
;
1367 /* ask for a change notify,
1368 on file or directory name changes */
1369 ZERO_STRUCT(notify
.smb2
);
1370 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1371 notify
.smb2
.in
.buffer_size
= 1000;
1372 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1373 notify
.smb2
.in
.file
.handle
= h1
;
1374 notify
.smb2
.in
.recursive
= true;
1376 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1378 WAIT_FOR_ASYNC_RESPONSE(req
);
1380 status
= smb2_util_close(tree1
, h1
);
1381 CHECK_STATUS(status
, NT_STATUS_OK
);
1383 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1384 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
1385 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1388 smb2_deltree(tree1
, BASEDIR
);
1393 basic testing of change notifies followed by a ulogoff
1396 static bool torture_smb2_notify_ulogoff(struct torture_context
*torture
,
1397 struct smb2_tree
*tree1
)
1401 union smb_notify notify
;
1403 struct smb2_handle h1
;
1404 struct smb2_request
*req
;
1406 smb2_deltree(tree1
, BASEDIR
);
1407 smb2_util_rmdir(tree1
, BASEDIR
);
1409 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1412 get a handle on the directory
1414 ZERO_STRUCT(io
.smb2
);
1415 io
.generic
.level
= RAW_OPEN_SMB2
;
1416 io
.smb2
.in
.create_flags
= 0;
1417 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1418 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1419 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1420 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1421 NTCREATEX_SHARE_ACCESS_WRITE
;
1422 io
.smb2
.in
.alloc_size
= 0;
1423 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1424 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1425 io
.smb2
.in
.security_flags
= 0;
1426 io
.smb2
.in
.fname
= BASEDIR
;
1428 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1429 CHECK_STATUS(status
, NT_STATUS_OK
);
1431 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1432 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1433 CHECK_STATUS(status
, NT_STATUS_OK
);
1434 h1
= io
.smb2
.out
.file
.handle
;
1436 /* ask for a change notify,
1437 on file or directory name changes */
1438 ZERO_STRUCT(notify
.smb2
);
1439 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1440 notify
.smb2
.in
.buffer_size
= 1000;
1441 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1442 notify
.smb2
.in
.file
.handle
= h1
;
1443 notify
.smb2
.in
.recursive
= true;
1445 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1447 WAIT_FOR_ASYNC_RESPONSE(req
);
1449 status
= smb2_logoff(tree1
->session
);
1450 CHECK_STATUS(status
, NT_STATUS_OK
);
1452 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1453 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
1454 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1457 smb2_deltree(tree1
, BASEDIR
);
1462 basic testing of change notifies followed by a session reconnect
1465 static bool torture_smb2_notify_session_reconnect(struct torture_context
*torture
,
1466 struct smb2_tree
*tree1
)
1470 union smb_notify notify
;
1472 struct smb2_handle h1
;
1473 struct smb2_request
*req
;
1474 uint64_t previous_session_id
= 0;
1475 struct smb2_session
*session2
= NULL
;
1477 smb2_deltree(tree1
, BASEDIR
);
1478 smb2_util_rmdir(tree1
, BASEDIR
);
1480 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY SESSION RECONNECT\n");
1483 get a handle on the directory
1485 ZERO_STRUCT(io
.smb2
);
1486 io
.generic
.level
= RAW_OPEN_SMB2
;
1487 io
.smb2
.in
.create_flags
= 0;
1488 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1489 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1490 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1491 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1492 NTCREATEX_SHARE_ACCESS_WRITE
;
1493 io
.smb2
.in
.alloc_size
= 0;
1494 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1495 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1496 io
.smb2
.in
.security_flags
= 0;
1497 io
.smb2
.in
.fname
= BASEDIR
;
1499 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1500 CHECK_STATUS(status
, NT_STATUS_OK
);
1502 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1503 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1504 CHECK_STATUS(status
, NT_STATUS_OK
);
1505 h1
= io
.smb2
.out
.file
.handle
;
1507 /* ask for a change notify,
1508 on file or directory name changes */
1509 ZERO_STRUCT(notify
.smb2
);
1510 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1511 notify
.smb2
.in
.buffer_size
= 1000;
1512 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1513 notify
.smb2
.in
.file
.handle
= h1
;
1514 notify
.smb2
.in
.recursive
= true;
1516 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1518 WAIT_FOR_ASYNC_RESPONSE(req
);
1520 previous_session_id
= smb2cli_session_current_id(tree1
->session
->smbXcli
);
1521 torture_assert(torture
, torture_smb2_session_setup(torture
,
1522 tree1
->session
->transport
,
1523 previous_session_id
,
1524 torture
, &session2
),
1525 "session setup with previous_session_id failed");
1527 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1528 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
1529 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1531 status
= smb2_logoff(tree1
->session
);
1532 CHECK_STATUS(status
, NT_STATUS_USER_SESSION_DELETED
);
1534 status
= smb2_logoff(session2
);
1535 CHECK_STATUS(status
, NT_STATUS_OK
);
1537 smb2_deltree(tree1
, BASEDIR
);
1542 basic testing of change notifies followed by an invalid reauth
1545 static bool torture_smb2_notify_invalid_reauth(struct torture_context
*torture
,
1546 struct smb2_tree
*tree1
,
1547 struct smb2_tree
*tree2
)
1551 union smb_notify notify
;
1553 struct smb2_handle h1
;
1554 struct smb2_request
*req
;
1555 struct cli_credentials
*invalid_creds
;
1557 smb2_deltree(tree2
, BASEDIR
);
1558 smb2_util_rmdir(tree2
, BASEDIR
);
1560 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY invalid REAUTH\n");
1563 get a handle on the directory
1565 ZERO_STRUCT(io
.smb2
);
1566 io
.generic
.level
= RAW_OPEN_SMB2
;
1567 io
.smb2
.in
.create_flags
= 0;
1568 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1569 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1570 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1571 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1572 NTCREATEX_SHARE_ACCESS_WRITE
;
1573 io
.smb2
.in
.alloc_size
= 0;
1574 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1575 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1576 io
.smb2
.in
.security_flags
= 0;
1577 io
.smb2
.in
.fname
= BASEDIR
;
1579 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1580 CHECK_STATUS(status
, NT_STATUS_OK
);
1582 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1583 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1584 CHECK_STATUS(status
, NT_STATUS_OK
);
1585 h1
= io
.smb2
.out
.file
.handle
;
1587 /* ask for a change notify,
1588 on file or directory name changes */
1589 ZERO_STRUCT(notify
.smb2
);
1590 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1591 notify
.smb2
.in
.buffer_size
= 1000;
1592 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1593 notify
.smb2
.in
.file
.handle
= h1
;
1594 notify
.smb2
.in
.recursive
= true;
1596 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1598 WAIT_FOR_ASYNC_RESPONSE(req
);
1600 invalid_creds
= cli_credentials_init(torture
);
1601 torture_assert(torture
, (invalid_creds
!= NULL
), "talloc error");
1602 cli_credentials_set_username(invalid_creds
, "__none__invalid__none__", CRED_SPECIFIED
);
1603 cli_credentials_set_domain(invalid_creds
, "__none__invalid__none__", CRED_SPECIFIED
);
1604 cli_credentials_set_password(invalid_creds
, "__none__invalid__none__", CRED_SPECIFIED
);
1605 cli_credentials_set_realm(invalid_creds
, NULL
, CRED_SPECIFIED
);
1606 cli_credentials_set_workstation(invalid_creds
, "", CRED_UNINITIALISED
);
1608 status
= smb2_session_setup_spnego(tree1
->session
,
1610 0 /* previous_session_id */);
1611 CHECK_STATUS(status
, NT_STATUS_LOGON_FAILURE
);
1613 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1614 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
1615 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1618 smb2_deltree(tree2
, BASEDIR
);
1622 static void tcp_dis_handler(struct smb2_transport
*t
, void *p
)
1624 struct smb2_tree
*tree
= (struct smb2_tree
*)p
;
1625 smb2_transport_dead(tree
->session
->transport
,
1626 NT_STATUS_LOCAL_DISCONNECT
);
1632 basic testing of change notifies followed by tcp disconnect
1635 static bool torture_smb2_notify_tcp_disconnect(
1636 struct torture_context
*torture
,
1637 struct smb2_tree
*tree
)
1641 union smb_notify notify
;
1643 struct smb2_handle h1
;
1644 struct smb2_request
*req
;
1646 smb2_deltree(tree
, BASEDIR
);
1647 smb2_util_rmdir(tree
, BASEDIR
);
1649 torture_comment(torture
,
1650 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1653 get a handle on the directory
1655 ZERO_STRUCT(io
.smb2
);
1656 io
.generic
.level
= RAW_OPEN_SMB2
;
1657 io
.smb2
.in
.create_flags
= 0;
1658 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1659 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1660 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1661 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1662 NTCREATEX_SHARE_ACCESS_WRITE
;
1663 io
.smb2
.in
.alloc_size
= 0;
1664 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1665 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1666 io
.smb2
.in
.security_flags
= 0;
1667 io
.smb2
.in
.fname
= BASEDIR
;
1669 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1670 CHECK_STATUS(status
, NT_STATUS_OK
);
1671 h1
= io
.smb2
.out
.file
.handle
;
1673 /* ask for a change notify,
1674 on file or directory name changes */
1675 ZERO_STRUCT(notify
.smb2
);
1676 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1677 notify
.smb2
.in
.buffer_size
= 1000;
1678 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1679 notify
.smb2
.in
.file
.handle
= h1
;
1680 notify
.smb2
.in
.recursive
= true;
1682 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1684 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1685 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1687 notify
.smb2
.in
.recursive
= true;
1688 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1689 smb2_transport_idle_handler(tree
->session
->transport
,
1690 tcp_dis_handler
, 250, tree
);
1692 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1693 CHECK_STATUS(status
, NT_STATUS_LOCAL_DISCONNECT
);
1700 test setting up two change notify requests on one handle
1703 static bool torture_smb2_notify_double(struct torture_context
*torture
,
1704 struct smb2_tree
*tree1
,
1705 struct smb2_tree
*tree2
)
1709 union smb_notify notify
;
1711 struct smb2_handle h1
;
1712 struct smb2_request
*req1
, *req2
;
1714 smb2_deltree(tree1
, BASEDIR
);
1715 smb2_util_rmdir(tree1
, BASEDIR
);
1717 torture_comment(torture
,
1718 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1721 get a handle on the directory
1723 ZERO_STRUCT(io
.smb2
);
1724 io
.generic
.level
= RAW_OPEN_SMB2
;
1725 io
.smb2
.in
.create_flags
= 0;
1726 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
1727 SEC_RIGHTS_FILE_WRITE
|
1728 SEC_RIGHTS_FILE_ALL
;
1729 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1730 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1731 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1732 NTCREATEX_SHARE_ACCESS_WRITE
;
1733 io
.smb2
.in
.alloc_size
= 0;
1734 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1735 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1736 io
.smb2
.in
.security_flags
= 0;
1737 io
.smb2
.in
.fname
= BASEDIR
;
1739 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1740 CHECK_STATUS(status
, NT_STATUS_OK
);
1741 h1
= io
.smb2
.out
.file
.handle
;
1743 /* ask for a change notify,
1744 on file or directory name changes */
1745 ZERO_STRUCT(notify
.smb2
);
1746 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1747 notify
.smb2
.in
.buffer_size
= 1000;
1748 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1749 notify
.smb2
.in
.file
.handle
= h1
;
1750 notify
.smb2
.in
.recursive
= true;
1752 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
1754 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1755 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1757 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
1759 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
1760 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1762 smb2_util_mkdir(tree2
, BASEDIR
"\\subdir-name");
1763 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
1764 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
1766 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1767 CHECK_STATUS(status
, NT_STATUS_OK
);
1768 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1769 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
1771 smb2_util_mkdir(tree2
, BASEDIR
"\\subdir-name2");
1773 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
1774 CHECK_STATUS(status
, NT_STATUS_OK
);
1775 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1776 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name2");
1779 smb2_deltree(tree1
, BASEDIR
);
1785 test multiple change notifies at different depths and with/without recursion
1788 static bool torture_smb2_notify_tree(struct torture_context
*torture
,
1789 struct smb2_tree
*tree
)
1792 union smb_notify notify
;
1794 struct smb2_request
*req
;
1801 struct smb2_handle h1
;
1804 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 30 },
1805 {BASEDIR
"\\zqy", true, FILE_NOTIFY_CHANGE_NAME
, 8 },
1806 {BASEDIR
"\\atsy", true, FILE_NOTIFY_CHANGE_NAME
, 4 },
1807 {BASEDIR
"\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1808 {BASEDIR
"\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME
, 13 },
1809 {BASEDIR
"\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME
, 7 },
1810 {BASEDIR
"\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1811 {BASEDIR
"\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1812 {BASEDIR
"\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1813 {BASEDIR
"\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1814 {BASEDIR
"\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1815 {BASEDIR
"\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1816 {BASEDIR
"\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME
, 40 },
1817 {BASEDIR
, true, FILE_NOTIFY_CHANGE_NAME
, 40 },
1818 {BASEDIR
, false,FILE_NOTIFY_CHANGE_NAME
, 6 },
1819 {BASEDIR
"\\atsy", false,FILE_NOTIFY_CHANGE_NAME
, 4 },
1820 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 24 },
1821 {BASEDIR
"\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME
, 0 },
1822 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME
, 0 },
1823 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 24 },
1827 bool all_done
= false;
1829 smb2_deltree(tree
, BASEDIR
);
1830 smb2_util_rmdir(tree
, BASEDIR
);
1832 torture_comment(torture
, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1834 ZERO_STRUCT(io
.smb2
);
1835 io
.generic
.level
= RAW_OPEN_SMB2
;
1836 io
.smb2
.in
.create_flags
= 0;
1837 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1838 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1839 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1840 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1841 NTCREATEX_SHARE_ACCESS_WRITE
;
1842 io
.smb2
.in
.alloc_size
= 0;
1843 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1844 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1845 io
.smb2
.in
.security_flags
= 0;
1846 io
.smb2
.in
.fname
= BASEDIR
;
1847 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1848 CHECK_STATUS(status
, NT_STATUS_OK
);
1850 ZERO_STRUCT(notify
.smb2
);
1851 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1852 notify
.smb2
.in
.buffer_size
= 20000;
1855 setup the directory tree, and the notify buffer on each directory
1857 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1858 io
.smb2
.in
.fname
= dirs
[i
].path
;
1859 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1860 CHECK_STATUS(status
, NT_STATUS_OK
);
1861 dirs
[i
].h1
= io
.smb2
.out
.file
.handle
;
1863 notify
.smb2
.in
.completion_filter
= dirs
[i
].filter
;
1864 notify
.smb2
.in
.file
.handle
= dirs
[i
].h1
;
1865 notify
.smb2
.in
.recursive
= dirs
[i
].recursive
;
1866 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1868 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1869 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1872 /* trigger 2 events in each dir */
1873 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1874 char *path
= talloc_asprintf(torture
, "%s\\test.dir",
1876 smb2_util_mkdir(tree
, path
);
1877 smb2_util_rmdir(tree
, path
);
1881 /* give a bit of time for the events to propogate */
1882 tv
= timeval_current();
1885 /* count events that have happened in each dir */
1886 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1887 notify
.smb2
.in
.completion_filter
= dirs
[i
].filter
;
1888 notify
.smb2
.in
.file
.handle
= dirs
[i
].h1
;
1889 notify
.smb2
.in
.recursive
= dirs
[i
].recursive
;
1890 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1892 notify
.smb2
.out
.num_changes
= 0;
1893 status
= smb2_notify_recv(req
, torture
,
1895 dirs
[i
].counted
+= notify
.smb2
.out
.num_changes
;
1900 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1901 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
1905 } while (!all_done
&& timeval_elapsed(&tv
) < 20);
1907 torture_comment(torture
, "took %.4f seconds to propogate all events\n",
1908 timeval_elapsed(&tv
));
1910 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1911 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
1912 torture_comment(torture
,
1913 "ERROR: i=%d expected %d got %d for '%s'\n",
1914 i
, dirs
[i
].expected
, dirs
[i
].counted
,
1921 run from the back, closing and deleting
1923 for (i
=ARRAY_SIZE(dirs
)-1;i
>=0;i
--) {
1924 smb2_util_close(tree
, dirs
[i
].h1
);
1925 smb2_util_rmdir(tree
, dirs
[i
].path
);
1929 smb2_deltree(tree
, BASEDIR
);
1930 smb2_util_rmdir(tree
, BASEDIR
);
1935 Test response when cached server events exceed single NT NOTFIY response
1939 static bool torture_smb2_notify_overflow(struct torture_context
*torture
,
1940 struct smb2_tree
*tree
)
1944 union smb_notify notify
;
1946 struct smb2_handle h1
, h2
;
1948 struct smb2_request
*req1
;
1951 smb2_deltree(tree
, BASEDIR
);
1952 smb2_util_rmdir(tree
, BASEDIR
);
1954 torture_comment(torture
, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1956 /* get a handle on the directory */
1957 ZERO_STRUCT(io
.smb2
);
1958 io
.generic
.level
= RAW_OPEN_SMB2
;
1959 io
.smb2
.in
.create_flags
= 0;
1960 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1961 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1962 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1963 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1964 NTCREATEX_SHARE_ACCESS_WRITE
;
1965 io
.smb2
.in
.alloc_size
= 0;
1966 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1967 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1968 io
.smb2
.in
.security_flags
= 0;
1969 io
.smb2
.in
.fname
= BASEDIR
;
1971 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1972 CHECK_STATUS(status
, NT_STATUS_OK
);
1973 h1
= io
.smb2
.out
.file
.handle
;
1975 /* ask for a change notify, on name changes. */
1976 ZERO_STRUCT(notify
.smb2
);
1977 notify
.smb2
.level
= RAW_NOTIFY_NTTRANS
;
1978 notify
.smb2
.in
.buffer_size
= 1000;
1979 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1980 notify
.smb2
.in
.file
.handle
= h1
;
1982 notify
.smb2
.in
.recursive
= true;
1983 req1
= smb2_notify_send(tree
, &(notify
.smb2
));
1985 /* cancel initial requests so the buffer is setup */
1987 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1988 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1990 /* open a lot of files, filling up the server side notify buffer */
1991 torture_comment(torture
,
1992 "Testing overflowed buffer notify on create of %d files\n",
1995 for (i
=0;i
<count
;i
++) {
1996 char *fname
= talloc_asprintf(torture
,
1997 BASEDIR
"\\test%d.txt", i
);
1999 ZERO_STRUCT(io1
.smb2
);
2000 io1
.generic
.level
= RAW_OPEN_SMB2
;
2001 io1
.smb2
.in
.create_flags
= 0;
2002 io1
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
2003 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2004 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2005 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2006 NTCREATEX_SHARE_ACCESS_WRITE
;
2007 io1
.smb2
.in
.alloc_size
= 0;
2008 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2009 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
2010 io1
.smb2
.in
.security_flags
= 0;
2011 io1
.smb2
.in
.fname
= fname
;
2013 h2
= custom_smb2_create(tree
, torture
, &(io1
.smb2
));
2015 smb2_util_close(tree
, h2
);
2018 req1
= smb2_notify_send(tree
, &(notify
.smb2
));
2019 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
2020 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
2021 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
2024 smb2_deltree(tree
, BASEDIR
);
2029 Test if notifications are returned for changes to the base directory.
2033 static bool torture_smb2_notify_basedir(struct torture_context
*torture
,
2034 struct smb2_tree
*tree1
,
2035 struct smb2_tree
*tree2
)
2039 union smb_notify notify
;
2041 struct smb2_handle h1
;
2042 struct smb2_request
*req1
;
2044 smb2_deltree(tree1
, BASEDIR
);
2045 smb2_util_rmdir(tree1
, BASEDIR
);
2047 torture_comment(torture
, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
2049 /* get a handle on the directory */
2050 ZERO_STRUCT(io
.smb2
);
2051 io
.generic
.level
= RAW_OPEN_SMB2
;
2052 io
.smb2
.in
.create_flags
= 0;
2053 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
2054 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2055 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2056 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2057 NTCREATEX_SHARE_ACCESS_WRITE
;
2058 io
.smb2
.in
.alloc_size
= 0;
2059 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
2060 io
.smb2
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
2061 io
.smb2
.in
.security_flags
= 0;
2062 io
.smb2
.in
.fname
= BASEDIR
;
2064 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
2065 CHECK_STATUS(status
, NT_STATUS_OK
);
2066 h1
= io
.smb2
.out
.file
.handle
;
2068 /* create a test file that will also be modified */
2069 io
.smb2
.in
.fname
= BASEDIR
"\\tname1";
2070 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
2071 status
= smb2_create(tree2
, torture
, &(io
.smb2
));
2072 CHECK_STATUS(status
,NT_STATUS_OK
);
2073 smb2_util_close(tree2
, io
.smb2
.out
.file
.handle
);
2075 /* ask for a change notify, on attribute changes. */
2076 ZERO_STRUCT(notify
.smb2
);
2077 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
2078 notify
.smb2
.in
.buffer_size
= 1000;
2079 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
2080 notify
.smb2
.in
.file
.handle
= h1
;
2081 notify
.smb2
.in
.recursive
= true;
2083 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
2085 /* set attribute on the base dir */
2086 smb2_util_setatr(tree2
, BASEDIR
, FILE_ATTRIBUTE_HIDDEN
);
2088 /* set attribute on a file to assure we receive a notification */
2089 smb2_util_setatr(tree2
, BASEDIR
"\\tname1", FILE_ATTRIBUTE_HIDDEN
);
2092 /* check how many responses were given, expect only 1 for the file */
2093 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
2094 CHECK_STATUS(status
, NT_STATUS_OK
);
2095 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2096 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
2097 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "tname1");
2100 smb2_deltree(tree1
, BASEDIR
);
2105 very simple change notify test
2107 static bool torture_smb2_notify_tcon(struct torture_context
*torture
,
2108 struct smb2_tree
*tree
)
2112 union smb_notify notify
;
2114 struct smb2_handle h1
= {{0}};
2115 struct smb2_request
*req
= NULL
;
2116 struct smb2_tree
*tree1
= NULL
;
2117 const char *fname
= BASEDIR
"\\subdir-name";
2119 smb2_deltree(tree
, BASEDIR
);
2120 smb2_util_rmdir(tree
, BASEDIR
);
2122 torture_comment(torture
, "TESTING SIMPLE CHANGE NOTIFY\n");
2125 get a handle on the directory
2128 ZERO_STRUCT(io
.smb2
);
2129 io
.generic
.level
= RAW_OPEN_SMB2
;
2130 io
.smb2
.in
.create_flags
= 0;
2131 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
2132 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2133 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
|
2134 FILE_ATTRIBUTE_DIRECTORY
;
2135 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2136 NTCREATEX_SHARE_ACCESS_WRITE
;
2137 io
.smb2
.in
.alloc_size
= 0;
2138 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
2139 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
2140 io
.smb2
.in
.security_flags
= 0;
2141 io
.smb2
.in
.fname
= BASEDIR
;
2143 status
= smb2_create(tree
, torture
, &(io
.smb2
));
2144 CHECK_STATUS(status
, NT_STATUS_OK
);
2145 h1
= io
.smb2
.out
.file
.handle
;
2147 /* ask for a change notify,
2148 on file or directory name changes */
2149 ZERO_STRUCT(notify
.smb2
);
2150 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
2151 notify
.smb2
.in
.buffer_size
= 1000;
2152 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
2153 notify
.smb2
.in
.file
.handle
= h1
;
2154 notify
.smb2
.in
.recursive
= true;
2156 torture_comment(torture
, "Testing notify mkdir\n");
2157 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2159 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2160 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
2162 notify
.smb2
.in
.recursive
= true;
2163 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2164 status
= smb2_util_mkdir(tree
, fname
);
2165 CHECK_STATUS(status
, NT_STATUS_OK
);
2167 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2168 CHECK_STATUS(status
, NT_STATUS_OK
);
2170 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2171 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
2172 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2174 torture_comment(torture
, "Testing notify rmdir\n");
2175 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2176 status
= smb2_util_rmdir(tree
, fname
);
2177 CHECK_STATUS(status
, NT_STATUS_OK
);
2179 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2180 CHECK_STATUS(status
, NT_STATUS_OK
);
2181 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2182 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
2183 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2185 torture_comment(torture
, "SIMPLE CHANGE NOTIFY OK\n");
2187 torture_comment(torture
, "TESTING WITH SECONDARY TCON\n");
2188 if (!torture_smb2_tree_connect(torture
, tree
->session
, tree
, &tree1
)) {
2189 torture_warning(torture
, "couldn't reconnect to share, bailing\n");
2194 torture_comment(torture
, "tid1=%d tid2=%d\n",
2195 smb2cli_tcon_current_id(tree
->smbXcli
),
2196 smb2cli_tcon_current_id(tree1
->smbXcli
));
2198 torture_comment(torture
, "Testing notify mkdir\n");
2199 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2200 smb2_util_mkdir(tree1
, fname
);
2202 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2203 CHECK_STATUS(status
, NT_STATUS_OK
);
2205 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2206 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
2207 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2209 torture_comment(torture
, "Testing notify rmdir\n");
2210 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2211 smb2_util_rmdir(tree
, fname
);
2213 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2214 CHECK_STATUS(status
, NT_STATUS_OK
);
2215 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2216 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
2217 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2219 torture_comment(torture
, "CHANGE NOTIFY WITH TCON OK\n");
2221 torture_comment(torture
, "Disconnecting secondary tree\n");
2222 status
= smb2_tdis(tree1
);
2223 CHECK_STATUS(status
, NT_STATUS_OK
);
2226 torture_comment(torture
, "Testing notify mkdir\n");
2227 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2228 smb2_util_mkdir(tree
, fname
);
2230 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2231 CHECK_STATUS(status
, NT_STATUS_OK
);
2233 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2234 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
2235 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2237 torture_comment(torture
, "Testing notify rmdir\n");
2238 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2239 smb2_util_rmdir(tree
, fname
);
2241 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2242 CHECK_STATUS(status
, NT_STATUS_OK
);
2243 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2244 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
2245 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2247 torture_comment(torture
, "CHANGE NOTIFY WITH TDIS OK\n");
2249 smb2_util_close(tree
, h1
);
2250 smb2_deltree(tree
, BASEDIR
);
2255 static bool torture_smb2_notify_rmdir(struct torture_context
*torture
,
2256 struct smb2_tree
*tree1
,
2257 struct smb2_tree
*tree2
,
2258 bool initial_delete_on_close
)
2262 union smb_notify notify
= {};
2263 union smb_setfileinfo sfinfo
= {};
2264 union smb_open io
= {};
2265 struct smb2_handle h
= {};
2266 struct smb2_request
*req
;
2268 torture_comment(torture
, "TESTING NOTIFY CANCEL FOR DELETED DIR\n");
2270 smb2_deltree(tree1
, BASEDIR
);
2271 smb2_util_rmdir(tree1
, BASEDIR
);
2273 ZERO_STRUCT(io
.smb2
);
2274 io
.generic
.level
= RAW_OPEN_SMB2
;
2275 io
.smb2
.in
.create_flags
= 0;
2276 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
2277 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2278 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2279 io
.smb2
.in
.share_access
=
2280 NTCREATEX_SHARE_ACCESS_READ
|
2281 NTCREATEX_SHARE_ACCESS_WRITE
|
2282 NTCREATEX_SHARE_ACCESS_DELETE
;
2283 io
.smb2
.in
.alloc_size
= 0;
2284 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2285 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
2286 io
.smb2
.in
.security_flags
= 0;
2287 io
.smb2
.in
.fname
= BASEDIR
;
2289 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
2290 CHECK_STATUS(status
, NT_STATUS_OK
);
2291 h
= io
.smb2
.out
.file
.handle
;
2293 ZERO_STRUCT(notify
.smb2
);
2294 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
2295 notify
.smb2
.in
.buffer_size
= 1000;
2296 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
2297 notify
.smb2
.in
.file
.handle
= h
;
2298 notify
.smb2
.in
.recursive
= false;
2300 io
.smb2
.in
.desired_access
|= SEC_STD_DELETE
;
2301 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
2302 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
2304 if (initial_delete_on_close
) {
2305 status
= smb2_util_rmdir(tree2
, BASEDIR
);
2306 CHECK_STATUS(status
, NT_STATUS_OK
);
2308 status
= smb2_create(tree2
, torture
, &(io
.smb2
));
2309 CHECK_STATUS(status
, NT_STATUS_OK
);
2311 sfinfo
.generic
.level
= RAW_SFILEINFO_DISPOSITION_INFORMATION
;
2312 sfinfo
.generic
.in
.file
.handle
= io
.smb2
.out
.file
.handle
;
2313 sfinfo
.disposition_info
.in
.delete_on_close
= 1;
2314 status
= smb2_setinfo_file(tree2
, &sfinfo
);
2315 CHECK_STATUS(status
, NT_STATUS_OK
);
2317 smb2_util_close(tree2
, io
.smb2
.out
.file
.handle
);
2320 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2321 CHECK_STATUS(status
, NT_STATUS_DELETE_PENDING
);
2325 smb2_util_close(tree1
, h
);
2326 smb2_deltree(tree1
, BASEDIR
);
2331 static bool torture_smb2_notify_rmdir1(struct torture_context
*torture
,
2332 struct smb2_tree
*tree
)
2334 return torture_smb2_notify_rmdir(torture
, tree
, tree
, false);
2337 static bool torture_smb2_notify_rmdir2(struct torture_context
*torture
,
2338 struct smb2_tree
*tree
)
2340 return torture_smb2_notify_rmdir(torture
, tree
, tree
, true);
2343 static bool torture_smb2_notify_rmdir3(struct torture_context
*torture
,
2344 struct smb2_tree
*tree1
,
2345 struct smb2_tree
*tree2
)
2347 return torture_smb2_notify_rmdir(torture
, tree1
, tree2
, false);
2350 static bool torture_smb2_notify_rmdir4(struct torture_context
*torture
,
2351 struct smb2_tree
*tree1
,
2352 struct smb2_tree
*tree2
)
2354 return torture_smb2_notify_rmdir(torture
, tree1
, tree2
, true);
2358 basic testing of SMB2 change notify
2360 struct torture_suite
*torture_smb2_notify_init(void)
2362 struct torture_suite
*suite
= torture_suite_create(talloc_autofree_context(), "notify");
2364 torture_suite_add_1smb2_test(suite
, "valid-req", test_valid_request
);
2365 torture_suite_add_1smb2_test(suite
, "tcon", torture_smb2_notify_tcon
);
2366 torture_suite_add_2smb2_test(suite
, "dir", torture_smb2_notify_dir
);
2367 torture_suite_add_2smb2_test(suite
, "mask", torture_smb2_notify_mask
);
2368 torture_suite_add_1smb2_test(suite
, "tdis", torture_smb2_notify_tree_disconnect
);
2369 torture_suite_add_1smb2_test(suite
, "tdis1", torture_smb2_notify_tree_disconnect_1
);
2370 torture_suite_add_2smb2_test(suite
, "mask-change", torture_smb2_notify_mask_change
);
2371 torture_suite_add_1smb2_test(suite
, "close", torture_smb2_notify_close
);
2372 torture_suite_add_1smb2_test(suite
, "logoff", torture_smb2_notify_ulogoff
);
2373 torture_suite_add_1smb2_test(suite
, "session-reconnect", torture_smb2_notify_session_reconnect
);
2374 torture_suite_add_2smb2_test(suite
, "invalid-reauth", torture_smb2_notify_invalid_reauth
);
2375 torture_suite_add_1smb2_test(suite
, "tree", torture_smb2_notify_tree
);
2376 torture_suite_add_2smb2_test(suite
, "basedir", torture_smb2_notify_basedir
);
2377 torture_suite_add_2smb2_test(suite
, "double", torture_smb2_notify_double
);
2378 torture_suite_add_1smb2_test(suite
, "file", torture_smb2_notify_file
);
2379 torture_suite_add_1smb2_test(suite
, "tcp", torture_smb2_notify_tcp_disconnect
);
2380 torture_suite_add_2smb2_test(suite
, "rec", torture_smb2_notify_recursive
);
2381 torture_suite_add_1smb2_test(suite
, "overflow", torture_smb2_notify_overflow
);
2382 torture_suite_add_1smb2_test(suite
, "rmdir1",
2383 torture_smb2_notify_rmdir1
);
2384 torture_suite_add_1smb2_test(suite
, "rmdir2",
2385 torture_smb2_notify_rmdir2
);
2386 torture_suite_add_2smb2_test(suite
, "rmdir3",
2387 torture_smb2_notify_rmdir3
);
2388 torture_suite_add_2smb2_test(suite
, "rmdir4",
2389 torture_smb2_notify_rmdir4
);
2391 suite
->description
= talloc_strdup(suite
, "SMB2-NOTIFY tests");