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
;
490 testing of recursive change notify
493 static bool torture_smb2_notify_recursive(struct torture_context
*torture
,
494 struct smb2_tree
*tree1
,
495 struct smb2_tree
*tree2
)
499 union smb_notify notify
;
500 union smb_open io
, io1
;
501 union smb_setfileinfo sinfo
;
502 struct smb2_handle h1
;
503 struct smb2_request
*req1
, *req2
;
505 smb2_deltree(tree1
, BASEDIR
);
506 smb2_util_rmdir(tree1
, BASEDIR
);
508 torture_comment(torture
, "TESTING CHANGE NOTIFY WITH RECURSION\n");
511 get a handle on the directory
513 ZERO_STRUCT(io
.smb2
);
514 io
.generic
.level
= RAW_OPEN_SMB2
;
515 io
.smb2
.in
.create_flags
= 0;
516 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
517 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
518 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
519 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
520 NTCREATEX_SHARE_ACCESS_WRITE
;
521 io
.smb2
.in
.alloc_size
= 0;
522 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
523 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
524 io
.smb2
.in
.security_flags
= 0;
525 io
.smb2
.in
.fname
= BASEDIR
;
527 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
528 CHECK_STATUS(status
, NT_STATUS_OK
);
529 h1
= io
.smb2
.out
.file
.handle
;
531 /* ask for a change notify, on file or directory name
532 changes. Setup both with and without recursion */
533 ZERO_STRUCT(notify
.smb2
);
534 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
535 notify
.smb2
.in
.buffer_size
= 1000;
536 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
|
537 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
538 FILE_NOTIFY_CHANGE_CREATION
;
539 notify
.smb2
.in
.file
.handle
= h1
;
541 notify
.smb2
.in
.recursive
= true;
542 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
544 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
545 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
547 notify
.smb2
.in
.recursive
= false;
548 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
550 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
551 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
553 ZERO_STRUCT(io1
.smb2
);
554 io1
.generic
.level
= RAW_OPEN_SMB2
;
555 io1
.smb2
.in
.create_flags
= NTCREATEX_FLAGS_EXTENDED
;
556 io1
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
557 SEC_RIGHTS_FILE_WRITE
|
559 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
560 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
561 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
562 NTCREATEX_SHARE_ACCESS_WRITE
|
563 NTCREATEX_SHARE_ACCESS_DELETE
;
564 io1
.smb2
.in
.alloc_size
= 0;
565 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
566 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
567 io1
.smb2
.in
.security_flags
= 0;
568 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name";
569 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
570 CHECK_STATUS(status
, NT_STATUS_OK
);
571 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
573 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname1";
574 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
575 CHECK_STATUS(status
, NT_STATUS_OK
);
577 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
578 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
579 sinfo
.rename_information
.in
.overwrite
= 0;
580 sinfo
.rename_information
.in
.root_fid
= 0;
581 sinfo
.rename_information
.in
.new_name
=
582 BASEDIR
"\\subdir-name\\subname1-r";
583 status
= smb2_setinfo_file(tree2
, &sinfo
);
584 CHECK_STATUS(status
, NT_STATUS_OK
);
586 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
587 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname2";
588 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
589 CHECK_STATUS(status
, NT_STATUS_OK
);
591 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
592 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
593 sinfo
.rename_information
.in
.overwrite
= true;
594 sinfo
.rename_information
.in
.root_fid
= 0;
595 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname2-r";
596 status
= smb2_setinfo_file(tree2
, &sinfo
);
597 CHECK_STATUS(status
, NT_STATUS_OK
);
599 io1
.smb2
.in
.fname
= BASEDIR
"\\subname2-r";
600 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
601 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
602 CHECK_STATUS(status
, NT_STATUS_OK
);
604 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
605 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
606 sinfo
.rename_information
.in
.overwrite
= true;
607 sinfo
.rename_information
.in
.root_fid
= 0;
608 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname3-r";
609 status
= smb2_setinfo_file(tree2
, &sinfo
);
610 CHECK_STATUS(status
, NT_STATUS_OK
);
612 notify
.smb2
.in
.completion_filter
= 0;
613 notify
.smb2
.in
.recursive
= true;
615 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
617 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name\\subname1-r");
618 CHECK_STATUS(status
, NT_STATUS_OK
);
619 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name");
620 CHECK_STATUS(status
, NT_STATUS_OK
);
621 status
= smb2_util_unlink(tree2
, BASEDIR
"\\subname3-r");
622 CHECK_STATUS(status
, NT_STATUS_OK
);
624 notify
.smb2
.in
.recursive
= false;
625 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
627 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
628 CHECK_STATUS(status
, NT_STATUS_OK
);
630 CHECK_VAL(notify
.smb2
.out
.num_changes
, 9);
631 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
632 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
633 CHECK_VAL(notify
.smb2
.out
.changes
[1].action
, NOTIFY_ACTION_ADDED
);
634 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[1].name
, "subdir-name\\subname1");
635 CHECK_VAL(notify
.smb2
.out
.changes
[2].action
, NOTIFY_ACTION_OLD_NAME
);
636 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[2].name
, "subdir-name\\subname1");
637 CHECK_VAL(notify
.smb2
.out
.changes
[3].action
, NOTIFY_ACTION_NEW_NAME
);
638 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[3].name
, "subdir-name\\subname1-r");
639 CHECK_VAL(notify
.smb2
.out
.changes
[4].action
, NOTIFY_ACTION_ADDED
);
640 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[4].name
, "subdir-name\\subname2");
641 CHECK_VAL(notify
.smb2
.out
.changes
[5].action
, NOTIFY_ACTION_REMOVED
);
642 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[5].name
, "subdir-name\\subname2");
643 CHECK_VAL(notify
.smb2
.out
.changes
[6].action
, NOTIFY_ACTION_ADDED
);
644 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[6].name
, "subname2-r");
645 CHECK_VAL(notify
.smb2
.out
.changes
[7].action
, NOTIFY_ACTION_OLD_NAME
);
646 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[7].name
, "subname2-r");
647 CHECK_VAL(notify
.smb2
.out
.changes
[8].action
, NOTIFY_ACTION_NEW_NAME
);
648 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[8].name
, "subname3-r");
651 smb2_deltree(tree1
, BASEDIR
);
656 testing of change notify mask change
659 static bool torture_smb2_notify_mask_change(struct torture_context
*torture
,
660 struct smb2_tree
*tree1
,
661 struct smb2_tree
*tree2
)
665 union smb_notify notify
;
666 union smb_open io
, io1
;
667 struct smb2_handle h1
;
668 struct smb2_request
*req1
, *req2
;
669 union smb_setfileinfo sinfo
;
671 smb2_deltree(tree1
, BASEDIR
);
672 smb2_util_rmdir(tree1
, BASEDIR
);
674 torture_comment(torture
, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
677 get a handle on the directory
679 ZERO_STRUCT(io
.smb2
);
680 io
.generic
.level
= RAW_OPEN_SMB2
;
681 io
.smb2
.in
.create_flags
= 0;
682 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
683 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
684 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
685 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
686 NTCREATEX_SHARE_ACCESS_WRITE
;
687 io
.smb2
.in
.alloc_size
= 0;
688 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
689 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
690 io
.smb2
.in
.security_flags
= 0;
691 io
.smb2
.in
.fname
= BASEDIR
;
693 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
694 CHECK_STATUS(status
, NT_STATUS_OK
);
695 h1
= io
.smb2
.out
.file
.handle
;
697 /* ask for a change notify, on file or directory name
698 changes. Setup both with and without recursion */
699 ZERO_STRUCT(notify
.smb2
);
700 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
701 notify
.smb2
.in
.buffer_size
= 1000;
702 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
703 notify
.smb2
.in
.file
.handle
= h1
;
705 notify
.smb2
.in
.recursive
= true;
706 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
709 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
710 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
713 notify
.smb2
.in
.recursive
= false;
714 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
717 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
718 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
720 notify
.smb2
.in
.recursive
= true;
721 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
723 /* Set to hidden then back again. */
724 ZERO_STRUCT(io1
.smb2
);
725 io1
.generic
.level
= RAW_OPEN_SMB2
;
726 io1
.smb2
.in
.create_flags
= 0;
727 io1
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
728 SEC_RIGHTS_FILE_WRITE
|
730 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
731 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
732 NTCREATEX_SHARE_ACCESS_WRITE
|
733 NTCREATEX_SHARE_ACCESS_DELETE
;
734 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
735 io1
.smb2
.in
.security_flags
= 0;
736 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
737 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
738 io1
.smb2
.in
.fname
= BASEDIR
"\\tname1";
740 smb2_util_close(tree1
,
741 custom_smb2_create(tree1
, torture
, &(io1
.smb2
)));
742 status
= smb2_util_setatr(tree1
, BASEDIR
"\\tname1",
743 FILE_ATTRIBUTE_HIDDEN
);
744 CHECK_STATUS(status
, NT_STATUS_OK
);
745 smb2_util_unlink(tree1
, BASEDIR
"\\tname1");
747 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
748 CHECK_STATUS(status
, NT_STATUS_OK
);
750 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
751 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
752 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "tname1");
754 /* Now try and change the mask to include other events.
755 * This should not work - once the mask is set on a directory
756 * h1 it seems to be fixed until the fnum is closed. */
758 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
|
759 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
760 FILE_NOTIFY_CHANGE_CREATION
;
761 notify
.smb2
.in
.recursive
= true;
762 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
764 notify
.smb2
.in
.recursive
= false;
765 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
767 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
768 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
769 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name";
770 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
771 CHECK_STATUS(status
, NT_STATUS_OK
);
772 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
775 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname1";
776 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
777 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
778 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
779 CHECK_STATUS(status
, NT_STATUS_OK
);
780 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
781 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
782 sinfo
.rename_information
.in
.overwrite
= true;
783 sinfo
.rename_information
.in
.root_fid
= 0;
784 sinfo
.rename_information
.in
.new_name
=
785 BASEDIR
"\\subdir-name\\subname1-r";
786 status
= smb2_setinfo_file(tree2
, &sinfo
);
787 CHECK_STATUS(status
, NT_STATUS_OK
);
789 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname2";
790 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
791 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
792 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
793 CHECK_STATUS(status
, NT_STATUS_OK
);
794 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
795 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname2-r";
796 status
= smb2_setinfo_file(tree2
, &sinfo
);
797 CHECK_STATUS(status
, NT_STATUS_OK
);
798 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
800 io1
.smb2
.in
.fname
= BASEDIR
"\\subname2-r";
801 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
802 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
803 CHECK_STATUS(status
, NT_STATUS_OK
);
804 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
805 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname3-r";
806 status
= smb2_setinfo_file(tree2
, &sinfo
);
807 CHECK_STATUS(status
, NT_STATUS_OK
);
808 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
810 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name\\subname1-r");
811 CHECK_STATUS(status
, NT_STATUS_OK
);
812 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name");
813 CHECK_STATUS(status
, NT_STATUS_OK
);
814 status
= smb2_util_unlink(tree2
, BASEDIR
"\\subname3-r");
815 CHECK_STATUS(status
, NT_STATUS_OK
);
817 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
818 CHECK_STATUS(status
, NT_STATUS_OK
);
820 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
821 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
822 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subname2-r");
824 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
825 CHECK_STATUS(status
, NT_STATUS_OK
);
827 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
828 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
829 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subname3-r");
836 smb2_deltree(tree1
, BASEDIR
);
841 testing of mask bits for change notify
844 static bool torture_smb2_notify_mask(struct torture_context
*torture
,
845 struct smb2_tree
*tree1
,
846 struct smb2_tree
*tree2
)
850 union smb_notify notify
;
851 union smb_open io
, io1
;
852 struct smb2_handle h1
, h2
;
856 union smb_setfileinfo sinfo
;
858 smb2_deltree(tree1
, BASEDIR
);
859 smb2_util_rmdir(tree1
, BASEDIR
);
861 torture_comment(torture
, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
865 get a handle on the directory
867 ZERO_STRUCT(io
.smb2
);
868 io
.generic
.level
= RAW_OPEN_SMB2
;
869 io
.smb2
.in
.create_flags
= 0;
870 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
871 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
872 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
873 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
874 NTCREATEX_SHARE_ACCESS_WRITE
;
875 io
.smb2
.in
.alloc_size
= 0;
876 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
877 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
878 io
.smb2
.in
.security_flags
= 0;
879 io
.smb2
.in
.fname
= BASEDIR
;
881 ZERO_STRUCT(notify
.smb2
);
882 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
883 notify
.smb2
.in
.buffer_size
= 1000;
884 notify
.smb2
.in
.recursive
= true;
886 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
887 expected, nchanges) \
889 do { for (mask=i=0;i<32;i++) { \
890 struct smb2_request *req; \
891 status = smb2_create(tree1, torture, &(io.smb2)); \
892 CHECK_STATUS(status, NT_STATUS_OK); \
893 h1 = io.smb2.out.file.handle; \
895 notify.smb2.in.file.handle = h1; \
896 notify.smb2.in.completion_filter = (1<<i); \
897 /* cancel initial requests so the buffer is setup */ \
898 req = smb2_notify_send(tree1, &(notify.smb2)); \
900 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
901 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
902 /* send the change notify request */ \
903 req = smb2_notify_send(tree1, &(notify.smb2)); \
905 smb_msleep(200); smb2_cancel(req); \
906 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
908 smb2_util_close(tree1, h1); \
909 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
910 CHECK_STATUS(status, NT_STATUS_OK); \
911 /* special case to cope with file rename behaviour */ \
912 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
913 notify.smb2.out.changes[0].action == \
914 NOTIFY_ACTION_MODIFIED && \
915 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
916 Action == NOTIFY_ACTION_OLD_NAME) { \
917 torture_comment(torture, \
918 "(rename file special handling OK)\n"); \
919 } else if (nchanges != notify.smb2.out.num_changes) { \
920 torture_result(torture, TORTURE_FAIL, \
921 "ERROR: nchanges=%d expected=%d "\
922 "action=%d filter=0x%08x\n", \
923 notify.smb2.out.num_changes, \
925 notify.smb2.out.changes[0].action, \
926 notify.smb2.in.completion_filter); \
928 } else if (notify.smb2.out.changes[0].action != Action) { \
929 torture_result(torture, TORTURE_FAIL, \
930 "ERROR: nchanges=%d action=%d " \
931 "expectedAction=%d filter=0x%08x\n", \
932 notify.smb2.out.num_changes, \
933 notify.smb2.out.changes[0].action, \
935 notify.smb2.in.completion_filter); \
937 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
939 torture_result(torture, TORTURE_FAIL, \
940 "ERROR: nchanges=%d action=%d " \
941 "filter=0x%08x name=%s\n", \
942 notify.smb2.out.num_changes, \
943 notify.smb2.out.changes[0].action, \
944 notify.smb2.in.completion_filter, \
945 notify.smb2.out.changes[0].name.s); \
953 torture_comment(torture
, "Testing mkdir\n");
954 NOTIFY_MASK_TEST("Testing mkdir",;,
955 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
956 smb2_util_rmdir(tree2
, BASEDIR
"\\tname1");,
958 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
960 torture_comment(torture
, "Testing create file\n");
961 ZERO_STRUCT(io1
.smb2
);
962 io1
.generic
.level
= RAW_OPEN_SMB2
;
963 io1
.smb2
.in
.create_flags
= 0;
964 io1
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
965 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
966 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
967 NTCREATEX_SHARE_ACCESS_WRITE
;
968 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
969 io1
.smb2
.in
.security_flags
= 0;
970 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
971 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
972 io1
.smb2
.in
.fname
= BASEDIR
"\\tname1";
974 NOTIFY_MASK_TEST("Testing create file",;,
975 smb2_util_close(tree2
, custom_smb2_create(tree2
,
976 torture
, &(io1
.smb2
)));,
977 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
979 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
981 torture_comment(torture
, "Testing unlink\n");
982 NOTIFY_MASK_TEST("Testing unlink",
983 smb2_util_close(tree2
, custom_smb2_create(tree2
,
984 torture
, &(io1
.smb2
)));,
985 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
987 NOTIFY_ACTION_REMOVED
,
988 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
990 torture_comment(torture
, "Testing rmdir\n");
991 NOTIFY_MASK_TEST("Testing rmdir",
992 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
993 smb2_util_rmdir(tree2
, BASEDIR
"\\tname1");,
995 NOTIFY_ACTION_REMOVED
,
996 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
998 torture_comment(torture
, "Testing rename file\n");
1000 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1001 sinfo
.rename_information
.in
.file
.handle
= h1
;
1002 sinfo
.rename_information
.in
.overwrite
= true;
1003 sinfo
.rename_information
.in
.root_fid
= 0;
1004 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\tname2";
1005 NOTIFY_MASK_TEST("Testing rename file",
1006 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1007 torture
, &(io1
.smb2
)));,
1008 smb2_setinfo_file(tree2
, &sinfo
);,
1009 smb2_util_unlink(tree2
, BASEDIR
"\\tname2");,
1010 NOTIFY_ACTION_OLD_NAME
,
1011 FILE_NOTIFY_CHANGE_FILE_NAME
, 2);
1013 torture_comment(torture
, "Testing rename dir\n");
1015 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1016 sinfo
.rename_information
.in
.file
.handle
= h1
;
1017 sinfo
.rename_information
.in
.overwrite
= true;
1018 sinfo
.rename_information
.in
.root_fid
= 0;
1019 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\tname2";
1020 NOTIFY_MASK_TEST("Testing rename dir",
1021 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
1022 smb2_setinfo_file(tree2
, &sinfo
);,
1023 smb2_util_rmdir(tree2
, BASEDIR
"\\tname2");,
1024 NOTIFY_ACTION_OLD_NAME
,
1025 FILE_NOTIFY_CHANGE_DIR_NAME
, 2);
1027 torture_comment(torture
, "Testing set path attribute\n");
1028 NOTIFY_MASK_TEST("Testing set path attribute",
1029 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1030 torture
, &(io
.smb2
)));,
1031 smb2_util_setatr(tree2
, BASEDIR
"\\tname1",
1032 FILE_ATTRIBUTE_HIDDEN
);,
1033 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
1034 NOTIFY_ACTION_MODIFIED
,
1035 FILE_NOTIFY_CHANGE_ATTRIBUTES
, 1);
1037 torture_comment(torture
, "Testing set path write time\n");
1039 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1040 sinfo
.generic
.in
.file
.handle
= h1
;
1041 sinfo
.basic_info
.in
.write_time
= 1000;
1042 NOTIFY_MASK_TEST("Testing set path write time",
1043 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1044 torture
, &(io1
.smb2
)));,
1045 smb2_setinfo_file(tree2
, &sinfo
);,
1046 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
1047 NOTIFY_ACTION_MODIFIED
,
1048 FILE_NOTIFY_CHANGE_LAST_WRITE
, 1);
1050 if (torture_setting_bool(torture
, "samba3", false)) {
1051 torture_comment(torture
,
1052 "Samba3 does not yet support create times "
1057 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1058 sinfo
.generic
.in
.file
.handle
= h1
;
1059 sinfo
.basic_info
.in
.create_time
= 0;
1060 torture_comment(torture
, "Testing set file create time\n");
1061 NOTIFY_MASK_TEST("Testing set file create time",
1062 smb2_create_complex_file(tree2
,
1063 BASEDIR
"\\tname1", &h2
);,
1064 smb2_setinfo_file(tree2
, &sinfo
);,
1065 (smb2_util_close(tree2
, h2
),
1066 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1067 NOTIFY_ACTION_MODIFIED
,
1068 FILE_NOTIFY_CHANGE_CREATION
, 1);
1072 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1073 sinfo
.generic
.in
.file
.handle
= h1
;
1074 sinfo
.basic_info
.in
.access_time
= 0;
1075 torture_comment(torture
, "Testing set file access time\n");
1076 NOTIFY_MASK_TEST("Testing set file access time",
1077 smb2_create_complex_file(tree2
, BASEDIR
"\\tname1", &h2
);,
1078 smb2_setinfo_file(tree2
, &sinfo
);,
1079 (smb2_util_close(tree2
, h2
),
1080 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1081 NOTIFY_ACTION_MODIFIED
,
1082 FILE_NOTIFY_CHANGE_LAST_ACCESS
, 1);
1085 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1086 sinfo
.generic
.in
.file
.handle
= h1
;
1087 sinfo
.basic_info
.in
.change_time
= 0;
1088 torture_comment(torture
, "Testing set file change time\n");
1089 NOTIFY_MASK_TEST("Testing set file change time",
1090 smb2_create_complex_file(tree2
, BASEDIR
"\\tname1", &h2
);,
1091 smb2_setinfo_file(tree2
, &sinfo
);,
1092 (smb2_util_close(tree2
, h2
),
1093 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1094 NOTIFY_ACTION_MODIFIED
,
1098 torture_comment(torture
, "Testing write\n");
1099 NOTIFY_MASK_TEST("Testing write",
1100 smb2_create_complex_file(tree2
, BASEDIR
"\\tname1", &h2
);,
1101 smb2_util_write(tree2
, h2
, &c
, 10000, 1);,
1102 (smb2_util_close(tree2
, h2
),
1103 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1104 NOTIFY_ACTION_MODIFIED
,
1108 smb2_deltree(tree1
, BASEDIR
);
1113 basic testing of change notify on files
1115 static bool torture_smb2_notify_file(struct torture_context
*torture
,
1116 struct smb2_tree
*tree
)
1122 union smb_notify notify
;
1123 struct smb2_request
*req
;
1124 struct smb2_handle h1
;
1125 const char *fname
= BASEDIR
"\\file.txt";
1127 smb2_deltree(tree
, BASEDIR
);
1128 smb2_util_rmdir(tree
, BASEDIR
);
1130 torture_comment(torture
, "TESTING CHANGE NOTIFY ON FILES\n");
1131 status
= torture_smb2_testdir(tree
, BASEDIR
, &h1
);
1132 CHECK_STATUS(status
, NT_STATUS_OK
);
1134 ZERO_STRUCT(io
.smb2
);
1135 io
.generic
.level
= RAW_OPEN_SMB2
;
1136 io
.smb2
.in
.create_flags
= 0;
1137 io
.smb2
.in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
;
1138 io
.smb2
.in
.create_options
= 0;
1139 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1140 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1141 NTCREATEX_SHARE_ACCESS_WRITE
;
1142 io
.smb2
.in
.alloc_size
= 0;
1143 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1144 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1145 io
.smb2
.in
.security_flags
= 0;
1146 io
.smb2
.in
.fname
= fname
;
1147 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1148 CHECK_STATUS(status
, NT_STATUS_OK
);
1149 h1
= io
.smb2
.out
.file
.handle
;
1151 /* ask for a change notify,
1152 on file or directory name changes */
1153 ZERO_STRUCT(notify
.smb2
);
1154 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1155 notify
.smb2
.in
.file
.handle
= h1
;
1156 notify
.smb2
.in
.buffer_size
= 1000;
1157 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_STREAM_NAME
;
1158 notify
.smb2
.in
.recursive
= false;
1160 torture_comment(torture
,
1161 "Testing if notifies on file handles are invalid (should be)\n");
1163 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1164 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1165 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1167 ZERO_STRUCT(cl
.smb2
);
1168 cl
.close
.level
= RAW_CLOSE_SMB2
;
1169 cl
.close
.in
.file
.handle
= h1
;
1170 status
= smb2_close(tree
, &(cl
.smb2
));
1171 CHECK_STATUS(status
, NT_STATUS_OK
);
1173 status
= smb2_util_unlink(tree
, fname
);
1174 CHECK_STATUS(status
, NT_STATUS_OK
);
1177 smb2_deltree(tree
, BASEDIR
);
1181 basic testing of change notifies followed by a tdis
1184 static bool torture_smb2_notify_tree_disconnect(
1185 struct torture_context
*torture
,
1186 struct smb2_tree
*tree
)
1190 union smb_notify notify
;
1192 struct smb2_handle h1
;
1193 struct smb2_request
*req
;
1195 smb2_deltree(tree
, BASEDIR
);
1196 smb2_util_rmdir(tree
, BASEDIR
);
1198 torture_comment(torture
, "TESTING CHANGE NOTIFY+CANCEL FOLLOWED BY "
1199 "TREE-DISCONNECT\n");
1202 get a handle on the directory
1204 ZERO_STRUCT(io
.smb2
);
1205 io
.generic
.level
= RAW_OPEN_SMB2
;
1206 io
.smb2
.in
.create_flags
= 0;
1207 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1208 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1209 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1210 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1211 NTCREATEX_SHARE_ACCESS_WRITE
;
1212 io
.smb2
.in
.alloc_size
= 0;
1213 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1214 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1215 io
.smb2
.in
.security_flags
= 0;
1216 io
.smb2
.in
.fname
= BASEDIR
;
1218 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1219 CHECK_STATUS(status
, NT_STATUS_OK
);
1220 h1
= io
.smb2
.out
.file
.handle
;
1222 /* ask for a change notify,
1223 on file or directory name changes */
1224 ZERO_STRUCT(notify
.smb2
);
1225 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1226 notify
.smb2
.in
.buffer_size
= 1000;
1227 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1228 notify
.smb2
.in
.file
.handle
= h1
;
1229 notify
.smb2
.in
.recursive
= true;
1231 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1233 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1235 status
= smb2_tdis(tree
);
1236 CHECK_STATUS(status
, NT_STATUS_OK
);
1238 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1240 smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1241 CHECK_STATUS(status
, NT_STATUS_OK
);
1242 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1245 smb2_deltree(tree
, BASEDIR
);
1250 testing of change notifies followed by a tdis - no cancel
1253 static bool torture_smb2_notify_tree_disconnect_1(
1254 struct torture_context
*torture
,
1255 struct smb2_tree
*tree
)
1259 union smb_notify notify
;
1261 struct smb2_handle h1
;
1262 struct smb2_request
*req
;
1264 smb2_deltree(tree
, BASEDIR
);
1265 smb2_util_rmdir(tree
, BASEDIR
);
1267 torture_comment(torture
, "TESTING CHANGE NOTIFY ASYNC FOLLOWED BY "
1268 "TREE-DISCONNECT\n");
1271 get a handle on the directory
1273 ZERO_STRUCT(io
.smb2
);
1274 io
.generic
.level
= RAW_OPEN_SMB2
;
1275 io
.smb2
.in
.create_flags
= 0;
1276 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1277 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1278 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1279 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1280 NTCREATEX_SHARE_ACCESS_WRITE
;
1281 io
.smb2
.in
.alloc_size
= 0;
1282 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1283 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1284 io
.smb2
.in
.security_flags
= 0;
1285 io
.smb2
.in
.fname
= BASEDIR
;
1287 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1288 CHECK_STATUS(status
, NT_STATUS_OK
);
1289 h1
= io
.smb2
.out
.file
.handle
;
1291 /* ask for a change notify,
1292 on file or directory name changes */
1293 ZERO_STRUCT(notify
.smb2
);
1294 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1295 notify
.smb2
.in
.buffer_size
= 1000;
1296 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1297 notify
.smb2
.in
.file
.handle
= h1
;
1298 notify
.smb2
.in
.recursive
= true;
1300 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1301 WAIT_FOR_ASYNC_RESPONSE(req
);
1303 status
= smb2_tdis(tree
);
1304 CHECK_STATUS(status
, NT_STATUS_OK
);
1306 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1307 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
1308 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1311 smb2_deltree(tree
, BASEDIR
);
1316 basic testing of change notifies followed by a close
1319 static bool torture_smb2_notify_close(struct torture_context
*torture
,
1320 struct smb2_tree
*tree1
)
1324 union smb_notify notify
;
1326 struct smb2_handle h1
;
1327 struct smb2_request
*req
;
1329 smb2_deltree(tree1
, BASEDIR
);
1330 smb2_util_rmdir(tree1
, BASEDIR
);
1332 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1335 get a handle on the directory
1337 ZERO_STRUCT(io
.smb2
);
1338 io
.generic
.level
= RAW_OPEN_SMB2
;
1339 io
.smb2
.in
.create_flags
= 0;
1340 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1341 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1342 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1343 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1344 NTCREATEX_SHARE_ACCESS_WRITE
;
1345 io
.smb2
.in
.alloc_size
= 0;
1346 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1347 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1348 io
.smb2
.in
.security_flags
= 0;
1349 io
.smb2
.in
.fname
= BASEDIR
;
1351 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1352 CHECK_STATUS(status
, NT_STATUS_OK
);
1354 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1355 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1356 CHECK_STATUS(status
, NT_STATUS_OK
);
1357 h1
= io
.smb2
.out
.file
.handle
;
1359 /* ask for a change notify,
1360 on file or directory name changes */
1361 ZERO_STRUCT(notify
.smb2
);
1362 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1363 notify
.smb2
.in
.buffer_size
= 1000;
1364 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1365 notify
.smb2
.in
.file
.handle
= h1
;
1366 notify
.smb2
.in
.recursive
= true;
1368 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1370 WAIT_FOR_ASYNC_RESPONSE(req
);
1372 status
= smb2_util_close(tree1
, h1
);
1373 CHECK_STATUS(status
, NT_STATUS_OK
);
1375 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1376 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
1377 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1380 smb2_deltree(tree1
, BASEDIR
);
1385 basic testing of change notifies followed by a ulogoff
1388 static bool torture_smb2_notify_ulogoff(struct torture_context
*torture
,
1389 struct smb2_tree
*tree1
)
1393 union smb_notify notify
;
1395 struct smb2_handle h1
;
1396 struct smb2_request
*req
;
1398 smb2_deltree(tree1
, BASEDIR
);
1399 smb2_util_rmdir(tree1
, BASEDIR
);
1401 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1404 get a handle on the directory
1406 ZERO_STRUCT(io
.smb2
);
1407 io
.generic
.level
= RAW_OPEN_SMB2
;
1408 io
.smb2
.in
.create_flags
= 0;
1409 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1410 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1411 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1412 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1413 NTCREATEX_SHARE_ACCESS_WRITE
;
1414 io
.smb2
.in
.alloc_size
= 0;
1415 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1416 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1417 io
.smb2
.in
.security_flags
= 0;
1418 io
.smb2
.in
.fname
= BASEDIR
;
1420 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1421 CHECK_STATUS(status
, NT_STATUS_OK
);
1423 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1424 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1425 CHECK_STATUS(status
, NT_STATUS_OK
);
1426 h1
= io
.smb2
.out
.file
.handle
;
1428 /* ask for a change notify,
1429 on file or directory name changes */
1430 ZERO_STRUCT(notify
.smb2
);
1431 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1432 notify
.smb2
.in
.buffer_size
= 1000;
1433 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1434 notify
.smb2
.in
.file
.handle
= h1
;
1435 notify
.smb2
.in
.recursive
= true;
1437 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1439 WAIT_FOR_ASYNC_RESPONSE(req
);
1441 status
= smb2_logoff(tree1
->session
);
1442 CHECK_STATUS(status
, NT_STATUS_OK
);
1444 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1445 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
1446 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1449 smb2_deltree(tree1
, BASEDIR
);
1454 basic testing of change notifies followed by a session reconnect
1457 static bool torture_smb2_notify_session_reconnect(struct torture_context
*torture
,
1458 struct smb2_tree
*tree1
)
1462 union smb_notify notify
;
1464 struct smb2_handle h1
;
1465 struct smb2_request
*req
;
1466 uint64_t previous_session_id
= 0;
1467 struct smb2_session
*session2
= NULL
;
1469 smb2_deltree(tree1
, BASEDIR
);
1470 smb2_util_rmdir(tree1
, BASEDIR
);
1472 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY SESSION RECONNECT\n");
1475 get a handle on the directory
1477 ZERO_STRUCT(io
.smb2
);
1478 io
.generic
.level
= RAW_OPEN_SMB2
;
1479 io
.smb2
.in
.create_flags
= 0;
1480 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1481 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1482 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1483 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1484 NTCREATEX_SHARE_ACCESS_WRITE
;
1485 io
.smb2
.in
.alloc_size
= 0;
1486 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1487 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1488 io
.smb2
.in
.security_flags
= 0;
1489 io
.smb2
.in
.fname
= BASEDIR
;
1491 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1492 CHECK_STATUS(status
, NT_STATUS_OK
);
1494 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1495 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1496 CHECK_STATUS(status
, NT_STATUS_OK
);
1497 h1
= io
.smb2
.out
.file
.handle
;
1499 /* ask for a change notify,
1500 on file or directory name changes */
1501 ZERO_STRUCT(notify
.smb2
);
1502 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1503 notify
.smb2
.in
.buffer_size
= 1000;
1504 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1505 notify
.smb2
.in
.file
.handle
= h1
;
1506 notify
.smb2
.in
.recursive
= true;
1508 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1510 WAIT_FOR_ASYNC_RESPONSE(req
);
1512 previous_session_id
= smb2cli_session_current_id(tree1
->session
->smbXcli
);
1513 torture_assert(torture
, torture_smb2_session_setup(torture
,
1514 tree1
->session
->transport
,
1515 previous_session_id
,
1516 torture
, &session2
),
1517 "session setup with previous_session_id failed");
1519 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1520 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
1521 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1523 status
= smb2_logoff(tree1
->session
);
1524 CHECK_STATUS(status
, NT_STATUS_USER_SESSION_DELETED
);
1526 status
= smb2_logoff(session2
);
1527 CHECK_STATUS(status
, NT_STATUS_OK
);
1529 smb2_deltree(tree1
, BASEDIR
);
1534 basic testing of change notifies followed by an invalid reauth
1537 static bool torture_smb2_notify_invalid_reauth(struct torture_context
*torture
,
1538 struct smb2_tree
*tree1
,
1539 struct smb2_tree
*tree2
)
1543 union smb_notify notify
;
1545 struct smb2_handle h1
;
1546 struct smb2_request
*req
;
1547 struct cli_credentials
*invalid_creds
;
1549 smb2_deltree(tree2
, BASEDIR
);
1550 smb2_util_rmdir(tree2
, BASEDIR
);
1552 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY invalid REAUTH\n");
1555 get a handle on the directory
1557 ZERO_STRUCT(io
.smb2
);
1558 io
.generic
.level
= RAW_OPEN_SMB2
;
1559 io
.smb2
.in
.create_flags
= 0;
1560 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1561 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1562 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1563 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1564 NTCREATEX_SHARE_ACCESS_WRITE
;
1565 io
.smb2
.in
.alloc_size
= 0;
1566 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1567 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1568 io
.smb2
.in
.security_flags
= 0;
1569 io
.smb2
.in
.fname
= BASEDIR
;
1571 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1572 CHECK_STATUS(status
, NT_STATUS_OK
);
1574 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1575 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1576 CHECK_STATUS(status
, NT_STATUS_OK
);
1577 h1
= io
.smb2
.out
.file
.handle
;
1579 /* ask for a change notify,
1580 on file or directory name changes */
1581 ZERO_STRUCT(notify
.smb2
);
1582 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1583 notify
.smb2
.in
.buffer_size
= 1000;
1584 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1585 notify
.smb2
.in
.file
.handle
= h1
;
1586 notify
.smb2
.in
.recursive
= true;
1588 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1590 WAIT_FOR_ASYNC_RESPONSE(req
);
1592 invalid_creds
= cli_credentials_init(torture
);
1593 torture_assert(torture
, (invalid_creds
!= NULL
), "talloc error");
1594 cli_credentials_set_username(invalid_creds
, "__none__invalid__none__", CRED_SPECIFIED
);
1595 cli_credentials_set_domain(invalid_creds
, "__none__invalid__none__", CRED_SPECIFIED
);
1596 cli_credentials_set_password(invalid_creds
, "__none__invalid__none__", CRED_SPECIFIED
);
1597 cli_credentials_set_realm(invalid_creds
, NULL
, CRED_SPECIFIED
);
1598 cli_credentials_set_workstation(invalid_creds
, "", CRED_UNINITIALISED
);
1600 status
= smb2_session_setup_spnego(tree1
->session
,
1602 0 /* previous_session_id */);
1603 CHECK_STATUS(status
, NT_STATUS_LOGON_FAILURE
);
1605 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1606 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
1607 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1610 smb2_deltree(tree2
, BASEDIR
);
1614 static void tcp_dis_handler(struct smb2_transport
*t
, void *p
)
1616 struct smb2_tree
*tree
= (struct smb2_tree
*)p
;
1617 smb2_transport_dead(tree
->session
->transport
,
1618 NT_STATUS_LOCAL_DISCONNECT
);
1624 basic testing of change notifies followed by tcp disconnect
1627 static bool torture_smb2_notify_tcp_disconnect(
1628 struct torture_context
*torture
,
1629 struct smb2_tree
*tree
)
1633 union smb_notify notify
;
1635 struct smb2_handle h1
;
1636 struct smb2_request
*req
;
1638 smb2_deltree(tree
, BASEDIR
);
1639 smb2_util_rmdir(tree
, BASEDIR
);
1641 torture_comment(torture
,
1642 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1645 get a handle on the directory
1647 ZERO_STRUCT(io
.smb2
);
1648 io
.generic
.level
= RAW_OPEN_SMB2
;
1649 io
.smb2
.in
.create_flags
= 0;
1650 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1651 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1652 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1653 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1654 NTCREATEX_SHARE_ACCESS_WRITE
;
1655 io
.smb2
.in
.alloc_size
= 0;
1656 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1657 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1658 io
.smb2
.in
.security_flags
= 0;
1659 io
.smb2
.in
.fname
= BASEDIR
;
1661 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1662 CHECK_STATUS(status
, NT_STATUS_OK
);
1663 h1
= io
.smb2
.out
.file
.handle
;
1665 /* ask for a change notify,
1666 on file or directory name changes */
1667 ZERO_STRUCT(notify
.smb2
);
1668 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1669 notify
.smb2
.in
.buffer_size
= 1000;
1670 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1671 notify
.smb2
.in
.file
.handle
= h1
;
1672 notify
.smb2
.in
.recursive
= true;
1674 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1676 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1677 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1679 notify
.smb2
.in
.recursive
= true;
1680 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1681 smb2_transport_idle_handler(tree
->session
->transport
,
1682 tcp_dis_handler
, 250, tree
);
1684 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1685 CHECK_STATUS(status
, NT_STATUS_LOCAL_DISCONNECT
);
1692 test setting up two change notify requests on one handle
1695 static bool torture_smb2_notify_double(struct torture_context
*torture
,
1696 struct smb2_tree
*tree1
,
1697 struct smb2_tree
*tree2
)
1701 union smb_notify notify
;
1703 struct smb2_handle h1
;
1704 struct smb2_request
*req1
, *req2
;
1706 smb2_deltree(tree1
, BASEDIR
);
1707 smb2_util_rmdir(tree1
, BASEDIR
);
1709 torture_comment(torture
,
1710 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1713 get a handle on the directory
1715 ZERO_STRUCT(io
.smb2
);
1716 io
.generic
.level
= RAW_OPEN_SMB2
;
1717 io
.smb2
.in
.create_flags
= 0;
1718 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
1719 SEC_RIGHTS_FILE_WRITE
|
1720 SEC_RIGHTS_FILE_ALL
;
1721 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1722 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1723 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1724 NTCREATEX_SHARE_ACCESS_WRITE
;
1725 io
.smb2
.in
.alloc_size
= 0;
1726 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1727 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1728 io
.smb2
.in
.security_flags
= 0;
1729 io
.smb2
.in
.fname
= BASEDIR
;
1731 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1732 CHECK_STATUS(status
, NT_STATUS_OK
);
1733 h1
= io
.smb2
.out
.file
.handle
;
1735 /* ask for a change notify,
1736 on file or directory name changes */
1737 ZERO_STRUCT(notify
.smb2
);
1738 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1739 notify
.smb2
.in
.buffer_size
= 1000;
1740 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1741 notify
.smb2
.in
.file
.handle
= h1
;
1742 notify
.smb2
.in
.recursive
= true;
1744 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
1746 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1747 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1749 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
1751 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
1752 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1754 smb2_util_mkdir(tree2
, BASEDIR
"\\subdir-name");
1755 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
1756 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
1758 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1759 CHECK_STATUS(status
, NT_STATUS_OK
);
1760 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1761 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
1763 smb2_util_mkdir(tree2
, BASEDIR
"\\subdir-name2");
1765 status
= smb2_notify_recv(req2
, 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-name2");
1771 smb2_deltree(tree1
, BASEDIR
);
1777 test multiple change notifies at different depths and with/without recursion
1780 static bool torture_smb2_notify_tree(struct torture_context
*torture
,
1781 struct smb2_tree
*tree
)
1784 union smb_notify notify
;
1786 struct smb2_request
*req
;
1793 struct smb2_handle h1
;
1796 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 30 },
1797 {BASEDIR
"\\zqy", true, FILE_NOTIFY_CHANGE_NAME
, 8 },
1798 {BASEDIR
"\\atsy", true, FILE_NOTIFY_CHANGE_NAME
, 4 },
1799 {BASEDIR
"\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1800 {BASEDIR
"\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME
, 13 },
1801 {BASEDIR
"\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME
, 7 },
1802 {BASEDIR
"\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1803 {BASEDIR
"\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1804 {BASEDIR
"\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1805 {BASEDIR
"\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1806 {BASEDIR
"\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1807 {BASEDIR
"\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1808 {BASEDIR
"\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME
, 40 },
1809 {BASEDIR
, true, FILE_NOTIFY_CHANGE_NAME
, 40 },
1810 {BASEDIR
, false,FILE_NOTIFY_CHANGE_NAME
, 6 },
1811 {BASEDIR
"\\atsy", false,FILE_NOTIFY_CHANGE_NAME
, 4 },
1812 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 24 },
1813 {BASEDIR
"\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME
, 0 },
1814 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME
, 0 },
1815 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 24 },
1819 bool all_done
= false;
1821 smb2_deltree(tree
, BASEDIR
);
1822 smb2_util_rmdir(tree
, BASEDIR
);
1824 torture_comment(torture
, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1826 ZERO_STRUCT(io
.smb2
);
1827 io
.generic
.level
= RAW_OPEN_SMB2
;
1828 io
.smb2
.in
.create_flags
= 0;
1829 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1830 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1831 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1832 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1833 NTCREATEX_SHARE_ACCESS_WRITE
;
1834 io
.smb2
.in
.alloc_size
= 0;
1835 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1836 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1837 io
.smb2
.in
.security_flags
= 0;
1838 io
.smb2
.in
.fname
= BASEDIR
;
1839 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1840 CHECK_STATUS(status
, NT_STATUS_OK
);
1842 ZERO_STRUCT(notify
.smb2
);
1843 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1844 notify
.smb2
.in
.buffer_size
= 20000;
1847 setup the directory tree, and the notify buffer on each directory
1849 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1850 io
.smb2
.in
.fname
= dirs
[i
].path
;
1851 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1852 CHECK_STATUS(status
, NT_STATUS_OK
);
1853 dirs
[i
].h1
= io
.smb2
.out
.file
.handle
;
1855 notify
.smb2
.in
.completion_filter
= dirs
[i
].filter
;
1856 notify
.smb2
.in
.file
.handle
= dirs
[i
].h1
;
1857 notify
.smb2
.in
.recursive
= dirs
[i
].recursive
;
1858 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1860 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1861 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1864 /* trigger 2 events in each dir */
1865 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1866 char *path
= talloc_asprintf(torture
, "%s\\test.dir",
1868 smb2_util_mkdir(tree
, path
);
1869 smb2_util_rmdir(tree
, path
);
1873 /* give a bit of time for the events to propogate */
1874 tv
= timeval_current();
1877 /* count events that have happened in each dir */
1878 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1879 notify
.smb2
.in
.file
.handle
= dirs
[i
].h1
;
1880 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1882 notify
.smb2
.out
.num_changes
= 0;
1883 status
= smb2_notify_recv(req
, torture
,
1885 dirs
[i
].counted
+= notify
.smb2
.out
.num_changes
;
1890 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1891 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
1895 } while (!all_done
&& timeval_elapsed(&tv
) < 20);
1897 torture_comment(torture
, "took %.4f seconds to propogate all events\n",
1898 timeval_elapsed(&tv
));
1900 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1901 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
1902 torture_comment(torture
,
1903 "ERROR: i=%d expected %d got %d for '%s'\n",
1904 i
, dirs
[i
].expected
, dirs
[i
].counted
,
1911 run from the back, closing and deleting
1913 for (i
=ARRAY_SIZE(dirs
)-1;i
>=0;i
--) {
1914 smb2_util_close(tree
, dirs
[i
].h1
);
1915 smb2_util_rmdir(tree
, dirs
[i
].path
);
1919 smb2_deltree(tree
, BASEDIR
);
1920 smb2_util_rmdir(tree
, BASEDIR
);
1925 Test response when cached server events exceed single NT NOTFIY response
1929 static bool torture_smb2_notify_overflow(struct torture_context
*torture
,
1930 struct smb2_tree
*tree
)
1934 union smb_notify notify
;
1936 struct smb2_handle h1
, h2
;
1938 struct smb2_request
*req1
;
1941 smb2_deltree(tree
, BASEDIR
);
1942 smb2_util_rmdir(tree
, BASEDIR
);
1944 torture_comment(torture
, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1946 /* get a handle on the directory */
1947 ZERO_STRUCT(io
.smb2
);
1948 io
.generic
.level
= RAW_OPEN_SMB2
;
1949 io
.smb2
.in
.create_flags
= 0;
1950 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1951 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1952 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1953 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1954 NTCREATEX_SHARE_ACCESS_WRITE
;
1955 io
.smb2
.in
.alloc_size
= 0;
1956 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1957 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1958 io
.smb2
.in
.security_flags
= 0;
1959 io
.smb2
.in
.fname
= BASEDIR
;
1961 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1962 CHECK_STATUS(status
, NT_STATUS_OK
);
1963 h1
= io
.smb2
.out
.file
.handle
;
1965 /* ask for a change notify, on name changes. */
1966 ZERO_STRUCT(notify
.smb2
);
1967 notify
.smb2
.level
= RAW_NOTIFY_NTTRANS
;
1968 notify
.smb2
.in
.buffer_size
= 1000;
1969 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1970 notify
.smb2
.in
.file
.handle
= h1
;
1972 notify
.smb2
.in
.recursive
= true;
1973 req1
= smb2_notify_send(tree
, &(notify
.smb2
));
1975 /* cancel initial requests so the buffer is setup */
1977 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1978 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1980 /* open a lot of files, filling up the server side notify buffer */
1981 torture_comment(torture
,
1982 "Testing overflowed buffer notify on create of %d files\n",
1985 for (i
=0;i
<count
;i
++) {
1986 char *fname
= talloc_asprintf(torture
,
1987 BASEDIR
"\\test%d.txt", i
);
1989 ZERO_STRUCT(io1
.smb2
);
1990 io1
.generic
.level
= RAW_OPEN_SMB2
;
1991 io1
.smb2
.in
.create_flags
= 0;
1992 io1
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1993 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1994 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1995 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1996 NTCREATEX_SHARE_ACCESS_WRITE
;
1997 io1
.smb2
.in
.alloc_size
= 0;
1998 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1999 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
2000 io1
.smb2
.in
.security_flags
= 0;
2001 io1
.smb2
.in
.fname
= fname
;
2003 h2
= custom_smb2_create(tree
, torture
, &(io1
.smb2
));
2005 smb2_util_close(tree
, h2
);
2008 req1
= smb2_notify_send(tree
, &(notify
.smb2
));
2009 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
2010 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
2011 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
2014 smb2_deltree(tree
, BASEDIR
);
2019 Test if notifications are returned for changes to the base directory.
2023 static bool torture_smb2_notify_basedir(struct torture_context
*torture
,
2024 struct smb2_tree
*tree1
,
2025 struct smb2_tree
*tree2
)
2029 union smb_notify notify
;
2031 struct smb2_handle h1
;
2032 struct smb2_request
*req1
;
2034 smb2_deltree(tree1
, BASEDIR
);
2035 smb2_util_rmdir(tree1
, BASEDIR
);
2037 torture_comment(torture
, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
2039 /* get a handle on the directory */
2040 ZERO_STRUCT(io
.smb2
);
2041 io
.generic
.level
= RAW_OPEN_SMB2
;
2042 io
.smb2
.in
.create_flags
= 0;
2043 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
2044 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2045 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2046 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2047 NTCREATEX_SHARE_ACCESS_WRITE
;
2048 io
.smb2
.in
.alloc_size
= 0;
2049 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
2050 io
.smb2
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
2051 io
.smb2
.in
.security_flags
= 0;
2052 io
.smb2
.in
.fname
= BASEDIR
;
2054 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
2055 CHECK_STATUS(status
, NT_STATUS_OK
);
2056 h1
= io
.smb2
.out
.file
.handle
;
2058 /* create a test file that will also be modified */
2059 io
.smb2
.in
.fname
= BASEDIR
"\\tname1";
2060 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
2061 status
= smb2_create(tree2
, torture
, &(io
.smb2
));
2062 CHECK_STATUS(status
,NT_STATUS_OK
);
2063 smb2_util_close(tree2
, io
.smb2
.out
.file
.handle
);
2065 /* ask for a change notify, on attribute changes. */
2066 ZERO_STRUCT(notify
.smb2
);
2067 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
2068 notify
.smb2
.in
.buffer_size
= 1000;
2069 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
2070 notify
.smb2
.in
.file
.handle
= h1
;
2071 notify
.smb2
.in
.recursive
= true;
2073 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
2075 /* set attribute on the base dir */
2076 smb2_util_setatr(tree2
, BASEDIR
, FILE_ATTRIBUTE_HIDDEN
);
2078 /* set attribute on a file to assure we receive a notification */
2079 smb2_util_setatr(tree2
, BASEDIR
"\\tname1", FILE_ATTRIBUTE_HIDDEN
);
2082 /* check how many responses were given, expect only 1 for the file */
2083 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
2084 CHECK_STATUS(status
, NT_STATUS_OK
);
2085 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2086 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
2087 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "tname1");
2090 smb2_deltree(tree1
, BASEDIR
);
2096 create a secondary tree connect - used to test for a bug in Samba3 messaging
2099 static struct smb2_tree
*secondary_tcon(struct smb2_tree
*tree
,
2100 struct torture_context
*tctx
)
2103 const char *share
, *host
;
2104 struct smb2_tree
*tree1
;
2105 union smb_tcon tcon
;
2107 share
= torture_setting_string(tctx
, "share", NULL
);
2108 host
= torture_setting_string(tctx
, "host", NULL
);
2110 torture_comment(tctx
,
2111 "create a second tree context on the same session\n");
2112 tree1
= smb2_tree_init(tree
->session
, tctx
, false);
2113 if (tree1
== NULL
) {
2114 torture_comment(tctx
, "Out of memory\n");
2118 ZERO_STRUCT(tcon
.smb2
);
2119 tcon
.generic
.level
= RAW_TCON_SMB2
;
2120 tcon
.smb2
.in
.path
= talloc_asprintf(tctx
, "\\\\%s\\%s", host
, share
);
2121 status
= smb2_tree_connect(tree
->session
, &(tcon
.smb2
));
2122 if (!NT_STATUS_IS_OK(status
)) {
2124 torture_comment(tctx
,"Failed to create secondary tree\n");
2128 smb2cli_tcon_set_values(tree1
->smbXcli
,
2129 tree1
->session
->smbXcli
,
2131 tcon
.smb2
.out
.share_type
,
2132 tcon
.smb2
.out
.flags
,
2133 tcon
.smb2
.out
.capabilities
,
2134 tcon
.smb2
.out
.access_mask
);
2136 torture_comment(tctx
,"tid1=%d tid2=%d\n",
2137 smb2cli_tcon_current_id(tree
->smbXcli
),
2138 smb2cli_tcon_current_id(tree1
->smbXcli
));
2145 very simple change notify test
2147 static bool torture_smb2_notify_tcon(struct torture_context
*torture
,
2148 struct smb2_tree
*tree
)
2152 union smb_notify notify
;
2154 struct smb2_handle h1
;
2155 struct smb2_request
*req
= NULL
;
2156 struct smb2_tree
*tree1
= NULL
;
2157 const char *fname
= BASEDIR
"\\subdir-name";
2159 smb2_deltree(tree
, BASEDIR
);
2160 smb2_util_rmdir(tree
, BASEDIR
);
2162 torture_comment(torture
, "TESTING SIMPLE CHANGE NOTIFY\n");
2165 get a handle on the directory
2168 ZERO_STRUCT(io
.smb2
);
2169 io
.generic
.level
= RAW_OPEN_SMB2
;
2170 io
.smb2
.in
.create_flags
= 0;
2171 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
2172 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2173 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
|
2174 FILE_ATTRIBUTE_DIRECTORY
;
2175 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2176 NTCREATEX_SHARE_ACCESS_WRITE
;
2177 io
.smb2
.in
.alloc_size
= 0;
2178 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
2179 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
2180 io
.smb2
.in
.security_flags
= 0;
2181 io
.smb2
.in
.fname
= BASEDIR
;
2183 status
= smb2_create(tree
, torture
, &(io
.smb2
));
2184 CHECK_STATUS(status
, NT_STATUS_OK
);
2185 h1
= io
.smb2
.out
.file
.handle
;
2187 /* ask for a change notify,
2188 on file or directory name changes */
2189 ZERO_STRUCT(notify
.smb2
);
2190 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
2191 notify
.smb2
.in
.buffer_size
= 1000;
2192 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
2193 notify
.smb2
.in
.file
.handle
= h1
;
2194 notify
.smb2
.in
.recursive
= true;
2196 torture_comment(torture
, "Testing notify mkdir\n");
2197 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2199 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2200 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
2202 notify
.smb2
.in
.recursive
= true;
2203 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2204 status
= smb2_util_mkdir(tree
, fname
);
2205 CHECK_STATUS(status
, NT_STATUS_OK
);
2207 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2208 CHECK_STATUS(status
, NT_STATUS_OK
);
2210 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2211 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
2212 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2214 torture_comment(torture
, "Testing notify rmdir\n");
2215 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2216 status
= smb2_util_rmdir(tree
, fname
);
2217 CHECK_STATUS(status
, NT_STATUS_OK
);
2219 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2220 CHECK_STATUS(status
, NT_STATUS_OK
);
2221 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2222 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
2223 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2225 torture_comment(torture
, "SIMPLE CHANGE NOTIFY OK\n");
2227 torture_comment(torture
, "TESTING WITH SECONDARY TCON\n");
2228 tree1
= secondary_tcon(tree
, torture
);
2230 torture_comment(torture
, "Testing notify mkdir\n");
2231 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2232 smb2_util_mkdir(tree1
, fname
);
2234 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2235 CHECK_STATUS(status
, NT_STATUS_OK
);
2237 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2238 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
2239 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2241 torture_comment(torture
, "Testing notify rmdir\n");
2242 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2243 smb2_util_rmdir(tree
, fname
);
2245 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2246 CHECK_STATUS(status
, NT_STATUS_OK
);
2247 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2248 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
2249 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2251 torture_comment(torture
, "CHANGE NOTIFY WITH TCON OK\n");
2253 torture_comment(torture
, "Disconnecting secondary tree\n");
2254 status
= smb2_tdis(tree1
);
2255 CHECK_STATUS(status
, NT_STATUS_OK
);
2258 torture_comment(torture
, "Testing notify mkdir\n");
2259 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2260 smb2_util_mkdir(tree
, fname
);
2262 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2263 CHECK_STATUS(status
, NT_STATUS_OK
);
2265 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2266 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
2267 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2269 torture_comment(torture
, "Testing notify rmdir\n");
2270 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2271 smb2_util_rmdir(tree
, fname
);
2273 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2274 CHECK_STATUS(status
, NT_STATUS_OK
);
2275 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2276 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
2277 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2279 torture_comment(torture
, "CHANGE NOTIFY WITH TDIS OK\n");
2281 smb2_util_close(tree
, h1
);
2282 smb2_deltree(tree
, BASEDIR
);
2288 basic testing of SMB2 change notify
2290 struct torture_suite
*torture_smb2_notify_init(void)
2292 struct torture_suite
*suite
= torture_suite_create(talloc_autofree_context(), "notify");
2294 torture_suite_add_1smb2_test(suite
, "valid-req", test_valid_request
);
2295 torture_suite_add_1smb2_test(suite
, "tcon", torture_smb2_notify_tcon
);
2296 torture_suite_add_2smb2_test(suite
, "dir", torture_smb2_notify_dir
);
2297 torture_suite_add_2smb2_test(suite
, "mask", torture_smb2_notify_mask
);
2298 torture_suite_add_1smb2_test(suite
, "tdis", torture_smb2_notify_tree_disconnect
);
2299 torture_suite_add_1smb2_test(suite
, "tdis1", torture_smb2_notify_tree_disconnect_1
);
2300 torture_suite_add_2smb2_test(suite
, "mask-change", torture_smb2_notify_mask_change
);
2301 torture_suite_add_1smb2_test(suite
, "close", torture_smb2_notify_close
);
2302 torture_suite_add_1smb2_test(suite
, "logoff", torture_smb2_notify_ulogoff
);
2303 torture_suite_add_1smb2_test(suite
, "session-reconnect", torture_smb2_notify_session_reconnect
);
2304 torture_suite_add_2smb2_test(suite
, "invalid-reauth", torture_smb2_notify_invalid_reauth
);
2305 torture_suite_add_1smb2_test(suite
, "tree", torture_smb2_notify_tree
);
2306 torture_suite_add_2smb2_test(suite
, "basedir", torture_smb2_notify_basedir
);
2307 torture_suite_add_2smb2_test(suite
, "double", torture_smb2_notify_double
);
2308 torture_suite_add_1smb2_test(suite
, "file", torture_smb2_notify_file
);
2309 torture_suite_add_1smb2_test(suite
, "tcp", torture_smb2_notify_tcp_disconnect
);
2310 torture_suite_add_2smb2_test(suite
, "rec", torture_smb2_notify_recursive
);
2311 torture_suite_add_1smb2_test(suite
, "overflow", torture_smb2_notify_overflow
);
2313 suite
->description
= talloc_strdup(suite
, "SMB2-NOTIFY tests");