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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libcli/smb2/smb2.h"
23 #include "libcli/smb2/smb2_calls.h"
24 #include "smb_server/smb_server.h"
25 #include "smb_server/service_smb_proto.h"
26 #include "smb_server/smb2/smb2_server.h"
27 #include "ntvfs/ntvfs.h"
29 static void smb2srv_create_send(struct ntvfs_request
*ntvfs
)
31 struct smb2srv_request
*req
;
34 SMB2SRV_CHECK_ASYNC_STATUS(io
, union smb_open
);
35 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x58, True
, io
->smb2
.out
.blob
.length
));
37 SSVAL(req
->out
.body
, 0x02, io
->smb2
.out
.oplock_flags
);
38 SIVAL(req
->out
.body
, 0x04, io
->smb2
.out
.create_action
);
39 SBVAL(req
->out
.body
, 0x08, io
->smb2
.out
.create_time
);
40 SBVAL(req
->out
.body
, 0x10, io
->smb2
.out
.access_time
);
41 SBVAL(req
->out
.body
, 0x18, io
->smb2
.out
.write_time
);
42 SBVAL(req
->out
.body
, 0x20, io
->smb2
.out
.change_time
);
43 SBVAL(req
->out
.body
, 0x28, io
->smb2
.out
.alloc_size
);
44 SBVAL(req
->out
.body
, 0x30, io
->smb2
.out
.size
);
45 SIVAL(req
->out
.body
, 0x38, io
->smb2
.out
.file_attr
);
46 SIVAL(req
->out
.body
, 0x3C, io
->smb2
.out
._pad
);
47 smb2srv_push_handle(req
->out
.body
, 0x40, io
->smb2
.out
.file
.ntvfs
);
48 SMB2SRV_CHECK(smb2_push_o32s32_blob(&req
->out
, 0x50, io
->smb2
.out
.blob
));
50 /* also setup the chained file handle */
51 req
->chained_file_handle
= req
->_chained_file_handle
;
52 smb2srv_push_handle(req
->chained_file_handle
, 0, io
->smb2
.out
.file
.ntvfs
);
54 smb2srv_send_reply(req
);
57 void smb2srv_create_recv(struct smb2srv_request
*req
)
62 SMB2SRV_CHECK_BODY_SIZE(req
, 0x38, True
);
63 SMB2SRV_TALLOC_IO_PTR(io
, union smb_open
);
64 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_create_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
66 io
->smb2
.level
= RAW_OPEN_SMB2
;
67 io
->smb2
.in
.oplock_flags
= SVAL(req
->in
.body
, 0x02);
68 io
->smb2
.in
.impersonation
= IVAL(req
->in
.body
, 0x04);
69 io
->smb2
.in
.unknown3
[0] = IVAL(req
->in
.body
, 0x08);
70 io
->smb2
.in
.unknown3
[1] = IVAL(req
->in
.body
, 0x0C);
71 io
->smb2
.in
.unknown3
[2] = IVAL(req
->in
.body
, 0x10);
72 io
->smb2
.in
.unknown3
[3] = IVAL(req
->in
.body
, 0x14);
73 io
->smb2
.in
.access_mask
= IVAL(req
->in
.body
, 0x18);
74 io
->smb2
.in
.file_attr
= IVAL(req
->in
.body
, 0x1C);
75 io
->smb2
.in
.share_access
= IVAL(req
->in
.body
, 0x20);
76 io
->smb2
.in
.open_disposition
= IVAL(req
->in
.body
, 0x24);
77 io
->smb2
.in
.create_options
= IVAL(req
->in
.body
, 0x28);
78 SMB2SRV_CHECK(smb2_pull_o16s16_string(&req
->in
, io
, req
->in
.body
+0x2C, &io
->smb2
.in
.fname
));
79 SMB2SRV_CHECK(smb2_pull_o32s32_blob(&req
->in
, io
, req
->in
.body
+0x30, &blob
));
80 /* TODO: parse the blob */
81 ZERO_STRUCT(io
->smb2
.in
.eas
);
83 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_open(req
->ntvfs
, io
));
86 static void smb2srv_close_send(struct ntvfs_request
*ntvfs
)
88 struct smb2srv_request
*req
;
91 SMB2SRV_CHECK_ASYNC_STATUS(io
, union smb_close
);
92 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x3C, False
, 0));
94 SSVAL(req
->out
.body
, 0x02, io
->smb2
.out
.flags
);
95 SIVAL(req
->out
.body
, 0x04, io
->smb2
.out
._pad
);
96 SBVAL(req
->out
.body
, 0x08, io
->smb2
.out
.create_time
);
97 SBVAL(req
->out
.body
, 0x10, io
->smb2
.out
.access_time
);
98 SBVAL(req
->out
.body
, 0x18, io
->smb2
.out
.write_time
);
99 SBVAL(req
->out
.body
, 0x20, io
->smb2
.out
.change_time
);
100 SBVAL(req
->out
.body
, 0x28, io
->smb2
.out
.alloc_size
);
101 SBVAL(req
->out
.body
, 0x30, io
->smb2
.out
.size
);
102 SIVAL(req
->out
.body
, 0x38, io
->smb2
.out
.file_attr
);
104 smb2srv_send_reply(req
);
107 void smb2srv_close_recv(struct smb2srv_request
*req
)
111 SMB2SRV_CHECK_BODY_SIZE(req
, 0x18, False
);
112 SMB2SRV_TALLOC_IO_PTR(io
, union smb_close
);
113 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_close_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
115 io
->smb2
.level
= RAW_CLOSE_SMB2
;
116 io
->smb2
.in
.flags
= SVAL(req
->in
.body
, 0x02);
117 io
->smb2
.in
._pad
= IVAL(req
->in
.body
, 0x04);
118 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x08);
120 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
121 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_close(req
->ntvfs
, io
));
124 static void smb2srv_flush_send(struct ntvfs_request
*ntvfs
)
126 struct smb2srv_request
*req
;
129 SMB2SRV_CHECK_ASYNC_STATUS(io
, union smb_flush
);
130 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x04, False
, 0));
132 SSVAL(req
->out
.body
, 0x02, 0);
134 smb2srv_send_reply(req
);
137 void smb2srv_flush_recv(struct smb2srv_request
*req
)
142 SMB2SRV_CHECK_BODY_SIZE(req
, 0x18, False
);
143 SMB2SRV_TALLOC_IO_PTR(io
, union smb_flush
);
144 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_flush_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
146 io
->smb2
.level
= RAW_FLUSH_SMB2
;
147 _pad
= SVAL(req
->in
.body
, 0x02);
148 io
->smb2
.in
.unknown
= IVAL(req
->in
.body
, 0x04);
149 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x08);
151 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
152 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_flush(req
->ntvfs
, io
));
155 static void smb2srv_read_send(struct ntvfs_request
*ntvfs
)
157 struct smb2srv_request
*req
;
160 SMB2SRV_CHECK_ASYNC_STATUS(io
, union smb_read
);
161 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x10, True
, io
->smb2
.out
.data
.length
));
163 /* TODO: avoid the memcpy */
164 SMB2SRV_CHECK(smb2_push_o16s32_blob(&req
->out
, 0x02, io
->smb2
.out
.data
));
165 SBVAL(req
->out
.body
, 0x08, io
->smb2
.out
.unknown1
);
167 smb2srv_send_reply(req
);
170 void smb2srv_read_recv(struct smb2srv_request
*req
)
174 SMB2SRV_CHECK_BODY_SIZE(req
, 0x30, True
);
175 SMB2SRV_TALLOC_IO_PTR(io
, union smb_read
);
176 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_read_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
178 io
->smb2
.level
= RAW_READ_SMB2
;
179 io
->smb2
.in
._pad
= SVAL(req
->in
.body
, 0x02);
180 io
->smb2
.in
.length
= IVAL(req
->in
.body
, 0x04);
181 io
->smb2
.in
.offset
= BVAL(req
->in
.body
, 0x08);
182 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x10);
183 io
->smb2
.in
.unknown1
= BVAL(req
->in
.body
, 0x20);
184 io
->smb2
.in
.unknown2
= BVAL(req
->in
.body
, 0x28);
186 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
188 /* preallocate the buffer for the backends */
189 io
->smb2
.out
.data
= data_blob_talloc(io
, NULL
, io
->smb2
.in
.length
);
190 if (io
->smb2
.out
.data
.length
!= io
->smb2
.in
.length
) {
191 SMB2SRV_CHECK(NT_STATUS_NO_MEMORY
);
194 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_read(req
->ntvfs
, io
));
197 static void smb2srv_write_send(struct ntvfs_request
*ntvfs
)
199 struct smb2srv_request
*req
;
202 SMB2SRV_CHECK_ASYNC_STATUS(io
, union smb_write
);
203 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x10, True
, 0));
205 SSVAL(req
->out
.body
, 0x02, io
->smb2
.out
._pad
);
206 SIVAL(req
->out
.body
, 0x04, io
->smb2
.out
.nwritten
);
207 SBVAL(req
->out
.body
, 0x08, io
->smb2
.out
.unknown1
);
209 smb2srv_send_reply(req
);
212 void smb2srv_write_recv(struct smb2srv_request
*req
)
216 SMB2SRV_CHECK_BODY_SIZE(req
, 0x30, True
);
217 SMB2SRV_TALLOC_IO_PTR(io
, union smb_write
);
218 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_write_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
220 /* TODO: avoid the memcpy */
221 io
->smb2
.level
= RAW_WRITE_SMB2
;
222 SMB2SRV_CHECK(smb2_pull_o16s32_blob(&req
->in
, io
, req
->in
.body
+0x02, &io
->smb2
.in
.data
));
223 io
->smb2
.in
.offset
= BVAL(req
->in
.body
, 0x08);
224 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x10);
225 io
->smb2
.in
.unknown1
= BVAL(req
->in
.body
, 0x20);
226 io
->smb2
.in
.unknown2
= BVAL(req
->in
.body
, 0x28);
228 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
229 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_write(req
->ntvfs
, io
));
232 static void smb2srv_lock_send(struct ntvfs_request
*ntvfs
)
234 struct smb2srv_request
*req
;
237 SMB2SRV_CHECK_ASYNC_STATUS_ERR(io
, union smb_lock
);
238 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x04, False
, 0));
240 SSVAL(req
->out
.body
, 0x02, io
->smb2
.out
.unknown1
);
242 smb2srv_send_reply(req
);
245 void smb2srv_lock_recv(struct smb2srv_request
*req
)
249 SMB2SRV_CHECK_BODY_SIZE(req
, 0x30, False
);
250 SMB2SRV_TALLOC_IO_PTR(io
, union smb_lock
);
251 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_lock_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
253 io
->smb2
.level
= RAW_LOCK_SMB2
;
255 io
->smb2
.in
.unknown1
= SVAL(req
->in
.body
, 0x02);
256 io
->smb2
.in
.unknown2
= IVAL(req
->in
.body
, 0x04);
257 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x08);
258 io
->smb2
.in
.offset
= BVAL(req
->in
.body
, 0x18);
259 io
->smb2
.in
.count
= BVAL(req
->in
.body
, 0x20);
260 io
->smb2
.in
.unknown5
= IVAL(req
->in
.body
, 0x24);
261 io
->smb2
.in
.flags
= IVAL(req
->in
.body
, 0x28);
263 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
264 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_lock(req
->ntvfs
, io
));
267 static void smb2srv_ioctl_send(struct ntvfs_request
*ntvfs
)
269 struct smb2srv_request
*req
;
272 SMB2SRV_CHECK_ASYNC_STATUS_ERR(io
, union smb_ioctl
);
273 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x30, True
, 0));
275 SSVAL(req
->out
.body
, 0x02, io
->smb2
.out
._pad
);
276 SIVAL(req
->out
.body
, 0x04, io
->smb2
.out
.function
);
277 if (io
->smb2
.level
== RAW_IOCTL_SMB2_NO_HANDLE
) {
278 struct smb2_handle h
;
279 h
.data
[0] = UINT64_MAX
;
280 h
.data
[1] = UINT64_MAX
;
281 smb2_push_handle(req
->out
.body
+ 0x08, &h
);
283 smb2srv_push_handle(req
->out
.body
, 0x08,io
->smb2
.in
.file
.ntvfs
);
285 SMB2SRV_CHECK(smb2_push_o32s32_blob(&req
->out
, 0x18, io
->smb2
.out
.in
));
286 SMB2SRV_CHECK(smb2_push_o32s32_blob(&req
->out
, 0x20, io
->smb2
.out
.out
));
287 SIVAL(req
->out
.body
, 0x28, io
->smb2
.out
.unknown2
);
288 SIVAL(req
->out
.body
, 0x2C, io
->smb2
.out
.unknown3
);
290 smb2srv_send_reply(req
);
293 void smb2srv_ioctl_recv(struct smb2srv_request
*req
)
296 struct smb2_handle h
;
298 SMB2SRV_CHECK_BODY_SIZE(req
, 0x38, True
);
299 SMB2SRV_TALLOC_IO_PTR(io
, union smb_ioctl
);
300 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_ioctl_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
302 /* TODO: avoid the memcpy */
303 io
->smb2
.in
._pad
= SVAL(req
->in
.body
, 0x02);
304 io
->smb2
.in
.function
= IVAL(req
->in
.body
, 0x04);
305 /* file handle ... */
306 SMB2SRV_CHECK(smb2_pull_o32s32_blob(&req
->in
, io
, req
->in
.body
+0x18, &io
->smb2
.in
.out
));
307 io
->smb2
.in
.unknown2
= IVAL(req
->in
.body
, 0x20);
308 SMB2SRV_CHECK(smb2_pull_o32s32_blob(&req
->in
, io
, req
->in
.body
+0x24, &io
->smb2
.in
.in
));
309 io
->smb2
.in
.max_response_size
= IVAL(req
->in
.body
, 0x2C);
310 io
->smb2
.in
.flags
= BVAL(req
->in
.body
, 0x30);
312 smb2_pull_handle(req
->in
.body
+ 0x08, &h
);
313 if (h
.data
[0] == UINT64_MAX
&& h
.data
[1] == UINT64_MAX
) {
314 io
->smb2
.level
= RAW_IOCTL_SMB2_NO_HANDLE
;
316 io
->smb2
.level
= RAW_IOCTL_SMB2
;
317 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x08);
318 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
321 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_ioctl(req
->ntvfs
, io
));
324 static void smb2srv_notify_send(struct ntvfs_request
*ntvfs
)
326 struct smb2srv_request
*req
;
327 union smb_notify
*io
;
331 DATA_BLOB blob
= data_blob(NULL
, 0);
333 SMB2SRV_CHECK_ASYNC_STATUS(io
, union smb_notify
);
334 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x08, True
, 0));
336 #define MAX_BYTES_PER_CHAR 3
338 /* work out how big the reply buffer could be */
339 for (i
=0;i
<io
->smb2
.out
.num_changes
;i
++) {
340 size
+= 12 + 3 + (1+strlen(io
->smb2
.out
.changes
[i
].name
.s
)) * MAX_BYTES_PER_CHAR
;
343 blob
= data_blob_talloc(req
, NULL
, size
);
344 if (size
> 0 && !blob
.data
) {
345 SMB2SRV_CHECK(NT_STATUS_NO_MEMORY
);
350 /* construct the changes buffer */
351 for (i
=0;i
<io
->smb2
.out
.num_changes
;i
++) {
355 SIVAL(p
, 4, io
->smb2
.out
.changes
[i
].action
);
356 len
= push_string(p
+ 12, io
->smb2
.out
.changes
[i
].name
.s
,
357 blob
.length
- (p
+12 - blob
.data
), STR_UNICODE
);
363 int pad
= 4 - (ofs
& 3);
364 memset(p
+ofs
, 0, pad
);
368 if (i
== io
->smb2
.out
.num_changes
-1) {
377 blob
.length
= p
- blob
.data
;
379 SMB2SRV_CHECK(smb2_push_o16s32_blob(&req
->out
, 0x02, blob
));
381 smb2srv_send_reply(req
);
384 void smb2srv_notify_recv(struct smb2srv_request
*req
)
386 union smb_notify
*io
;
388 SMB2SRV_CHECK_BODY_SIZE(req
, 0x20, False
);
389 SMB2SRV_TALLOC_IO_PTR(io
, union smb_notify
);
390 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_notify_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
392 io
->smb2
.level
= RAW_NOTIFY_SMB2
;
393 io
->smb2
.in
.recursive
= SVAL(req
->in
.body
, 0x02);
394 io
->smb2
.in
.buffer_size
= IVAL(req
->in
.body
, 0x04);
395 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x08);
396 io
->smb2
.in
.completion_filter
= IVAL(req
->in
.body
, 0x18);
397 io
->smb2
.in
.unknown
= BVAL(req
->in
.body
, 0x1C);
399 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
400 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_notify(req
->ntvfs
, io
));
403 void smb2srv_break_recv(struct smb2srv_request
*req
)
405 smb2srv_send_error(req
, NT_STATUS_NOT_IMPLEMENTED
);