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 smb2srv_send_reply(req
);
53 void smb2srv_create_recv(struct smb2srv_request
*req
)
58 SMB2SRV_CHECK_BODY_SIZE(req
, 0x38, True
);
59 SMB2SRV_TALLOC_IO_PTR(io
, union smb_open
);
60 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_create_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
62 io
->smb2
.level
= RAW_OPEN_SMB2
;
63 io
->smb2
.in
.oplock_flags
= SVAL(req
->in
.body
, 0x02);
64 io
->smb2
.in
.impersonation
= IVAL(req
->in
.body
, 0x04);
65 io
->smb2
.in
.unknown3
[0] = IVAL(req
->in
.body
, 0x08);
66 io
->smb2
.in
.unknown3
[1] = IVAL(req
->in
.body
, 0x0C);
67 io
->smb2
.in
.unknown3
[2] = IVAL(req
->in
.body
, 0x10);
68 io
->smb2
.in
.unknown3
[3] = IVAL(req
->in
.body
, 0x14);
69 io
->smb2
.in
.access_mask
= IVAL(req
->in
.body
, 0x18);
70 io
->smb2
.in
.file_attr
= IVAL(req
->in
.body
, 0x1C);
71 io
->smb2
.in
.share_access
= IVAL(req
->in
.body
, 0x20);
72 io
->smb2
.in
.open_disposition
= IVAL(req
->in
.body
, 0x24);
73 io
->smb2
.in
.create_options
= IVAL(req
->in
.body
, 0x28);
74 SMB2SRV_CHECK(smb2_pull_o16s16_string(&req
->in
, io
, req
->in
.body
+0x2C, &io
->smb2
.in
.fname
));
75 SMB2SRV_CHECK(smb2_pull_o32s32_blob(&req
->in
, io
, req
->in
.body
+0x30, &blob
));
76 /* TODO: parse the blob */
77 ZERO_STRUCT(io
->smb2
.in
.eas
);
79 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_open(req
->ntvfs
, io
));
82 static void smb2srv_close_send(struct ntvfs_request
*ntvfs
)
84 struct smb2srv_request
*req
;
87 SMB2SRV_CHECK_ASYNC_STATUS(io
, union smb_close
);
88 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x3C, False
, 0));
90 SSVAL(req
->out
.body
, 0x02, io
->smb2
.out
.flags
);
91 SIVAL(req
->out
.body
, 0x04, io
->smb2
.out
._pad
);
92 SBVAL(req
->out
.body
, 0x08, io
->smb2
.out
.create_time
);
93 SBVAL(req
->out
.body
, 0x10, io
->smb2
.out
.access_time
);
94 SBVAL(req
->out
.body
, 0x18, io
->smb2
.out
.write_time
);
95 SBVAL(req
->out
.body
, 0x20, io
->smb2
.out
.change_time
);
96 SBVAL(req
->out
.body
, 0x28, io
->smb2
.out
.alloc_size
);
97 SBVAL(req
->out
.body
, 0x30, io
->smb2
.out
.size
);
98 SIVAL(req
->out
.body
, 0x38, io
->smb2
.out
.file_attr
);
100 smb2srv_send_reply(req
);
103 void smb2srv_close_recv(struct smb2srv_request
*req
)
107 SMB2SRV_CHECK_BODY_SIZE(req
, 0x18, False
);
108 SMB2SRV_TALLOC_IO_PTR(io
, union smb_close
);
109 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_close_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
111 io
->smb2
.level
= RAW_CLOSE_SMB2
;
112 io
->smb2
.in
.flags
= SVAL(req
->in
.body
, 0x02);
113 io
->smb2
.in
._pad
= IVAL(req
->in
.body
, 0x04);
114 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x08);
116 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
117 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_close(req
->ntvfs
, io
));
120 static void smb2srv_flush_send(struct ntvfs_request
*ntvfs
)
122 struct smb2srv_request
*req
;
125 SMB2SRV_CHECK_ASYNC_STATUS(io
, union smb_flush
);
126 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x04, False
, 0));
128 SSVAL(req
->out
.body
, 0x02, 0);
130 smb2srv_send_reply(req
);
133 void smb2srv_flush_recv(struct smb2srv_request
*req
)
138 SMB2SRV_CHECK_BODY_SIZE(req
, 0x18, False
);
139 SMB2SRV_TALLOC_IO_PTR(io
, union smb_flush
);
140 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_flush_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
142 io
->smb2
.level
= RAW_FLUSH_SMB2
;
143 _pad
= SVAL(req
->in
.body
, 0x02);
144 io
->smb2
.in
.unknown
= IVAL(req
->in
.body
, 0x04);
145 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x08);
147 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
148 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_flush(req
->ntvfs
, io
));
151 static void smb2srv_read_send(struct ntvfs_request
*ntvfs
)
153 struct smb2srv_request
*req
;
156 SMB2SRV_CHECK_ASYNC_STATUS(io
, union smb_read
);
157 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x10, True
, io
->smb2
.out
.data
.length
));
159 SMB2SRV_CHECK(smb2_push_o16s32_blob(&req
->out
, 0x02, io
->smb2
.out
.data
));
160 SBVAL(req
->out
.body
, 0x08, io
->smb2
.out
.unknown1
);
162 smb2srv_send_reply(req
);
165 void smb2srv_read_recv(struct smb2srv_request
*req
)
169 SMB2SRV_CHECK_BODY_SIZE(req
, 0x30, True
);
170 SMB2SRV_TALLOC_IO_PTR(io
, union smb_read
);
171 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_read_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
173 io
->smb2
.level
= RAW_READ_SMB2
;
174 io
->smb2
.in
._pad
= SVAL(req
->in
.body
, 0x02);
175 io
->smb2
.in
.length
= IVAL(req
->in
.body
, 0x04);
176 io
->smb2
.in
.offset
= BVAL(req
->in
.body
, 0x08);
177 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x10);
178 io
->smb2
.in
.unknown1
= BVAL(req
->in
.body
, 0x20);
179 io
->smb2
.in
.unknown2
= BVAL(req
->in
.body
, 0x28);
181 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
183 /* preallocate the buffer for the backends */
184 io
->smb2
.out
.data
= data_blob_talloc(io
, NULL
, io
->smb2
.in
.length
);
185 if (io
->smb2
.out
.data
.length
!= io
->smb2
.in
.length
) {
186 SMB2SRV_CHECK(NT_STATUS_NO_MEMORY
);
189 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_read(req
->ntvfs
, io
));
192 static void smb2srv_write_send(struct ntvfs_request
*ntvfs
)
194 struct smb2srv_request
*req
;
197 SMB2SRV_CHECK_ASYNC_STATUS(io
, union smb_write
);
198 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x10, True
, 0));
200 SSVAL(req
->out
.body
, 0x02, io
->smb2
.out
._pad
);
201 SIVAL(req
->out
.body
, 0x04, io
->smb2
.out
.nwritten
);
202 SBVAL(req
->out
.body
, 0x08, io
->smb2
.out
.unknown1
);
204 smb2srv_send_reply(req
);
207 void smb2srv_write_recv(struct smb2srv_request
*req
)
211 SMB2SRV_CHECK_BODY_SIZE(req
, 0x30, True
);
212 SMB2SRV_TALLOC_IO_PTR(io
, union smb_write
);
213 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_write_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
215 /* TODO: avoid the memcpy */
216 io
->smb2
.level
= RAW_WRITE_SMB2
;
217 SMB2SRV_CHECK(smb2_pull_o16s32_blob(&req
->in
, io
, req
->in
.body
+0x02, &io
->smb2
.in
.data
));
218 io
->smb2
.in
.offset
= BVAL(req
->in
.body
, 0x08);
219 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x10);
220 io
->smb2
.in
.unknown1
= BVAL(req
->in
.body
, 0x20);
221 io
->smb2
.in
.unknown2
= BVAL(req
->in
.body
, 0x28);
223 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
224 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_write(req
->ntvfs
, io
));
227 void smb2srv_lock_recv(struct smb2srv_request
*req
)
229 smb2srv_send_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
232 static void smb2srv_ioctl_send(struct ntvfs_request
*ntvfs
)
234 struct smb2srv_request
*req
;
237 SMB2SRV_CHECK_ASYNC_STATUS_ERR(io
, union smb_ioctl
);
238 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x30, True
, 0));
240 SSVAL(req
->out
.body
, 0x02, io
->smb2
.out
._pad
);
241 SIVAL(req
->out
.body
, 0x04, io
->smb2
.out
.function
);
242 if (io
->smb2
.level
== RAW_IOCTL_SMB2_NO_HANDLE
) {
243 struct smb2_handle h
;
244 h
.data
[0] = UINT64_MAX
;
245 h
.data
[1] = UINT64_MAX
;
246 smb2_push_handle(req
->out
.body
+ 0x08, &h
);
248 smb2srv_push_handle(req
->out
.body
, 0x08,io
->smb2
.in
.file
.ntvfs
);
250 SMB2SRV_CHECK(smb2_push_o32s32_blob(&req
->out
, 0x18, io
->smb2
.out
.in
));
251 SMB2SRV_CHECK(smb2_push_o32s32_blob(&req
->out
, 0x20, io
->smb2
.out
.out
));
252 SIVAL(req
->out
.body
, 0x28, io
->smb2
.out
.unknown2
);
253 SIVAL(req
->out
.body
, 0x2C, io
->smb2
.out
.unknown3
);
255 smb2srv_send_reply(req
);
258 void smb2srv_ioctl_recv(struct smb2srv_request
*req
)
261 struct smb2_handle h
;
263 SMB2SRV_CHECK_BODY_SIZE(req
, 0x38, True
);
264 SMB2SRV_TALLOC_IO_PTR(io
, union smb_ioctl
);
265 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_ioctl_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
267 /* TODO: avoid the memcpy */
268 io
->smb2
.in
._pad
= SVAL(req
->in
.body
, 0x02);
269 io
->smb2
.in
.function
= IVAL(req
->in
.body
, 0x04);
270 /* file handle ... */
271 SMB2SRV_CHECK(smb2_pull_o32s32_blob(&req
->in
, io
, req
->in
.body
+0x18, &io
->smb2
.in
.out
));
272 io
->smb2
.in
.unknown2
= IVAL(req
->in
.body
, 0x20);
273 SMB2SRV_CHECK(smb2_pull_o32s32_blob(&req
->in
, io
, req
->in
.body
+0x24, &io
->smb2
.in
.in
));
274 io
->smb2
.in
.max_response_size
= IVAL(req
->in
.body
, 0x2C);
275 io
->smb2
.in
.flags
= BVAL(req
->in
.body
, 0x30);
277 smb2_pull_handle(req
->in
.body
+ 0x08, &h
);
278 if (h
.data
[0] == UINT64_MAX
&& h
.data
[1] == UINT64_MAX
) {
279 io
->smb2
.level
= RAW_IOCTL_SMB2_NO_HANDLE
;
281 io
->smb2
.level
= RAW_IOCTL_SMB2
;
282 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x08);
283 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
286 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_ioctl(req
->ntvfs
, io
));
289 void smb2srv_cancel_recv(struct smb2srv_request
*req
)
291 smb2srv_send_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
294 static void smb2srv_notify_send(struct ntvfs_request
*ntvfs
)
296 struct smb2srv_request
*req
;
297 union smb_notify
*io
;
301 DATA_BLOB blob
= data_blob(NULL
, 0);
303 SMB2SRV_CHECK_ASYNC_STATUS(io
, union smb_notify
);
304 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x08, True
, 0));
306 #define MAX_BYTES_PER_CHAR 3
308 /* work out how big the reply buffer could be */
309 for (i
=0;i
<io
->smb2
.out
.num_changes
;i
++) {
310 size
+= 12 + 3 + (1+strlen(io
->smb2
.out
.changes
[i
].name
.s
)) * MAX_BYTES_PER_CHAR
;
313 blob
= data_blob_talloc(req
, NULL
, size
);
314 if (size
> 0 && !blob
.data
) {
315 SMB2SRV_CHECK(NT_STATUS_NO_MEMORY
);
320 /* construct the changes buffer */
321 for (i
=0;i
<io
->smb2
.out
.num_changes
;i
++) {
325 SIVAL(p
, 4, io
->smb2
.out
.changes
[i
].action
);
326 len
= push_string(p
+ 12, io
->smb2
.out
.changes
[i
].name
.s
,
327 blob
.length
- (p
+12 - blob
.data
), STR_UNICODE
);
333 int pad
= 4 - (ofs
& 3);
334 memset(p
+ofs
, 0, pad
);
338 if (i
== io
->smb2
.out
.num_changes
-1) {
347 blob
.length
= p
- blob
.data
;
349 SMB2SRV_CHECK(smb2_push_o16s32_blob(&req
->out
, 0x02, blob
));
351 smb2srv_send_reply(req
);
354 void smb2srv_notify_recv(struct smb2srv_request
*req
)
356 union smb_notify
*io
;
358 SMB2SRV_CHECK_BODY_SIZE(req
, 0x20, False
);
359 SMB2SRV_TALLOC_IO_PTR(io
, union smb_notify
);
360 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_notify_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
362 io
->smb2
.level
= RAW_NOTIFY_SMB2
;
363 io
->smb2
.in
.recursive
= SVAL(req
->in
.body
, 0x02);
364 io
->smb2
.in
.buffer_size
= IVAL(req
->in
.body
, 0x04);
365 io
->smb2
.in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x08);
366 io
->smb2
.in
.completion_filter
= IVAL(req
->in
.body
, 0x18);
367 io
->smb2
.in
.unknown
= BVAL(req
->in
.body
, 0x1C);
369 SMB2SRV_CHECK_FILE_HANDLE(io
->smb2
.in
.file
.ntvfs
);
370 SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_notify(req
->ntvfs
, io
));
373 void smb2srv_break_recv(struct smb2srv_request
*req
)
375 smb2srv_send_error(req
, NT_STATUS_NOT_IMPLEMENTED
);