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/smb2/smb2_server.h"
25 #include "smbd/service_stream.h"
26 #include "ntvfs/ntvfs.h"
29 send an oplock break request to a client
31 static NTSTATUS
smb2srv_send_oplock_break(void *p
, struct ntvfs_handle
*h
, uint8_t level
)
33 struct smbsrv_handle
*handle
= talloc_get_type(h
->frontend_data
.private_data
,
34 struct smbsrv_handle
);
35 struct smb2srv_request
*req
;
38 /* setup a dummy request structure */
39 req
= smb2srv_init_request(handle
->tcon
->smb_conn
);
40 NT_STATUS_HAVE_NO_MEMORY(req
);
42 req
->in
.buffer
= talloc_array(req
, uint8_t,
43 NBT_HDR_SIZE
+ SMB2_MIN_SIZE
);
44 NT_STATUS_HAVE_NO_MEMORY(req
->in
.buffer
);
45 req
->in
.size
= NBT_HDR_SIZE
+ SMB2_MIN_SIZE
;
46 req
->in
.allocated
= req
->in
.size
;
48 req
->in
.hdr
= req
->in
.buffer
+ NBT_HDR_SIZE
;
49 req
->in
.body
= req
->in
.hdr
+ SMB2_HDR_BODY
;
50 req
->in
.body_size
= req
->in
.size
- (SMB2_HDR_BODY
+NBT_HDR_SIZE
);
51 req
->in
.dynamic
= NULL
;
53 req
->seqnum
= UINT64_MAX
;
55 smb2srv_setup_bufinfo(req
);
57 SIVAL(req
->in
.hdr
, 0, SMB2_MAGIC
);
58 SSVAL(req
->in
.hdr
, SMB2_HDR_LENGTH
, SMB2_HDR_BODY
);
59 SSVAL(req
->in
.hdr
, SMB2_HDR_EPOCH
, 0);
60 SIVAL(req
->in
.hdr
, SMB2_HDR_STATUS
, 0);
61 SSVAL(req
->in
.hdr
, SMB2_HDR_OPCODE
, SMB2_OP_BREAK
);
62 SSVAL(req
->in
.hdr
, SMB2_HDR_CREDIT
, 0);
63 SIVAL(req
->in
.hdr
, SMB2_HDR_FLAGS
, 0);
64 SIVAL(req
->in
.hdr
, SMB2_HDR_NEXT_COMMAND
, 0);
65 SBVAL(req
->in
.hdr
, SMB2_HDR_MESSAGE_ID
, 0);
66 SIVAL(req
->in
.hdr
, SMB2_HDR_PID
, 0);
67 SIVAL(req
->in
.hdr
, SMB2_HDR_TID
, 0);
68 SBVAL(req
->in
.hdr
, SMB2_HDR_SESSION_ID
, 0);
69 memset(req
->in
.hdr
+SMB2_HDR_SIGNATURE
, 0, 16);
71 SSVAL(req
->in
.body
, 0, 2);
73 status
= smb2srv_setup_reply(req
, 0x18, false, 0);
74 NT_STATUS_NOT_OK_RETURN(status
);
76 SSVAL(req
->out
.hdr
, SMB2_HDR_CREDIT
, 0x0000);
78 SSVAL(req
->out
.body
, 0x02, 0x0001);
79 SIVAL(req
->out
.body
, 0x04, 0x00000000);
80 smb2srv_push_handle(req
->out
.body
, 0x08, h
);
82 smb2srv_send_reply(req
);
87 struct ntvfs_handle
*smb2srv_pull_handle(struct smb2srv_request
*req
, const uint8_t *base
, unsigned int offset
)
89 struct smbsrv_tcon
*tcon
;
90 struct smbsrv_handle
*handle
;
96 * if there're chained requests used the cached handle
98 * TODO: check if this also correct when the given handle
101 if (req
->chained_file_handle
) {
102 base
= req
->chained_file_handle
;
106 hid
= IVAL(base
, offset
);
107 tid
= IVAL(base
, offset
+ 4);
108 uid
= BVAL(base
, offset
+ 8);
110 /* if it's the wildcard handle, don't waste time to search it... */
111 if (hid
== UINT32_MAX
&& tid
== UINT32_MAX
&& uid
== UINT64_MAX
) {
116 * if the (v)uid part doesn't match the given session the handle isn't
119 if (uid
!= req
->session
->vuid
) {
124 * the handle can belong to a different tcon
125 * as that TID in the SMB2 header says, but
126 * the request should succeed nevertheless!
128 * because of this we put the 32 bit TID into the
129 * 128 bit handle, so that we can extract the tcon from the
133 if (tid
!= req
->tcon
->tid
) {
134 tcon
= smbsrv_smb2_tcon_find(req
->session
, tid
, req
->request_time
);
140 handle
= smbsrv_smb2_handle_find(tcon
, hid
, req
->request_time
);
146 * as the smb2srv_tcon is a child object of the smb2srv_session
147 * the handle belongs to the correct session!
149 * Note: no check is needed here for SMB2
153 * as the handle may have overwritten the tcon
154 * we need to set it on the request so that the
155 * correct ntvfs context will be used for the ntvfs_*() request
157 * TODO: check if that's correct for chained requests as well!
160 return handle
->ntvfs
;
163 void smb2srv_push_handle(uint8_t *base
, unsigned int offset
, struct ntvfs_handle
*ntvfs
)
165 struct smbsrv_handle
*handle
= talloc_get_type(ntvfs
->frontend_data
.private_data
,
166 struct smbsrv_handle
);
169 * the handle is 128 bit on the wire
171 SIVAL(base
, offset
, handle
->hid
);
172 SIVAL(base
, offset
+ 4, handle
->tcon
->tid
);
173 SBVAL(base
, offset
+ 8, handle
->session
->vuid
);
176 static NTSTATUS
smb2srv_handle_create_new(void *private_data
, struct ntvfs_request
*ntvfs
, struct ntvfs_handle
**_h
)
178 struct smb2srv_request
*req
= talloc_get_type(ntvfs
->frontend_data
.private_data
,
179 struct smb2srv_request
);
180 struct smbsrv_handle
*handle
;
181 struct ntvfs_handle
*h
;
183 handle
= smbsrv_handle_new(req
->session
, req
->tcon
, req
, req
->request_time
);
184 if (!handle
) return NT_STATUS_INSUFFICIENT_RESOURCES
;
186 h
= talloc_zero(handle
, struct ntvfs_handle
);
190 * note: we don't set handle->ntvfs yet,
191 * this will be done by smbsrv_handle_make_valid()
192 * this makes sure the handle is invalid for clients
193 * until the ntvfs subsystem has made it valid
196 h
->session_info
= ntvfs
->session_info
;
197 h
->smbpid
= ntvfs
->smbpid
;
199 h
->frontend_data
.private_data
= handle
;
205 return NT_STATUS_NO_MEMORY
;
208 static NTSTATUS
smb2srv_handle_make_valid(void *private_data
, struct ntvfs_handle
*h
)
210 struct smbsrv_tcon
*tcon
= talloc_get_type(private_data
, struct smbsrv_tcon
);
211 struct smbsrv_handle
*handle
= talloc_get_type(h
->frontend_data
.private_data
,
212 struct smbsrv_handle
);
213 /* this tells the frontend that the handle is valid */
215 /* this moves the smbsrv_request to the smbsrv_tcon memory context */
216 talloc_steal(tcon
, handle
);
220 static void smb2srv_handle_destroy(void *private_data
, struct ntvfs_handle
*h
)
222 struct smbsrv_handle
*handle
= talloc_get_type(h
->frontend_data
.private_data
,
223 struct smbsrv_handle
);
227 static struct ntvfs_handle
*smb2srv_handle_search_by_wire_key(void *private_data
, struct ntvfs_request
*ntvfs
, const DATA_BLOB
*key
)
232 static DATA_BLOB
smb2srv_handle_get_wire_key(void *private_data
, struct ntvfs_handle
*handle
, TALLOC_CTX
*mem_ctx
)
234 return data_blob(NULL
, 0);
237 static NTSTATUS
smb2srv_tcon_backend(struct smb2srv_request
*req
, union smb_tcon
*io
)
239 struct smbsrv_tcon
*tcon
;
241 enum ntvfs_type type
;
242 const char *service
= io
->smb2
.in
.path
;
243 struct share_config
*scfg
;
244 const char *sharetype
;
245 uint64_t ntvfs_caps
= 0;
247 if (strncmp(service
, "\\\\", 2) == 0) {
248 const char *p
= strchr(service
+2, '\\');
254 status
= share_get_config(req
, req
->smb_conn
->share_context
, service
, &scfg
);
255 if (!NT_STATUS_IS_OK(status
)) {
256 DEBUG(0,("smb2srv_tcon_backend: couldn't find service %s\n", service
));
257 return NT_STATUS_BAD_NETWORK_NAME
;
260 if (!socket_check_access(req
->smb_conn
->connection
->socket
,
262 share_string_list_option(req
, scfg
, SHARE_HOSTS_ALLOW
),
263 share_string_list_option(req
, scfg
, SHARE_HOSTS_DENY
))) {
264 return NT_STATUS_ACCESS_DENIED
;
267 /* work out what sort of connection this is */
268 sharetype
= share_string_option(scfg
, SHARE_TYPE
, "DISK");
269 if (sharetype
&& strcmp(sharetype
, "IPC") == 0) {
271 } else if (sharetype
&& strcmp(sharetype
, "PRINTER") == 0) {
277 tcon
= smbsrv_smb2_tcon_new(req
->session
, scfg
->name
);
279 DEBUG(0,("smb2srv_tcon_backend: Couldn't find free connection.\n"));
280 return NT_STATUS_INSUFFICIENT_RESOURCES
;
284 ntvfs_caps
= NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS
;
286 /* init ntvfs function pointers */
287 status
= ntvfs_init_connection(tcon
, scfg
, type
,
288 req
->smb_conn
->negotiate
.protocol
,
290 req
->smb_conn
->connection
->event
.ctx
,
291 req
->smb_conn
->connection
->msg_ctx
,
292 req
->smb_conn
->lp_ctx
,
293 req
->smb_conn
->connection
->server_id
,
295 if (!NT_STATUS_IS_OK(status
)) {
296 DEBUG(0, ("smb2srv_tcon_backend: ntvfs_init_connection failed for service %s\n",
301 status
= ntvfs_set_oplock_handler(tcon
->ntvfs
, smb2srv_send_oplock_break
, tcon
);
302 if (!NT_STATUS_IS_OK(status
)) {
303 DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the oplock handler!\n"));
307 status
= ntvfs_set_addresses(tcon
->ntvfs
,
308 req
->smb_conn
->connection
->local_address
,
309 req
->smb_conn
->connection
->remote_address
);
310 if (!NT_STATUS_IS_OK(status
)) {
311 DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the address!\n"));
315 status
= ntvfs_set_handle_callbacks(tcon
->ntvfs
,
316 smb2srv_handle_create_new
,
317 smb2srv_handle_make_valid
,
318 smb2srv_handle_destroy
,
319 smb2srv_handle_search_by_wire_key
,
320 smb2srv_handle_get_wire_key
,
322 if (!NT_STATUS_IS_OK(status
)) {
323 DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the handle callbacks!\n"));
327 req
->ntvfs
= ntvfs_request_create(req
->tcon
->ntvfs
, req
,
328 req
->session
->session_info
,
329 SVAL(req
->in
.hdr
, SMB2_HDR_PID
),
333 status
= NT_STATUS_NO_MEMORY
;
337 io
->smb2
.out
.share_type
= (unsigned)type
; /* 1 - DISK, 2 - Print, 3 - IPC */
338 io
->smb2
.out
.reserved
= 0;
339 io
->smb2
.out
.flags
= 0x00000000;
340 io
->smb2
.out
.capabilities
= 0;
341 io
->smb2
.out
.access_mask
= SEC_RIGHTS_FILE_ALL
;
343 io
->smb2
.out
.tid
= tcon
->tid
;
345 /* Invoke NTVFS connection hook */
346 status
= ntvfs_connect(req
->ntvfs
, io
);
347 if (!NT_STATUS_IS_OK(status
)) {
348 DEBUG(0,("smb2srv_tcon_backend: NTVFS ntvfs_connect() failed: %s!\n", nt_errstr(status
)));
360 static void smb2srv_tcon_send(struct smb2srv_request
*req
, union smb_tcon
*io
)
362 if (!NT_STATUS_IS_OK(req
->status
)) {
363 smb2srv_send_error(req
, req
->status
);
367 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x10, false, 0));
369 SIVAL(req
->out
.hdr
, SMB2_HDR_TID
, io
->smb2
.out
.tid
);
371 SCVAL(req
->out
.body
, 0x02, io
->smb2
.out
.share_type
);
372 SCVAL(req
->out
.body
, 0x03, io
->smb2
.out
.reserved
);
373 SIVAL(req
->out
.body
, 0x04, io
->smb2
.out
.flags
);
374 SIVAL(req
->out
.body
, 0x08, io
->smb2
.out
.capabilities
);
375 SIVAL(req
->out
.body
, 0x0C, io
->smb2
.out
.access_mask
);
377 smb2srv_send_reply(req
);
380 void smb2srv_tcon_recv(struct smb2srv_request
*req
)
384 SMB2SRV_CHECK_BODY_SIZE(req
, 0x08, true);
385 SMB2SRV_TALLOC_IO_PTR(io
, union smb_tcon
);
387 io
->smb2
.level
= RAW_TCON_SMB2
;
388 io
->smb2
.in
.reserved
= SVAL(req
->in
.body
, 0x02);
389 SMB2SRV_CHECK(smb2_pull_o16s16_string(&req
->in
, io
, req
->in
.body
+0x04, &io
->smb2
.in
.path
));
391 /* the VFS backend does not yet handle NULL paths */
392 if (io
->smb2
.in
.path
== NULL
) {
393 io
->smb2
.in
.path
= "";
396 req
->status
= smb2srv_tcon_backend(req
, io
);
398 if (req
->control_flags
& SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY
) {
402 smb2srv_tcon_send(req
, io
);
405 static NTSTATUS
smb2srv_tdis_backend(struct smb2srv_request
*req
)
407 /* TODO: call ntvfs backends to close file of this tcon */
408 talloc_free(req
->tcon
);
413 static void smb2srv_tdis_send(struct smb2srv_request
*req
)
417 if (NT_STATUS_IS_ERR(req
->status
)) {
418 smb2srv_send_error(req
, req
->status
);
422 status
= smb2srv_setup_reply(req
, 0x04, false, 0);
423 if (!NT_STATUS_IS_OK(status
)) {
424 smbsrv_terminate_connection(req
->smb_conn
, nt_errstr(status
));
429 SSVAL(req
->out
.body
, 0x02, 0);
431 smb2srv_send_reply(req
);
434 void smb2srv_tdis_recv(struct smb2srv_request
*req
)
438 SMB2SRV_CHECK_BODY_SIZE(req
, 0x04, false);
440 _pad
= SVAL(req
->in
.body
, 0x02);
442 req
->status
= smb2srv_tdis_backend(req
);
444 if (req
->control_flags
& SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY
) {
448 smb2srv_tdis_send(req
);