2 Unix SMB/CIFS implementation.
6 Copyright (C) Stefan Metzmacher 2006
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
26 #include "torture/torture.h"
27 #include "torture/smb2/proto.h"
29 #include "libcli/raw/libcliraw.h"
30 #include "lib/events/events.h"
32 #define CHECK_STATUS(status, correct) do { \
33 if (!NT_STATUS_EQUAL(status, correct)) { \
34 printf("(%s) Incorrect status %s - should be %s\n", \
35 __location__, nt_errstr(status), nt_errstr(correct)); \
40 #define CHECK_VALUE(v, correct) do { \
41 if ((v) != (correct)) { \
42 printf("(%s) Incorrect value %s=%d - should be %d\n", \
43 __location__, #v, v, correct); \
48 #define CHECK_WIRE_STR(field, value) do { \
49 if (!field.s || strcmp(field.s, value)) { \
50 printf("(%s) %s [%s] != %s\n", \
51 __location__, #field, field.s, value); \
56 #define FNAME "smb2-notify01.dat"
58 #define TARGET_IS_WIN7(_tctx) (torture_setting_bool(_tctx, "win7", false))
60 static bool test_valid_request(struct torture_context
*tctx
, struct smb2_tree
*tree
)
64 struct smb2_handle dh
;
66 struct smb2_request
*req
;
67 uint32_t max_buffer_size
= 0x00080000;
69 if (TARGET_IS_WIN7(tctx
)) {
70 max_buffer_size
= 0x00010000;
73 smb2_util_unlink(tree
, FNAME
);
75 status
= smb2_util_roothandle(tree
, &dh
);
76 CHECK_STATUS(status
, NT_STATUS_OK
);
78 n
.in
.recursive
= 0x0000;
79 n
.in
.buffer_size
= max_buffer_size
;
80 n
.in
.file
.handle
= dh
;
81 n
.in
.completion_filter
= 0x00000FFF;
82 n
.in
.unknown
= 0x00000000;
83 req
= smb2_notify_send(tree
, &n
);
85 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
86 if (event_loop_once(req
->transport
->socket
->event
.ctx
) != 0) {
91 status
= torture_setup_complex_file(tree
, FNAME
);
92 CHECK_STATUS(status
, NT_STATUS_OK
);
94 status
= smb2_notify_recv(req
, tctx
, &n
);
95 CHECK_STATUS(status
, NT_STATUS_OK
);
96 CHECK_VALUE(n
.out
.num_changes
, 1);
97 CHECK_VALUE(n
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
98 CHECK_WIRE_STR(n
.out
.changes
[0].name
, FNAME
);
101 * if the change response doesn't fit in the buffer
102 * NOTIFY_ENUM_DIR is returned.
104 n
.in
.buffer_size
= 0x00000000;
105 req
= smb2_notify_send(tree
, &n
);
107 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
108 if (event_loop_once(req
->transport
->socket
->event
.ctx
) != 0) {
113 status
= torture_setup_complex_file(tree
, FNAME
);
114 CHECK_STATUS(status
, NT_STATUS_OK
);
116 status
= smb2_notify_recv(req
, tctx
, &n
);
117 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
120 * if the change response fits in the buffer we get
123 n
.in
.buffer_size
= max_buffer_size
;
124 req
= smb2_notify_send(tree
, &n
);
126 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
127 if (event_loop_once(req
->transport
->socket
->event
.ctx
) != 0) {
132 status
= torture_setup_complex_file(tree
, FNAME
);
133 CHECK_STATUS(status
, NT_STATUS_OK
);
135 status
= smb2_notify_recv(req
, tctx
, &n
);
136 CHECK_STATUS(status
, NT_STATUS_OK
);
137 CHECK_VALUE(n
.out
.num_changes
, 3);
138 CHECK_VALUE(n
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
139 CHECK_WIRE_STR(n
.out
.changes
[0].name
, FNAME
);
140 CHECK_VALUE(n
.out
.changes
[1].action
, NOTIFY_ACTION_ADDED
);
141 CHECK_WIRE_STR(n
.out
.changes
[1].name
, FNAME
);
142 CHECK_VALUE(n
.out
.changes
[2].action
, NOTIFY_ACTION_MODIFIED
);
143 CHECK_WIRE_STR(n
.out
.changes
[2].name
, FNAME
);
145 /* if the first notify returns NOTIFY_ENUM_DIR, all do */
146 status
= smb2_util_close(tree
, dh
);
147 CHECK_STATUS(status
, NT_STATUS_OK
);
148 status
= smb2_util_roothandle(tree
, &dh
);
149 CHECK_STATUS(status
, NT_STATUS_OK
);
151 n
.in
.recursive
= 0x0000;
152 n
.in
.buffer_size
= 0x00000001;
153 n
.in
.file
.handle
= dh
;
154 n
.in
.completion_filter
= 0x00000FFF;
155 n
.in
.unknown
= 0x00000000;
156 req
= smb2_notify_send(tree
, &n
);
158 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
159 if (event_loop_once(req
->transport
->socket
->event
.ctx
) != 0) {
164 status
= torture_setup_complex_file(tree
, FNAME
);
165 CHECK_STATUS(status
, NT_STATUS_OK
);
167 status
= smb2_notify_recv(req
, tctx
, &n
);
168 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
170 n
.in
.buffer_size
= max_buffer_size
;
171 req
= smb2_notify_send(tree
, &n
);
172 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
173 if (event_loop_once(req
->transport
->socket
->event
.ctx
) != 0) {
178 status
= torture_setup_complex_file(tree
, FNAME
);
179 CHECK_STATUS(status
, NT_STATUS_OK
);
181 status
= smb2_notify_recv(req
, tctx
, &n
);
182 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
184 /* if the buffer size is too large, we get invalid parameter */
185 n
.in
.recursive
= 0x0000;
186 n
.in
.buffer_size
= max_buffer_size
+ 1;
187 n
.in
.file
.handle
= dh
;
188 n
.in
.completion_filter
= 0x00000FFF;
189 n
.in
.unknown
= 0x00000000;
190 req
= smb2_notify_send(tree
, &n
);
191 status
= smb2_notify_recv(req
, tctx
, &n
);
192 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
198 /* basic testing of SMB2 notify
200 bool torture_smb2_notify(struct torture_context
*torture
)
202 struct smb2_tree
*tree
;
205 if (!torture_smb2_connection(torture
, &tree
)) {
209 ret
&= test_valid_request(torture
, tree
);