2 Unix SMB2 implementation.
4 Copyright (C) Stefan Metzmacher 2005
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "libcli/smb2/smb2.h"
22 #include "libcli/smb2/smb2_calls.h"
23 #include "smb_server/smb_server.h"
24 #include "smb_server/service_smb_proto.h"
25 #include "smb_server/smb2/smb2_server.h"
26 #include "ntvfs/ntvfs.h"
28 static void smb2srv_create_send(struct ntvfs_request
*ntvfs
)
30 struct smb2srv_request
*req
;
33 SMB2SRV_CHECK_ASYNC_STATUS(io
, union smb_open
);
34 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x58, true, io
->smb2
.out
.blob
.length
));
36 SSVAL(req
->out
.body
, 0x02, io
->smb2
.out
.oplock_flags
);
37 SIVAL(req
->out
.body
, 0x04, io
->smb2
.out
.create_action
);
38 SBVAL(req
->out
.body
, 0x08, io
->smb2
.out
.create_time
);
39 SBVAL(req
->out
.body
, 0x10, io
->smb2
.out
.access_time
);
40 SBVAL(req
->out
.body
, 0x18, io
->smb2
.out
.write_time
);
41 SBVAL(req
->out
.body
, 0x20, io
->smb2
.out
.change_time
);
42 SBVAL(req
->out
.body
, 0x28, io
->smb2
.out
.alloc_size
);
43 SBVAL(req
->out
.body
, 0x30, io
->smb2
.out
.size
);
44 SIVAL(req
->out
.body
, 0x38, io
->smb2
.out
.file_attr
);
45 SIVAL(req
->out
.body
, 0x3C, io
->smb2
.out
._pad
);
46 smb2srv_push_handle(req
->out
.body
, 0x40, io
->smb2
.out
.file
.ntvfs
);
47 SMB2SRV_CHECK(smb2_push_o32s32_blob(&req
->out
, 0x50, io
->smb2
.out
.blob
));
49 /* also setup the chained file handle */
50 req
->chained_file_handle
= req
->_chained_file_handle
;
51 smb2srv_push_handle(req
->chained_file_handle
, 0, io
->smb2
.out
.file
.ntvfs
);
53 smb2srv_send_reply(req
);
56 void smb2srv_create_recv(struct smb2srv_request
*req
)
61 SMB2SRV_CHECK_BODY_SIZE(req
, 0x38, true);
62 SMB2SRV_TALLOC_IO_PTR(io
, union smb_open
);
63 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_create_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
65 io
->smb2
.level
= RAW_OPEN_SMB2
;
66 io
->smb2
.in
.oplock_flags
= SVAL(req
->in
.body
, 0x02);
67 io
->smb2
.in
.impersonation
= IVAL(req
->in
.body
, 0x04);
68 io
->smb2
.in
.unknown3
[0] = IVAL(req
->in
.body
, 0x08);
69 io
->smb2
.in
.unknown3
[1] = IVAL(req
->in
.body
, 0x0C);
70 io
->smb2
.in
.unknown3
[2] = IVAL(req
->in
.body
, 0x10);
71 io
->smb2
.in
.unknown3
[3] = IVAL(req
->in
.body
, 0x14);
72 io
->smb2
.in
.access_mask
= IVAL(req
->in
.body
, 0x18);
73 io
->smb2
.in
.file_attr
= IVAL(req
->in
.body
, 0x1C);
74 io
->smb2
.in
.share_access
= IVAL(req
->in
.body
, 0x20);
75 io
->smb2
.in
.open_disposition
= IVAL(req
->in
.body
, 0x24);
76 io
->smb2
.in
.create_options
= IVAL(req
->in
.body
, 0x28);
77 SMB2SRV_CHECK(smb2_pull_o16s16_string(&req
->in
, io
, req
->in
.body
+0x2C, &io
->smb2
.in
.fname
));
78 SMB2SRV_CHECK(smb2_pull_o32s32_blob(&req
->in
, io
, req
->in
.body
+0x30, &blob
));
79 /* TODO: parse the blob */
80 ZERO_STRUCT(io
->smb2
.in
.eas
);
82 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_open(req
->ntvfs
, io
));
85 static void smb2srv_close_send(struct ntvfs_request
*ntvfs
)
87 struct smb2srv_request
*req
;
90 SMB2SRV_CHECK_ASYNC_STATUS(io
, union smb_close
);
91 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x3C, false, 0));
93 SSVAL(req
->out
.body
, 0x02, io
->smb2
.out
.flags
);
94 SIVAL(req
->out
.body
, 0x04, io
->smb2
.out
._pad
);
95 SBVAL(req
->out
.body
, 0x08, io
->smb2
.out
.create_time
);
96 SBVAL(req
->out
.body
, 0x10, io
->smb2
.out
.access_time
);
97 SBVAL(req
->out
.body
, 0x18, io
->smb2
.out
.write_time
);
98 SBVAL(req
->out
.body
, 0x20, io
->smb2
.out
.change_time
);
99 SBVAL(req
->out
.body
, 0x28, io
->smb2
.out
.alloc_size
);
100 SBVAL(req
->out
.body
, 0x30, io
->smb2
.out
.size
);
101 SIVAL(req
->out
.body
, 0x38, io
->smb2
.out
.file_attr
);
103 smb2srv_send_reply(req
);
106 void smb2srv_close_recv(struct smb2srv_request
*req
)
110 SMB2SRV_CHECK_BODY_SIZE(req
, 0x18, false);
111 SMB2SRV_TALLOC_IO_PTR(io
, union smb_close
);
112 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_close_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
114 io
->smb2
.level
= RAW_CLOSE_SMB2
;
115 io
->smb2
.in
.flags
= SVAL(req
->in
.body
, 0x02);
116 io
->smb2
.in
._pad
= IVAL(req
->in
.body
, 0x04);
117 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x08);
119 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
120 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_close(req
->ntvfs
, io
));
123 static void smb2srv_flush_send(struct ntvfs_request
*ntvfs
)
125 struct smb2srv_request
*req
;
128 SMB2SRV_CHECK_ASYNC_STATUS(io
, union smb_flush
);
129 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x04, false, 0));
131 SSVAL(req
->out
.body
, 0x02, 0);
133 smb2srv_send_reply(req
);
136 void smb2srv_flush_recv(struct smb2srv_request
*req
)
141 SMB2SRV_CHECK_BODY_SIZE(req
, 0x18, false);
142 SMB2SRV_TALLOC_IO_PTR(io
, union smb_flush
);
143 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_flush_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
145 io
->smb2
.level
= RAW_FLUSH_SMB2
;
146 _pad
= SVAL(req
->in
.body
, 0x02);
147 io
->smb2
.in
.unknown
= IVAL(req
->in
.body
, 0x04);
148 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x08);
150 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
151 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_flush(req
->ntvfs
, io
));
154 static void smb2srv_read_send(struct ntvfs_request
*ntvfs
)
156 struct smb2srv_request
*req
;
159 SMB2SRV_CHECK_ASYNC_STATUS(io
, union smb_read
);
160 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x10, true, io
->smb2
.out
.data
.length
));
162 /* TODO: avoid the memcpy */
163 SMB2SRV_CHECK(smb2_push_o16s32_blob(&req
->out
, 0x02, io
->smb2
.out
.data
));
164 SBVAL(req
->out
.body
, 0x08, io
->smb2
.out
.unknown1
);
166 smb2srv_send_reply(req
);
169 void smb2srv_read_recv(struct smb2srv_request
*req
)
173 SMB2SRV_CHECK_BODY_SIZE(req
, 0x30, true);
174 SMB2SRV_TALLOC_IO_PTR(io
, union smb_read
);
175 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_read_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
177 io
->smb2
.level
= RAW_READ_SMB2
;
178 io
->smb2
.in
._pad
= SVAL(req
->in
.body
, 0x02);
179 io
->smb2
.in
.length
= IVAL(req
->in
.body
, 0x04);
180 io
->smb2
.in
.offset
= BVAL(req
->in
.body
, 0x08);
181 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x10);
182 io
->smb2
.in
.unknown1
= BVAL(req
->in
.body
, 0x20);
183 io
->smb2
.in
.unknown2
= BVAL(req
->in
.body
, 0x28);
185 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
187 /* preallocate the buffer for the backends */
188 io
->smb2
.out
.data
= data_blob_talloc(io
, NULL
, io
->smb2
.in
.length
);
189 if (io
->smb2
.out
.data
.length
!= io
->smb2
.in
.length
) {
190 SMB2SRV_CHECK(NT_STATUS_NO_MEMORY
);
193 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_read(req
->ntvfs
, io
));
196 static void smb2srv_write_send(struct ntvfs_request
*ntvfs
)
198 struct smb2srv_request
*req
;
201 SMB2SRV_CHECK_ASYNC_STATUS(io
, union smb_write
);
202 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x10, true, 0));
204 SSVAL(req
->out
.body
, 0x02, io
->smb2
.out
._pad
);
205 SIVAL(req
->out
.body
, 0x04, io
->smb2
.out
.nwritten
);
206 SBVAL(req
->out
.body
, 0x08, io
->smb2
.out
.unknown1
);
208 smb2srv_send_reply(req
);
211 void smb2srv_write_recv(struct smb2srv_request
*req
)
215 SMB2SRV_CHECK_BODY_SIZE(req
, 0x30, true);
216 SMB2SRV_TALLOC_IO_PTR(io
, union smb_write
);
217 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_write_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
219 /* TODO: avoid the memcpy */
220 io
->smb2
.level
= RAW_WRITE_SMB2
;
221 SMB2SRV_CHECK(smb2_pull_o16s32_blob(&req
->in
, io
, req
->in
.body
+0x02, &io
->smb2
.in
.data
));
222 io
->smb2
.in
.offset
= BVAL(req
->in
.body
, 0x08);
223 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x10);
224 io
->smb2
.in
.unknown1
= BVAL(req
->in
.body
, 0x20);
225 io
->smb2
.in
.unknown2
= BVAL(req
->in
.body
, 0x28);
227 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
228 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_write(req
->ntvfs
, io
));
231 static void smb2srv_lock_send(struct ntvfs_request
*ntvfs
)
233 struct smb2srv_request
*req
;
236 SMB2SRV_CHECK_ASYNC_STATUS_ERR(io
, union smb_lock
);
237 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x04, false, 0));
239 SSVAL(req
->out
.body
, 0x02, io
->smb2
.out
.unknown1
);
241 smb2srv_send_reply(req
);
244 void smb2srv_lock_recv(struct smb2srv_request
*req
)
248 SMB2SRV_CHECK_BODY_SIZE(req
, 0x30, false);
249 SMB2SRV_TALLOC_IO_PTR(io
, union smb_lock
);
250 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_lock_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
252 io
->smb2
.level
= RAW_LOCK_SMB2
;
254 io
->smb2
.in
.unknown1
= SVAL(req
->in
.body
, 0x02);
255 io
->smb2
.in
.unknown2
= IVAL(req
->in
.body
, 0x04);
256 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x08);
257 io
->smb2
.in
.offset
= BVAL(req
->in
.body
, 0x18);
258 io
->smb2
.in
.count
= BVAL(req
->in
.body
, 0x20);
259 io
->smb2
.in
.unknown5
= IVAL(req
->in
.body
, 0x24);
260 io
->smb2
.in
.flags
= IVAL(req
->in
.body
, 0x28);
262 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
263 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_lock(req
->ntvfs
, io
));
266 static void smb2srv_ioctl_send(struct ntvfs_request
*ntvfs
)
268 struct smb2srv_request
*req
;
271 SMB2SRV_CHECK_ASYNC_STATUS_ERR(io
, union smb_ioctl
);
272 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x30, true, 0));
274 SSVAL(req
->out
.body
, 0x02, io
->smb2
.out
._pad
);
275 SIVAL(req
->out
.body
, 0x04, io
->smb2
.out
.function
);
276 if (io
->smb2
.level
== RAW_IOCTL_SMB2_NO_HANDLE
) {
277 struct smb2_handle h
;
278 h
.data
[0] = UINT64_MAX
;
279 h
.data
[1] = UINT64_MAX
;
280 smb2_push_handle(req
->out
.body
+ 0x08, &h
);
282 smb2srv_push_handle(req
->out
.body
, 0x08,io
->smb2
.in
.file
.ntvfs
);
284 SMB2SRV_CHECK(smb2_push_o32s32_blob(&req
->out
, 0x18, io
->smb2
.out
.in
));
285 SMB2SRV_CHECK(smb2_push_o32s32_blob(&req
->out
, 0x20, io
->smb2
.out
.out
));
286 SIVAL(req
->out
.body
, 0x28, io
->smb2
.out
.unknown2
);
287 SIVAL(req
->out
.body
, 0x2C, io
->smb2
.out
.unknown3
);
289 smb2srv_send_reply(req
);
292 void smb2srv_ioctl_recv(struct smb2srv_request
*req
)
295 struct smb2_handle h
;
297 SMB2SRV_CHECK_BODY_SIZE(req
, 0x38, true);
298 SMB2SRV_TALLOC_IO_PTR(io
, union smb_ioctl
);
299 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_ioctl_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
301 /* TODO: avoid the memcpy */
302 io
->smb2
.in
._pad
= SVAL(req
->in
.body
, 0x02);
303 io
->smb2
.in
.function
= IVAL(req
->in
.body
, 0x04);
304 /* file handle ... */
305 SMB2SRV_CHECK(smb2_pull_o32s32_blob(&req
->in
, io
, req
->in
.body
+0x18, &io
->smb2
.in
.out
));
306 io
->smb2
.in
.unknown2
= IVAL(req
->in
.body
, 0x20);
307 SMB2SRV_CHECK(smb2_pull_o32s32_blob(&req
->in
, io
, req
->in
.body
+0x24, &io
->smb2
.in
.in
));
308 io
->smb2
.in
.max_response_size
= IVAL(req
->in
.body
, 0x2C);
309 io
->smb2
.in
.flags
= BVAL(req
->in
.body
, 0x30);
311 smb2_pull_handle(req
->in
.body
+ 0x08, &h
);
312 if (h
.data
[0] == UINT64_MAX
&& h
.data
[1] == UINT64_MAX
) {
313 io
->smb2
.level
= RAW_IOCTL_SMB2_NO_HANDLE
;
315 io
->smb2
.level
= RAW_IOCTL_SMB2
;
316 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x08);
317 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
320 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_ioctl(req
->ntvfs
, io
));
323 static void smb2srv_notify_send(struct ntvfs_request
*ntvfs
)
325 struct smb2srv_request
*req
;
326 union smb_notify
*io
;
330 DATA_BLOB blob
= data_blob(NULL
, 0);
332 SMB2SRV_CHECK_ASYNC_STATUS(io
, union smb_notify
);
333 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x08, true, 0));
335 #define MAX_BYTES_PER_CHAR 3
337 /* work out how big the reply buffer could be */
338 for (i
=0;i
<io
->smb2
.out
.num_changes
;i
++) {
339 size
+= 12 + 3 + (1+strlen(io
->smb2
.out
.changes
[i
].name
.s
)) * MAX_BYTES_PER_CHAR
;
342 blob
= data_blob_talloc(req
, NULL
, size
);
343 if (size
> 0 && !blob
.data
) {
344 SMB2SRV_CHECK(NT_STATUS_NO_MEMORY
);
349 /* construct the changes buffer */
350 for (i
=0;i
<io
->smb2
.out
.num_changes
;i
++) {
354 SIVAL(p
, 4, io
->smb2
.out
.changes
[i
].action
);
355 len
= push_string(p
+ 12, io
->smb2
.out
.changes
[i
].name
.s
,
356 blob
.length
- (p
+12 - blob
.data
), STR_UNICODE
);
362 int pad
= 4 - (ofs
& 3);
363 memset(p
+ofs
, 0, pad
);
367 if (i
== io
->smb2
.out
.num_changes
-1) {
376 blob
.length
= p
- blob
.data
;
378 SMB2SRV_CHECK(smb2_push_o16s32_blob(&req
->out
, 0x02, blob
));
380 smb2srv_send_reply(req
);
383 void smb2srv_notify_recv(struct smb2srv_request
*req
)
385 union smb_notify
*io
;
387 SMB2SRV_CHECK_BODY_SIZE(req
, 0x20, false);
388 SMB2SRV_TALLOC_IO_PTR(io
, union smb_notify
);
389 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_notify_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
391 io
->smb2
.level
= RAW_NOTIFY_SMB2
;
392 io
->smb2
.in
.recursive
= SVAL(req
->in
.body
, 0x02);
393 io
->smb2
.in
.buffer_size
= IVAL(req
->in
.body
, 0x04);
394 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x08);
395 io
->smb2
.in
.completion_filter
= IVAL(req
->in
.body
, 0x18);
396 io
->smb2
.in
.unknown
= BVAL(req
->in
.body
, 0x1C);
398 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
399 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_notify(req
->ntvfs
, io
));
402 void smb2srv_break_recv(struct smb2srv_request
*req
)
404 smb2srv_send_error(req
, NT_STATUS_NOT_IMPLEMENTED
);