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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
27 #include "torture/torture.h"
28 #include "torture/smb2/proto.h"
30 #include "libcli/raw/libcliraw.h"
31 #include "lib/events/events.h"
33 #define CHECK_STATUS(status, correct) do { \
34 if (!NT_STATUS_EQUAL(status, correct)) { \
35 printf("(%s) Incorrect status %s - should be %s\n", \
36 __location__, nt_errstr(status), nt_errstr(correct)); \
41 #define CHECK_VALUE(v, correct) do { \
42 if ((v) != (correct)) { \
43 printf("(%s) Incorrect value %s=%d - should be %d\n", \
44 __location__, #v, v, correct); \
49 #define CHECK_WIRE_STR(field, value) do { \
50 if (!field.s || strcmp(field.s, value)) { \
51 printf("(%s) %s [%s] != %s\n", \
52 __location__, #field, field.s, value); \
57 #define FNAME "smb2-notify01.dat"
59 static BOOL test_valid_request(TALLOC_CTX *mem_ctx, struct smb2_tree *tree)
63 struct smb2_handle dh;
65 struct smb2_request *req;
67 status = smb2_util_roothandle(tree, &dh);
68 CHECK_STATUS(status, NT_STATUS_OK);
70 n.in.recursive = 0x0000;
71 n.in.buffer_size = 0x00080000;
72 n.in.file.handle = dh;
73 n.in.completion_filter = 0x00000FFF;
74 n.in.unknown = 0x00000000;
75 req = smb2_notify_send(tree, &n);
77 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
78 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
83 status = torture_setup_complex_file(tree, FNAME);
84 CHECK_STATUS(status, NT_STATUS_OK);
86 status = smb2_notify_recv(req, mem_ctx, &n);
87 CHECK_STATUS(status, NT_STATUS_OK);
88 CHECK_VALUE(n.out.num_changes, 1);
89 CHECK_VALUE(n.out.changes[0].action, NOTIFY_ACTION_REMOVED);
90 CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
93 * if the change response doesn't fit in the buffer
94 * NOTIFY_ENUM_DIR is returned.
96 n.in.buffer_size = 0x00000000;
97 req = smb2_notify_send(tree, &n);
99 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
100 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
105 status = torture_setup_complex_file(tree, FNAME);
106 CHECK_STATUS(status, NT_STATUS_OK);
108 status = smb2_notify_recv(req, mem_ctx, &n);
109 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
112 * if the change response fits in the buffer we get
115 n.in.buffer_size = 0x00080000;
116 req = smb2_notify_send(tree, &n);
118 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
119 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
124 status = torture_setup_complex_file(tree, FNAME);
125 CHECK_STATUS(status, NT_STATUS_OK);
127 status = smb2_notify_recv(req, mem_ctx, &n);
128 CHECK_STATUS(status, NT_STATUS_OK);
129 CHECK_VALUE(n.out.num_changes, 3);
130 CHECK_VALUE(n.out.changes[0].action, NOTIFY_ACTION_REMOVED);
131 CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
132 CHECK_VALUE(n.out.changes[1].action, NOTIFY_ACTION_ADDED);
133 CHECK_WIRE_STR(n.out.changes[1].name, FNAME);
134 CHECK_VALUE(n.out.changes[2].action, NOTIFY_ACTION_MODIFIED);
135 CHECK_WIRE_STR(n.out.changes[2].name, FNAME);
137 /* if the first notify returns NOTIFY_ENUM_DIR, all do */
138 status = smb2_util_close(tree, dh);
139 CHECK_STATUS(status, NT_STATUS_OK);
140 status = smb2_util_roothandle(tree, &dh);
141 CHECK_STATUS(status, NT_STATUS_OK);
143 n.in.recursive = 0x0000;
144 n.in.buffer_size = 0x00000001;
145 n.in.file.handle = dh;
146 n.in.completion_filter = 0x00000FFF;
147 n.in.unknown = 0x00000000;
148 req = smb2_notify_send(tree, &n);
150 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
151 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
156 status = torture_setup_complex_file(tree, FNAME);
157 CHECK_STATUS(status, NT_STATUS_OK);
159 status = smb2_notify_recv(req, mem_ctx, &n);
160 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
162 n.in.buffer_size = 0x00080000;
163 req = smb2_notify_send(tree, &n);
164 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
165 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
170 status = torture_setup_complex_file(tree, FNAME);
171 CHECK_STATUS(status, NT_STATUS_OK);
173 status = smb2_notify_recv(req, mem_ctx, &n);
174 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
176 /* if the buffer size is too large, we get invalid parameter */
177 n.in.recursive = 0x0000;
178 n.in.buffer_size = 0x00080001;
179 n.in.file.handle = dh;
180 n.in.completion_filter = 0x00000FFF;
181 n.in.unknown = 0x00000000;
182 req = smb2_notify_send(tree, &n);
183 status = smb2_notify_recv(req, mem_ctx, &n);
184 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
190 /* basic testing of SMB2 notify
192 BOOL torture_smb2_notify(struct torture_context *torture)
194 TALLOC_CTX *mem_ctx = talloc_new(NULL);
195 struct smb2_tree *tree;
198 if (!torture_smb2_connection(mem_ctx, &tree)) {
202 ret &= test_valid_request(mem_ctx, tree);
204 talloc_free(mem_ctx);