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 "librpc/gen_ndr/security.h"
28 #include "smbd/service_stream.h"
29 #include "ntvfs/ntvfs.h"
32 send an oplock break request to a client
34 static NTSTATUS
smb2srv_send_oplock_break(void *p
, struct ntvfs_handle
*ntvfs
, uint8_t level
)
36 DEBUG(0,("TODO: we don't pass SMB2 oplock breaks to the Clients yet!\n"));
40 struct ntvfs_handle
*smb2srv_pull_handle(struct smb2srv_request
*req
, const uint8_t *base
, uint_t offset
)
42 struct smbsrv_tcon
*tcon
;
43 struct smbsrv_handle
*handle
;
49 * if there're chained requests used the cached handle
51 * TODO: check if this also correct when the given handle
54 if (req
->chained_file_handle
) {
55 base
= req
->chained_file_handle
;
59 hid
= BVAL(base
, offset
);
60 tid
= IVAL(base
, offset
+ 8);
61 pad
= IVAL(base
, offset
+ 12);
63 if (pad
!= UINT32_MAX
) {
67 /* if it's the wildcard handle, don't waste time to search it... */
68 if (hid
== UINT64_MAX
&& tid
== UINT32_MAX
) {
73 * the handle can belong to a different tcon
74 * as that TID in the SMB2 header says, but
75 * the request should succeed nevertheless!
77 * because if this we put the 32 bit TID into the
78 * 128 bit handle, so that we can extract the tcon from the
82 if (tid
!= req
->tcon
->tid
) {
83 tcon
= smbsrv_smb2_tcon_find(req
->session
, tid
, req
->request_time
);
89 handle
= smbsrv_smb2_handle_find(tcon
, hid
, req
->request_time
);
95 * as the smb2srv_tcon is a child object of the smb2srv_session
96 * the handle belongs to the correct session!
98 * Note: no check is needed here for SMB2
102 * as the handle may have overwritten the tcon
103 * we need to set it on the request so that the
104 * correct ntvfs context will be used for the ntvfs_*() request
107 return handle
->ntvfs
;
110 void smb2srv_push_handle(uint8_t *base
, uint_t offset
, struct ntvfs_handle
*ntvfs
)
112 struct smbsrv_handle
*handle
= talloc_get_type(ntvfs
->frontend_data
.private_data
,
113 struct smbsrv_handle
);
116 * the handle is 128 bit on the wire
118 SBVAL(base
, offset
, handle
->hid
);
119 SIVAL(base
, offset
+ 8, handle
->tcon
->tid
);
120 SIVAL(base
, offset
+ 12,UINT32_MAX
);
123 static NTSTATUS
smb2srv_handle_create_new(void *private_data
, struct ntvfs_request
*ntvfs
, struct ntvfs_handle
**_h
)
125 struct smb2srv_request
*req
= talloc_get_type(ntvfs
->frontend_data
.private_data
,
126 struct smb2srv_request
);
127 struct smbsrv_handle
*handle
;
128 struct ntvfs_handle
*h
;
130 handle
= smbsrv_handle_new(req
->session
, req
->tcon
, req
, req
->request_time
);
131 if (!handle
) return NT_STATUS_INSUFFICIENT_RESOURCES
;
133 h
= talloc_zero(handle
, struct ntvfs_handle
);
137 * note: we don't set handle->ntvfs yet,
138 * this will be done by smbsrv_handle_make_valid()
139 * this makes sure the handle is invalid for clients
140 * until the ntvfs subsystem has made it valid
143 h
->session_info
= ntvfs
->session_info
;
144 h
->smbpid
= ntvfs
->smbpid
;
146 h
->frontend_data
.private_data
= handle
;
152 return NT_STATUS_NO_MEMORY
;
155 static NTSTATUS
smb2srv_handle_make_valid(void *private_data
, struct ntvfs_handle
*h
)
157 struct smbsrv_tcon
*tcon
= talloc_get_type(private_data
, struct smbsrv_tcon
);
158 struct smbsrv_handle
*handle
= talloc_get_type(h
->frontend_data
.private_data
,
159 struct smbsrv_handle
);
160 /* this tells the frontend that the handle is valid */
162 /* this moves the smbsrv_request to the smbsrv_tcon memory context */
163 talloc_steal(tcon
, handle
);
167 static void smb2srv_handle_destroy(void *private_data
, struct ntvfs_handle
*h
)
169 struct smbsrv_handle
*handle
= talloc_get_type(h
->frontend_data
.private_data
,
170 struct smbsrv_handle
);
174 static struct ntvfs_handle
*smb2srv_handle_search_by_wire_key(void *private_data
, struct ntvfs_request
*ntvfs
, const DATA_BLOB
*key
)
179 static DATA_BLOB
smb2srv_handle_get_wire_key(void *private_data
, struct ntvfs_handle
*handle
, TALLOC_CTX
*mem_ctx
)
181 return data_blob(NULL
, 0);
184 static NTSTATUS
smb2srv_tcon_backend(struct smb2srv_request
*req
, union smb_tcon
*io
)
186 struct smbsrv_tcon
*tcon
;
188 enum ntvfs_type type
;
191 const char *service
= io
->smb2
.in
.path
;
192 struct share_config
*scfg
;
193 const char *sharetype
;
195 if (strncmp(service
, "\\\\", 2) == 0) {
196 const char *p
= strchr(service
+2, '\\');
202 status
= share_get_config(req
, req
->smb_conn
->share_context
, service
, &scfg
);
203 if (!NT_STATUS_IS_OK(status
)) {
204 DEBUG(0,("smb2srv_tcon_backend: couldn't find service %s\n", service
));
205 return NT_STATUS_BAD_NETWORK_NAME
;
208 if (!socket_check_access(req
->smb_conn
->connection
->socket
,
210 share_string_list_option(req
, scfg
, SHARE_HOSTS_ALLOW
),
211 share_string_list_option(req
, scfg
, SHARE_HOSTS_DENY
))) {
212 return NT_STATUS_ACCESS_DENIED
;
215 /* work out what sort of connection this is */
216 sharetype
= share_string_option(scfg
, SHARE_TYPE
, "DISK");
217 if (sharetype
&& strcmp(sharetype
, "IPC") == 0) {
220 unknown2
= 0x00000030;
221 } else if (sharetype
&& strcmp(sharetype
, "PRINTER") == 0) {
224 unknown2
= 0x00000000;
228 unknown2
= 0x00000800;
231 tcon
= smbsrv_smb2_tcon_new(req
->session
, scfg
->name
);
233 DEBUG(0,("smb2srv_tcon_backend: Couldn't find free connection.\n"));
234 return NT_STATUS_INSUFFICIENT_RESOURCES
;
238 /* init ntvfs function pointers */
239 status
= ntvfs_init_connection(tcon
, scfg
, type
,
240 req
->smb_conn
->negotiate
.protocol
,
241 req
->smb_conn
->connection
->event
.ctx
,
242 req
->smb_conn
->connection
->msg_ctx
,
243 req
->smb_conn
->connection
->server_id
,
245 if (!NT_STATUS_IS_OK(status
)) {
246 DEBUG(0, ("smb2srv_tcon_backend: ntvfs_init_connection failed for service %s\n",
251 status
= ntvfs_set_oplock_handler(tcon
->ntvfs
, smb2srv_send_oplock_break
, tcon
);
252 if (!NT_STATUS_IS_OK(status
)) {
253 DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the oplock handler!\n"));
257 status
= ntvfs_set_addr_callbacks(tcon
->ntvfs
, smbsrv_get_my_addr
, smbsrv_get_peer_addr
, req
->smb_conn
);
258 if (!NT_STATUS_IS_OK(status
)) {
259 DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the addr callbacks!\n"));
263 status
= ntvfs_set_handle_callbacks(tcon
->ntvfs
,
264 smb2srv_handle_create_new
,
265 smb2srv_handle_make_valid
,
266 smb2srv_handle_destroy
,
267 smb2srv_handle_search_by_wire_key
,
268 smb2srv_handle_get_wire_key
,
270 if (!NT_STATUS_IS_OK(status
)) {
271 DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the handle callbacks!\n"));
275 req
->ntvfs
= ntvfs_request_create(req
->tcon
->ntvfs
, req
,
276 req
->session
->session_info
,
277 0, /* TODO: fill in PID */
281 status
= NT_STATUS_NO_MEMORY
;
285 /* Invoke NTVFS connection hook */
286 status
= ntvfs_connect(req
->ntvfs
, scfg
->name
);
287 if (!NT_STATUS_IS_OK(status
)) {
288 DEBUG(0,("smb2srv_tcon_backend: NTVFS ntvfs_connect() failed!\n"));
292 io
->smb2
.out
.unknown1
= type_smb2
; /* 1 - DISK, 2 - Print, 3 - IPC */
293 io
->smb2
.out
.unknown2
= unknown2
;
294 io
->smb2
.out
.unknown3
= 0x00000000;
295 io
->smb2
.out
.access_mask
= SEC_RIGHTS_FILE_ALL
;
297 io
->smb2
.out
.tid
= tcon
->tid
;
307 static void smb2srv_tcon_send(struct smb2srv_request
*req
, union smb_tcon
*io
)
311 if (!NT_STATUS_IS_OK(req
->status
)) {
312 smb2srv_send_error(req
, req
->status
);
315 if (io
->smb2
.out
.unknown1
== 0x0002) {
316 /* if it's an IPC share vista returns 0x0005 */
322 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x10, False
, 0));
324 SIVAL(req
->out
.hdr
, SMB2_HDR_TID
, io
->smb2
.out
.tid
);
325 SSVAL(req
->out
.hdr
, SMB2_HDR_UNKNOWN1
,unknown1
);
327 SSVAL(req
->out
.body
, 0x02, io
->smb2
.out
.unknown1
);
328 SIVAL(req
->out
.body
, 0x04, io
->smb2
.out
.unknown2
);
329 SIVAL(req
->out
.body
, 0x08, io
->smb2
.out
.unknown3
);
330 SIVAL(req
->out
.body
, 0x0C, io
->smb2
.out
.access_mask
);
332 smb2srv_send_reply(req
);
335 void smb2srv_tcon_recv(struct smb2srv_request
*req
)
339 SMB2SRV_CHECK_BODY_SIZE(req
, 0x08, True
);
340 SMB2SRV_TALLOC_IO_PTR(io
, union smb_tcon
);
342 io
->smb2
.level
= RAW_TCON_SMB2
;
343 io
->smb2
.in
.unknown1
= SVAL(req
->in
.body
, 0x02);
344 SMB2SRV_CHECK(smb2_pull_o16s16_string(&req
->in
, io
, req
->in
.body
+0x04, &io
->smb2
.in
.path
));
346 req
->status
= smb2srv_tcon_backend(req
, io
);
348 if (req
->control_flags
& SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY
) {
352 smb2srv_tcon_send(req
, io
);
355 static NTSTATUS
smb2srv_tdis_backend(struct smb2srv_request
*req
)
357 /* TODO: call ntvfs backends to close file of this tcon */
358 talloc_free(req
->tcon
);
363 static void smb2srv_tdis_send(struct smb2srv_request
*req
)
367 if (NT_STATUS_IS_ERR(req
->status
)) {
368 smb2srv_send_error(req
, req
->status
);
372 status
= smb2srv_setup_reply(req
, 0x04, False
, 0);
373 if (!NT_STATUS_IS_OK(status
)) {
374 smbsrv_terminate_connection(req
->smb_conn
, nt_errstr(status
));
379 SSVAL(req
->out
.body
, 0x02, 0);
381 smb2srv_send_reply(req
);
384 void smb2srv_tdis_recv(struct smb2srv_request
*req
)
388 SMB2SRV_CHECK_BODY_SIZE(req
, 0x04, False
);
390 _pad
= SVAL(req
->in
.body
, 0x02);
392 req
->status
= smb2srv_tdis_backend(req
);
394 if (req
->control_flags
& SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY
) {
398 smb2srv_tdis_send(req
);