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 ****************************************************************************/
31 static NTSTATUS
make_connection_scfg(struct smbsrv_request
*req
,
32 struct share_config
*scfg
,
37 struct smbsrv_tcon
*tcon
;
39 uint64_t ntvfs_caps
= 0;
41 tcon
= smbsrv_smb_tcon_new(req
->smb_conn
, scfg
->name
);
43 DEBUG(0,("Couldn't find free connection.\n"));
44 return NT_STATUS_INSUFFICIENT_RESOURCES
;
48 if (req
->smb_conn
->negotiate
.client_caps
& CAP_LEVEL_II_OPLOCKS
) {
49 ntvfs_caps
|= NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS
;
52 /* init ntvfs function pointers */
53 status
= ntvfs_init_connection(tcon
, scfg
, type
,
54 req
->smb_conn
->negotiate
.protocol
,
56 req
->smb_conn
->connection
->event
.ctx
,
57 req
->smb_conn
->connection
->msg_ctx
,
58 req
->smb_conn
->lp_ctx
,
59 req
->smb_conn
->connection
->server_id
,
61 if (!NT_STATUS_IS_OK(status
)) {
62 DEBUG(0, ("make_connection_scfg: connection failed for service %s\n",
67 status
= ntvfs_set_oplock_handler(tcon
->ntvfs
, smbsrv_send_oplock_break
, tcon
);
68 if (!NT_STATUS_IS_OK(status
)) {
69 DEBUG(0,("make_connection: NTVFS failed to set the oplock handler!\n"));
73 status
= ntvfs_set_addr_callbacks(tcon
->ntvfs
, smbsrv_get_my_addr
, smbsrv_get_peer_addr
, req
->smb_conn
);
74 if (!NT_STATUS_IS_OK(status
)) {
75 DEBUG(0,("make_connection: NTVFS failed to set the addr callbacks!\n"));
79 status
= ntvfs_set_handle_callbacks(tcon
->ntvfs
,
80 smbsrv_handle_create_new
,
81 smbsrv_handle_make_valid
,
82 smbsrv_handle_destroy
,
83 smbsrv_handle_search_by_wire_key
,
84 smbsrv_handle_get_wire_key
,
86 if (!NT_STATUS_IS_OK(status
)) {
87 DEBUG(0,("make_connection: NTVFS failed to set the handle callbacks!\n"));
91 req
->ntvfs
= ntvfs_request_create(req
->tcon
->ntvfs
, req
,
92 req
->session
->session_info
,
93 SVAL(req
->in
.hdr
,HDR_PID
),
97 status
= NT_STATUS_NO_MEMORY
;
101 /* Invoke NTVFS connection hook */
102 status
= ntvfs_connect(req
->ntvfs
, scfg
->name
);
103 if (!NT_STATUS_IS_OK(status
)) {
104 DEBUG(0,("make_connection: NTVFS make connection failed!\n"));
116 /****************************************************************************
117 Make a connection to a service.
120 ****************************************************************************/
121 static NTSTATUS
make_connection(struct smbsrv_request
*req
,
122 const char *service
, DATA_BLOB password
,
126 enum ntvfs_type type
;
127 const char *type_str
;
128 struct share_config
*scfg
;
129 const char *sharetype
;
131 /* the service might be of the form \\SERVER\SHARE. Should we put
132 the server name we get from this somewhere? */
133 if (strncmp(service
, "\\\\", 2) == 0) {
134 char *p
= strchr(service
+2, '\\');
140 status
= share_get_config(req
, req
->smb_conn
->share_context
, service
, &scfg
);
141 if (!NT_STATUS_IS_OK(status
)) {
142 DEBUG(0,("make_connection: couldn't find service %s\n", service
));
143 return NT_STATUS_BAD_NETWORK_NAME
;
146 /* TODO: check the password, when it's share level security! */
148 if (!socket_check_access(req
->smb_conn
->connection
->socket
,
150 share_string_list_option(req
, scfg
, SHARE_HOSTS_ALLOW
),
151 share_string_list_option(req
, scfg
, SHARE_HOSTS_DENY
))) {
152 return NT_STATUS_ACCESS_DENIED
;
155 /* work out what sort of connection this is */
156 sharetype
= share_string_option(scfg
, "type", "DISK");
157 if (sharetype
&& strcmp(sharetype
, "IPC") == 0) {
160 } else if (sharetype
&& strcmp(sharetype
, "PRINTER") == 0) {
168 if (strcmp(dev
, "?????") != 0 && strcasecmp(type_str
, dev
) != 0) {
169 /* the client gave us the wrong device type */
170 return NT_STATUS_BAD_DEVICE_TYPE
;
173 return make_connection_scfg(req
, scfg
, type
, password
, dev
);
177 backend for tree connect call
179 NTSTATUS
smbsrv_tcon_backend(struct smbsrv_request
*req
, union smb_tcon
*con
)
183 if (con
->generic
.level
== RAW_TCON_TCON
) {
185 password
= data_blob_string_const(con
->tcon
.in
.password
);
187 status
= make_connection(req
, con
->tcon
.in
.service
, password
, con
->tcon
.in
.dev
);
189 if (!NT_STATUS_IS_OK(status
)) {
193 con
->tcon
.out
.max_xmit
= req
->smb_conn
->negotiate
.max_recv
;
194 con
->tcon
.out
.tid
= req
->tcon
->tid
;
199 /* TODO: take a look at tconx.in.flags! */
201 status
= make_connection(req
, con
->tconx
.in
.path
, con
->tconx
.in
.password
,
202 con
->tconx
.in
.device
);
203 if (!NT_STATUS_IS_OK(status
)) {
207 con
->tconx
.out
.tid
= req
->tcon
->tid
;
208 con
->tconx
.out
.dev_type
= talloc_strdup(req
, req
->tcon
->ntvfs
->dev_type
);
209 con
->tconx
.out
.fs_type
= talloc_strdup(req
, req
->tcon
->ntvfs
->fs_type
);
210 con
->tconx
.out
.options
= SMB_SUPPORT_SEARCH_BITS
| (share_int_option(req
->tcon
->ntvfs
->config
, SHARE_CSC_POLICY
, SHARE_CSC_POLICY_DEFAULT
) << 2);
211 if (share_bool_option(req
->tcon
->ntvfs
->config
, SHARE_MSDFS_ROOT
, SHARE_MSDFS_ROOT_DEFAULT
) && lp_host_msdfs(req
->smb_conn
->lp_ctx
)) {
212 con
->tconx
.out
.options
|= SMB_SHARE_IN_DFS
;