• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/samba-3.5.8/source4/smb_server/smb/
1/*
2   Unix SMB/CIFS implementation.
3   service (connection) handling
4   Copyright (C) Andrew Tridgell 1992-2003
5
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.
10
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.
15
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/>.
18*/
19
20#include "includes.h"
21#include "smb_server/smb_server.h"
22#include "smbd/service_stream.h"
23#include "ntvfs/ntvfs.h"
24#include "param/param.h"
25
26/****************************************************************************
27  Make a connection, given the snum to connect to, and the vuser of the
28  connecting user if appropriate.
29  Does note invoke the NTVFS connection hook
30****************************************************************************/
31static NTSTATUS make_connection_scfg(struct smbsrv_request *req,
32				     struct share_config *scfg,
33				     enum ntvfs_type type,
34				     DATA_BLOB password,
35				     const char *dev)
36{
37	struct smbsrv_tcon *tcon;
38	NTSTATUS status;
39	uint64_t ntvfs_caps = 0;
40
41	tcon = smbsrv_smb_tcon_new(req->smb_conn, scfg->name);
42	if (!tcon) {
43		DEBUG(0,("Couldn't find free connection.\n"));
44		return NT_STATUS_INSUFFICIENT_RESOURCES;
45	}
46	req->tcon = tcon;
47
48	if (req->smb_conn->negotiate.client_caps & CAP_LEVEL_II_OPLOCKS) {
49		ntvfs_caps |= NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS;
50	}
51
52	/* init ntvfs function pointers */
53	status = ntvfs_init_connection(tcon, scfg, type,
54				       req->smb_conn->negotiate.protocol,
55				       ntvfs_caps,
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,
60				       &tcon->ntvfs);
61	if (!NT_STATUS_IS_OK(status)) {
62		DEBUG(0, ("make_connection_scfg: connection failed for service %s\n",
63			  scfg->name));
64		goto failed;
65	}
66
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"));
70		goto failed;
71	}
72
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"));
76		goto failed;
77	}
78
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,
85					    tcon);
86	if (!NT_STATUS_IS_OK(status)) {
87		DEBUG(0,("make_connection: NTVFS failed to set the handle callbacks!\n"));
88		goto failed;
89	}
90
91	return NT_STATUS_OK;
92
93failed:
94	req->tcon = NULL;
95	talloc_free(tcon);
96	return status;
97}
98
99/****************************************************************************
100 Make a connection to a service.
101 *
102 * @param service
103****************************************************************************/
104static NTSTATUS make_connection(struct smbsrv_request *req,
105				const char *service, DATA_BLOB password,
106				const char *dev)
107{
108	NTSTATUS status;
109	enum ntvfs_type type;
110	const char *type_str;
111	struct share_config *scfg;
112	const char *sharetype;
113
114	/* the service might be of the form \\SERVER\SHARE. Should we put
115	   the server name we get from this somewhere? */
116	if (strncmp(service, "\\\\", 2) == 0) {
117		char *p = strchr(service+2, '\\');
118		if (p) {
119			service = p + 1;
120		}
121	}
122
123	status = share_get_config(req, req->smb_conn->share_context, service, &scfg);
124	if (!NT_STATUS_IS_OK(status)) {
125		DEBUG(0,("make_connection: couldn't find service %s\n", service));
126		return NT_STATUS_BAD_NETWORK_NAME;
127	}
128
129	/* TODO: check the password, when it's share level security! */
130
131	if (!socket_check_access(req->smb_conn->connection->socket,
132				 scfg->name,
133				 share_string_list_option(req, scfg, SHARE_HOSTS_ALLOW),
134				 share_string_list_option(req, scfg, SHARE_HOSTS_DENY))) {
135		return NT_STATUS_ACCESS_DENIED;
136	}
137
138	/* work out what sort of connection this is */
139	sharetype = share_string_option(scfg, "type", "DISK");
140	if (sharetype && strcmp(sharetype, "IPC") == 0) {
141		type = NTVFS_IPC;
142		type_str = "IPC";
143	} else if (sharetype && strcmp(sharetype, "PRINTER") == 0) {
144		type = NTVFS_PRINT;
145		type_str = "LPT:";
146	} else {
147		type = NTVFS_DISK;
148		type_str = "A:";
149	}
150
151	if (strcmp(dev, "?????") != 0 && strcasecmp(type_str, dev) != 0) {
152		/* the client gave us the wrong device type */
153		return NT_STATUS_BAD_DEVICE_TYPE;
154	}
155
156	return make_connection_scfg(req, scfg, type, password, dev);
157}
158
159/*
160  backend for tree connect call, in preparation for calling ntvfs_connect()
161*/
162NTSTATUS smbsrv_tcon_backend(struct smbsrv_request *req, union smb_tcon *con)
163{
164	NTSTATUS status;
165
166	if (con->generic.level == RAW_TCON_TCON) {
167		DATA_BLOB password;
168		password = data_blob_string_const(con->tcon.in.password);
169
170		status = make_connection(req, con->tcon.in.service, password, con->tcon.in.dev);
171
172		if (!NT_STATUS_IS_OK(status)) {
173			return status;
174		}
175
176		con->tcon.out.max_xmit = req->smb_conn->negotiate.max_recv;
177		con->tcon.out.tid = req->tcon->tid;
178
179		return status;
180	}
181
182	/* TODO: take a look at tconx.in.flags! */
183
184	status = make_connection(req, con->tconx.in.path, con->tconx.in.password,
185				 con->tconx.in.device);
186	if (!NT_STATUS_IS_OK(status)) {
187		return status;
188	}
189
190	con->tconx.out.tid = req->tcon->tid;
191	con->tconx.out.options = SMB_SUPPORT_SEARCH_BITS | (share_int_option(req->tcon->ntvfs->config, SHARE_CSC_POLICY, SHARE_CSC_POLICY_DEFAULT) << 2);
192	if (share_bool_option(req->tcon->ntvfs->config, SHARE_MSDFS_ROOT, SHARE_MSDFS_ROOT_DEFAULT) && lp_host_msdfs(req->smb_conn->lp_ctx)) {
193		con->tconx.out.options |= SMB_SHARE_IN_DFS;
194	}
195
196	return status;
197}
198