2 Unix SMB/CIFS implementation.
3 service (connection) handling
4 Copyright (C) Andrew Tridgell 1992-2003
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 "smb_server/smb_server.h"
22 #include "smbd/service_stream.h"
23 #include "ntvfs/ntvfs.h"
24 #include "param/share.h"
25 #include "param/param.h"
27 /****************************************************************************
28 Make a connection, given the snum to connect to, and the vuser of the
29 connecting user if appropriate.
30 Does note invoke the NTVFS connection hook
31 ****************************************************************************/
32 static NTSTATUS
make_connection_scfg(struct smbsrv_request
*req
,
33 struct share_config
*scfg
,
38 struct smbsrv_tcon
*tcon
;
40 uint64_t ntvfs_caps
= 0;
42 tcon
= smbsrv_smb_tcon_new(req
->smb_conn
, scfg
->name
);
44 DEBUG(0,("Couldn't find free connection.\n"));
45 return NT_STATUS_INSUFFICIENT_RESOURCES
;
49 if (req
->smb_conn
->negotiate
.client_caps
& CAP_LEVEL_II_OPLOCKS
) {
50 ntvfs_caps
|= NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS
;
53 /* init ntvfs function pointers */
54 status
= ntvfs_init_connection(tcon
, scfg
, type
,
55 req
->smb_conn
->negotiate
.protocol
,
57 req
->smb_conn
->connection
->event
.ctx
,
58 req
->smb_conn
->connection
->msg_ctx
,
59 req
->smb_conn
->lp_ctx
,
60 req
->smb_conn
->connection
->server_id
,
62 if (!NT_STATUS_IS_OK(status
)) {
63 DEBUG(0, ("make_connection_scfg: connection failed for service %s\n",
68 status
= ntvfs_set_oplock_handler(tcon
->ntvfs
, smbsrv_send_oplock_break
, tcon
);
69 if (!NT_STATUS_IS_OK(status
)) {
70 DEBUG(0,("make_connection: NTVFS failed to set the oplock handler!\n"));
74 status
= ntvfs_set_addr_callbacks(tcon
->ntvfs
, smbsrv_get_my_addr
, smbsrv_get_peer_addr
, req
->smb_conn
);
75 if (!NT_STATUS_IS_OK(status
)) {
76 DEBUG(0,("make_connection: NTVFS failed to set the addr callbacks!\n"));
80 status
= ntvfs_set_handle_callbacks(tcon
->ntvfs
,
81 smbsrv_handle_create_new
,
82 smbsrv_handle_make_valid
,
83 smbsrv_handle_destroy
,
84 smbsrv_handle_search_by_wire_key
,
85 smbsrv_handle_get_wire_key
,
87 if (!NT_STATUS_IS_OK(status
)) {
88 DEBUG(0,("make_connection: NTVFS failed to set the handle callbacks!\n"));
100 /****************************************************************************
101 Make a connection to a service.
104 ****************************************************************************/
105 static NTSTATUS
make_connection(struct smbsrv_request
*req
,
106 const char *service
, DATA_BLOB password
,
110 enum ntvfs_type type
;
111 const char *type_str
;
112 struct share_config
*scfg
;
113 const char *sharetype
;
115 /* the service might be of the form \\SERVER\SHARE. Should we put
116 the server name we get from this somewhere? */
117 if (strncmp(service
, "\\\\", 2) == 0) {
118 char *p
= strchr(service
+2, '\\');
124 status
= share_get_config(req
, req
->smb_conn
->share_context
, service
, &scfg
);
125 if (!NT_STATUS_IS_OK(status
)) {
126 DEBUG(0,("make_connection: couldn't find service %s\n", service
));
127 return NT_STATUS_BAD_NETWORK_NAME
;
130 /* TODO: check the password, when it's share level security! */
132 if (!socket_check_access(req
->smb_conn
->connection
->socket
,
134 share_string_list_option(req
, scfg
, SHARE_HOSTS_ALLOW
),
135 share_string_list_option(req
, scfg
, SHARE_HOSTS_DENY
))) {
136 return NT_STATUS_ACCESS_DENIED
;
139 /* work out what sort of connection this is */
140 sharetype
= share_string_option(scfg
, "type", "DISK");
141 if (sharetype
&& strcmp(sharetype
, "IPC") == 0) {
144 } else if (sharetype
&& strcmp(sharetype
, "PRINTER") == 0) {
152 if (strcmp(dev
, "?????") != 0 && strcasecmp(type_str
, dev
) != 0) {
153 /* the client gave us the wrong device type */
154 return NT_STATUS_BAD_DEVICE_TYPE
;
157 return make_connection_scfg(req
, scfg
, type
, password
, dev
);
161 backend for tree connect call, in preparation for calling ntvfs_connect()
163 NTSTATUS
smbsrv_tcon_backend(struct smbsrv_request
*req
, union smb_tcon
*con
)
167 if (con
->generic
.level
== RAW_TCON_TCON
) {
169 password
= data_blob_string_const(con
->tcon
.in
.password
);
171 status
= make_connection(req
, con
->tcon
.in
.service
, password
, con
->tcon
.in
.dev
);
173 if (!NT_STATUS_IS_OK(status
)) {
177 con
->tcon
.out
.max_xmit
= req
->smb_conn
->negotiate
.max_recv
;
178 con
->tcon
.out
.tid
= req
->tcon
->tid
;
183 /* TODO: take a look at tconx.in.flags! */
185 status
= make_connection(req
, con
->tconx
.in
.path
, con
->tconx
.in
.password
,
186 con
->tconx
.in
.device
);
187 if (!NT_STATUS_IS_OK(status
)) {
191 con
->tconx
.out
.tid
= req
->tcon
->tid
;
192 con
->tconx
.out
.options
= SMB_SUPPORT_SEARCH_BITS
| (share_int_option(req
->tcon
->ntvfs
->config
, SHARE_CSC_POLICY
, SHARE_CSC_POLICY_DEFAULT
) << 2);
193 if (share_bool_option(req
->tcon
->ntvfs
->config
, SHARE_MSDFS_ROOT
, SHARE_MSDFS_ROOT_DEFAULT
) && lp_host_msdfs(req
->smb_conn
->lp_ctx
)) {
194 con
->tconx
.out
.options
|= SMB_SHARE_IN_DFS
;