r16910: - don't search the wildcard handle
[Samba/aatanasov.git] / source / smb_server / smb2 / tcon.c
blob38bf4d7ef079aef78c7df734729f48ce5a2d1ad2
1 /*
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.
21 #include "includes.h"
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"));
37 return NT_STATUS_OK;
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;
44 uint64_t hid;
45 uint32_t tid;
46 uint32_t pad;
48 hid = BVAL(base, offset);
49 tid = IVAL(base, offset + 8);
50 pad = IVAL(base, offset + 12);
52 if (pad != 0xFFFFFFFF) {
53 return NULL;
56 /* if it's the wildcard handle, don't waste time to search it... */
57 if (hid == UINT64_MAX && tid == UINT32_MAX) {
58 return NULL;
61 /* TODO: add comments */
62 tcon = req->tcon;
63 if (tid != req->tcon->tid) {
64 tcon = smbsrv_smb2_tcon_find(req->session, tid, req->request_time);
65 if (!tcon) {
66 return NULL;
70 handle = smbsrv_smb2_handle_find(tcon, hid, req->request_time);
71 if (!handle) {
72 return NULL;
75 req->tcon = tcon;
76 return handle->ntvfs;
79 void smb2srv_push_handle(uint8_t *base, uint_t offset, struct ntvfs_handle *ntvfs)
81 struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
82 struct smbsrv_handle);
84 /*
85 * the handle is 128 bit on the wire
87 SBVAL(base, offset, handle->hid);
88 SIVAL(base, offset + 8, handle->tcon->tid);
89 SIVAL(base, offset + 12,0xFFFFFFFF);
92 static NTSTATUS smb2srv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h)
94 struct smb2srv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
95 struct smb2srv_request);
96 struct smbsrv_handle *handle;
97 struct ntvfs_handle *h;
99 handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time);
100 if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
102 h = talloc_zero(handle, struct ntvfs_handle);
103 if (!h) goto nomem;
106 * note: we don't set handle->ntvfs yet,
107 * this will be done by smbsrv_handle_make_valid()
108 * this makes sure the handle is invalid for clients
109 * until the ntvfs subsystem has made it valid
111 h->ctx = ntvfs->ctx;
112 h->session_info = ntvfs->session_info;
113 h->smbpid = ntvfs->smbpid;
115 h->frontend_data.private_data = handle;
117 *_h = h;
118 return NT_STATUS_OK;
119 nomem:
120 talloc_free(handle);
121 return NT_STATUS_NO_MEMORY;
124 static NTSTATUS smb2srv_handle_make_valid(void *private_data, struct ntvfs_handle *h)
126 struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon);
127 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
128 struct smbsrv_handle);
129 /* this tells the frontend that the handle is valid */
130 handle->ntvfs = h;
131 /* this moves the smbsrv_request to the smbsrv_tcon memory context */
132 talloc_steal(tcon, handle);
133 return NT_STATUS_OK;
136 static void smb2srv_handle_destroy(void *private_data, struct ntvfs_handle *h)
138 struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
139 struct smbsrv_handle);
140 talloc_free(handle);
143 static struct ntvfs_handle *smb2srv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key)
145 return NULL;
148 static DATA_BLOB smb2srv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx)
150 return data_blob(NULL, 0);
153 static NTSTATUS smb2srv_tcon_backend(struct smb2srv_request *req, union smb_tcon *io)
155 struct smbsrv_tcon *tcon;
156 NTSTATUS status;
157 enum ntvfs_type type;
158 uint16_t type_smb2;
159 int snum;
160 const char *service = io->smb2.in.path;
162 if (strncmp(service, "\\\\", 2) == 0) {
163 const char *p = strchr(service+2, '\\');
164 if (p) {
165 service = p + 1;
169 snum = lp_find_valid_service(service);
170 if (snum == -1) {
171 DEBUG(0,("smb2srv_tcon_backend: couldn't find service %s\n", service));
172 return NT_STATUS_BAD_NETWORK_NAME;
175 if (!socket_check_access(req->smb_conn->connection->socket,
176 lp_servicename(snum),
177 lp_hostsallow(snum),
178 lp_hostsdeny(snum))) {
179 return NT_STATUS_ACCESS_DENIED;
182 /* work out what sort of connection this is */
183 if (strcmp(lp_fstype(snum), "IPC") == 0) {
184 type = NTVFS_IPC;
185 type_smb2 = 0x0003;
186 } else if (lp_print_ok(snum)) {
187 type = NTVFS_PRINT;
188 type_smb2 = 0x0002;
189 } else {
190 type = NTVFS_DISK;
191 type_smb2 = 0x0001;
194 tcon = smbsrv_smb2_tcon_new(req->session, lp_servicename(snum));
195 if (!tcon) {
196 DEBUG(0,("smb2srv_tcon_backend: Couldn't find free connection.\n"));
197 return NT_STATUS_INSUFFICIENT_RESOURCES;
199 req->tcon = tcon;
201 /* init ntvfs function pointers */
202 status = ntvfs_init_connection(tcon, snum, type,
203 req->smb_conn->negotiate.protocol,
204 req->smb_conn->connection->event.ctx,
205 req->smb_conn->connection->msg_ctx,
206 req->smb_conn->connection->server_id,
207 &tcon->ntvfs);
208 if (!NT_STATUS_IS_OK(status)) {
209 DEBUG(0, ("smb2srv_tcon_backend: ntvfs_init_connection failed for service %s\n",
210 lp_servicename(snum)));
211 goto failed;
214 status = ntvfs_set_oplock_handler(tcon->ntvfs, smb2srv_send_oplock_break, tcon);
215 if (!NT_STATUS_IS_OK(status)) {
216 DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the oplock handler!\n"));
217 goto failed;
220 status = ntvfs_set_addr_callbacks(tcon->ntvfs, smbsrv_get_my_addr, smbsrv_get_peer_addr, req->smb_conn);
221 if (!NT_STATUS_IS_OK(status)) {
222 DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the addr callbacks!\n"));
223 goto failed;
226 status = ntvfs_set_handle_callbacks(tcon->ntvfs,
227 smb2srv_handle_create_new,
228 smb2srv_handle_make_valid,
229 smb2srv_handle_destroy,
230 smb2srv_handle_search_by_wire_key,
231 smb2srv_handle_get_wire_key,
232 tcon);
233 if (!NT_STATUS_IS_OK(status)) {
234 DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the handle callbacks!\n"));
235 goto failed;
238 req->ntvfs = ntvfs_request_create(req->tcon->ntvfs, req,
239 req->session->session_info,
240 0, /* TODO: fill in PID */
241 0, /* TODO: fill in MID */
242 req->request_time,
243 req, NULL, 0);
244 if (!req->ntvfs) {
245 status = NT_STATUS_NO_MEMORY;
246 goto failed;
249 /* Invoke NTVFS connection hook */
250 status = ntvfs_connect(req->ntvfs, lp_servicename(snum));
251 if (!NT_STATUS_IS_OK(status)) {
252 DEBUG(0,("smb2srv_tcon_backend: NTVFS ntvfs_connect() failed!\n"));
253 goto failed;
256 io->smb2.out.unknown1 = type_smb2; /* 1 - DISK, 2 - Print, 3 - IPC */
257 io->smb2.out.unknown2 = 0x00000000;
258 io->smb2.out.unknown3 = 0x00000000;
259 io->smb2.out.access_mask= SEC_RIGHTS_FILE_ALL;
261 io->smb2.out.tid = tcon->tid;
263 return NT_STATUS_OK;
265 failed:
266 req->tcon = NULL;
267 talloc_free(tcon);
268 return status;
271 static void smb2srv_tcon_send(struct smb2srv_request *req, union smb_tcon *io)
273 if (NT_STATUS_IS_ERR(req->status)) {
274 smb2srv_send_error(req, req->status);
275 return;
278 SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x10, False, 0));
280 SBVAL(req->out.hdr, SMB2_HDR_TID, io->smb2.out.tid);
282 SSVAL(req->out.body, 0x02, io->smb2.out.unknown1);
283 SIVAL(req->out.body, 0x04, io->smb2.out.unknown2);
284 SIVAL(req->out.body, 0x08, io->smb2.out.unknown3);
285 SIVAL(req->out.body, 0x0C, io->smb2.out.access_mask);
287 smb2srv_send_reply(req);
290 void smb2srv_tcon_recv(struct smb2srv_request *req)
292 union smb_tcon *io;
294 SMB2SRV_CHECK_BODY_SIZE(req, 0x08, True);
295 SMB2SRV_TALLOC_IO_PTR(io, union smb_tcon);
297 io->smb2.level = RAW_TCON_SMB2;
298 io->smb2.in.unknown1 = SVAL(req->in.body, 0x02);
299 SMB2SRV_CHECK(smb2_pull_o16s16_string(&req->in, io, req->in.body+0x04, &io->smb2.in.path));
301 req->status = smb2srv_tcon_backend(req, io);
303 if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {
304 talloc_free(req);
305 return;
307 smb2srv_tcon_send(req, io);
310 static NTSTATUS smb2srv_tdis_backend(struct smb2srv_request *req)
312 /* TODO: call ntvfs backends to close file of this tcon */
313 talloc_free(req->tcon);
314 req->tcon = NULL;
315 return NT_STATUS_OK;
318 static void smb2srv_tdis_send(struct smb2srv_request *req)
320 NTSTATUS status;
322 if (NT_STATUS_IS_ERR(req->status)) {
323 smb2srv_send_error(req, req->status);
324 return;
327 status = smb2srv_setup_reply(req, 0x04, False, 0);
328 if (!NT_STATUS_IS_OK(status)) {
329 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
330 talloc_free(req);
331 return;
334 SSVAL(req->out.body, 0x02, 0);
336 smb2srv_send_reply(req);
339 void smb2srv_tdis_recv(struct smb2srv_request *req)
341 uint16_t _pad;
343 SMB2SRV_CHECK_BODY_SIZE(req, 0x04, False);
345 _pad = SVAL(req->in.body, 0x02);
347 req->status = smb2srv_tdis_backend(req);
349 if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {
350 talloc_free(req);
351 return;
353 smb2srv_tdis_send(req);