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(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(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(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(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(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
, h2
;
238 struct smb2_request
*req
, *req2
;
239 const char *fname
= BASEDIR
"\\subdir-name";
240 extern int torture_numops
;
242 torture_comment(torture
, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
244 smb2_deltree(tree1
, BASEDIR
);
245 smb2_util_rmdir(tree1
, BASEDIR
);
247 get a handle on the directory
249 ZERO_STRUCT(io
.smb2
);
250 io
.generic
.level
= RAW_OPEN_SMB2
;
251 io
.smb2
.in
.create_flags
= 0;
252 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
253 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
254 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
255 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
256 NTCREATEX_SHARE_ACCESS_WRITE
;
257 io
.smb2
.in
.alloc_size
= 0;
258 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
259 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
260 io
.smb2
.in
.security_flags
= 0;
261 io
.smb2
.in
.fname
= BASEDIR
;
263 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
264 CHECK_STATUS(status
, NT_STATUS_OK
);
265 h1
= io
.smb2
.out
.file
.handle
;
267 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
268 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
;
269 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
270 CHECK_STATUS(status
, NT_STATUS_OK
);
271 h2
= io
.smb2
.out
.file
.handle
;
273 /* ask for a change notify,
274 on file or directory name changes */
275 ZERO_STRUCT(notify
.smb2
);
276 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
277 notify
.smb2
.in
.buffer_size
= 1000;
278 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
279 notify
.smb2
.in
.file
.handle
= h1
;
280 notify
.smb2
.in
.recursive
= true;
282 torture_comment(torture
, "Testing notify cancel\n");
284 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
286 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
287 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
289 torture_comment(torture
, "Testing notify mkdir\n");
291 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
292 smb2_util_mkdir(tree2
, fname
);
294 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
295 CHECK_STATUS(status
, NT_STATUS_OK
);
297 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
298 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
299 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
301 torture_comment(torture
, "Testing notify rmdir\n");
303 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
304 smb2_util_rmdir(tree2
, fname
);
306 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
307 CHECK_STATUS(status
, NT_STATUS_OK
);
308 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
309 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
310 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
312 torture_comment(torture
,
313 "Testing notify mkdir - rmdir - mkdir - rmdir\n");
315 smb2_util_mkdir(tree2
, fname
);
316 smb2_util_rmdir(tree2
, fname
);
317 smb2_util_mkdir(tree2
, fname
);
318 smb2_util_rmdir(tree2
, fname
);
320 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
321 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
322 CHECK_STATUS(status
, NT_STATUS_OK
);
323 CHECK_VAL(notify
.smb2
.out
.num_changes
, 4);
324 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
325 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
326 CHECK_VAL(notify
.smb2
.out
.changes
[1].action
, NOTIFY_ACTION_REMOVED
);
327 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[1].name
, "subdir-name");
328 CHECK_VAL(notify
.smb2
.out
.changes
[2].action
, NOTIFY_ACTION_ADDED
);
329 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[2].name
, "subdir-name");
330 CHECK_VAL(notify
.smb2
.out
.changes
[3].action
, NOTIFY_ACTION_REMOVED
);
331 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[3].name
, "subdir-name");
333 count
= torture_numops
;
334 torture_comment(torture
,
335 "Testing buffered notify on create of %d files\n", count
);
336 for (i
=0;i
<count
;i
++) {
337 struct smb2_handle h12
;
338 char *fname2
= talloc_asprintf(torture
, BASEDIR
"\\test%d.txt",
341 ZERO_STRUCT(io
.smb2
);
342 io
.generic
.level
= RAW_OPEN_SMB2
;
343 io
.smb2
.in
.create_flags
= 0;
344 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
345 io
.smb2
.in
.create_options
=
346 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
347 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
348 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
349 NTCREATEX_SHARE_ACCESS_WRITE
;
350 io
.smb2
.in
.alloc_size
= 0;
351 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
352 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
353 io
.smb2
.in
.security_flags
= 0;
354 io
.smb2
.in
.fname
= fname2
;
356 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
357 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OK
)) {
358 torture_comment(torture
, "Failed to create %s \n",
363 h12
= io
.smb2
.out
.file
.handle
;
365 smb2_util_close(tree1
, h12
);
368 /* (1st notify) setup a new notify on a different directory handle.
369 This new notify won't see the events above. */
370 notify
.smb2
.in
.file
.handle
= h2
;
371 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
373 /* (2nd notify) whereas this notify will see the above buffered events,
374 and it directly returns the buffered events */
375 notify
.smb2
.in
.file
.handle
= h1
;
376 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
378 status
= smb2_util_unlink(tree1
, BASEDIR
"\\nonexistent.txt");
379 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
381 /* (1st unlink) as the 2nd notify directly returns,
382 this unlink is only seen by the 1st notify and
383 the 3rd notify (later) */
384 torture_comment(torture
,
385 "Testing notify on unlink for the first file\n");
386 status
= smb2_util_unlink(tree2
, BASEDIR
"\\test0.txt");
387 CHECK_STATUS(status
, NT_STATUS_OK
);
389 /* receive the reply from the 2nd notify */
390 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
391 CHECK_STATUS(status
, NT_STATUS_OK
);
393 CHECK_VAL(notify
.smb2
.out
.num_changes
, count
);
394 for (i
=1;i
<count
;i
++) {
395 CHECK_VAL(notify
.smb2
.out
.changes
[i
].action
,
396 NOTIFY_ACTION_ADDED
);
398 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "test0.txt");
400 torture_comment(torture
, "and now from the 1st notify\n");
401 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
402 CHECK_STATUS(status
, NT_STATUS_OK
);
403 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
404 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
405 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "test0.txt");
407 torture_comment(torture
,
408 "(3rd notify) this notify will only see the 1st unlink\n");
409 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
411 status
= smb2_util_unlink(tree1
, BASEDIR
"\\nonexistent.txt");
412 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
414 for (i
=1;i
<count
;i
++) {
415 char *fname2
= talloc_asprintf(torture
,
416 BASEDIR
"\\test%d.txt", i
);
417 status
= smb2_util_unlink(tree2
, fname2
);
418 CHECK_STATUS(status
, NT_STATUS_OK
);
422 /* receive the 3rd notify */
423 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
424 CHECK_STATUS(status
, NT_STATUS_OK
);
425 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
426 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
427 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "test0.txt");
429 /* and we now see the rest of the unlink calls on both
430 * directory handles */
431 notify
.smb2
.in
.file
.handle
= h1
;
433 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
434 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
435 CHECK_STATUS(status
, NT_STATUS_OK
);
436 CHECK_VAL(notify
.smb2
.out
.num_changes
, count
-1);
437 for (i
=0;i
<notify
.smb2
.out
.num_changes
;i
++) {
438 CHECK_VAL(notify
.smb2
.out
.changes
[i
].action
,
439 NOTIFY_ACTION_REMOVED
);
441 notify
.smb2
.in
.file
.handle
= h2
;
442 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
443 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
444 CHECK_STATUS(status
, NT_STATUS_OK
);
445 CHECK_VAL(notify
.smb2
.out
.num_changes
, count
-1);
446 for (i
=0;i
<notify
.smb2
.out
.num_changes
;i
++) {
447 CHECK_VAL(notify
.smb2
.out
.changes
[i
].action
,
448 NOTIFY_ACTION_REMOVED
);
451 torture_comment(torture
,
452 "Testing if a close() on the dir handle triggers the notify reply\n");
454 notify
.smb2
.in
.file
.handle
= h1
;
455 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
457 ZERO_STRUCT(cl
.smb2
);
458 cl
.smb2
.level
= RAW_CLOSE_SMB2
;
459 cl
.smb2
.in
.file
.handle
= h1
;
460 status
= smb2_close(tree1
, &(cl
.smb2
));
461 CHECK_STATUS(status
, NT_STATUS_OK
);
463 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
464 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
465 CHECK_VAL(notify
.smb2
.out
.num_changes
, 9);
468 smb2_util_close(tree1
, h1
);
469 smb2_util_close(tree1
, h2
);
470 smb2_deltree(tree1
, BASEDIR
);
474 static struct smb2_handle
custom_smb2_create(struct smb2_tree
*tree
,
475 struct torture_context
*torture
,
476 struct smb2_create
*smb2
)
478 struct smb2_handle h1
;
481 smb2_deltree(tree
, smb2
->in
.fname
);
482 status
= smb2_create(tree
, torture
, smb2
);
483 CHECK_STATUS(status
, NT_STATUS_OK
);
484 h1
= smb2
->out
.file
.handle
;
487 h1
= (struct smb2_handle
) {
495 testing of recursive change notify
498 static bool torture_smb2_notify_recursive(struct torture_context
*torture
,
499 struct smb2_tree
*tree1
,
500 struct smb2_tree
*tree2
)
504 union smb_notify notify
;
505 union smb_open io
, io1
;
506 union smb_setfileinfo sinfo
;
507 struct smb2_handle h1
;
508 struct smb2_request
*req1
, *req2
;
510 smb2_deltree(tree1
, BASEDIR
);
511 smb2_util_rmdir(tree1
, BASEDIR
);
513 torture_comment(torture
, "TESTING CHANGE NOTIFY WITH RECURSION\n");
516 get a handle on the directory
518 ZERO_STRUCT(io
.smb2
);
519 io
.generic
.level
= RAW_OPEN_SMB2
;
520 io
.smb2
.in
.create_flags
= 0;
521 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
522 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
523 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
524 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
525 NTCREATEX_SHARE_ACCESS_WRITE
;
526 io
.smb2
.in
.alloc_size
= 0;
527 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
528 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
529 io
.smb2
.in
.security_flags
= 0;
530 io
.smb2
.in
.fname
= BASEDIR
;
532 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
533 CHECK_STATUS(status
, NT_STATUS_OK
);
534 h1
= io
.smb2
.out
.file
.handle
;
536 /* ask for a change notify, on file or directory name
537 changes. Setup both with and without recursion */
538 ZERO_STRUCT(notify
.smb2
);
539 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
540 notify
.smb2
.in
.buffer_size
= 1000;
541 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
|
542 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
543 FILE_NOTIFY_CHANGE_CREATION
;
544 notify
.smb2
.in
.file
.handle
= h1
;
546 notify
.smb2
.in
.recursive
= true;
547 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
549 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
550 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
552 notify
.smb2
.in
.recursive
= false;
553 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
555 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
556 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
558 ZERO_STRUCT(io1
.smb2
);
559 io1
.generic
.level
= RAW_OPEN_SMB2
;
560 io1
.smb2
.in
.create_flags
= NTCREATEX_FLAGS_EXTENDED
;
561 io1
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
562 SEC_RIGHTS_FILE_WRITE
|
564 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
565 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
566 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
567 NTCREATEX_SHARE_ACCESS_WRITE
|
568 NTCREATEX_SHARE_ACCESS_DELETE
;
569 io1
.smb2
.in
.alloc_size
= 0;
570 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
571 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
572 io1
.smb2
.in
.security_flags
= 0;
573 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name";
574 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
575 CHECK_STATUS(status
, NT_STATUS_OK
);
576 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
578 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname1";
579 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
580 CHECK_STATUS(status
, NT_STATUS_OK
);
582 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
583 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
584 sinfo
.rename_information
.in
.overwrite
= 0;
585 sinfo
.rename_information
.in
.root_fid
= 0;
586 sinfo
.rename_information
.in
.new_name
=
587 BASEDIR
"\\subdir-name\\subname1-r";
588 status
= smb2_setinfo_file(tree2
, &sinfo
);
589 CHECK_STATUS(status
, NT_STATUS_OK
);
591 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
592 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname2";
593 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
594 CHECK_STATUS(status
, NT_STATUS_OK
);
596 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
597 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
598 sinfo
.rename_information
.in
.overwrite
= true;
599 sinfo
.rename_information
.in
.root_fid
= 0;
600 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname2-r";
601 status
= smb2_setinfo_file(tree2
, &sinfo
);
602 CHECK_STATUS(status
, NT_STATUS_OK
);
604 io1
.smb2
.in
.fname
= BASEDIR
"\\subname2-r";
605 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
606 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
607 CHECK_STATUS(status
, NT_STATUS_OK
);
609 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
610 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
611 sinfo
.rename_information
.in
.overwrite
= true;
612 sinfo
.rename_information
.in
.root_fid
= 0;
613 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname3-r";
614 status
= smb2_setinfo_file(tree2
, &sinfo
);
615 CHECK_STATUS(status
, NT_STATUS_OK
);
617 notify
.smb2
.in
.completion_filter
= 0;
618 notify
.smb2
.in
.recursive
= true;
620 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
622 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name\\subname1-r");
623 CHECK_STATUS(status
, NT_STATUS_OK
);
624 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name");
625 CHECK_STATUS(status
, NT_STATUS_OK
);
626 status
= smb2_util_unlink(tree2
, BASEDIR
"\\subname3-r");
627 CHECK_STATUS(status
, NT_STATUS_OK
);
629 notify
.smb2
.in
.recursive
= false;
630 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
632 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
633 CHECK_STATUS(status
, NT_STATUS_OK
);
635 CHECK_VAL(notify
.smb2
.out
.num_changes
, 9);
636 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
637 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
638 CHECK_VAL(notify
.smb2
.out
.changes
[1].action
, NOTIFY_ACTION_ADDED
);
639 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[1].name
, "subdir-name\\subname1");
640 CHECK_VAL(notify
.smb2
.out
.changes
[2].action
, NOTIFY_ACTION_OLD_NAME
);
641 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[2].name
, "subdir-name\\subname1");
642 CHECK_VAL(notify
.smb2
.out
.changes
[3].action
, NOTIFY_ACTION_NEW_NAME
);
643 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[3].name
, "subdir-name\\subname1-r");
644 CHECK_VAL(notify
.smb2
.out
.changes
[4].action
, NOTIFY_ACTION_ADDED
);
645 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[4].name
, "subdir-name\\subname2");
646 CHECK_VAL(notify
.smb2
.out
.changes
[5].action
, NOTIFY_ACTION_REMOVED
);
647 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[5].name
, "subdir-name\\subname2");
648 CHECK_VAL(notify
.smb2
.out
.changes
[6].action
, NOTIFY_ACTION_ADDED
);
649 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[6].name
, "subname2-r");
650 CHECK_VAL(notify
.smb2
.out
.changes
[7].action
, NOTIFY_ACTION_OLD_NAME
);
651 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[7].name
, "subname2-r");
652 CHECK_VAL(notify
.smb2
.out
.changes
[8].action
, NOTIFY_ACTION_NEW_NAME
);
653 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[8].name
, "subname3-r");
656 smb2_deltree(tree1
, BASEDIR
);
661 testing of change notify mask change
664 static bool torture_smb2_notify_mask_change(struct torture_context
*torture
,
665 struct smb2_tree
*tree1
,
666 struct smb2_tree
*tree2
)
670 union smb_notify notify
;
671 union smb_open io
, io1
;
672 struct smb2_handle h1
;
673 struct smb2_request
*req1
, *req2
;
674 union smb_setfileinfo sinfo
;
676 smb2_deltree(tree1
, BASEDIR
);
677 smb2_util_rmdir(tree1
, BASEDIR
);
679 torture_comment(torture
, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
682 get a handle on the directory
684 ZERO_STRUCT(io
.smb2
);
685 io
.generic
.level
= RAW_OPEN_SMB2
;
686 io
.smb2
.in
.create_flags
= 0;
687 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
688 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
689 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
690 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
691 NTCREATEX_SHARE_ACCESS_WRITE
;
692 io
.smb2
.in
.alloc_size
= 0;
693 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
694 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
695 io
.smb2
.in
.security_flags
= 0;
696 io
.smb2
.in
.fname
= BASEDIR
;
698 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
699 CHECK_STATUS(status
, NT_STATUS_OK
);
700 h1
= io
.smb2
.out
.file
.handle
;
702 /* ask for a change notify, on file or directory name
703 changes. Setup both with and without recursion */
704 ZERO_STRUCT(notify
.smb2
);
705 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
706 notify
.smb2
.in
.buffer_size
= 1000;
707 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
708 notify
.smb2
.in
.file
.handle
= h1
;
710 notify
.smb2
.in
.recursive
= true;
711 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
714 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
715 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
718 notify
.smb2
.in
.recursive
= false;
719 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
722 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
723 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
725 notify
.smb2
.in
.recursive
= true;
726 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
728 /* Set to hidden then back again. */
729 ZERO_STRUCT(io1
.smb2
);
730 io1
.generic
.level
= RAW_OPEN_SMB2
;
731 io1
.smb2
.in
.create_flags
= 0;
732 io1
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
733 SEC_RIGHTS_FILE_WRITE
|
735 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
736 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
737 NTCREATEX_SHARE_ACCESS_WRITE
|
738 NTCREATEX_SHARE_ACCESS_DELETE
;
739 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
740 io1
.smb2
.in
.security_flags
= 0;
741 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
742 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
743 io1
.smb2
.in
.fname
= BASEDIR
"\\tname1";
745 smb2_util_close(tree1
,
746 custom_smb2_create(tree1
, torture
, &(io1
.smb2
)));
747 status
= smb2_util_setatr(tree1
, BASEDIR
"\\tname1",
748 FILE_ATTRIBUTE_HIDDEN
);
749 CHECK_STATUS(status
, NT_STATUS_OK
);
750 smb2_util_unlink(tree1
, BASEDIR
"\\tname1");
752 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
753 CHECK_STATUS(status
, NT_STATUS_OK
);
755 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
756 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
757 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "tname1");
759 /* Now try and change the mask to include other events.
760 * This should not work - once the mask is set on a directory
761 * h1 it seems to be fixed until the fnum is closed. */
763 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
|
764 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
765 FILE_NOTIFY_CHANGE_CREATION
;
766 notify
.smb2
.in
.recursive
= true;
767 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
769 notify
.smb2
.in
.recursive
= false;
770 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
772 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
773 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
774 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name";
775 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
776 CHECK_STATUS(status
, NT_STATUS_OK
);
777 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
780 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname1";
781 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
782 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
783 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
784 CHECK_STATUS(status
, NT_STATUS_OK
);
785 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
786 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
787 sinfo
.rename_information
.in
.overwrite
= true;
788 sinfo
.rename_information
.in
.root_fid
= 0;
789 sinfo
.rename_information
.in
.new_name
=
790 BASEDIR
"\\subdir-name\\subname1-r";
791 status
= smb2_setinfo_file(tree2
, &sinfo
);
792 CHECK_STATUS(status
, NT_STATUS_OK
);
794 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname2";
795 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
796 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
797 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
798 CHECK_STATUS(status
, NT_STATUS_OK
);
799 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
800 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname2-r";
801 status
= smb2_setinfo_file(tree2
, &sinfo
);
802 CHECK_STATUS(status
, NT_STATUS_OK
);
803 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
805 io1
.smb2
.in
.fname
= BASEDIR
"\\subname2-r";
806 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
807 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
808 CHECK_STATUS(status
, NT_STATUS_OK
);
809 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
810 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname3-r";
811 status
= smb2_setinfo_file(tree2
, &sinfo
);
812 CHECK_STATUS(status
, NT_STATUS_OK
);
813 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
815 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name\\subname1-r");
816 CHECK_STATUS(status
, NT_STATUS_OK
);
817 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name");
818 CHECK_STATUS(status
, NT_STATUS_OK
);
819 status
= smb2_util_unlink(tree2
, BASEDIR
"\\subname3-r");
820 CHECK_STATUS(status
, NT_STATUS_OK
);
822 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
823 CHECK_STATUS(status
, NT_STATUS_OK
);
825 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
826 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
827 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subname2-r");
829 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
830 CHECK_STATUS(status
, NT_STATUS_OK
);
832 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
833 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
834 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subname3-r");
841 smb2_deltree(tree1
, BASEDIR
);
846 testing of mask bits for change notify
849 static bool torture_smb2_notify_mask(struct torture_context
*torture
,
850 struct smb2_tree
*tree1
,
851 struct smb2_tree
*tree2
)
855 union smb_notify notify
;
856 union smb_open io
, io1
;
857 struct smb2_handle h1
, h2
;
861 union smb_setfileinfo sinfo
;
863 smb2_deltree(tree1
, BASEDIR
);
864 smb2_util_rmdir(tree1
, BASEDIR
);
866 torture_comment(torture
, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
872 get a handle on the directory
874 ZERO_STRUCT(io
.smb2
);
875 io
.generic
.level
= RAW_OPEN_SMB2
;
876 io
.smb2
.in
.create_flags
= 0;
877 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
878 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
879 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
880 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
881 NTCREATEX_SHARE_ACCESS_WRITE
;
882 io
.smb2
.in
.alloc_size
= 0;
883 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
884 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
885 io
.smb2
.in
.security_flags
= 0;
886 io
.smb2
.in
.fname
= BASEDIR
;
888 ZERO_STRUCT(notify
.smb2
);
889 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
890 notify
.smb2
.in
.buffer_size
= 1000;
891 notify
.smb2
.in
.recursive
= true;
893 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
894 expected, nchanges) \
896 do { for (mask=i=0;i<32;i++) { \
897 struct smb2_request *req; \
898 status = smb2_create(tree1, torture, &(io.smb2)); \
899 CHECK_STATUS(status, NT_STATUS_OK); \
900 h1 = io.smb2.out.file.handle; \
902 notify.smb2.in.file.handle = h1; \
903 notify.smb2.in.completion_filter = (1<<i); \
904 /* cancel initial requests so the buffer is setup */ \
905 req = smb2_notify_send(tree1, &(notify.smb2)); \
907 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
908 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
909 /* send the change notify request */ \
910 req = smb2_notify_send(tree1, &(notify.smb2)); \
912 smb_msleep(200); smb2_cancel(req); \
913 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
915 smb2_util_close(tree1, h1); \
916 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
917 CHECK_STATUS(status, NT_STATUS_OK); \
918 /* special case to cope with file rename behaviour */ \
919 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
920 notify.smb2.out.changes[0].action == \
921 NOTIFY_ACTION_MODIFIED && \
922 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
923 Action == NOTIFY_ACTION_OLD_NAME) { \
924 torture_comment(torture, \
925 "(rename file special handling OK)\n"); \
926 } else if (nchanges != notify.smb2.out.num_changes) { \
927 torture_result(torture, TORTURE_FAIL, \
928 "ERROR: nchanges=%d expected=%d "\
929 "action=%d filter=0x%08x\n", \
930 notify.smb2.out.num_changes, \
932 notify.smb2.out.changes[0].action, \
933 notify.smb2.in.completion_filter); \
935 } else if (notify.smb2.out.changes[0].action != Action) { \
936 torture_result(torture, TORTURE_FAIL, \
937 "ERROR: nchanges=%d action=%d " \
938 "expectedAction=%d filter=0x%08x\n", \
939 notify.smb2.out.num_changes, \
940 notify.smb2.out.changes[0].action, \
942 notify.smb2.in.completion_filter); \
944 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
946 torture_result(torture, TORTURE_FAIL, \
947 "ERROR: nchanges=%d action=%d " \
948 "filter=0x%08x name=%s\n", \
949 notify.smb2.out.num_changes, \
950 notify.smb2.out.changes[0].action, \
951 notify.smb2.in.completion_filter, \
952 notify.smb2.out.changes[0].name.s); \
960 torture_comment(torture
, "Testing mkdir\n");
961 NOTIFY_MASK_TEST("Testing mkdir",;,
962 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
963 smb2_util_rmdir(tree2
, BASEDIR
"\\tname1");,
965 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
967 torture_comment(torture
, "Testing create file\n");
968 ZERO_STRUCT(io1
.smb2
);
969 io1
.generic
.level
= RAW_OPEN_SMB2
;
970 io1
.smb2
.in
.create_flags
= 0;
971 io1
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
972 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
973 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
974 NTCREATEX_SHARE_ACCESS_WRITE
;
975 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
976 io1
.smb2
.in
.security_flags
= 0;
977 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
978 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
979 io1
.smb2
.in
.fname
= BASEDIR
"\\tname1";
981 NOTIFY_MASK_TEST("Testing create file",;,
982 smb2_util_close(tree2
, custom_smb2_create(tree2
,
983 torture
, &(io1
.smb2
)));,
984 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
986 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
988 torture_comment(torture
, "Testing unlink\n");
989 NOTIFY_MASK_TEST("Testing unlink",
990 smb2_util_close(tree2
, custom_smb2_create(tree2
,
991 torture
, &(io1
.smb2
)));,
992 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
994 NOTIFY_ACTION_REMOVED
,
995 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
997 torture_comment(torture
, "Testing rmdir\n");
998 NOTIFY_MASK_TEST("Testing rmdir",
999 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
1000 smb2_util_rmdir(tree2
, BASEDIR
"\\tname1");,
1002 NOTIFY_ACTION_REMOVED
,
1003 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
1005 torture_comment(torture
, "Testing rename file\n");
1007 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1008 sinfo
.rename_information
.in
.file
.handle
= h1
;
1009 sinfo
.rename_information
.in
.overwrite
= true;
1010 sinfo
.rename_information
.in
.root_fid
= 0;
1011 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\tname2";
1012 NOTIFY_MASK_TEST("Testing rename file",
1013 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1014 torture
, &(io1
.smb2
)));,
1015 smb2_setinfo_file(tree2
, &sinfo
);,
1016 smb2_util_unlink(tree2
, BASEDIR
"\\tname2");,
1017 NOTIFY_ACTION_OLD_NAME
,
1018 FILE_NOTIFY_CHANGE_FILE_NAME
, 2);
1020 torture_comment(torture
, "Testing rename dir\n");
1022 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1023 sinfo
.rename_information
.in
.file
.handle
= h1
;
1024 sinfo
.rename_information
.in
.overwrite
= true;
1025 sinfo
.rename_information
.in
.root_fid
= 0;
1026 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\tname2";
1027 NOTIFY_MASK_TEST("Testing rename dir",
1028 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
1029 smb2_setinfo_file(tree2
, &sinfo
);,
1030 smb2_util_rmdir(tree2
, BASEDIR
"\\tname2");,
1031 NOTIFY_ACTION_OLD_NAME
,
1032 FILE_NOTIFY_CHANGE_DIR_NAME
, 2);
1034 torture_comment(torture
, "Testing set path attribute\n");
1035 NOTIFY_MASK_TEST("Testing set path attribute",
1036 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1037 torture
, &(io
.smb2
)));,
1038 smb2_util_setatr(tree2
, BASEDIR
"\\tname1",
1039 FILE_ATTRIBUTE_HIDDEN
);,
1040 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
1041 NOTIFY_ACTION_MODIFIED
,
1042 FILE_NOTIFY_CHANGE_ATTRIBUTES
, 1);
1044 torture_comment(torture
, "Testing set path write time\n");
1046 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1047 sinfo
.generic
.in
.file
.handle
= h1
;
1048 sinfo
.basic_info
.in
.write_time
= 1000;
1049 NOTIFY_MASK_TEST("Testing set path write time",
1050 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1051 torture
, &(io1
.smb2
)));,
1052 smb2_setinfo_file(tree2
, &sinfo
);,
1053 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
1054 NOTIFY_ACTION_MODIFIED
,
1055 FILE_NOTIFY_CHANGE_LAST_WRITE
, 1);
1057 if (torture_setting_bool(torture
, "samba3", false)) {
1058 torture_comment(torture
,
1059 "Samba3 does not yet support create times "
1064 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1065 sinfo
.generic
.in
.file
.handle
= h1
;
1066 sinfo
.basic_info
.in
.create_time
= 0;
1067 torture_comment(torture
, "Testing set file create time\n");
1068 NOTIFY_MASK_TEST("Testing set file create time",
1069 smb2_create_complex_file(tree2
,
1070 BASEDIR
"\\tname1", &h2
);,
1071 smb2_setinfo_file(tree2
, &sinfo
);,
1072 (smb2_util_close(tree2
, h2
),
1073 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1074 NOTIFY_ACTION_MODIFIED
,
1075 FILE_NOTIFY_CHANGE_CREATION
, 1);
1079 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1080 sinfo
.generic
.in
.file
.handle
= h1
;
1081 sinfo
.basic_info
.in
.access_time
= 0;
1082 torture_comment(torture
, "Testing set file access time\n");
1083 NOTIFY_MASK_TEST("Testing set file access time",
1084 smb2_create_complex_file(tree2
, BASEDIR
"\\tname1", &h2
);,
1085 smb2_setinfo_file(tree2
, &sinfo
);,
1086 (smb2_util_close(tree2
, h2
),
1087 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1088 NOTIFY_ACTION_MODIFIED
,
1089 FILE_NOTIFY_CHANGE_LAST_ACCESS
, 1);
1092 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1093 sinfo
.generic
.in
.file
.handle
= h1
;
1094 sinfo
.basic_info
.in
.change_time
= 0;
1095 torture_comment(torture
, "Testing set file change time\n");
1096 NOTIFY_MASK_TEST("Testing set file change time",
1097 smb2_create_complex_file(tree2
, BASEDIR
"\\tname1", &h2
);,
1098 smb2_setinfo_file(tree2
, &sinfo
);,
1099 (smb2_util_close(tree2
, h2
),
1100 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1101 NOTIFY_ACTION_MODIFIED
,
1105 torture_comment(torture
, "Testing write\n");
1106 NOTIFY_MASK_TEST("Testing write",
1107 smb2_create_complex_file(tree2
, BASEDIR
"\\tname1", &h2
);,
1108 smb2_util_write(tree2
, h2
, &c
, 10000, 1);,
1109 (smb2_util_close(tree2
, h2
),
1110 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1111 NOTIFY_ACTION_MODIFIED
,
1115 smb2_deltree(tree1
, BASEDIR
);
1120 basic testing of change notify on files
1122 static bool torture_smb2_notify_file(struct torture_context
*torture
,
1123 struct smb2_tree
*tree
)
1129 union smb_notify notify
;
1130 struct smb2_request
*req
;
1131 struct smb2_handle h1
;
1132 const char *fname
= BASEDIR
"\\file.txt";
1134 smb2_deltree(tree
, BASEDIR
);
1135 smb2_util_rmdir(tree
, BASEDIR
);
1137 torture_comment(torture
, "TESTING CHANGE NOTIFY ON FILES\n");
1138 status
= torture_smb2_testdir(tree
, BASEDIR
, &h1
);
1139 CHECK_STATUS(status
, NT_STATUS_OK
);
1141 ZERO_STRUCT(io
.smb2
);
1142 io
.generic
.level
= RAW_OPEN_SMB2
;
1143 io
.smb2
.in
.create_flags
= 0;
1144 io
.smb2
.in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
;
1145 io
.smb2
.in
.create_options
= 0;
1146 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1147 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1148 NTCREATEX_SHARE_ACCESS_WRITE
;
1149 io
.smb2
.in
.alloc_size
= 0;
1150 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1151 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1152 io
.smb2
.in
.security_flags
= 0;
1153 io
.smb2
.in
.fname
= fname
;
1154 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1155 CHECK_STATUS(status
, NT_STATUS_OK
);
1156 h1
= io
.smb2
.out
.file
.handle
;
1158 /* ask for a change notify,
1159 on file or directory name changes */
1160 ZERO_STRUCT(notify
.smb2
);
1161 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1162 notify
.smb2
.in
.file
.handle
= h1
;
1163 notify
.smb2
.in
.buffer_size
= 1000;
1164 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_STREAM_NAME
;
1165 notify
.smb2
.in
.recursive
= false;
1167 torture_comment(torture
,
1168 "Testing if notifies on file handles are invalid (should be)\n");
1170 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1171 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1172 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1174 ZERO_STRUCT(cl
.smb2
);
1175 cl
.close
.level
= RAW_CLOSE_SMB2
;
1176 cl
.close
.in
.file
.handle
= h1
;
1177 status
= smb2_close(tree
, &(cl
.smb2
));
1178 CHECK_STATUS(status
, NT_STATUS_OK
);
1180 status
= smb2_util_unlink(tree
, fname
);
1181 CHECK_STATUS(status
, NT_STATUS_OK
);
1184 smb2_deltree(tree
, BASEDIR
);
1188 basic testing of change notifies followed by a tdis
1191 static bool torture_smb2_notify_tree_disconnect(
1192 struct torture_context
*torture
,
1193 struct smb2_tree
*tree
)
1197 union smb_notify notify
;
1199 struct smb2_handle h1
;
1200 struct smb2_request
*req
;
1202 smb2_deltree(tree
, BASEDIR
);
1203 smb2_util_rmdir(tree
, BASEDIR
);
1205 torture_comment(torture
, "TESTING CHANGE NOTIFY+CANCEL FOLLOWED BY "
1206 "TREE-DISCONNECT\n");
1209 get a handle on the directory
1211 ZERO_STRUCT(io
.smb2
);
1212 io
.generic
.level
= RAW_OPEN_SMB2
;
1213 io
.smb2
.in
.create_flags
= 0;
1214 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1215 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1216 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1217 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1218 NTCREATEX_SHARE_ACCESS_WRITE
;
1219 io
.smb2
.in
.alloc_size
= 0;
1220 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1221 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1222 io
.smb2
.in
.security_flags
= 0;
1223 io
.smb2
.in
.fname
= BASEDIR
;
1225 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1226 CHECK_STATUS(status
, NT_STATUS_OK
);
1227 h1
= io
.smb2
.out
.file
.handle
;
1229 /* ask for a change notify,
1230 on file or directory name changes */
1231 ZERO_STRUCT(notify
.smb2
);
1232 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1233 notify
.smb2
.in
.buffer_size
= 1000;
1234 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1235 notify
.smb2
.in
.file
.handle
= h1
;
1236 notify
.smb2
.in
.recursive
= true;
1238 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1240 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1242 status
= smb2_tdis(tree
);
1243 CHECK_STATUS(status
, NT_STATUS_OK
);
1245 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1247 smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1248 CHECK_STATUS(status
, NT_STATUS_OK
);
1249 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1252 smb2_deltree(tree
, BASEDIR
);
1257 testing of change notifies followed by a tdis - no cancel
1260 static bool torture_smb2_notify_tree_disconnect_1(
1261 struct torture_context
*torture
,
1262 struct smb2_tree
*tree
)
1266 union smb_notify notify
;
1268 struct smb2_handle h1
;
1269 struct smb2_request
*req
;
1271 smb2_deltree(tree
, BASEDIR
);
1272 smb2_util_rmdir(tree
, BASEDIR
);
1274 torture_comment(torture
, "TESTING CHANGE NOTIFY ASYNC FOLLOWED BY "
1275 "TREE-DISCONNECT\n");
1278 get a handle on the directory
1280 ZERO_STRUCT(io
.smb2
);
1281 io
.generic
.level
= RAW_OPEN_SMB2
;
1282 io
.smb2
.in
.create_flags
= 0;
1283 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1284 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1285 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1286 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1287 NTCREATEX_SHARE_ACCESS_WRITE
;
1288 io
.smb2
.in
.alloc_size
= 0;
1289 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1290 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1291 io
.smb2
.in
.security_flags
= 0;
1292 io
.smb2
.in
.fname
= BASEDIR
;
1294 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1295 CHECK_STATUS(status
, NT_STATUS_OK
);
1296 h1
= io
.smb2
.out
.file
.handle
;
1298 /* ask for a change notify,
1299 on file or directory name changes */
1300 ZERO_STRUCT(notify
.smb2
);
1301 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1302 notify
.smb2
.in
.buffer_size
= 1000;
1303 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1304 notify
.smb2
.in
.file
.handle
= h1
;
1305 notify
.smb2
.in
.recursive
= true;
1307 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1308 WAIT_FOR_ASYNC_RESPONSE(req
);
1310 status
= smb2_tdis(tree
);
1311 CHECK_STATUS(status
, NT_STATUS_OK
);
1313 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1314 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
1315 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1318 smb2_deltree(tree
, BASEDIR
);
1323 basic testing of change notifies followed by a close
1326 static bool torture_smb2_notify_close(struct torture_context
*torture
,
1327 struct smb2_tree
*tree1
)
1331 union smb_notify notify
;
1333 struct smb2_handle h1
;
1334 struct smb2_request
*req
;
1336 smb2_deltree(tree1
, BASEDIR
);
1337 smb2_util_rmdir(tree1
, BASEDIR
);
1339 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1342 get a handle on the directory
1344 ZERO_STRUCT(io
.smb2
);
1345 io
.generic
.level
= RAW_OPEN_SMB2
;
1346 io
.smb2
.in
.create_flags
= 0;
1347 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1348 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1349 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1350 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1351 NTCREATEX_SHARE_ACCESS_WRITE
;
1352 io
.smb2
.in
.alloc_size
= 0;
1353 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1354 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1355 io
.smb2
.in
.security_flags
= 0;
1356 io
.smb2
.in
.fname
= BASEDIR
;
1358 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1359 CHECK_STATUS(status
, NT_STATUS_OK
);
1361 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1362 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1363 CHECK_STATUS(status
, NT_STATUS_OK
);
1364 h1
= io
.smb2
.out
.file
.handle
;
1366 /* ask for a change notify,
1367 on file or directory name changes */
1368 ZERO_STRUCT(notify
.smb2
);
1369 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1370 notify
.smb2
.in
.buffer_size
= 1000;
1371 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1372 notify
.smb2
.in
.file
.handle
= h1
;
1373 notify
.smb2
.in
.recursive
= true;
1375 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1377 WAIT_FOR_ASYNC_RESPONSE(req
);
1379 status
= smb2_util_close(tree1
, h1
);
1380 CHECK_STATUS(status
, NT_STATUS_OK
);
1382 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1383 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
1384 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1387 smb2_deltree(tree1
, BASEDIR
);
1392 basic testing of change notifies followed by a ulogoff
1395 static bool torture_smb2_notify_ulogoff(struct torture_context
*torture
,
1396 struct smb2_tree
*tree1
)
1400 union smb_notify notify
;
1402 struct smb2_handle h1
;
1403 struct smb2_request
*req
;
1405 smb2_deltree(tree1
, BASEDIR
);
1406 smb2_util_rmdir(tree1
, BASEDIR
);
1408 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1411 get a handle on the directory
1413 ZERO_STRUCT(io
.smb2
);
1414 io
.generic
.level
= RAW_OPEN_SMB2
;
1415 io
.smb2
.in
.create_flags
= 0;
1416 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1417 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1418 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1419 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1420 NTCREATEX_SHARE_ACCESS_WRITE
;
1421 io
.smb2
.in
.alloc_size
= 0;
1422 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1423 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1424 io
.smb2
.in
.security_flags
= 0;
1425 io
.smb2
.in
.fname
= BASEDIR
;
1427 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1428 CHECK_STATUS(status
, NT_STATUS_OK
);
1430 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1431 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1432 CHECK_STATUS(status
, NT_STATUS_OK
);
1433 h1
= io
.smb2
.out
.file
.handle
;
1435 /* ask for a change notify,
1436 on file or directory name changes */
1437 ZERO_STRUCT(notify
.smb2
);
1438 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1439 notify
.smb2
.in
.buffer_size
= 1000;
1440 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1441 notify
.smb2
.in
.file
.handle
= h1
;
1442 notify
.smb2
.in
.recursive
= true;
1444 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1446 WAIT_FOR_ASYNC_RESPONSE(req
);
1448 status
= smb2_logoff(tree1
->session
);
1449 CHECK_STATUS(status
, NT_STATUS_OK
);
1451 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1452 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
1453 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1456 smb2_deltree(tree1
, BASEDIR
);
1461 basic testing of change notifies followed by a session reconnect
1464 static bool torture_smb2_notify_session_reconnect(struct torture_context
*torture
,
1465 struct smb2_tree
*tree1
)
1469 union smb_notify notify
;
1471 struct smb2_handle h1
;
1472 struct smb2_request
*req
;
1473 uint64_t previous_session_id
= 0;
1474 struct smb2_session
*session2
= NULL
;
1476 smb2_deltree(tree1
, BASEDIR
);
1477 smb2_util_rmdir(tree1
, BASEDIR
);
1479 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY SESSION RECONNECT\n");
1482 get a handle on the directory
1484 ZERO_STRUCT(io
.smb2
);
1485 io
.generic
.level
= RAW_OPEN_SMB2
;
1486 io
.smb2
.in
.create_flags
= 0;
1487 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1488 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1489 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1490 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1491 NTCREATEX_SHARE_ACCESS_WRITE
;
1492 io
.smb2
.in
.alloc_size
= 0;
1493 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1494 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1495 io
.smb2
.in
.security_flags
= 0;
1496 io
.smb2
.in
.fname
= BASEDIR
;
1498 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1499 CHECK_STATUS(status
, NT_STATUS_OK
);
1501 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1502 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1503 CHECK_STATUS(status
, NT_STATUS_OK
);
1504 h1
= io
.smb2
.out
.file
.handle
;
1506 /* ask for a change notify,
1507 on file or directory name changes */
1508 ZERO_STRUCT(notify
.smb2
);
1509 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1510 notify
.smb2
.in
.buffer_size
= 1000;
1511 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1512 notify
.smb2
.in
.file
.handle
= h1
;
1513 notify
.smb2
.in
.recursive
= true;
1515 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1517 WAIT_FOR_ASYNC_RESPONSE(req
);
1519 previous_session_id
= smb2cli_session_current_id(tree1
->session
->smbXcli
);
1520 torture_assert(torture
, torture_smb2_session_setup(torture
,
1521 tree1
->session
->transport
,
1522 previous_session_id
,
1523 torture
, &session2
),
1524 "session setup with previous_session_id failed");
1526 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1527 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
1528 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1530 status
= smb2_logoff(tree1
->session
);
1531 CHECK_STATUS(status
, NT_STATUS_USER_SESSION_DELETED
);
1533 status
= smb2_logoff(session2
);
1534 CHECK_STATUS(status
, NT_STATUS_OK
);
1536 smb2_deltree(tree1
, BASEDIR
);
1541 basic testing of change notifies followed by an invalid reauth
1544 static bool torture_smb2_notify_invalid_reauth(struct torture_context
*torture
,
1545 struct smb2_tree
*tree1
,
1546 struct smb2_tree
*tree2
)
1550 union smb_notify notify
;
1552 struct smb2_handle h1
;
1553 struct smb2_request
*req
;
1554 struct cli_credentials
*invalid_creds
;
1556 smb2_deltree(tree2
, BASEDIR
);
1557 smb2_util_rmdir(tree2
, BASEDIR
);
1559 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY invalid REAUTH\n");
1562 get a handle on the directory
1564 ZERO_STRUCT(io
.smb2
);
1565 io
.generic
.level
= RAW_OPEN_SMB2
;
1566 io
.smb2
.in
.create_flags
= 0;
1567 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1568 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1569 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1570 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1571 NTCREATEX_SHARE_ACCESS_WRITE
;
1572 io
.smb2
.in
.alloc_size
= 0;
1573 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1574 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1575 io
.smb2
.in
.security_flags
= 0;
1576 io
.smb2
.in
.fname
= BASEDIR
;
1578 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1579 CHECK_STATUS(status
, NT_STATUS_OK
);
1581 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1582 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1583 CHECK_STATUS(status
, NT_STATUS_OK
);
1584 h1
= io
.smb2
.out
.file
.handle
;
1586 /* ask for a change notify,
1587 on file or directory name changes */
1588 ZERO_STRUCT(notify
.smb2
);
1589 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1590 notify
.smb2
.in
.buffer_size
= 1000;
1591 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1592 notify
.smb2
.in
.file
.handle
= h1
;
1593 notify
.smb2
.in
.recursive
= true;
1595 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1597 WAIT_FOR_ASYNC_RESPONSE(req
);
1599 invalid_creds
= cli_credentials_init(torture
);
1600 torture_assert(torture
, (invalid_creds
!= NULL
), "talloc error");
1601 cli_credentials_set_username(invalid_creds
, "__none__invalid__none__", CRED_SPECIFIED
);
1602 cli_credentials_set_domain(invalid_creds
, "__none__invalid__none__", CRED_SPECIFIED
);
1603 cli_credentials_set_password(invalid_creds
, "__none__invalid__none__", CRED_SPECIFIED
);
1604 cli_credentials_set_realm(invalid_creds
, NULL
, CRED_SPECIFIED
);
1605 cli_credentials_set_workstation(invalid_creds
, "", CRED_UNINITIALISED
);
1607 status
= smb2_session_setup_spnego(tree1
->session
,
1609 0 /* previous_session_id */);
1610 CHECK_STATUS(status
, NT_STATUS_LOGON_FAILURE
);
1612 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1613 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
1614 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1617 smb2_deltree(tree2
, BASEDIR
);
1621 static void tcp_dis_handler(struct smb2_transport
*t
, void *p
)
1623 struct smb2_tree
*tree
= (struct smb2_tree
*)p
;
1624 smb2_transport_dead(tree
->session
->transport
,
1625 NT_STATUS_LOCAL_DISCONNECT
);
1631 basic testing of change notifies followed by tcp disconnect
1634 static bool torture_smb2_notify_tcp_disconnect(
1635 struct torture_context
*torture
,
1636 struct smb2_tree
*tree
)
1640 union smb_notify notify
;
1642 struct smb2_handle h1
;
1643 struct smb2_request
*req
;
1645 smb2_deltree(tree
, BASEDIR
);
1646 smb2_util_rmdir(tree
, BASEDIR
);
1648 torture_comment(torture
,
1649 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1652 get a handle on the directory
1654 ZERO_STRUCT(io
.smb2
);
1655 io
.generic
.level
= RAW_OPEN_SMB2
;
1656 io
.smb2
.in
.create_flags
= 0;
1657 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1658 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1659 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1660 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1661 NTCREATEX_SHARE_ACCESS_WRITE
;
1662 io
.smb2
.in
.alloc_size
= 0;
1663 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1664 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1665 io
.smb2
.in
.security_flags
= 0;
1666 io
.smb2
.in
.fname
= BASEDIR
;
1668 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1669 CHECK_STATUS(status
, NT_STATUS_OK
);
1670 h1
= io
.smb2
.out
.file
.handle
;
1672 /* ask for a change notify,
1673 on file or directory name changes */
1674 ZERO_STRUCT(notify
.smb2
);
1675 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1676 notify
.smb2
.in
.buffer_size
= 1000;
1677 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1678 notify
.smb2
.in
.file
.handle
= h1
;
1679 notify
.smb2
.in
.recursive
= true;
1681 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1683 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1684 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1686 notify
.smb2
.in
.recursive
= true;
1687 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1688 smb2_transport_idle_handler(tree
->session
->transport
,
1689 tcp_dis_handler
, 250, tree
);
1691 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1692 CHECK_STATUS(status
, NT_STATUS_LOCAL_DISCONNECT
);
1699 test setting up two change notify requests on one handle
1702 static bool torture_smb2_notify_double(struct torture_context
*torture
,
1703 struct smb2_tree
*tree1
,
1704 struct smb2_tree
*tree2
)
1708 union smb_notify notify
;
1710 struct smb2_handle h1
;
1711 struct smb2_request
*req1
, *req2
;
1713 smb2_deltree(tree1
, BASEDIR
);
1714 smb2_util_rmdir(tree1
, BASEDIR
);
1716 torture_comment(torture
,
1717 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1720 get a handle on the directory
1722 ZERO_STRUCT(io
.smb2
);
1723 io
.generic
.level
= RAW_OPEN_SMB2
;
1724 io
.smb2
.in
.create_flags
= 0;
1725 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
1726 SEC_RIGHTS_FILE_WRITE
|
1727 SEC_RIGHTS_FILE_ALL
;
1728 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1729 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1730 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1731 NTCREATEX_SHARE_ACCESS_WRITE
;
1732 io
.smb2
.in
.alloc_size
= 0;
1733 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1734 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1735 io
.smb2
.in
.security_flags
= 0;
1736 io
.smb2
.in
.fname
= BASEDIR
;
1738 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1739 CHECK_STATUS(status
, NT_STATUS_OK
);
1740 h1
= io
.smb2
.out
.file
.handle
;
1742 /* ask for a change notify,
1743 on file or directory name changes */
1744 ZERO_STRUCT(notify
.smb2
);
1745 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1746 notify
.smb2
.in
.buffer_size
= 1000;
1747 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1748 notify
.smb2
.in
.file
.handle
= h1
;
1749 notify
.smb2
.in
.recursive
= true;
1751 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
1753 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1754 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1756 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
1758 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
1759 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1761 smb2_util_mkdir(tree2
, BASEDIR
"\\subdir-name");
1762 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
1763 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
1765 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1766 CHECK_STATUS(status
, NT_STATUS_OK
);
1767 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1768 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
1770 smb2_util_mkdir(tree2
, BASEDIR
"\\subdir-name2");
1772 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
1773 CHECK_STATUS(status
, NT_STATUS_OK
);
1774 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1775 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name2");
1778 smb2_deltree(tree1
, BASEDIR
);
1784 test multiple change notifies at different depths and with/without recursion
1787 static bool torture_smb2_notify_tree(struct torture_context
*torture
,
1788 struct smb2_tree
*tree
)
1791 union smb_notify notify
;
1793 struct smb2_request
*req
;
1800 struct smb2_handle h1
;
1803 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 30 },
1804 {BASEDIR
"\\zqy", true, FILE_NOTIFY_CHANGE_NAME
, 8 },
1805 {BASEDIR
"\\atsy", true, FILE_NOTIFY_CHANGE_NAME
, 4 },
1806 {BASEDIR
"\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1807 {BASEDIR
"\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME
, 13 },
1808 {BASEDIR
"\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME
, 7 },
1809 {BASEDIR
"\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1810 {BASEDIR
"\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1811 {BASEDIR
"\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1812 {BASEDIR
"\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1813 {BASEDIR
"\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1814 {BASEDIR
"\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1815 {BASEDIR
"\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME
, 40 },
1816 {BASEDIR
, true, FILE_NOTIFY_CHANGE_NAME
, 40 },
1817 {BASEDIR
, false,FILE_NOTIFY_CHANGE_NAME
, 6 },
1818 {BASEDIR
"\\atsy", false,FILE_NOTIFY_CHANGE_NAME
, 4 },
1819 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 24 },
1820 {BASEDIR
"\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME
, 0 },
1821 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME
, 0 },
1822 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 24 },
1826 bool all_done
= false;
1828 smb2_deltree(tree
, BASEDIR
);
1829 smb2_util_rmdir(tree
, BASEDIR
);
1831 torture_comment(torture
, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1833 ZERO_STRUCT(io
.smb2
);
1834 io
.generic
.level
= RAW_OPEN_SMB2
;
1835 io
.smb2
.in
.create_flags
= 0;
1836 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1837 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1838 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1839 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1840 NTCREATEX_SHARE_ACCESS_WRITE
;
1841 io
.smb2
.in
.alloc_size
= 0;
1842 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1843 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1844 io
.smb2
.in
.security_flags
= 0;
1845 io
.smb2
.in
.fname
= BASEDIR
;
1846 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1847 CHECK_STATUS(status
, NT_STATUS_OK
);
1849 ZERO_STRUCT(notify
.smb2
);
1850 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1851 notify
.smb2
.in
.buffer_size
= 20000;
1854 setup the directory tree, and the notify buffer on each directory
1856 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1857 io
.smb2
.in
.fname
= dirs
[i
].path
;
1858 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1859 CHECK_STATUS(status
, NT_STATUS_OK
);
1860 dirs
[i
].h1
= io
.smb2
.out
.file
.handle
;
1862 notify
.smb2
.in
.completion_filter
= dirs
[i
].filter
;
1863 notify
.smb2
.in
.file
.handle
= dirs
[i
].h1
;
1864 notify
.smb2
.in
.recursive
= dirs
[i
].recursive
;
1865 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1867 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1868 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1871 /* trigger 2 events in each dir */
1872 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1873 char *path
= talloc_asprintf(torture
, "%s\\test.dir",
1875 smb2_util_mkdir(tree
, path
);
1876 smb2_util_rmdir(tree
, path
);
1880 /* give a bit of time for the events to propogate */
1881 tv
= timeval_current();
1884 /* count events that have happened in each dir */
1885 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1886 notify
.smb2
.in
.completion_filter
= dirs
[i
].filter
;
1887 notify
.smb2
.in
.file
.handle
= dirs
[i
].h1
;
1888 notify
.smb2
.in
.recursive
= dirs
[i
].recursive
;
1889 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1891 notify
.smb2
.out
.num_changes
= 0;
1892 status
= smb2_notify_recv(req
, torture
,
1894 dirs
[i
].counted
+= notify
.smb2
.out
.num_changes
;
1899 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1900 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
1904 } while (!all_done
&& timeval_elapsed(&tv
) < 20);
1906 torture_comment(torture
, "took %.4f seconds to propogate all events\n",
1907 timeval_elapsed(&tv
));
1909 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1910 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
1911 torture_comment(torture
,
1912 "ERROR: i=%d expected %d got %d for '%s'\n",
1913 i
, dirs
[i
].expected
, dirs
[i
].counted
,
1920 run from the back, closing and deleting
1922 for (i
=ARRAY_SIZE(dirs
)-1;i
>=0;i
--) {
1923 smb2_util_close(tree
, dirs
[i
].h1
);
1924 smb2_util_rmdir(tree
, dirs
[i
].path
);
1928 smb2_deltree(tree
, BASEDIR
);
1929 smb2_util_rmdir(tree
, BASEDIR
);
1934 Test response when cached server events exceed single NT NOTFIY response
1938 static bool torture_smb2_notify_overflow(struct torture_context
*torture
,
1939 struct smb2_tree
*tree
)
1943 union smb_notify notify
;
1945 struct smb2_handle h1
, h2
;
1947 struct smb2_request
*req1
;
1950 smb2_deltree(tree
, BASEDIR
);
1951 smb2_util_rmdir(tree
, BASEDIR
);
1953 torture_comment(torture
, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1955 /* get a handle on the directory */
1956 ZERO_STRUCT(io
.smb2
);
1957 io
.generic
.level
= RAW_OPEN_SMB2
;
1958 io
.smb2
.in
.create_flags
= 0;
1959 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1960 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1961 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1962 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1963 NTCREATEX_SHARE_ACCESS_WRITE
;
1964 io
.smb2
.in
.alloc_size
= 0;
1965 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1966 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1967 io
.smb2
.in
.security_flags
= 0;
1968 io
.smb2
.in
.fname
= BASEDIR
;
1970 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1971 CHECK_STATUS(status
, NT_STATUS_OK
);
1972 h1
= io
.smb2
.out
.file
.handle
;
1974 /* ask for a change notify, on name changes. */
1975 ZERO_STRUCT(notify
.smb2
);
1976 notify
.smb2
.level
= RAW_NOTIFY_NTTRANS
;
1977 notify
.smb2
.in
.buffer_size
= 1000;
1978 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1979 notify
.smb2
.in
.file
.handle
= h1
;
1981 notify
.smb2
.in
.recursive
= true;
1982 req1
= smb2_notify_send(tree
, &(notify
.smb2
));
1984 /* cancel initial requests so the buffer is setup */
1986 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1987 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1989 /* open a lot of files, filling up the server side notify buffer */
1990 torture_comment(torture
,
1991 "Testing overflowed buffer notify on create of %d files\n",
1994 for (i
=0;i
<count
;i
++) {
1995 char *fname
= talloc_asprintf(torture
,
1996 BASEDIR
"\\test%d.txt", i
);
1998 ZERO_STRUCT(io1
.smb2
);
1999 io1
.generic
.level
= RAW_OPEN_SMB2
;
2000 io1
.smb2
.in
.create_flags
= 0;
2001 io1
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
2002 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2003 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2004 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2005 NTCREATEX_SHARE_ACCESS_WRITE
;
2006 io1
.smb2
.in
.alloc_size
= 0;
2007 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2008 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
2009 io1
.smb2
.in
.security_flags
= 0;
2010 io1
.smb2
.in
.fname
= fname
;
2012 h2
= custom_smb2_create(tree
, torture
, &(io1
.smb2
));
2014 smb2_util_close(tree
, h2
);
2017 req1
= smb2_notify_send(tree
, &(notify
.smb2
));
2018 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
2019 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
2020 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
2023 smb2_deltree(tree
, BASEDIR
);
2028 Test if notifications are returned for changes to the base directory.
2032 static bool torture_smb2_notify_basedir(struct torture_context
*torture
,
2033 struct smb2_tree
*tree1
,
2034 struct smb2_tree
*tree2
)
2038 union smb_notify notify
;
2040 struct smb2_handle h1
;
2041 struct smb2_request
*req1
;
2043 smb2_deltree(tree1
, BASEDIR
);
2044 smb2_util_rmdir(tree1
, BASEDIR
);
2046 torture_comment(torture
, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
2048 /* get a handle on the directory */
2049 ZERO_STRUCT(io
.smb2
);
2050 io
.generic
.level
= RAW_OPEN_SMB2
;
2051 io
.smb2
.in
.create_flags
= 0;
2052 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
2053 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2054 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2055 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2056 NTCREATEX_SHARE_ACCESS_WRITE
;
2057 io
.smb2
.in
.alloc_size
= 0;
2058 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
2059 io
.smb2
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
2060 io
.smb2
.in
.security_flags
= 0;
2061 io
.smb2
.in
.fname
= BASEDIR
;
2063 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
2064 CHECK_STATUS(status
, NT_STATUS_OK
);
2065 h1
= io
.smb2
.out
.file
.handle
;
2067 /* create a test file that will also be modified */
2068 io
.smb2
.in
.fname
= BASEDIR
"\\tname1";
2069 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
2070 status
= smb2_create(tree2
, torture
, &(io
.smb2
));
2071 CHECK_STATUS(status
,NT_STATUS_OK
);
2072 smb2_util_close(tree2
, io
.smb2
.out
.file
.handle
);
2074 /* ask for a change notify, on attribute changes. */
2075 ZERO_STRUCT(notify
.smb2
);
2076 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
2077 notify
.smb2
.in
.buffer_size
= 1000;
2078 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
2079 notify
.smb2
.in
.file
.handle
= h1
;
2080 notify
.smb2
.in
.recursive
= true;
2082 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
2084 /* set attribute on the base dir */
2085 smb2_util_setatr(tree2
, BASEDIR
, FILE_ATTRIBUTE_HIDDEN
);
2087 /* set attribute on a file to assure we receive a notification */
2088 smb2_util_setatr(tree2
, BASEDIR
"\\tname1", FILE_ATTRIBUTE_HIDDEN
);
2091 /* check how many responses were given, expect only 1 for the file */
2092 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
2093 CHECK_STATUS(status
, NT_STATUS_OK
);
2094 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2095 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
2096 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "tname1");
2099 smb2_deltree(tree1
, BASEDIR
);
2104 very simple change notify test
2106 static bool torture_smb2_notify_tcon(struct torture_context
*torture
,
2107 struct smb2_tree
*tree
)
2111 union smb_notify notify
;
2113 struct smb2_handle h1
;
2114 struct smb2_request
*req
= NULL
;
2115 struct smb2_tree
*tree1
= NULL
;
2116 const char *fname
= BASEDIR
"\\subdir-name";
2118 smb2_deltree(tree
, BASEDIR
);
2119 smb2_util_rmdir(tree
, BASEDIR
);
2121 torture_comment(torture
, "TESTING SIMPLE CHANGE NOTIFY\n");
2124 get a handle on the directory
2127 ZERO_STRUCT(io
.smb2
);
2128 io
.generic
.level
= RAW_OPEN_SMB2
;
2129 io
.smb2
.in
.create_flags
= 0;
2130 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
2131 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2132 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
|
2133 FILE_ATTRIBUTE_DIRECTORY
;
2134 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2135 NTCREATEX_SHARE_ACCESS_WRITE
;
2136 io
.smb2
.in
.alloc_size
= 0;
2137 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
2138 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
2139 io
.smb2
.in
.security_flags
= 0;
2140 io
.smb2
.in
.fname
= BASEDIR
;
2142 status
= smb2_create(tree
, torture
, &(io
.smb2
));
2143 CHECK_STATUS(status
, NT_STATUS_OK
);
2144 h1
= io
.smb2
.out
.file
.handle
;
2146 /* ask for a change notify,
2147 on file or directory name changes */
2148 ZERO_STRUCT(notify
.smb2
);
2149 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
2150 notify
.smb2
.in
.buffer_size
= 1000;
2151 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
2152 notify
.smb2
.in
.file
.handle
= h1
;
2153 notify
.smb2
.in
.recursive
= true;
2155 torture_comment(torture
, "Testing notify mkdir\n");
2156 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2158 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2159 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
2161 notify
.smb2
.in
.recursive
= true;
2162 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2163 status
= smb2_util_mkdir(tree
, fname
);
2164 CHECK_STATUS(status
, NT_STATUS_OK
);
2166 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2167 CHECK_STATUS(status
, NT_STATUS_OK
);
2169 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2170 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
2171 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2173 torture_comment(torture
, "Testing notify rmdir\n");
2174 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2175 status
= smb2_util_rmdir(tree
, fname
);
2176 CHECK_STATUS(status
, NT_STATUS_OK
);
2178 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2179 CHECK_STATUS(status
, NT_STATUS_OK
);
2180 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2181 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
2182 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2184 torture_comment(torture
, "SIMPLE CHANGE NOTIFY OK\n");
2186 torture_comment(torture
, "TESTING WITH SECONDARY TCON\n");
2187 if (!torture_smb2_tree_connect(torture
, tree
->session
, tree
, &tree1
)) {
2188 torture_warning(torture
, "couldn't reconnect to share, bailing\n");
2193 torture_comment(torture
, "tid1=%d tid2=%d\n",
2194 smb2cli_tcon_current_id(tree
->smbXcli
),
2195 smb2cli_tcon_current_id(tree1
->smbXcli
));
2197 torture_comment(torture
, "Testing notify mkdir\n");
2198 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2199 smb2_util_mkdir(tree1
, fname
);
2201 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2202 CHECK_STATUS(status
, NT_STATUS_OK
);
2204 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2205 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
2206 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2208 torture_comment(torture
, "Testing notify rmdir\n");
2209 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2210 smb2_util_rmdir(tree
, fname
);
2212 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2213 CHECK_STATUS(status
, NT_STATUS_OK
);
2214 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2215 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
2216 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2218 torture_comment(torture
, "CHANGE NOTIFY WITH TCON OK\n");
2220 torture_comment(torture
, "Disconnecting secondary tree\n");
2221 status
= smb2_tdis(tree1
);
2222 CHECK_STATUS(status
, NT_STATUS_OK
);
2225 torture_comment(torture
, "Testing notify mkdir\n");
2226 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2227 smb2_util_mkdir(tree
, fname
);
2229 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2230 CHECK_STATUS(status
, NT_STATUS_OK
);
2232 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2233 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
2234 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2236 torture_comment(torture
, "Testing notify rmdir\n");
2237 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2238 smb2_util_rmdir(tree
, fname
);
2240 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2241 CHECK_STATUS(status
, NT_STATUS_OK
);
2242 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2243 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
2244 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2246 torture_comment(torture
, "CHANGE NOTIFY WITH TDIS OK\n");
2248 smb2_util_close(tree
, h1
);
2249 smb2_deltree(tree
, BASEDIR
);
2254 static bool torture_smb2_notify_rmdir(struct torture_context
*torture
,
2255 struct smb2_tree
*tree1
,
2256 struct smb2_tree
*tree2
,
2257 bool initial_delete_on_close
)
2261 union smb_notify notify
= {};
2262 union smb_setfileinfo sfinfo
= {};
2263 union smb_open io
= {};
2264 struct smb2_handle h
= {};
2265 struct smb2_request
*req
;
2267 torture_comment(torture
, "TESTING NOTIFY CANCEL FOR DELETED DIR\n");
2269 smb2_deltree(tree1
, BASEDIR
);
2270 smb2_util_rmdir(tree1
, BASEDIR
);
2272 ZERO_STRUCT(io
.smb2
);
2273 io
.generic
.level
= RAW_OPEN_SMB2
;
2274 io
.smb2
.in
.create_flags
= 0;
2275 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
2276 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2277 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2278 io
.smb2
.in
.share_access
=
2279 NTCREATEX_SHARE_ACCESS_READ
|
2280 NTCREATEX_SHARE_ACCESS_WRITE
|
2281 NTCREATEX_SHARE_ACCESS_DELETE
;
2282 io
.smb2
.in
.alloc_size
= 0;
2283 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2284 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
2285 io
.smb2
.in
.security_flags
= 0;
2286 io
.smb2
.in
.fname
= BASEDIR
;
2288 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
2289 CHECK_STATUS(status
, NT_STATUS_OK
);
2290 h
= io
.smb2
.out
.file
.handle
;
2292 ZERO_STRUCT(notify
.smb2
);
2293 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
2294 notify
.smb2
.in
.buffer_size
= 1000;
2295 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
2296 notify
.smb2
.in
.file
.handle
= h
;
2297 notify
.smb2
.in
.recursive
= false;
2299 io
.smb2
.in
.desired_access
|= SEC_STD_DELETE
;
2300 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
2301 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
2303 if (initial_delete_on_close
) {
2304 status
= smb2_util_rmdir(tree2
, BASEDIR
);
2305 CHECK_STATUS(status
, NT_STATUS_OK
);
2307 status
= smb2_create(tree2
, torture
, &(io
.smb2
));
2308 CHECK_STATUS(status
, NT_STATUS_OK
);
2310 sfinfo
.generic
.level
= RAW_SFILEINFO_DISPOSITION_INFORMATION
;
2311 sfinfo
.generic
.in
.file
.handle
= io
.smb2
.out
.file
.handle
;
2312 sfinfo
.disposition_info
.in
.delete_on_close
= 1;
2313 status
= smb2_setinfo_file(tree2
, &sfinfo
);
2314 CHECK_STATUS(status
, NT_STATUS_OK
);
2316 smb2_util_close(tree2
, io
.smb2
.out
.file
.handle
);
2319 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2320 CHECK_STATUS(status
, NT_STATUS_DELETE_PENDING
);
2324 smb2_util_close(tree1
, h
);
2325 smb2_deltree(tree1
, BASEDIR
);
2330 static bool torture_smb2_notify_rmdir1(struct torture_context
*torture
,
2331 struct smb2_tree
*tree
)
2333 return torture_smb2_notify_rmdir(torture
, tree
, tree
, false);
2336 static bool torture_smb2_notify_rmdir2(struct torture_context
*torture
,
2337 struct smb2_tree
*tree
)
2339 return torture_smb2_notify_rmdir(torture
, tree
, tree
, true);
2342 static bool torture_smb2_notify_rmdir3(struct torture_context
*torture
,
2343 struct smb2_tree
*tree1
,
2344 struct smb2_tree
*tree2
)
2346 return torture_smb2_notify_rmdir(torture
, tree1
, tree2
, false);
2349 static bool torture_smb2_notify_rmdir4(struct torture_context
*torture
,
2350 struct smb2_tree
*tree1
,
2351 struct smb2_tree
*tree2
)
2353 return torture_smb2_notify_rmdir(torture
, tree1
, tree2
, true);
2357 basic testing of SMB2 change notify
2359 struct torture_suite
*torture_smb2_notify_init(void)
2361 struct torture_suite
*suite
= torture_suite_create(talloc_autofree_context(), "notify");
2363 torture_suite_add_1smb2_test(suite
, "valid-req", test_valid_request
);
2364 torture_suite_add_1smb2_test(suite
, "tcon", torture_smb2_notify_tcon
);
2365 torture_suite_add_2smb2_test(suite
, "dir", torture_smb2_notify_dir
);
2366 torture_suite_add_2smb2_test(suite
, "mask", torture_smb2_notify_mask
);
2367 torture_suite_add_1smb2_test(suite
, "tdis", torture_smb2_notify_tree_disconnect
);
2368 torture_suite_add_1smb2_test(suite
, "tdis1", torture_smb2_notify_tree_disconnect_1
);
2369 torture_suite_add_2smb2_test(suite
, "mask-change", torture_smb2_notify_mask_change
);
2370 torture_suite_add_1smb2_test(suite
, "close", torture_smb2_notify_close
);
2371 torture_suite_add_1smb2_test(suite
, "logoff", torture_smb2_notify_ulogoff
);
2372 torture_suite_add_1smb2_test(suite
, "session-reconnect", torture_smb2_notify_session_reconnect
);
2373 torture_suite_add_2smb2_test(suite
, "invalid-reauth", torture_smb2_notify_invalid_reauth
);
2374 torture_suite_add_1smb2_test(suite
, "tree", torture_smb2_notify_tree
);
2375 torture_suite_add_2smb2_test(suite
, "basedir", torture_smb2_notify_basedir
);
2376 torture_suite_add_2smb2_test(suite
, "double", torture_smb2_notify_double
);
2377 torture_suite_add_1smb2_test(suite
, "file", torture_smb2_notify_file
);
2378 torture_suite_add_1smb2_test(suite
, "tcp", torture_smb2_notify_tcp_disconnect
);
2379 torture_suite_add_2smb2_test(suite
, "rec", torture_smb2_notify_recursive
);
2380 torture_suite_add_1smb2_test(suite
, "overflow", torture_smb2_notify_overflow
);
2381 torture_suite_add_1smb2_test(suite
, "rmdir1",
2382 torture_smb2_notify_rmdir1
);
2383 torture_suite_add_1smb2_test(suite
, "rmdir2",
2384 torture_smb2_notify_rmdir2
);
2385 torture_suite_add_2smb2_test(suite
, "rmdir3",
2386 torture_smb2_notify_rmdir3
);
2387 torture_suite_add_2smb2_test(suite
, "rmdir4",
2388 torture_smb2_notify_rmdir4
);
2390 suite
->description
= talloc_strdup(suite
, "SMB2-NOTIFY tests");