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/cmdline.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_transport_credits_ask_num(tree
->session
->transport
, 256);
96 smb2_util_unlink(tree
, FNAME
);
98 status
= smb2_util_roothandle(tree
, &dh
);
99 CHECK_STATUS(status
, NT_STATUS_OK
);
102 smb2cli_conn_max_trans_size(tree
->session
->transport
->conn
);
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_simple_file(torture
, tree
, FNAME
);
118 CHECK_STATUS(status
, NT_STATUS_OK
);
120 status
= smb2_notify_recv(req
, torture
, &n
);
121 CHECK_STATUS(status
, NT_STATUS_OK
);
122 CHECK_VAL(n
.out
.num_changes
, 1);
123 CHECK_VAL(n
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
124 CHECK_WIRE_STR(n
.out
.changes
[0].name
, FNAME
);
127 * if the change response doesn't fit in the buffer
128 * NOTIFY_ENUM_DIR is returned.
130 n
.in
.buffer_size
= 0x00000000;
131 req
= smb2_notify_send(tree
, &n
);
133 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
134 if (tevent_loop_once(torture
->ev
) != 0) {
139 status
= torture_setup_simple_file(torture
, tree
, FNAME
);
140 CHECK_STATUS(status
, NT_STATUS_OK
);
142 status
= smb2_notify_recv(req
, torture
, &n
);
143 CHECK_STATUS(status
, NT_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_simple_file(torture
, tree
, FNAME
);
159 CHECK_STATUS(status
, NT_STATUS_OK
);
161 status
= smb2_notify_recv(req
, torture
, &n
);
162 CHECK_STATUS(status
, NT_STATUS_OK
);
163 CHECK_VAL(n
.out
.num_changes
, 3);
164 CHECK_VAL(n
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
165 CHECK_WIRE_STR(n
.out
.changes
[0].name
, FNAME
);
166 CHECK_VAL(n
.out
.changes
[1].action
, NOTIFY_ACTION_ADDED
);
167 CHECK_WIRE_STR(n
.out
.changes
[1].name
, FNAME
);
168 CHECK_VAL(n
.out
.changes
[2].action
, NOTIFY_ACTION_MODIFIED
);
169 CHECK_WIRE_STR(n
.out
.changes
[2].name
, FNAME
);
171 /* if the first notify returns NOTIFY_ENUM_DIR, all do */
172 status
= smb2_util_close(tree
, dh
);
173 CHECK_STATUS(status
, NT_STATUS_OK
);
174 status
= smb2_util_roothandle(tree
, &dh
);
175 CHECK_STATUS(status
, NT_STATUS_OK
);
177 n
.in
.recursive
= 0x0000;
178 n
.in
.buffer_size
= 0x00000001;
179 n
.in
.file
.handle
= dh
;
180 n
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ALL
;
181 n
.in
.unknown
= 0x00000000;
182 req
= smb2_notify_send(tree
, &n
);
184 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
185 if (tevent_loop_once(torture
->ev
) != 0) {
190 status
= torture_setup_simple_file(torture
, tree
, FNAME
);
191 CHECK_STATUS(status
, NT_STATUS_OK
);
193 status
= smb2_notify_recv(req
, torture
, &n
);
194 CHECK_STATUS(status
, NT_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_simple_file(torture
, tree
, FNAME
);
205 CHECK_STATUS(status
, NT_STATUS_OK
);
207 status
= smb2_notify_recv(req
, torture
, &n
);
208 CHECK_STATUS(status
, NT_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
228 #define BASEDIR_DIR BASEDIR "_DIR"
230 static bool torture_smb2_notify_dir(struct torture_context
*torture
,
231 struct smb2_tree
*tree1
,
232 struct smb2_tree
*tree2
)
236 union smb_notify notify
;
240 struct smb2_handle h1
= {{0}};
241 struct smb2_handle h2
= {{0}};
242 struct smb2_request
*req
, *req2
;
243 const char *fname
= BASEDIR_DIR
"\\subdir-name";
244 extern int torture_numops
;
246 torture_comment(torture
, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
248 smb2_deltree(tree1
, BASEDIR_DIR
);
249 smb2_util_rmdir(tree1
, BASEDIR_DIR
);
251 get a handle on the directory
253 ZERO_STRUCT(io
.smb2
);
254 io
.generic
.level
= RAW_OPEN_SMB2
;
255 io
.smb2
.in
.create_flags
= 0;
256 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
257 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
258 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
259 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
260 NTCREATEX_SHARE_ACCESS_WRITE
;
261 io
.smb2
.in
.alloc_size
= 0;
262 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
263 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
264 io
.smb2
.in
.security_flags
= 0;
265 io
.smb2
.in
.fname
= BASEDIR_DIR
;
267 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
268 CHECK_STATUS(status
, NT_STATUS_OK
);
269 h1
= io
.smb2
.out
.file
.handle
;
271 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
272 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
;
273 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
274 CHECK_STATUS(status
, NT_STATUS_OK
);
275 h2
= io
.smb2
.out
.file
.handle
;
277 /* ask for a change notify,
278 on file or directory name changes */
279 ZERO_STRUCT(notify
.smb2
);
280 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
281 notify
.smb2
.in
.buffer_size
= 1000;
282 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
283 notify
.smb2
.in
.file
.handle
= h1
;
284 notify
.smb2
.in
.recursive
= true;
286 torture_comment(torture
, "Testing notify cancel\n");
288 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
290 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
291 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
293 torture_comment(torture
, "Testing notify mkdir\n");
295 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
296 smb2_util_mkdir(tree2
, fname
);
298 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
299 CHECK_STATUS(status
, NT_STATUS_OK
);
301 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
302 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
303 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
305 torture_comment(torture
, "Testing notify rmdir\n");
307 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
308 smb2_util_rmdir(tree2
, fname
);
310 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
311 CHECK_STATUS(status
, NT_STATUS_OK
);
312 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
313 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
314 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
316 torture_comment(torture
,
317 "Testing notify mkdir - rmdir - mkdir - rmdir\n");
319 smb2_util_mkdir(tree2
, fname
);
320 smb2_util_rmdir(tree2
, fname
);
321 smb2_util_mkdir(tree2
, fname
);
322 smb2_util_rmdir(tree2
, fname
);
324 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
325 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
326 CHECK_STATUS(status
, NT_STATUS_OK
);
327 CHECK_VAL(notify
.smb2
.out
.num_changes
, 4);
328 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
329 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
330 CHECK_VAL(notify
.smb2
.out
.changes
[1].action
, NOTIFY_ACTION_REMOVED
);
331 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[1].name
, "subdir-name");
332 CHECK_VAL(notify
.smb2
.out
.changes
[2].action
, NOTIFY_ACTION_ADDED
);
333 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[2].name
, "subdir-name");
334 CHECK_VAL(notify
.smb2
.out
.changes
[3].action
, NOTIFY_ACTION_REMOVED
);
335 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[3].name
, "subdir-name");
337 count
= torture_numops
;
338 torture_comment(torture
,
339 "Testing buffered notify on create of %d files\n", count
);
340 for (i
=0;i
<count
;i
++) {
341 struct smb2_handle h12
;
342 char *fname2
= talloc_asprintf(torture
,
343 BASEDIR_DIR
"\\test%d.txt",
346 ZERO_STRUCT(io
.smb2
);
347 io
.generic
.level
= RAW_OPEN_SMB2
;
348 io
.smb2
.in
.create_flags
= 0;
349 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
350 io
.smb2
.in
.create_options
=
351 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
352 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
353 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
354 NTCREATEX_SHARE_ACCESS_WRITE
;
355 io
.smb2
.in
.alloc_size
= 0;
356 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
357 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
358 io
.smb2
.in
.security_flags
= 0;
359 io
.smb2
.in
.fname
= fname2
;
361 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
362 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OK
)) {
363 torture_comment(torture
, "Failed to create %s \n",
368 h12
= io
.smb2
.out
.file
.handle
;
370 smb2_util_close(tree1
, h12
);
373 /* (1st notify) setup a new notify on a different directory handle.
374 This new notify won't see the events above. */
375 notify
.smb2
.in
.file
.handle
= h2
;
376 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
378 /* (2nd notify) whereas this notify will see the above buffered events,
379 and it directly returns the buffered events */
380 notify
.smb2
.in
.file
.handle
= h1
;
381 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
383 status
= smb2_util_unlink(tree1
, BASEDIR_DIR
"\\nonexistent.txt");
384 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
386 /* (1st unlink) as the 2nd notify directly returns,
387 this unlink is only seen by the 1st notify and
388 the 3rd notify (later) */
389 torture_comment(torture
,
390 "Testing notify on unlink for the first file\n");
391 status
= smb2_util_unlink(tree2
, BASEDIR_DIR
"\\test0.txt");
392 CHECK_STATUS(status
, NT_STATUS_OK
);
394 /* receive the reply from the 2nd notify */
395 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
396 CHECK_STATUS(status
, NT_STATUS_OK
);
398 CHECK_VAL(notify
.smb2
.out
.num_changes
, count
);
399 for (i
=1;i
<count
;i
++) {
400 CHECK_VAL(notify
.smb2
.out
.changes
[i
].action
,
401 NOTIFY_ACTION_ADDED
);
403 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "test0.txt");
405 torture_comment(torture
, "and now from the 1st notify\n");
406 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
407 CHECK_STATUS(status
, NT_STATUS_OK
);
408 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
409 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
410 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "test0.txt");
412 torture_comment(torture
,
413 "(3rd notify) this notify will only see the 1st unlink\n");
414 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
416 status
= smb2_util_unlink(tree1
, BASEDIR_DIR
"\\nonexistent.txt");
417 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
419 for (i
=1;i
<count
;i
++) {
420 char *fname2
= talloc_asprintf(torture
,
421 BASEDIR_DIR
"\\test%d.txt", i
);
422 status
= smb2_util_unlink(tree2
, fname2
);
423 CHECK_STATUS(status
, NT_STATUS_OK
);
427 /* receive the 3rd notify */
428 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
429 CHECK_STATUS(status
, NT_STATUS_OK
);
430 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
431 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
432 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "test0.txt");
434 /* and we now see the rest of the unlink calls on both
435 * directory handles */
436 notify
.smb2
.in
.file
.handle
= h1
;
438 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
439 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
440 CHECK_STATUS(status
, NT_STATUS_OK
);
441 CHECK_VAL(notify
.smb2
.out
.num_changes
, count
-1);
442 for (i
=0;i
<notify
.smb2
.out
.num_changes
;i
++) {
443 CHECK_VAL(notify
.smb2
.out
.changes
[i
].action
,
444 NOTIFY_ACTION_REMOVED
);
446 notify
.smb2
.in
.file
.handle
= h2
;
447 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
448 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
449 CHECK_STATUS(status
, NT_STATUS_OK
);
450 CHECK_VAL(notify
.smb2
.out
.num_changes
, count
-1);
451 for (i
=0;i
<notify
.smb2
.out
.num_changes
;i
++) {
452 CHECK_VAL(notify
.smb2
.out
.changes
[i
].action
,
453 NOTIFY_ACTION_REMOVED
);
456 torture_comment(torture
,
457 "Testing if a close() on the dir handle triggers the notify reply\n");
459 notify
.smb2
.in
.file
.handle
= h1
;
460 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
462 ZERO_STRUCT(cl
.smb2
);
463 cl
.smb2
.level
= RAW_CLOSE_SMB2
;
464 cl
.smb2
.in
.file
.handle
= h1
;
465 status
= smb2_close(tree1
, &(cl
.smb2
));
466 CHECK_STATUS(status
, NT_STATUS_OK
);
468 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
469 CHECK_STATUS(status
, NT_STATUS_NOTIFY_CLEANUP
);
470 CHECK_VAL(notify
.smb2
.out
.num_changes
, 9);
473 smb2_util_close(tree1
, h1
);
474 smb2_util_close(tree1
, h2
);
475 smb2_deltree(tree1
, BASEDIR_DIR
);
479 static struct smb2_handle
custom_smb2_create(struct smb2_tree
*tree
,
480 struct torture_context
*torture
,
481 struct smb2_create
*smb2
)
483 struct smb2_handle h1
;
486 smb2_deltree(tree
, smb2
->in
.fname
);
487 status
= smb2_create(tree
, torture
, smb2
);
488 CHECK_STATUS(status
, NT_STATUS_OK
);
489 h1
= smb2
->out
.file
.handle
;
492 h1
= (struct smb2_handle
) {
500 testing of recursive change notify
503 #define BASEDIR_REC BASEDIR "_REC"
505 static bool torture_smb2_notify_recursive(struct torture_context
*torture
,
506 struct smb2_tree
*tree1
,
507 struct smb2_tree
*tree2
)
511 union smb_notify notify
;
512 union smb_open io
, io1
;
513 union smb_setfileinfo sinfo
;
514 struct smb2_handle h1
;
515 struct smb2_request
*req1
, *req2
;
517 smb2_deltree(tree1
, BASEDIR_REC
);
518 smb2_util_rmdir(tree1
, BASEDIR_REC
);
520 torture_comment(torture
, "TESTING CHANGE NOTIFY WITH RECURSION\n");
523 get a handle on the directory
525 ZERO_STRUCT(io
.smb2
);
526 io
.generic
.level
= RAW_OPEN_SMB2
;
527 io
.smb2
.in
.create_flags
= 0;
528 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
529 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
530 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
531 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
532 NTCREATEX_SHARE_ACCESS_WRITE
;
533 io
.smb2
.in
.alloc_size
= 0;
534 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
535 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
536 io
.smb2
.in
.security_flags
= 0;
537 io
.smb2
.in
.fname
= BASEDIR_REC
;
539 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
540 CHECK_STATUS(status
, NT_STATUS_OK
);
541 h1
= io
.smb2
.out
.file
.handle
;
543 /* ask for a change notify, on file or directory name
544 changes. Setup both with and without recursion */
545 ZERO_STRUCT(notify
.smb2
);
546 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
547 notify
.smb2
.in
.buffer_size
= 1000;
548 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
|
549 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
550 FILE_NOTIFY_CHANGE_CREATION
;
551 notify
.smb2
.in
.file
.handle
= h1
;
553 notify
.smb2
.in
.recursive
= true;
554 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
556 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
557 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
559 notify
.smb2
.in
.recursive
= false;
560 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
562 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
563 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
565 ZERO_STRUCT(io1
.smb2
);
566 io1
.generic
.level
= RAW_OPEN_SMB2
;
567 io1
.smb2
.in
.create_flags
= NTCREATEX_FLAGS_EXTENDED
;
568 io1
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
569 SEC_RIGHTS_FILE_WRITE
|
571 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
572 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
573 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
574 NTCREATEX_SHARE_ACCESS_WRITE
|
575 NTCREATEX_SHARE_ACCESS_DELETE
;
576 io1
.smb2
.in
.alloc_size
= 0;
577 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
578 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
579 io1
.smb2
.in
.security_flags
= 0;
580 io1
.smb2
.in
.fname
= BASEDIR_REC
"\\subdir-name";
581 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
582 CHECK_STATUS(status
, NT_STATUS_OK
);
583 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
585 io1
.smb2
.in
.fname
= BASEDIR_REC
"\\subdir-name\\subname1";
586 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
587 CHECK_STATUS(status
, NT_STATUS_OK
);
589 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
590 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
591 sinfo
.rename_information
.in
.overwrite
= 0;
592 sinfo
.rename_information
.in
.root_fid
= 0;
593 sinfo
.rename_information
.in
.new_name
=
594 BASEDIR_REC
"\\subdir-name\\subname1-r";
595 status
= smb2_setinfo_file(tree2
, &sinfo
);
596 CHECK_STATUS(status
, NT_STATUS_OK
);
598 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
599 io1
.smb2
.in
.fname
= BASEDIR_REC
"\\subdir-name\\subname2";
600 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
601 CHECK_STATUS(status
, NT_STATUS_OK
);
603 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
604 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
605 sinfo
.rename_information
.in
.overwrite
= true;
606 sinfo
.rename_information
.in
.root_fid
= 0;
607 sinfo
.rename_information
.in
.new_name
= BASEDIR_REC
"\\subname2-r";
608 status
= smb2_setinfo_file(tree2
, &sinfo
);
609 CHECK_STATUS(status
, NT_STATUS_OK
);
611 io1
.smb2
.in
.fname
= BASEDIR_REC
"\\subname2-r";
612 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
613 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
614 CHECK_STATUS(status
, NT_STATUS_OK
);
616 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
617 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
618 sinfo
.rename_information
.in
.overwrite
= true;
619 sinfo
.rename_information
.in
.root_fid
= 0;
620 sinfo
.rename_information
.in
.new_name
= BASEDIR_REC
"\\subname3-r";
621 status
= smb2_setinfo_file(tree2
, &sinfo
);
622 CHECK_STATUS(status
, NT_STATUS_OK
);
624 notify
.smb2
.in
.completion_filter
= 0;
625 notify
.smb2
.in
.recursive
= true;
627 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
629 status
= smb2_util_rmdir(tree2
,
630 BASEDIR_REC
"\\subdir-name\\subname1-r");
631 CHECK_STATUS(status
, NT_STATUS_OK
);
632 status
= smb2_util_rmdir(tree2
,
633 BASEDIR_REC
"\\subdir-name");
634 CHECK_STATUS(status
, NT_STATUS_OK
);
635 status
= smb2_util_unlink(tree2
, BASEDIR_REC
"\\subname3-r");
636 CHECK_STATUS(status
, NT_STATUS_OK
);
638 notify
.smb2
.in
.recursive
= false;
639 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
641 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
642 CHECK_STATUS(status
, NT_STATUS_OK
);
644 CHECK_VAL(notify
.smb2
.out
.num_changes
, 9);
645 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
646 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
647 CHECK_VAL(notify
.smb2
.out
.changes
[1].action
, NOTIFY_ACTION_ADDED
);
648 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[1].name
, "subdir-name\\subname1");
649 CHECK_VAL(notify
.smb2
.out
.changes
[2].action
, NOTIFY_ACTION_OLD_NAME
);
650 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[2].name
, "subdir-name\\subname1");
651 CHECK_VAL(notify
.smb2
.out
.changes
[3].action
, NOTIFY_ACTION_NEW_NAME
);
652 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[3].name
, "subdir-name\\subname1-r");
653 CHECK_VAL(notify
.smb2
.out
.changes
[4].action
, NOTIFY_ACTION_ADDED
);
654 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[4].name
, "subdir-name\\subname2");
655 CHECK_VAL(notify
.smb2
.out
.changes
[5].action
, NOTIFY_ACTION_REMOVED
);
656 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[5].name
, "subdir-name\\subname2");
657 CHECK_VAL(notify
.smb2
.out
.changes
[6].action
, NOTIFY_ACTION_ADDED
);
658 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[6].name
, "subname2-r");
659 CHECK_VAL(notify
.smb2
.out
.changes
[7].action
, NOTIFY_ACTION_OLD_NAME
);
660 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[7].name
, "subname2-r");
661 CHECK_VAL(notify
.smb2
.out
.changes
[8].action
, NOTIFY_ACTION_NEW_NAME
);
662 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[8].name
, "subname3-r");
665 smb2_deltree(tree1
, BASEDIR_REC
);
670 testing of change notify mask change
673 #define BASEDIR_MC BASEDIR "_MC"
675 static bool torture_smb2_notify_mask_change(struct torture_context
*torture
,
676 struct smb2_tree
*tree1
,
677 struct smb2_tree
*tree2
)
681 union smb_notify notify
;
682 union smb_open io
, io1
;
683 struct smb2_handle h1
;
684 struct smb2_request
*req1
, *req2
;
685 union smb_setfileinfo sinfo
;
687 smb2_deltree(tree1
, BASEDIR_MC
);
688 smb2_util_rmdir(tree1
, BASEDIR_MC
);
690 torture_comment(torture
, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
693 get a handle on the directory
695 ZERO_STRUCT(io
.smb2
);
696 io
.generic
.level
= RAW_OPEN_SMB2
;
697 io
.smb2
.in
.create_flags
= 0;
698 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
699 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
700 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
701 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
702 NTCREATEX_SHARE_ACCESS_WRITE
;
703 io
.smb2
.in
.alloc_size
= 0;
704 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
705 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
706 io
.smb2
.in
.security_flags
= 0;
707 io
.smb2
.in
.fname
= BASEDIR_MC
;
709 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
710 CHECK_STATUS(status
, NT_STATUS_OK
);
711 h1
= io
.smb2
.out
.file
.handle
;
713 /* ask for a change notify, on file or directory name
714 changes. Setup both with and without recursion */
715 ZERO_STRUCT(notify
.smb2
);
716 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
717 notify
.smb2
.in
.buffer_size
= 1000;
718 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
719 notify
.smb2
.in
.file
.handle
= h1
;
721 notify
.smb2
.in
.recursive
= true;
722 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
725 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
726 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
729 notify
.smb2
.in
.recursive
= false;
730 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
733 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
734 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
736 notify
.smb2
.in
.recursive
= true;
737 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
739 /* Set to hidden then back again. */
740 ZERO_STRUCT(io1
.smb2
);
741 io1
.generic
.level
= RAW_OPEN_SMB2
;
742 io1
.smb2
.in
.create_flags
= 0;
743 io1
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
744 SEC_RIGHTS_FILE_WRITE
|
746 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
747 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
748 NTCREATEX_SHARE_ACCESS_WRITE
|
749 NTCREATEX_SHARE_ACCESS_DELETE
;
750 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
751 io1
.smb2
.in
.security_flags
= 0;
752 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
753 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
754 io1
.smb2
.in
.fname
= BASEDIR_MC
"\\tname1";
756 smb2_util_close(tree1
,
757 custom_smb2_create(tree1
, torture
, &(io1
.smb2
)));
758 status
= smb2_util_setatr(tree1
, BASEDIR_MC
"\\tname1",
759 FILE_ATTRIBUTE_HIDDEN
);
760 CHECK_STATUS(status
, NT_STATUS_OK
);
761 smb2_util_unlink(tree1
, BASEDIR_MC
"\\tname1");
763 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
764 CHECK_STATUS(status
, NT_STATUS_OK
);
766 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
767 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
768 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "tname1");
770 /* Now try and change the mask to include other events.
771 * This should not work - once the mask is set on a directory
772 * h1 it seems to be fixed until the fnum is closed. */
774 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
|
775 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
776 FILE_NOTIFY_CHANGE_CREATION
;
777 notify
.smb2
.in
.recursive
= true;
778 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
780 notify
.smb2
.in
.recursive
= false;
781 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
783 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
784 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
785 io1
.smb2
.in
.fname
= BASEDIR_MC
"\\subdir-name";
786 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
787 CHECK_STATUS(status
, NT_STATUS_OK
);
788 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
791 io1
.smb2
.in
.fname
= BASEDIR_MC
"\\subdir-name\\subname1";
792 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
793 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
794 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
795 CHECK_STATUS(status
, NT_STATUS_OK
);
796 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
797 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
798 sinfo
.rename_information
.in
.overwrite
= true;
799 sinfo
.rename_information
.in
.root_fid
= 0;
800 sinfo
.rename_information
.in
.new_name
=
801 BASEDIR_MC
"\\subdir-name\\subname1-r";
802 status
= smb2_setinfo_file(tree2
, &sinfo
);
803 CHECK_STATUS(status
, NT_STATUS_OK
);
805 io1
.smb2
.in
.fname
= BASEDIR_MC
"\\subdir-name\\subname2";
806 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
807 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
808 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
809 CHECK_STATUS(status
, NT_STATUS_OK
);
810 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
811 sinfo
.rename_information
.in
.new_name
= BASEDIR_MC
"\\subname2-r";
812 status
= smb2_setinfo_file(tree2
, &sinfo
);
813 CHECK_STATUS(status
, NT_STATUS_OK
);
814 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
816 io1
.smb2
.in
.fname
= BASEDIR_MC
"\\subname2-r";
817 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
818 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
819 CHECK_STATUS(status
, NT_STATUS_OK
);
820 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
821 sinfo
.rename_information
.in
.new_name
= BASEDIR_MC
"\\subname3-r";
822 status
= smb2_setinfo_file(tree2
, &sinfo
);
823 CHECK_STATUS(status
, NT_STATUS_OK
);
824 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
826 status
= smb2_util_rmdir(tree2
, BASEDIR_MC
"\\subdir-name\\subname1-r");
827 CHECK_STATUS(status
, NT_STATUS_OK
);
828 status
= smb2_util_rmdir(tree2
, BASEDIR_MC
"\\subdir-name");
829 CHECK_STATUS(status
, NT_STATUS_OK
);
830 status
= smb2_util_unlink(tree2
, BASEDIR_MC
"\\subname3-r");
831 CHECK_STATUS(status
, NT_STATUS_OK
);
833 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
834 CHECK_STATUS(status
, NT_STATUS_OK
);
836 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
837 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
838 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subname2-r");
840 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
841 CHECK_STATUS(status
, NT_STATUS_OK
);
843 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
844 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
845 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subname3-r");
852 smb2_deltree(tree1
, BASEDIR_MC
);
857 testing of mask bits for change notify
860 #define BASEDIR_MSK BASEDIR "_MSK"
862 static bool torture_smb2_notify_mask(struct torture_context
*torture
,
863 struct smb2_tree
*tree1
,
864 struct smb2_tree
*tree2
)
868 union smb_notify notify
;
869 union smb_open io
, io1
;
870 struct smb2_handle h1
, h2
;
873 union smb_setfileinfo sinfo
;
875 smb2_deltree(tree1
, BASEDIR_MSK
);
876 smb2_util_rmdir(tree1
, BASEDIR_MSK
);
878 torture_comment(torture
, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
884 get a handle on the directory
886 ZERO_STRUCT(io
.smb2
);
887 io
.generic
.level
= RAW_OPEN_SMB2
;
888 io
.smb2
.in
.create_flags
= 0;
889 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
890 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
891 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
892 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
893 NTCREATEX_SHARE_ACCESS_WRITE
;
894 io
.smb2
.in
.alloc_size
= 0;
895 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
896 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
897 io
.smb2
.in
.security_flags
= 0;
898 io
.smb2
.in
.fname
= BASEDIR_MSK
;
900 ZERO_STRUCT(notify
.smb2
);
901 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
902 notify
.smb2
.in
.buffer_size
= 1000;
903 notify
.smb2
.in
.recursive
= true;
905 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
906 expected, nchanges) \
908 do { for (i=0;i<32;i++) { \
909 struct smb2_request *req; \
910 status = smb2_create(tree1, torture, &(io.smb2)); \
911 CHECK_STATUS(status, NT_STATUS_OK); \
912 h1 = io.smb2.out.file.handle; \
914 notify.smb2.in.file.handle = h1; \
915 notify.smb2.in.completion_filter = ((uint32_t)1<<i); \
916 /* cancel initial requests so the buffer is setup */ \
917 req = smb2_notify_send(tree1, &(notify.smb2)); \
919 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
920 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
921 /* send the change notify request */ \
922 req = smb2_notify_send(tree1, &(notify.smb2)); \
924 smb_msleep(200); smb2_cancel(req); \
925 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
927 smb2_util_close(tree1, h1); \
928 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
929 CHECK_STATUS(status, NT_STATUS_OK); \
930 /* special case to cope with file rename behaviour */ \
931 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
932 notify.smb2.out.changes[0].action == \
933 NOTIFY_ACTION_MODIFIED && \
934 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
935 Action == NOTIFY_ACTION_OLD_NAME) { \
936 torture_comment(torture, \
937 "(rename file special handling OK)\n"); \
938 } else if (nchanges != notify.smb2.out.num_changes) { \
939 torture_result(torture, TORTURE_FAIL, \
940 "ERROR: nchanges=%d expected=%d "\
941 "action=%d filter=0x%08x\n", \
942 notify.smb2.out.num_changes, \
944 notify.smb2.out.changes[0].action, \
945 notify.smb2.in.completion_filter); \
947 } else if (notify.smb2.out.changes[0].action != Action) { \
948 torture_result(torture, TORTURE_FAIL, \
949 "ERROR: nchanges=%d action=%d " \
950 "expectedAction=%d filter=0x%08x\n", \
951 notify.smb2.out.num_changes, \
952 notify.smb2.out.changes[0].action, \
954 notify.smb2.in.completion_filter); \
956 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
958 torture_result(torture, TORTURE_FAIL, \
959 "ERROR: nchanges=%d action=%d " \
960 "filter=0x%08x name=%s\n", \
961 notify.smb2.out.num_changes, \
962 notify.smb2.out.changes[0].action, \
963 notify.smb2.in.completion_filter, \
964 notify.smb2.out.changes[0].name.s); \
971 torture_comment(torture
, "Testing mkdir\n");
972 NOTIFY_MASK_TEST("Testing mkdir",;,
973 smb2_util_mkdir(tree2
, BASEDIR_MSK
"\\tname1");,
974 smb2_util_rmdir(tree2
, BASEDIR_MSK
"\\tname1");,
976 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
978 torture_comment(torture
, "Testing create file\n");
979 ZERO_STRUCT(io1
.smb2
);
980 io1
.generic
.level
= RAW_OPEN_SMB2
;
981 io1
.smb2
.in
.create_flags
= 0;
982 io1
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
983 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
984 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
985 NTCREATEX_SHARE_ACCESS_WRITE
;
986 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
987 io1
.smb2
.in
.security_flags
= 0;
988 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
989 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
990 io1
.smb2
.in
.fname
= BASEDIR_MSK
"\\tname1";
992 NOTIFY_MASK_TEST("Testing create file",;,
993 smb2_util_close(tree2
, custom_smb2_create(tree2
,
994 torture
, &(io1
.smb2
)));,
995 smb2_util_unlink(tree2
, BASEDIR_MSK
"\\tname1");,
997 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
999 torture_comment(torture
, "Testing unlink\n");
1000 NOTIFY_MASK_TEST("Testing unlink",
1001 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1002 torture
, &(io1
.smb2
)));,
1003 smb2_util_unlink(tree2
, BASEDIR_MSK
"\\tname1");,
1005 NOTIFY_ACTION_REMOVED
,
1006 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
1008 torture_comment(torture
, "Testing rmdir\n");
1009 NOTIFY_MASK_TEST("Testing rmdir",
1010 smb2_util_mkdir(tree2
, BASEDIR_MSK
"\\tname1");,
1011 smb2_util_rmdir(tree2
, BASEDIR_MSK
"\\tname1");,
1013 NOTIFY_ACTION_REMOVED
,
1014 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
1016 torture_comment(torture
, "Testing rename file\n");
1018 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1019 sinfo
.rename_information
.in
.file
.handle
= h1
;
1020 sinfo
.rename_information
.in
.overwrite
= true;
1021 sinfo
.rename_information
.in
.root_fid
= 0;
1022 sinfo
.rename_information
.in
.new_name
= BASEDIR_MSK
"\\tname2";
1023 NOTIFY_MASK_TEST("Testing rename file",
1024 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1025 torture
, &(io1
.smb2
)));,
1026 smb2_setinfo_file(tree2
, &sinfo
);,
1027 smb2_util_unlink(tree2
, BASEDIR_MSK
"\\tname2");,
1028 NOTIFY_ACTION_OLD_NAME
,
1029 FILE_NOTIFY_CHANGE_FILE_NAME
, 2);
1031 torture_comment(torture
, "Testing rename dir\n");
1033 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1034 sinfo
.rename_information
.in
.file
.handle
= h1
;
1035 sinfo
.rename_information
.in
.overwrite
= true;
1036 sinfo
.rename_information
.in
.root_fid
= 0;
1037 sinfo
.rename_information
.in
.new_name
= BASEDIR_MSK
"\\tname2";
1038 NOTIFY_MASK_TEST("Testing rename dir",
1039 smb2_util_mkdir(tree2
, BASEDIR_MSK
"\\tname1");,
1040 smb2_setinfo_file(tree2
, &sinfo
);,
1041 smb2_util_rmdir(tree2
, BASEDIR_MSK
"\\tname2");,
1042 NOTIFY_ACTION_OLD_NAME
,
1043 FILE_NOTIFY_CHANGE_DIR_NAME
, 2);
1045 torture_comment(torture
, "Testing set path attribute\n");
1046 NOTIFY_MASK_TEST("Testing set path attribute",
1047 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1048 torture
, &(io
.smb2
)));,
1049 smb2_util_setatr(tree2
, BASEDIR_MSK
"\\tname1",
1050 FILE_ATTRIBUTE_HIDDEN
);,
1051 smb2_util_unlink(tree2
, BASEDIR_MSK
"\\tname1");,
1052 NOTIFY_ACTION_MODIFIED
,
1053 FILE_NOTIFY_CHANGE_ATTRIBUTES
, 1);
1055 torture_comment(torture
, "Testing set path write time\n");
1057 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1058 sinfo
.generic
.in
.file
.handle
= h1
;
1059 sinfo
.basic_info
.in
.write_time
= 1000;
1060 NOTIFY_MASK_TEST("Testing set path write time",
1061 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1062 torture
, &(io1
.smb2
)));,
1063 smb2_setinfo_file(tree2
, &sinfo
);,
1064 smb2_util_unlink(tree2
, BASEDIR_MSK
"\\tname1");,
1065 NOTIFY_ACTION_MODIFIED
,
1066 FILE_NOTIFY_CHANGE_LAST_WRITE
, 1);
1068 if (torture_setting_bool(torture
, "samba3", false)) {
1069 torture_comment(torture
,
1070 "Samba3 does not yet support create times "
1075 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1076 sinfo
.generic
.in
.file
.handle
= h1
;
1077 sinfo
.basic_info
.in
.create_time
= 0;
1078 torture_comment(torture
, "Testing set file create time\n");
1079 NOTIFY_MASK_TEST("Testing set file create time",
1080 smb2_create_complex_file(torture
, tree2
,
1081 BASEDIR_MSK
"\\tname1", &h2
);,
1082 smb2_setinfo_file(tree2
, &sinfo
);,
1083 (smb2_util_close(tree2
, h2
),
1084 smb2_util_unlink(tree2
, BASEDIR_MSK
"\\tname1"));,
1085 NOTIFY_ACTION_MODIFIED
,
1086 FILE_NOTIFY_CHANGE_CREATION
, 1);
1090 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1091 sinfo
.generic
.in
.file
.handle
= h1
;
1092 sinfo
.basic_info
.in
.access_time
= 0;
1093 torture_comment(torture
, "Testing set file access time\n");
1094 NOTIFY_MASK_TEST("Testing set file access time",
1095 smb2_create_complex_file(torture
,
1097 BASEDIR_MSK
"\\tname1",
1099 smb2_setinfo_file(tree2
, &sinfo
);,
1100 (smb2_util_close(tree2
, h2
),
1101 smb2_util_unlink(tree2
, BASEDIR_MSK
"\\tname1"));,
1102 NOTIFY_ACTION_MODIFIED
,
1103 FILE_NOTIFY_CHANGE_LAST_ACCESS
, 1);
1106 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1107 sinfo
.generic
.in
.file
.handle
= h1
;
1108 sinfo
.basic_info
.in
.change_time
= 0;
1109 torture_comment(torture
, "Testing set file change time\n");
1110 NOTIFY_MASK_TEST("Testing set file change time",
1111 smb2_create_complex_file(torture
,
1113 BASEDIR_MSK
"\\tname1",
1115 smb2_setinfo_file(tree2
, &sinfo
);,
1116 (smb2_util_close(tree2
, h2
),
1117 smb2_util_unlink(tree2
, BASEDIR_MSK
"\\tname1"));,
1118 NOTIFY_ACTION_MODIFIED
,
1122 torture_comment(torture
, "Testing write\n");
1123 NOTIFY_MASK_TEST("Testing write",
1124 smb2_create_complex_file(torture
,
1126 BASEDIR_MSK
"\\tname1",
1128 smb2_util_write(tree2
, h2
, &c
, 10000, 1);,
1129 (smb2_util_close(tree2
, h2
),
1130 smb2_util_unlink(tree2
, BASEDIR_MSK
"\\tname1"));,
1131 NOTIFY_ACTION_MODIFIED
,
1135 smb2_deltree(tree1
, BASEDIR_MSK
);
1139 #define BASEDIR_FL BASEDIR "_FL"
1141 basic testing of change notify on files
1143 static bool torture_smb2_notify_file(struct torture_context
*torture
,
1144 struct smb2_tree
*tree
)
1150 union smb_notify notify
;
1151 struct smb2_request
*req
;
1152 struct smb2_handle h1
;
1153 const char *fname
= BASEDIR_FL
"\\file.txt";
1155 smb2_deltree(tree
, BASEDIR_FL
);
1156 smb2_util_rmdir(tree
, BASEDIR_FL
);
1158 torture_comment(torture
, "TESTING CHANGE NOTIFY ON FILES\n");
1159 status
= torture_smb2_testdir(tree
, BASEDIR_FL
, &h1
);
1160 CHECK_STATUS(status
, NT_STATUS_OK
);
1162 ZERO_STRUCT(io
.smb2
);
1163 io
.generic
.level
= RAW_OPEN_SMB2
;
1164 io
.smb2
.in
.create_flags
= 0;
1165 io
.smb2
.in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
;
1166 io
.smb2
.in
.create_options
= 0;
1167 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1168 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1169 NTCREATEX_SHARE_ACCESS_WRITE
;
1170 io
.smb2
.in
.alloc_size
= 0;
1171 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1172 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1173 io
.smb2
.in
.security_flags
= 0;
1174 io
.smb2
.in
.fname
= fname
;
1175 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1176 CHECK_STATUS(status
, NT_STATUS_OK
);
1177 h1
= io
.smb2
.out
.file
.handle
;
1179 /* ask for a change notify,
1180 on file or directory name changes */
1181 ZERO_STRUCT(notify
.smb2
);
1182 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1183 notify
.smb2
.in
.file
.handle
= h1
;
1184 notify
.smb2
.in
.buffer_size
= 1000;
1185 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_STREAM_NAME
;
1186 notify
.smb2
.in
.recursive
= false;
1188 torture_comment(torture
,
1189 "Testing if notifies on file handles are invalid (should be)\n");
1191 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1192 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1193 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1195 ZERO_STRUCT(cl
.smb2
);
1196 cl
.close
.level
= RAW_CLOSE_SMB2
;
1197 cl
.close
.in
.file
.handle
= h1
;
1198 status
= smb2_close(tree
, &(cl
.smb2
));
1199 CHECK_STATUS(status
, NT_STATUS_OK
);
1201 status
= smb2_util_unlink(tree
, fname
);
1202 CHECK_STATUS(status
, NT_STATUS_OK
);
1205 smb2_deltree(tree
, BASEDIR_FL
);
1209 basic testing of change notifies followed by a tdis
1212 #define BASEDIR_TD BASEDIR "_TD"
1214 static bool torture_smb2_notify_tree_disconnect(
1215 struct torture_context
*torture
,
1216 struct smb2_tree
*tree
)
1220 union smb_notify notify
;
1222 struct smb2_handle h1
;
1223 struct smb2_request
*req
;
1225 smb2_deltree(tree
, BASEDIR_TD
);
1226 smb2_util_rmdir(tree
, BASEDIR_TD
);
1228 torture_comment(torture
, "TESTING CHANGE NOTIFY+CANCEL FOLLOWED BY "
1229 "TREE-DISCONNECT\n");
1232 get a handle on the directory
1234 ZERO_STRUCT(io
.smb2
);
1235 io
.generic
.level
= RAW_OPEN_SMB2
;
1236 io
.smb2
.in
.create_flags
= 0;
1237 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1238 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1239 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1240 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1241 NTCREATEX_SHARE_ACCESS_WRITE
;
1242 io
.smb2
.in
.alloc_size
= 0;
1243 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1244 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1245 io
.smb2
.in
.security_flags
= 0;
1246 io
.smb2
.in
.fname
= BASEDIR_TD
;
1248 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1249 CHECK_STATUS(status
, NT_STATUS_OK
);
1250 h1
= io
.smb2
.out
.file
.handle
;
1252 /* ask for a change notify,
1253 on file or directory name changes */
1254 ZERO_STRUCT(notify
.smb2
);
1255 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1256 notify
.smb2
.in
.buffer_size
= 1000;
1257 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1258 notify
.smb2
.in
.file
.handle
= h1
;
1259 notify
.smb2
.in
.recursive
= true;
1261 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1263 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1265 status
= smb2_tdis(tree
);
1266 CHECK_STATUS(status
, NT_STATUS_OK
);
1268 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1270 smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1271 CHECK_STATUS(status
, NT_STATUS_OK
);
1272 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1275 smb2_deltree(tree
, BASEDIR_TD
);
1280 testing of change notifies followed by a tdis - no cancel
1283 #define BASEDIR_NTDIS BASEDIR "_NTDIS"
1285 static bool torture_smb2_notify_tree_disconnect_1(
1286 struct torture_context
*torture
,
1287 struct smb2_tree
*tree
)
1291 union smb_notify notify
;
1293 struct smb2_handle h1
;
1294 struct smb2_request
*req
;
1296 smb2_deltree(tree
, BASEDIR_NTDIS
);
1297 smb2_util_rmdir(tree
, BASEDIR_NTDIS
);
1299 torture_comment(torture
, "TESTING CHANGE NOTIFY ASYNC FOLLOWED BY "
1300 "TREE-DISCONNECT\n");
1303 get a handle on the directory
1305 ZERO_STRUCT(io
.smb2
);
1306 io
.generic
.level
= RAW_OPEN_SMB2
;
1307 io
.smb2
.in
.create_flags
= 0;
1308 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1309 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1310 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1311 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1312 NTCREATEX_SHARE_ACCESS_WRITE
;
1313 io
.smb2
.in
.alloc_size
= 0;
1314 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1315 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1316 io
.smb2
.in
.security_flags
= 0;
1317 io
.smb2
.in
.fname
= BASEDIR_NTDIS
;
1319 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1320 CHECK_STATUS(status
, NT_STATUS_OK
);
1321 h1
= io
.smb2
.out
.file
.handle
;
1323 /* ask for a change notify,
1324 on file or directory name changes */
1325 ZERO_STRUCT(notify
.smb2
);
1326 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1327 notify
.smb2
.in
.buffer_size
= 1000;
1328 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1329 notify
.smb2
.in
.file
.handle
= h1
;
1330 notify
.smb2
.in
.recursive
= true;
1332 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1333 WAIT_FOR_ASYNC_RESPONSE(req
);
1335 status
= smb2_tdis(tree
);
1336 CHECK_STATUS(status
, NT_STATUS_OK
);
1338 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1339 CHECK_STATUS(status
, NT_STATUS_NOTIFY_CLEANUP
);
1340 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1343 smb2_deltree(tree
, BASEDIR_NTDIS
);
1348 basic testing of change notifies followed by a close
1351 #define BASEDIR_CNC BASEDIR "_CNC"
1353 static bool torture_smb2_notify_close(struct torture_context
*torture
,
1354 struct smb2_tree
*tree1
)
1358 union smb_notify notify
;
1360 struct smb2_handle h1
;
1361 struct smb2_request
*req
;
1363 smb2_deltree(tree1
, BASEDIR_CNC
);
1364 smb2_util_rmdir(tree1
, BASEDIR_CNC
);
1366 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1369 get a handle on the directory
1371 ZERO_STRUCT(io
.smb2
);
1372 io
.generic
.level
= RAW_OPEN_SMB2
;
1373 io
.smb2
.in
.create_flags
= 0;
1374 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1375 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1376 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1377 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1378 NTCREATEX_SHARE_ACCESS_WRITE
;
1379 io
.smb2
.in
.alloc_size
= 0;
1380 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1381 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1382 io
.smb2
.in
.security_flags
= 0;
1383 io
.smb2
.in
.fname
= BASEDIR_CNC
;
1385 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1386 CHECK_STATUS(status
, NT_STATUS_OK
);
1388 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1389 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1390 CHECK_STATUS(status
, NT_STATUS_OK
);
1391 h1
= io
.smb2
.out
.file
.handle
;
1393 /* ask for a change notify,
1394 on file or directory name changes */
1395 ZERO_STRUCT(notify
.smb2
);
1396 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1397 notify
.smb2
.in
.buffer_size
= 1000;
1398 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1399 notify
.smb2
.in
.file
.handle
= h1
;
1400 notify
.smb2
.in
.recursive
= true;
1402 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1404 WAIT_FOR_ASYNC_RESPONSE(req
);
1406 status
= smb2_util_close(tree1
, h1
);
1407 CHECK_STATUS(status
, NT_STATUS_OK
);
1409 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1410 CHECK_STATUS(status
, NT_STATUS_NOTIFY_CLEANUP
);
1411 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1414 smb2_deltree(tree1
, BASEDIR_CNC
);
1419 basic testing of change notifies followed by a ulogoff
1422 #define BASEDIR_NUL BASEDIR "_NUL"
1423 static bool torture_smb2_notify_ulogoff(struct torture_context
*torture
,
1424 struct smb2_tree
*tree1
)
1428 union smb_notify notify
;
1430 struct smb2_handle h1
;
1431 struct smb2_request
*req
;
1433 smb2_deltree(tree1
, BASEDIR_NUL
);
1434 smb2_util_rmdir(tree1
, BASEDIR_NUL
);
1436 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1439 get a handle on the directory
1441 ZERO_STRUCT(io
.smb2
);
1442 io
.generic
.level
= RAW_OPEN_SMB2
;
1443 io
.smb2
.in
.create_flags
= 0;
1444 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1445 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1446 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1447 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1448 NTCREATEX_SHARE_ACCESS_WRITE
;
1449 io
.smb2
.in
.alloc_size
= 0;
1450 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1451 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1452 io
.smb2
.in
.security_flags
= 0;
1453 io
.smb2
.in
.fname
= BASEDIR_NUL
;
1455 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1456 CHECK_STATUS(status
, NT_STATUS_OK
);
1458 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1459 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1460 CHECK_STATUS(status
, NT_STATUS_OK
);
1461 h1
= io
.smb2
.out
.file
.handle
;
1463 /* ask for a change notify,
1464 on file or directory name changes */
1465 ZERO_STRUCT(notify
.smb2
);
1466 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1467 notify
.smb2
.in
.buffer_size
= 1000;
1468 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1469 notify
.smb2
.in
.file
.handle
= h1
;
1470 notify
.smb2
.in
.recursive
= true;
1472 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1474 WAIT_FOR_ASYNC_RESPONSE(req
);
1476 status
= smb2_logoff(tree1
->session
);
1477 CHECK_STATUS(status
, NT_STATUS_OK
);
1479 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1480 CHECK_STATUS(status
, NT_STATUS_NOTIFY_CLEANUP
);
1481 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1484 smb2_deltree(tree1
, BASEDIR_NUL
);
1489 basic testing of change notifies followed by a session reconnect
1492 #define BASEDIR_NSR BASEDIR "_NSR"
1494 static bool torture_smb2_notify_session_reconnect(struct torture_context
*torture
,
1495 struct smb2_tree
*tree1
)
1499 union smb_notify notify
;
1501 struct smb2_handle h1
;
1502 struct smb2_request
*req
;
1503 uint64_t previous_session_id
= 0;
1504 struct smb2_session
*session2
= NULL
;
1506 smb2_deltree(tree1
, BASEDIR_NSR
);
1507 smb2_util_rmdir(tree1
, BASEDIR_NSR
);
1509 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY SESSION RECONNECT\n");
1512 get a handle on the directory
1514 ZERO_STRUCT(io
.smb2
);
1515 io
.generic
.level
= RAW_OPEN_SMB2
;
1516 io
.smb2
.in
.create_flags
= 0;
1517 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1518 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1519 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1520 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1521 NTCREATEX_SHARE_ACCESS_WRITE
;
1522 io
.smb2
.in
.alloc_size
= 0;
1523 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1524 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1525 io
.smb2
.in
.security_flags
= 0;
1526 io
.smb2
.in
.fname
= BASEDIR_NSR
;
1528 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1529 CHECK_STATUS(status
, NT_STATUS_OK
);
1531 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1532 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1533 CHECK_STATUS(status
, NT_STATUS_OK
);
1534 h1
= io
.smb2
.out
.file
.handle
;
1536 /* ask for a change notify,
1537 on file or directory name changes */
1538 ZERO_STRUCT(notify
.smb2
);
1539 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1540 notify
.smb2
.in
.buffer_size
= 1000;
1541 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1542 notify
.smb2
.in
.file
.handle
= h1
;
1543 notify
.smb2
.in
.recursive
= true;
1545 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1547 WAIT_FOR_ASYNC_RESPONSE(req
);
1549 previous_session_id
= smb2cli_session_current_id(tree1
->session
->smbXcli
);
1550 torture_assert(torture
, torture_smb2_session_setup(torture
,
1551 tree1
->session
->transport
,
1552 previous_session_id
,
1553 torture
, &session2
),
1554 "session setup with previous_session_id failed");
1556 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1557 CHECK_STATUS(status
, NT_STATUS_NOTIFY_CLEANUP
);
1558 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1560 status
= smb2_logoff(tree1
->session
);
1561 CHECK_STATUS(status
, NT_STATUS_USER_SESSION_DELETED
);
1563 status
= smb2_logoff(session2
);
1564 CHECK_STATUS(status
, NT_STATUS_OK
);
1566 smb2_deltree(tree1
, BASEDIR_NSR
);
1571 basic testing of change notifies followed by an invalid reauth
1574 #define BASEDIR_IR BASEDIR "_IR"
1576 static bool torture_smb2_notify_invalid_reauth(struct torture_context
*torture
,
1577 struct smb2_tree
*tree1
,
1578 struct smb2_tree
*tree2
)
1582 union smb_notify notify
;
1584 struct smb2_handle h1
;
1585 struct smb2_request
*req
;
1586 struct cli_credentials
*invalid_creds
;
1588 smb2_deltree(tree2
, BASEDIR_IR
);
1589 smb2_util_rmdir(tree2
, BASEDIR_IR
);
1591 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY invalid REAUTH\n");
1594 get a handle on the directory
1596 ZERO_STRUCT(io
.smb2
);
1597 io
.generic
.level
= RAW_OPEN_SMB2
;
1598 io
.smb2
.in
.create_flags
= 0;
1599 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1600 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1601 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1602 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1603 NTCREATEX_SHARE_ACCESS_WRITE
;
1604 io
.smb2
.in
.alloc_size
= 0;
1605 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1606 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1607 io
.smb2
.in
.security_flags
= 0;
1608 io
.smb2
.in
.fname
= BASEDIR_IR
;
1610 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1611 CHECK_STATUS(status
, NT_STATUS_OK
);
1613 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1614 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1615 CHECK_STATUS(status
, NT_STATUS_OK
);
1616 h1
= io
.smb2
.out
.file
.handle
;
1618 /* ask for a change notify,
1619 on file or directory name changes */
1620 ZERO_STRUCT(notify
.smb2
);
1621 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1622 notify
.smb2
.in
.buffer_size
= 1000;
1623 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1624 notify
.smb2
.in
.file
.handle
= h1
;
1625 notify
.smb2
.in
.recursive
= true;
1627 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1629 WAIT_FOR_ASYNC_RESPONSE(req
);
1631 invalid_creds
= cli_credentials_init(torture
);
1632 torture_assert(torture
, (invalid_creds
!= NULL
), "talloc error");
1633 cli_credentials_set_username(invalid_creds
, "__none__invalid__none__", CRED_SPECIFIED
);
1634 cli_credentials_set_domain(invalid_creds
, "__none__invalid__none__", CRED_SPECIFIED
);
1635 cli_credentials_set_password(invalid_creds
, "__none__invalid__none__", CRED_SPECIFIED
);
1636 cli_credentials_set_realm(invalid_creds
, NULL
, CRED_SPECIFIED
);
1637 cli_credentials_set_workstation(invalid_creds
, "", CRED_UNINITIALISED
);
1639 status
= smb2_session_setup_spnego(tree1
->session
,
1641 0 /* previous_session_id */);
1642 CHECK_STATUS(status
, NT_STATUS_LOGON_FAILURE
);
1644 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1645 CHECK_STATUS(status
, NT_STATUS_NOTIFY_CLEANUP
);
1646 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1649 * Demonstrate that the session is no longer valid.
1651 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1652 CHECK_STATUS(status
, NT_STATUS_USER_SESSION_DELETED
);
1654 smb2_deltree(tree2
, BASEDIR_IR
);
1658 static void tcp_dis_handler(struct smb2_transport
*t
, void *p
)
1660 struct smb2_tree
*tree
= (struct smb2_tree
*)p
;
1661 smb2_transport_dead(tree
->session
->transport
,
1662 NT_STATUS_LOCAL_DISCONNECT
);
1668 basic testing of change notifies followed by tcp disconnect
1671 #define BASEDIR_NTCPD BASEDIR "_NTCPD"
1673 static bool torture_smb2_notify_tcp_disconnect(
1674 struct torture_context
*torture
,
1675 struct smb2_tree
*tree
)
1679 union smb_notify notify
;
1681 struct smb2_handle h1
;
1682 struct smb2_request
*req
;
1684 smb2_deltree(tree
, BASEDIR_NTCPD
);
1685 smb2_util_rmdir(tree
, BASEDIR_NTCPD
);
1687 torture_comment(torture
,
1688 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1691 get a handle on the directory
1693 ZERO_STRUCT(io
.smb2
);
1694 io
.generic
.level
= RAW_OPEN_SMB2
;
1695 io
.smb2
.in
.create_flags
= 0;
1696 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1697 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1698 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1699 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1700 NTCREATEX_SHARE_ACCESS_WRITE
;
1701 io
.smb2
.in
.alloc_size
= 0;
1702 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1703 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1704 io
.smb2
.in
.security_flags
= 0;
1705 io
.smb2
.in
.fname
= BASEDIR_NTCPD
;
1707 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1708 CHECK_STATUS(status
, NT_STATUS_OK
);
1709 h1
= io
.smb2
.out
.file
.handle
;
1711 /* ask for a change notify,
1712 on file or directory name changes */
1713 ZERO_STRUCT(notify
.smb2
);
1714 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1715 notify
.smb2
.in
.buffer_size
= 1000;
1716 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1717 notify
.smb2
.in
.file
.handle
= h1
;
1718 notify
.smb2
.in
.recursive
= true;
1720 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1722 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1723 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1725 notify
.smb2
.in
.recursive
= true;
1726 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1727 smb2_transport_idle_handler(tree
->session
->transport
,
1728 tcp_dis_handler
, 250000, tree
);
1730 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1731 CHECK_STATUS(status
, NT_STATUS_LOCAL_DISCONNECT
);
1738 test setting up two change notify requests on one handle
1741 #define BASEDIR_NDOH BASEDIR "_NDOH"
1743 static bool torture_smb2_notify_double(struct torture_context
*torture
,
1744 struct smb2_tree
*tree1
,
1745 struct smb2_tree
*tree2
)
1749 union smb_notify notify
;
1751 struct smb2_handle h1
;
1752 struct smb2_request
*req1
, *req2
;
1754 smb2_deltree(tree1
, BASEDIR_NDOH
);
1755 smb2_util_rmdir(tree1
, BASEDIR_NDOH
);
1757 torture_comment(torture
,
1758 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1761 get a handle on the directory
1763 ZERO_STRUCT(io
.smb2
);
1764 io
.generic
.level
= RAW_OPEN_SMB2
;
1765 io
.smb2
.in
.create_flags
= 0;
1766 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
1767 SEC_RIGHTS_FILE_WRITE
|
1768 SEC_RIGHTS_FILE_ALL
;
1769 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1770 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1771 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1772 NTCREATEX_SHARE_ACCESS_WRITE
;
1773 io
.smb2
.in
.alloc_size
= 0;
1774 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1775 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1776 io
.smb2
.in
.security_flags
= 0;
1777 io
.smb2
.in
.fname
= BASEDIR_NDOH
;
1779 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1780 CHECK_STATUS(status
, NT_STATUS_OK
);
1781 h1
= io
.smb2
.out
.file
.handle
;
1783 /* ask for a change notify,
1784 on file or directory name changes */
1785 ZERO_STRUCT(notify
.smb2
);
1786 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1787 notify
.smb2
.in
.buffer_size
= 1000;
1788 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1789 notify
.smb2
.in
.file
.handle
= h1
;
1790 notify
.smb2
.in
.recursive
= true;
1792 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
1794 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1795 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1797 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
1799 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
1800 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1802 smb2_util_mkdir(tree2
, BASEDIR_NDOH
"\\subdir-name");
1803 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
1804 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
1806 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1807 CHECK_STATUS(status
, NT_STATUS_OK
);
1808 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1809 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
1811 smb2_util_mkdir(tree2
, BASEDIR_NDOH
"\\subdir-name2");
1813 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
1814 CHECK_STATUS(status
, NT_STATUS_OK
);
1815 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1816 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name2");
1819 smb2_deltree(tree1
, BASEDIR_NDOH
);
1825 test multiple change notifies at different depths and with/without recursion
1828 #define BASEDIR_TREE BASEDIR "_TREE"
1830 static bool torture_smb2_notify_tree(struct torture_context
*torture
,
1831 struct smb2_tree
*tree
)
1834 union smb_notify notify
;
1836 struct smb2_request
*req
;
1843 struct smb2_handle h1
;
1847 .path
= BASEDIR_TREE
"\\abc",
1849 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1853 .path
= BASEDIR_TREE
"\\zqy",
1855 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1859 .path
= BASEDIR_TREE
"\\atsy",
1861 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1865 .path
= BASEDIR_TREE
"\\abc\\foo",
1867 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1871 .path
= BASEDIR_TREE
"\\abc\\blah",
1873 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1877 .path
= BASEDIR_TREE
"\\abc\\blah",
1879 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1883 .path
= BASEDIR_TREE
"\\abc\\blah\\a",
1885 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1889 .path
= BASEDIR_TREE
"\\abc\\blah\\b",
1891 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1895 .path
= BASEDIR_TREE
"\\abc\\blah\\c",
1897 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1901 .path
= BASEDIR_TREE
"\\abc\\fooblah",
1903 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1907 .path
= BASEDIR_TREE
"\\zqy\\xx",
1909 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1913 .path
= BASEDIR_TREE
"\\zqy\\yyy",
1915 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1919 .path
= BASEDIR_TREE
"\\zqy\\..",
1921 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1925 .path
= BASEDIR_TREE
,
1927 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1931 .path
= BASEDIR_TREE
,
1933 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1937 .path
= BASEDIR_TREE
"\\atsy",
1939 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1943 .path
= BASEDIR_TREE
"\\abc",
1945 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1949 .path
= BASEDIR_TREE
"\\abc",
1951 .filter
= FILE_NOTIFY_CHANGE_FILE_NAME
,
1955 .path
= BASEDIR_TREE
"\\abc",
1957 .filter
= FILE_NOTIFY_CHANGE_FILE_NAME
,
1961 .path
= BASEDIR_TREE
"\\abc",
1963 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1969 bool all_done
= false;
1971 smb2_deltree(tree
, BASEDIR_TREE
);
1972 smb2_util_rmdir(tree
, BASEDIR_TREE
);
1974 torture_comment(torture
, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1976 ZERO_STRUCT(io
.smb2
);
1977 io
.generic
.level
= RAW_OPEN_SMB2
;
1978 io
.smb2
.in
.create_flags
= 0;
1979 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1980 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1981 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1982 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1983 NTCREATEX_SHARE_ACCESS_WRITE
;
1984 io
.smb2
.in
.alloc_size
= 0;
1985 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1986 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1987 io
.smb2
.in
.security_flags
= 0;
1988 io
.smb2
.in
.fname
= BASEDIR_TREE
;
1989 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1990 CHECK_STATUS(status
, NT_STATUS_OK
);
1992 ZERO_STRUCT(notify
.smb2
);
1993 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1994 notify
.smb2
.in
.buffer_size
= 20000;
1997 setup the directory tree, and the notify buffer on each directory
1999 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
2000 io
.smb2
.in
.fname
= dirs
[i
].path
;
2001 status
= smb2_create(tree
, torture
, &(io
.smb2
));
2002 CHECK_STATUS(status
, NT_STATUS_OK
);
2003 dirs
[i
].h1
= io
.smb2
.out
.file
.handle
;
2005 notify
.smb2
.in
.completion_filter
= dirs
[i
].filter
;
2006 notify
.smb2
.in
.file
.handle
= dirs
[i
].h1
;
2007 notify
.smb2
.in
.recursive
= dirs
[i
].recursive
;
2008 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2010 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2011 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
2014 /* trigger 2 events in each dir */
2015 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
2016 char *path
= talloc_asprintf(torture
, "%s\\test.dir",
2018 smb2_util_mkdir(tree
, path
);
2019 smb2_util_rmdir(tree
, path
);
2023 /* give a bit of time for the events to propagate */
2024 tv
= timeval_current();
2027 /* count events that have happened in each dir */
2028 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
2029 notify
.smb2
.in
.completion_filter
= dirs
[i
].filter
;
2030 notify
.smb2
.in
.file
.handle
= dirs
[i
].h1
;
2031 notify
.smb2
.in
.recursive
= dirs
[i
].recursive
;
2032 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2034 notify
.smb2
.out
.num_changes
= 0;
2035 status
= smb2_notify_recv(req
, torture
,
2037 dirs
[i
].counted
+= notify
.smb2
.out
.num_changes
;
2042 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
2043 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
2047 } while (!all_done
&& timeval_elapsed(&tv
) < 20);
2049 torture_comment(torture
, "took %.4f seconds to propagate all events\n",
2050 timeval_elapsed(&tv
));
2052 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
2053 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
2054 torture_comment(torture
,
2055 "ERROR: i=%d expected %d got %d for '%s'\n",
2056 i
, dirs
[i
].expected
, dirs
[i
].counted
,
2063 run from the back, closing and deleting
2065 for (i
=ARRAY_SIZE(dirs
)-1;i
>=0;i
--) {
2066 smb2_util_close(tree
, dirs
[i
].h1
);
2067 smb2_util_rmdir(tree
, dirs
[i
].path
);
2071 smb2_deltree(tree
, BASEDIR_TREE
);
2072 smb2_util_rmdir(tree
, BASEDIR_TREE
);
2077 Test response when cached server events exceed single NT NOTFIY response
2081 #define BASEDIR_OVF BASEDIR "_OVF"
2083 static bool torture_smb2_notify_overflow(struct torture_context
*torture
,
2084 struct smb2_tree
*tree
)
2088 union smb_notify notify
;
2090 struct smb2_handle h1
, h2
;
2092 struct smb2_request
*req1
;
2095 smb2_deltree(tree
, BASEDIR_OVF
);
2096 smb2_util_rmdir(tree
, BASEDIR_OVF
);
2098 torture_comment(torture
, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
2100 /* get a handle on the directory */
2101 ZERO_STRUCT(io
.smb2
);
2102 io
.generic
.level
= RAW_OPEN_SMB2
;
2103 io
.smb2
.in
.create_flags
= 0;
2104 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
2105 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2106 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2107 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2108 NTCREATEX_SHARE_ACCESS_WRITE
;
2109 io
.smb2
.in
.alloc_size
= 0;
2110 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2111 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
2112 io
.smb2
.in
.security_flags
= 0;
2113 io
.smb2
.in
.fname
= BASEDIR_OVF
;
2115 status
= smb2_create(tree
, torture
, &(io
.smb2
));
2116 CHECK_STATUS(status
, NT_STATUS_OK
);
2117 h1
= io
.smb2
.out
.file
.handle
;
2119 /* ask for a change notify, on name changes. */
2120 ZERO_STRUCT(notify
.smb2
);
2121 notify
.smb2
.level
= RAW_NOTIFY_NTTRANS
;
2122 notify
.smb2
.in
.buffer_size
= 1000;
2123 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
2124 notify
.smb2
.in
.file
.handle
= h1
;
2126 notify
.smb2
.in
.recursive
= true;
2127 req1
= smb2_notify_send(tree
, &(notify
.smb2
));
2129 /* cancel initial requests so the buffer is setup */
2131 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
2132 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
2134 /* open a lot of files, filling up the server side notify buffer */
2135 torture_comment(torture
,
2136 "Testing overflowed buffer notify on create of %d files\n",
2139 for (i
=0;i
<count
;i
++) {
2140 char *fname
= talloc_asprintf(torture
,
2141 BASEDIR_OVF
"\\test%d.txt", i
);
2143 ZERO_STRUCT(io1
.smb2
);
2144 io1
.generic
.level
= RAW_OPEN_SMB2
;
2145 io1
.smb2
.in
.create_flags
= 0;
2146 io1
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
2147 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2148 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2149 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2150 NTCREATEX_SHARE_ACCESS_WRITE
;
2151 io1
.smb2
.in
.alloc_size
= 0;
2152 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2153 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
2154 io1
.smb2
.in
.security_flags
= 0;
2155 io1
.smb2
.in
.fname
= fname
;
2157 h2
= custom_smb2_create(tree
, torture
, &(io1
.smb2
));
2159 smb2_util_close(tree
, h2
);
2162 req1
= smb2_notify_send(tree
, &(notify
.smb2
));
2163 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
2164 CHECK_STATUS(status
, NT_STATUS_NOTIFY_ENUM_DIR
);
2165 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
2168 smb2_deltree(tree
, BASEDIR_OVF
);
2173 Test if notifications are returned for changes to the base directory.
2177 #define BASEDIR_BAS BASEDIR "_BAS"
2179 static bool torture_smb2_notify_basedir(struct torture_context
*torture
,
2180 struct smb2_tree
*tree1
,
2181 struct smb2_tree
*tree2
)
2185 union smb_notify notify
;
2187 struct smb2_handle h1
;
2188 struct smb2_request
*req1
;
2190 smb2_deltree(tree1
, BASEDIR_BAS
);
2191 smb2_util_rmdir(tree1
, BASEDIR_BAS
);
2193 torture_comment(torture
, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
2195 /* get a handle on the directory */
2196 ZERO_STRUCT(io
.smb2
);
2197 io
.generic
.level
= RAW_OPEN_SMB2
;
2198 io
.smb2
.in
.create_flags
= 0;
2199 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
2200 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2201 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2202 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2203 NTCREATEX_SHARE_ACCESS_WRITE
;
2204 io
.smb2
.in
.alloc_size
= 0;
2205 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
2206 io
.smb2
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
2207 io
.smb2
.in
.security_flags
= 0;
2208 io
.smb2
.in
.fname
= BASEDIR_BAS
;
2210 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
2211 CHECK_STATUS(status
, NT_STATUS_OK
);
2212 h1
= io
.smb2
.out
.file
.handle
;
2214 /* create a test file that will also be modified */
2215 io
.smb2
.in
.fname
= BASEDIR_BAS
"\\tname1";
2216 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
2217 status
= smb2_create(tree2
, torture
, &(io
.smb2
));
2218 CHECK_STATUS(status
,NT_STATUS_OK
);
2219 smb2_util_close(tree2
, io
.smb2
.out
.file
.handle
);
2221 /* ask for a change notify, on attribute changes. */
2222 ZERO_STRUCT(notify
.smb2
);
2223 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
2224 notify
.smb2
.in
.buffer_size
= 1000;
2225 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
2226 notify
.smb2
.in
.file
.handle
= h1
;
2227 notify
.smb2
.in
.recursive
= true;
2229 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
2231 /* set attribute on the base dir */
2232 smb2_util_setatr(tree2
, BASEDIR_BAS
, FILE_ATTRIBUTE_HIDDEN
);
2234 /* set attribute on a file to assure we receive a notification */
2235 smb2_util_setatr(tree2
, BASEDIR_BAS
"\\tname1", FILE_ATTRIBUTE_HIDDEN
);
2238 /* check how many responses were given, expect only 1 for the file */
2239 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
2240 CHECK_STATUS(status
, NT_STATUS_OK
);
2241 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2242 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
2243 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "tname1");
2246 smb2_deltree(tree1
, BASEDIR_BAS
);
2251 very simple change notify test
2254 #define BASEDIR_TCON BASEDIR "_TCON"
2256 static bool torture_smb2_notify_tcon(struct torture_context
*torture
,
2257 struct smb2_tree
*tree
)
2261 union smb_notify notify
;
2263 struct smb2_handle h1
= {{0}};
2264 struct smb2_request
*req
= NULL
;
2265 struct smb2_tree
*tree1
= NULL
;
2266 const char *fname
= BASEDIR_TCON
"\\subdir-name";
2268 smb2_deltree(tree
, BASEDIR_TCON
);
2269 smb2_util_rmdir(tree
, BASEDIR_TCON
);
2271 torture_comment(torture
, "TESTING SIMPLE CHANGE NOTIFY\n");
2274 get a handle on the directory
2277 ZERO_STRUCT(io
.smb2
);
2278 io
.generic
.level
= RAW_OPEN_SMB2
;
2279 io
.smb2
.in
.create_flags
= 0;
2280 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
2281 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2282 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
|
2283 FILE_ATTRIBUTE_DIRECTORY
;
2284 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2285 NTCREATEX_SHARE_ACCESS_WRITE
;
2286 io
.smb2
.in
.alloc_size
= 0;
2287 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
2288 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
2289 io
.smb2
.in
.security_flags
= 0;
2290 io
.smb2
.in
.fname
= BASEDIR_TCON
;
2292 status
= smb2_create(tree
, torture
, &(io
.smb2
));
2293 CHECK_STATUS(status
, NT_STATUS_OK
);
2294 h1
= io
.smb2
.out
.file
.handle
;
2296 /* ask for a change notify,
2297 on file or directory name changes */
2298 ZERO_STRUCT(notify
.smb2
);
2299 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
2300 notify
.smb2
.in
.buffer_size
= 1000;
2301 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
2302 notify
.smb2
.in
.file
.handle
= h1
;
2303 notify
.smb2
.in
.recursive
= true;
2305 torture_comment(torture
, "Testing notify mkdir\n");
2306 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2308 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2309 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
2311 notify
.smb2
.in
.recursive
= true;
2312 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2313 status
= smb2_util_mkdir(tree
, fname
);
2314 CHECK_STATUS(status
, NT_STATUS_OK
);
2316 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2317 CHECK_STATUS(status
, NT_STATUS_OK
);
2319 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2320 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
2321 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2323 torture_comment(torture
, "Testing notify rmdir\n");
2324 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2325 status
= smb2_util_rmdir(tree
, fname
);
2326 CHECK_STATUS(status
, NT_STATUS_OK
);
2328 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2329 CHECK_STATUS(status
, NT_STATUS_OK
);
2330 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2331 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
2332 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2334 torture_comment(torture
, "SIMPLE CHANGE NOTIFY OK\n");
2336 torture_comment(torture
, "TESTING WITH SECONDARY TCON\n");
2337 if (!torture_smb2_tree_connect(torture
, tree
->session
, tree
, &tree1
)) {
2338 torture_warning(torture
, "couldn't reconnect to share, bailing\n");
2343 torture_comment(torture
, "tid1=%d tid2=%d\n",
2344 smb2cli_tcon_current_id(tree
->smbXcli
),
2345 smb2cli_tcon_current_id(tree1
->smbXcli
));
2347 torture_comment(torture
, "Testing notify mkdir\n");
2348 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2349 smb2_util_mkdir(tree1
, fname
);
2351 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2352 CHECK_STATUS(status
, NT_STATUS_OK
);
2354 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2355 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
2356 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2358 torture_comment(torture
, "Testing notify rmdir\n");
2359 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2360 smb2_util_rmdir(tree
, fname
);
2362 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2363 CHECK_STATUS(status
, NT_STATUS_OK
);
2364 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2365 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
2366 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2368 torture_comment(torture
, "CHANGE NOTIFY WITH TCON OK\n");
2370 torture_comment(torture
, "Disconnecting secondary tree\n");
2371 status
= smb2_tdis(tree1
);
2372 CHECK_STATUS(status
, NT_STATUS_OK
);
2375 torture_comment(torture
, "Testing notify mkdir\n");
2376 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2377 smb2_util_mkdir(tree
, fname
);
2379 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2380 CHECK_STATUS(status
, NT_STATUS_OK
);
2382 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2383 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
2384 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2386 torture_comment(torture
, "Testing notify rmdir\n");
2387 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2388 smb2_util_rmdir(tree
, fname
);
2390 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2391 CHECK_STATUS(status
, NT_STATUS_OK
);
2392 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2393 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
2394 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2396 torture_comment(torture
, "CHANGE NOTIFY WITH TDIS OK\n");
2398 smb2_util_close(tree
, h1
);
2399 smb2_deltree(tree
, BASEDIR_TCON
);
2404 #define BASEDIR_RMD BASEDIR "_RMD"
2406 static bool torture_smb2_notify_rmdir(struct torture_context
*torture
,
2407 struct smb2_tree
*tree1
,
2408 struct smb2_tree
*tree2
,
2409 bool initial_delete_on_close
)
2413 union smb_notify notify
= {};
2414 union smb_setfileinfo sfinfo
= {};
2415 union smb_open io
= {};
2416 struct smb2_handle h
= {};
2417 struct smb2_request
*req
;
2419 torture_comment(torture
, "TESTING NOTIFY CANCEL FOR DELETED DIR\n");
2421 smb2_deltree(tree1
, BASEDIR_RMD
);
2422 smb2_util_rmdir(tree1
, BASEDIR_RMD
);
2424 ZERO_STRUCT(io
.smb2
);
2425 io
.generic
.level
= RAW_OPEN_SMB2
;
2426 io
.smb2
.in
.create_flags
= 0;
2427 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
2428 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2429 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2430 io
.smb2
.in
.share_access
=
2431 NTCREATEX_SHARE_ACCESS_READ
|
2432 NTCREATEX_SHARE_ACCESS_WRITE
|
2433 NTCREATEX_SHARE_ACCESS_DELETE
;
2434 io
.smb2
.in
.alloc_size
= 0;
2435 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2436 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
2437 io
.smb2
.in
.security_flags
= 0;
2438 io
.smb2
.in
.fname
= BASEDIR_RMD
;
2440 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
2441 CHECK_STATUS(status
, NT_STATUS_OK
);
2442 h
= io
.smb2
.out
.file
.handle
;
2444 ZERO_STRUCT(notify
.smb2
);
2445 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
2446 notify
.smb2
.in
.buffer_size
= 1000;
2447 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
2448 notify
.smb2
.in
.file
.handle
= h
;
2449 notify
.smb2
.in
.recursive
= false;
2451 io
.smb2
.in
.desired_access
|= SEC_STD_DELETE
;
2452 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
2453 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
2455 if (initial_delete_on_close
) {
2456 status
= smb2_util_rmdir(tree2
, BASEDIR_RMD
);
2457 CHECK_STATUS(status
, NT_STATUS_OK
);
2459 status
= smb2_create(tree2
, torture
, &(io
.smb2
));
2460 CHECK_STATUS(status
, NT_STATUS_OK
);
2462 sfinfo
.generic
.level
= RAW_SFILEINFO_DISPOSITION_INFORMATION
;
2463 sfinfo
.generic
.in
.file
.handle
= io
.smb2
.out
.file
.handle
;
2464 sfinfo
.disposition_info
.in
.delete_on_close
= 1;
2465 status
= smb2_setinfo_file(tree2
, &sfinfo
);
2466 CHECK_STATUS(status
, NT_STATUS_OK
);
2468 smb2_util_close(tree2
, io
.smb2
.out
.file
.handle
);
2471 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2472 CHECK_STATUS(status
, NT_STATUS_DELETE_PENDING
);
2476 smb2_util_close(tree1
, h
);
2477 smb2_deltree(tree1
, BASEDIR_RMD
);
2482 static bool torture_smb2_notify_rmdir1(struct torture_context
*torture
,
2483 struct smb2_tree
*tree
)
2485 return torture_smb2_notify_rmdir(torture
, tree
, tree
, false);
2488 static bool torture_smb2_notify_rmdir2(struct torture_context
*torture
,
2489 struct smb2_tree
*tree
)
2491 return torture_smb2_notify_rmdir(torture
, tree
, tree
, true);
2494 static bool torture_smb2_notify_rmdir3(struct torture_context
*torture
,
2495 struct smb2_tree
*tree1
,
2496 struct smb2_tree
*tree2
)
2498 return torture_smb2_notify_rmdir(torture
, tree1
, tree2
, false);
2501 static bool torture_smb2_notify_rmdir4(struct torture_context
*torture
,
2502 struct smb2_tree
*tree1
,
2503 struct smb2_tree
*tree2
)
2505 return torture_smb2_notify_rmdir(torture
, tree1
, tree2
, true);
2508 static void notify_timeout(struct tevent_context
*ev
,
2509 struct tevent_timer
*te
,
2510 struct timeval current_time
,
2513 struct smb2_request
*req
= talloc_get_type_abort(
2514 private_data
, struct smb2_request
);
2519 #define BASEDIR_INR BASEDIR "_INR"
2521 static bool torture_smb2_inotify_rename(struct torture_context
*torture
,
2522 struct smb2_tree
*tree1
,
2523 struct smb2_tree
*tree2
)
2526 struct smb2_notify notify
;
2527 struct notify_changes change1
= {0};
2528 struct notify_changes change2
= {0};
2529 struct smb2_create create
;
2530 union smb_setfileinfo sinfo
;
2531 struct smb2_handle h1
= {{0}};
2532 struct smb2_handle h2
= {{0}};
2533 struct smb2_request
*req
;
2534 struct tevent_timer
*te
= NULL
;
2537 smb2_deltree(tree1
, BASEDIR_INR
);
2539 torture_comment(torture
, "Testing change notify of a rename with inotify\n");
2541 status
= torture_smb2_testdir(tree1
, BASEDIR_INR
, &h1
);
2542 torture_assert_ntstatus_ok_goto(torture
, status
, ok
, done
, "torture_smb2_testdir failed");
2544 ZERO_STRUCT(create
);
2545 create
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
2546 SEC_RIGHTS_FILE_WRITE
|
2547 SEC_RIGHTS_FILE_ALL
;
2548 create
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2549 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2550 create
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2551 NTCREATEX_SHARE_ACCESS_WRITE
|
2552 NTCREATEX_SHARE_ACCESS_DELETE
;
2553 create
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
2554 create
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
2555 create
.in
.fname
= BASEDIR_INR
"\\subdir-name";
2557 status
= smb2_create(tree2
, torture
, &create
);
2558 torture_assert_ntstatus_ok_goto(torture
, status
, ok
, done
, "smb2_create failed\n");
2559 h2
= create
.out
.file
.handle
;
2561 ZERO_STRUCT(notify
);
2562 notify
.level
= RAW_NOTIFY_SMB2
;
2563 notify
.in
.buffer_size
= 4096;
2564 notify
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
2565 notify
.in
.file
.handle
= h1
;
2566 notify
.in
.recursive
= true;
2567 req
= smb2_notify_send(tree1
, ¬ify
);
2568 torture_assert_not_null_goto(torture
, req
, ok
, done
, "smb2_notify_send failed\n");
2570 while (!NT_STATUS_EQUAL(req
->status
, NT_STATUS_PENDING
)) {
2571 if (tevent_loop_once(torture
->ev
) != 0) {
2577 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
2578 sinfo
.rename_information
.in
.file
.handle
= h2
;
2579 sinfo
.rename_information
.in
.new_name
= BASEDIR_INR
"\\subdir-name-r";
2581 status
= smb2_setinfo_file(tree2
, &sinfo
);
2582 torture_assert_ntstatus_ok_goto(torture
, status
, ok
, done
, "smb2_setinfo_file failed\n");
2584 smb2_util_close(tree2
, h2
);
2586 te
= tevent_add_timer(torture
->ev
,
2588 tevent_timeval_current_ofs(1, 0),
2591 torture_assert_not_null_goto(torture
, te
, ok
, done
, "tevent_add_timer failed\n");
2593 status
= smb2_notify_recv(req
, torture
, ¬ify
);
2594 torture_assert_ntstatus_ok_goto(torture
, status
, ok
, done
, "smb2_notify_recv failed\n");
2596 torture_assert_goto(torture
, notify
.out
.num_changes
== 1 || notify
.out
.num_changes
== 2,
2597 ok
, done
, "bad notify\n");
2599 change1
= notify
.out
.changes
[0];
2600 if (notify
.out
.num_changes
== 2) {
2601 change2
= notify
.out
.changes
[1];
2604 * We may only get one event at a time, so check for the
2605 * matching second event for the oldname/newname or
2606 * removed/added pair.
2608 ZERO_STRUCT(notify
);
2609 notify
.level
= RAW_NOTIFY_SMB2
;
2610 notify
.in
.buffer_size
= 4096;
2611 notify
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
2612 notify
.in
.file
.handle
= h1
;
2613 notify
.in
.recursive
= true;
2614 req
= smb2_notify_send(tree1
, ¬ify
);
2615 torture_assert_not_null_goto(torture
, req
, ok
, done
, "smb2_notify_send failed\n");
2617 status
= smb2_notify_recv(req
, torture
, ¬ify
);
2618 torture_assert_ntstatus_ok_goto(torture
, status
, ok
, done
, "smb2_notify_recv failed\n");
2620 torture_assert_goto(torture
, notify
.out
.num_changes
== 1, ok
, done
,
2623 change2
= notify
.out
.changes
[0];
2626 if ((change1
.action
!= NOTIFY_ACTION_OLD_NAME
) &&
2627 (change1
.action
!= NOTIFY_ACTION_REMOVED
))
2629 torture_fail_goto(torture
, done
, "bad change notification\n");
2631 torture_assert_str_equal_goto(torture
, change1
.name
.s
, "subdir-name",
2632 ok
, done
, "bad change notification\n");
2634 if ((change2
.action
!= NOTIFY_ACTION_NEW_NAME
) &&
2635 (change2
.action
!= NOTIFY_ACTION_ADDED
))
2637 torture_fail_goto(torture
, done
, "bad change notification\n");
2639 torture_assert_str_equal_goto(torture
, change2
.name
.s
, "subdir-name-r",
2640 ok
, done
, "bad change notification\n");
2644 if (!smb2_util_handle_empty(h1
)) {
2645 smb2_util_close(tree1
, h1
);
2647 if (!smb2_util_handle_empty(h2
)) {
2648 smb2_util_close(tree2
, h2
);
2651 smb2_deltree(tree1
, BASEDIR_INR
);
2656 Test asking for a change notify on a handle without permissions.
2659 #define BASEDIR_HPERM BASEDIR "_HPERM"
2661 static bool torture_smb2_notify_handle_permissions(
2662 struct torture_context
*torture
,
2663 struct smb2_tree
*tree
)
2667 union smb_notify notify
;
2669 struct smb2_handle h1
= {{0}};
2670 struct smb2_request
*req
;
2672 smb2_deltree(tree
, BASEDIR_HPERM
);
2673 smb2_util_rmdir(tree
, BASEDIR_HPERM
);
2675 torture_comment(torture
,
2676 "TESTING CHANGE NOTIFY "
2677 "ON A HANDLE WITHOUT PERMISSIONS\n");
2680 get a handle on the directory
2682 ZERO_STRUCT(io
.smb2
);
2683 io
.generic
.level
= RAW_OPEN_SMB2
;
2684 io
.smb2
.in
.create_flags
= 0;
2685 io
.smb2
.in
.desired_access
= SEC_FILE_READ_ATTRIBUTE
;
2686 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2687 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2688 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2689 NTCREATEX_SHARE_ACCESS_WRITE
;
2690 io
.smb2
.in
.alloc_size
= 0;
2691 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2692 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
2693 io
.smb2
.in
.security_flags
= 0;
2694 io
.smb2
.in
.fname
= BASEDIR_HPERM
;
2696 status
= smb2_create(tree
, torture
, &io
.smb2
);
2697 CHECK_STATUS(status
, NT_STATUS_OK
);
2698 h1
= io
.smb2
.out
.file
.handle
;
2700 /* ask for a change notify,
2701 on file or directory name changes */
2702 ZERO_STRUCT(notify
.smb2
);
2703 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
2704 notify
.smb2
.in
.buffer_size
= 1000;
2705 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
2706 notify
.smb2
.in
.file
.handle
= h1
;
2707 notify
.smb2
.in
.recursive
= true;
2709 req
= smb2_notify_send(tree
, ¬ify
.smb2
);
2710 torture_assert_goto(torture
,
2714 "smb2_notify_send failed\n");
2717 * Cancel it, we don't really want to wait.
2720 status
= smb2_notify_recv(req
, torture
, ¬ify
.smb2
);
2721 /* Handle h1 doesn't have permissions for ChangeNotify. */
2722 CHECK_STATUS(status
, NT_STATUS_ACCESS_DENIED
);
2725 if (!smb2_util_handle_empty(h1
)) {
2726 smb2_util_close(tree
, h1
);
2728 smb2_deltree(tree
, BASEDIR_HPERM
);
2733 basic testing of SMB2 change notify
2735 struct torture_suite
*torture_smb2_notify_init(TALLOC_CTX
*ctx
)
2737 struct torture_suite
*suite
= torture_suite_create(ctx
, "notify");
2739 torture_suite_add_1smb2_test(suite
, "valid-req", test_valid_request
);
2740 torture_suite_add_1smb2_test(suite
, "tcon", torture_smb2_notify_tcon
);
2741 torture_suite_add_2smb2_test(suite
, "dir", torture_smb2_notify_dir
);
2742 torture_suite_add_2smb2_test(suite
, "mask", torture_smb2_notify_mask
);
2743 torture_suite_add_1smb2_test(suite
, "tdis", torture_smb2_notify_tree_disconnect
);
2744 torture_suite_add_1smb2_test(suite
, "tdis1", torture_smb2_notify_tree_disconnect_1
);
2745 torture_suite_add_2smb2_test(suite
, "mask-change", torture_smb2_notify_mask_change
);
2746 torture_suite_add_1smb2_test(suite
, "close", torture_smb2_notify_close
);
2747 torture_suite_add_1smb2_test(suite
, "logoff", torture_smb2_notify_ulogoff
);
2748 torture_suite_add_1smb2_test(suite
, "session-reconnect", torture_smb2_notify_session_reconnect
);
2749 torture_suite_add_2smb2_test(suite
, "invalid-reauth", torture_smb2_notify_invalid_reauth
);
2750 torture_suite_add_1smb2_test(suite
, "tree", torture_smb2_notify_tree
);
2751 torture_suite_add_2smb2_test(suite
, "basedir", torture_smb2_notify_basedir
);
2752 torture_suite_add_2smb2_test(suite
, "double", torture_smb2_notify_double
);
2753 torture_suite_add_1smb2_test(suite
, "file", torture_smb2_notify_file
);
2754 torture_suite_add_1smb2_test(suite
, "tcp", torture_smb2_notify_tcp_disconnect
);
2755 torture_suite_add_2smb2_test(suite
, "rec", torture_smb2_notify_recursive
);
2756 torture_suite_add_1smb2_test(suite
, "overflow", torture_smb2_notify_overflow
);
2757 torture_suite_add_1smb2_test(suite
, "rmdir1",
2758 torture_smb2_notify_rmdir1
);
2759 torture_suite_add_1smb2_test(suite
, "rmdir2",
2760 torture_smb2_notify_rmdir2
);
2761 torture_suite_add_2smb2_test(suite
, "rmdir3",
2762 torture_smb2_notify_rmdir3
);
2763 torture_suite_add_2smb2_test(suite
, "rmdir4",
2764 torture_smb2_notify_rmdir4
);
2765 torture_suite_add_1smb2_test(suite
,
2766 "handle-permissions",
2767 torture_smb2_notify_handle_permissions
);
2769 suite
->description
= talloc_strdup(suite
, "SMB2-NOTIFY tests");
2775 basic testing of SMB2 change notify
2777 struct torture_suite
*torture_smb2_notify_inotify_init(TALLOC_CTX
*ctx
)
2779 struct torture_suite
*suite
= torture_suite_create(ctx
, "notify-inotify");
2781 suite
->description
= talloc_strdup(suite
, "SMB2-NOTIFY tests that use inotify");
2783 torture_suite_add_2smb2_test(suite
, "inotify-rename", torture_smb2_inotify_rename
);