Line data Source code
1 : /*
2 : Unix SMB2 implementation.
3 :
4 : Copyright (C) Stefan Metzmacher 2005
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 "libcli/smb2/smb2.h"
22 : #include "libcli/smb2/smb2_calls.h"
23 : #include "smb_server/smb_server.h"
24 : #include "smb_server/smb2/smb2_server.h"
25 : #include "samba/service_stream.h"
26 : #include "ntvfs/ntvfs.h"
27 :
28 : /*
29 : send an oplock break request to a client
30 : */
31 53 : static NTSTATUS smb2srv_send_oplock_break(void *p, struct ntvfs_handle *h, uint8_t level)
32 : {
33 53 : struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
34 : struct smbsrv_handle);
35 0 : struct smb2srv_request *req;
36 0 : NTSTATUS status;
37 :
38 : /* setup a dummy request structure */
39 53 : req = smb2srv_init_request(handle->tcon->smb_conn);
40 53 : NT_STATUS_HAVE_NO_MEMORY(req);
41 :
42 53 : req->in.buffer = talloc_array(req, uint8_t,
43 : NBT_HDR_SIZE + SMB2_MIN_SIZE);
44 53 : NT_STATUS_HAVE_NO_MEMORY(req->in.buffer);
45 53 : req->in.size = NBT_HDR_SIZE + SMB2_MIN_SIZE;
46 53 : req->in.allocated = req->in.size;
47 :
48 53 : req->in.hdr = req->in.buffer+ NBT_HDR_SIZE;
49 53 : req->in.body = req->in.hdr + SMB2_HDR_BODY;
50 53 : req->in.body_size = req->in.size - (SMB2_HDR_BODY+NBT_HDR_SIZE);
51 53 : req->in.dynamic = NULL;
52 :
53 53 : req->seqnum = UINT64_MAX;
54 :
55 53 : smb2srv_setup_bufinfo(req);
56 :
57 53 : SIVAL(req->in.hdr, 0, SMB2_MAGIC);
58 53 : SSVAL(req->in.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
59 53 : SSVAL(req->in.hdr, SMB2_HDR_EPOCH, 0);
60 53 : SIVAL(req->in.hdr, SMB2_HDR_STATUS, 0);
61 53 : SSVAL(req->in.hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
62 53 : SSVAL(req->in.hdr, SMB2_HDR_CREDIT, 0);
63 53 : SIVAL(req->in.hdr, SMB2_HDR_FLAGS, 0);
64 53 : SIVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND, 0);
65 53 : SBVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID, 0);
66 53 : SIVAL(req->in.hdr, SMB2_HDR_PID, 0);
67 53 : SIVAL(req->in.hdr, SMB2_HDR_TID, 0);
68 53 : SBVAL(req->in.hdr, SMB2_HDR_SESSION_ID, 0);
69 53 : memset(req->in.hdr+SMB2_HDR_SIGNATURE, 0, 16);
70 :
71 53 : SSVAL(req->in.body, 0, 2);
72 :
73 53 : status = smb2srv_setup_reply(req, 0x18, false, 0);
74 53 : NT_STATUS_NOT_OK_RETURN(status);
75 :
76 53 : SSVAL(req->out.hdr, SMB2_HDR_CREDIT, 0x0000);
77 :
78 53 : SSVAL(req->out.body, 0x02, 0x0001);
79 53 : SIVAL(req->out.body, 0x04, 0x00000000);
80 53 : smb2srv_push_handle(req->out.body, 0x08, h);
81 :
82 53 : smb2srv_send_reply(req);
83 :
84 53 : return NT_STATUS_OK;
85 : }
86 :
87 196887 : struct ntvfs_handle *smb2srv_pull_handle(struct smb2srv_request *req, const uint8_t *base, unsigned int offset)
88 : {
89 0 : struct smbsrv_tcon *tcon;
90 0 : struct smbsrv_handle *handle;
91 0 : uint32_t hid;
92 0 : uint32_t tid;
93 0 : uint64_t uid;
94 :
95 : /*
96 : * if there're chained requests used the cached handle
97 : *
98 : * TODO: check if this also correct when the given handle
99 : * isn't all 0xFF.
100 : */
101 196887 : if (req->chained_file_handle) {
102 0 : base = req->chained_file_handle;
103 0 : offset = 0;
104 : }
105 :
106 196887 : hid = IVAL(base, offset);
107 196887 : tid = IVAL(base, offset + 4);
108 196887 : uid = BVAL(base, offset + 8);
109 :
110 : /* if it's the wildcard handle, don't waste time to search it... */
111 196887 : if (hid == UINT32_MAX && tid == UINT32_MAX && uid == UINT64_MAX) {
112 0 : return NULL;
113 : }
114 :
115 : /*
116 : * if the (v)uid part doesn't match the given session the handle isn't
117 : * valid
118 : */
119 196887 : if (uid != req->session->vuid) {
120 484 : return NULL;
121 : }
122 :
123 : /*
124 : * the handle can belong to a different tcon
125 : * as that TID in the SMB2 header says, but
126 : * the request should succeed nevertheless!
127 : *
128 : * because of this we put the 32 bit TID into the
129 : * 128 bit handle, so that we can extract the tcon from the
130 : * handle
131 : */
132 196403 : tcon = req->tcon;
133 196403 : if (tid != req->tcon->tid) {
134 0 : tcon = smbsrv_smb2_tcon_find(req->session, tid, req->request_time);
135 0 : if (!tcon) {
136 0 : return NULL;
137 : }
138 : }
139 :
140 196403 : handle = smbsrv_smb2_handle_find(tcon, hid, req->request_time);
141 196403 : if (!handle) {
142 13 : return NULL;
143 : }
144 :
145 : /*
146 : * as the smb2srv_tcon is a child object of the smb2srv_session
147 : * the handle belongs to the correct session!
148 : *
149 : * Note: no check is needed here for SMB2
150 : */
151 :
152 : /*
153 : * as the handle may have overwritten the tcon
154 : * we need to set it on the request so that the
155 : * correct ntvfs context will be used for the ntvfs_*() request
156 : *
157 : * TODO: check if that's correct for chained requests as well!
158 : */
159 196390 : req->tcon = tcon;
160 196390 : return handle->ntvfs;
161 : }
162 :
163 333251 : void smb2srv_push_handle(uint8_t *base, unsigned int offset, struct ntvfs_handle *ntvfs)
164 : {
165 333251 : struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
166 : struct smbsrv_handle);
167 :
168 : /*
169 : * the handle is 128 bit on the wire
170 : */
171 333251 : SIVAL(base, offset, handle->hid);
172 333251 : SIVAL(base, offset + 4, handle->tcon->tid);
173 333251 : SBVAL(base, offset + 8, handle->session->vuid);
174 333251 : }
175 :
176 143477 : static NTSTATUS smb2srv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h)
177 : {
178 143477 : struct smb2srv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
179 : struct smb2srv_request);
180 0 : struct smbsrv_handle *handle;
181 0 : struct ntvfs_handle *h;
182 :
183 143477 : handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time);
184 143477 : if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
185 :
186 143477 : h = talloc_zero(handle, struct ntvfs_handle);
187 143477 : if (!h) goto nomem;
188 :
189 : /*
190 : * note: we don't set handle->ntvfs yet,
191 : * this will be done by smbsrv_handle_make_valid()
192 : * this makes sure the handle is invalid for clients
193 : * until the ntvfs subsystem has made it valid
194 : */
195 143477 : h->ctx = ntvfs->ctx;
196 143477 : h->session_info = ntvfs->session_info;
197 143477 : h->smbpid = ntvfs->smbpid;
198 :
199 143477 : h->frontend_data.private_data = handle;
200 :
201 143477 : *_h = h;
202 143477 : return NT_STATUS_OK;
203 0 : nomem:
204 0 : talloc_free(handle);
205 0 : return NT_STATUS_NO_MEMORY;
206 : }
207 :
208 142834 : static NTSTATUS smb2srv_handle_make_valid(void *private_data, struct ntvfs_handle *h)
209 : {
210 142834 : struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon);
211 142834 : struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
212 : struct smbsrv_handle);
213 : /* this tells the frontend that the handle is valid */
214 142834 : handle->ntvfs = h;
215 : /* this moves the smbsrv_request to the smbsrv_tcon memory context */
216 142834 : talloc_steal(tcon, handle);
217 142834 : return NT_STATUS_OK;
218 : }
219 :
220 143379 : static void smb2srv_handle_destroy(void *private_data, struct ntvfs_handle *h)
221 : {
222 143379 : struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
223 : struct smbsrv_handle);
224 143379 : talloc_free(handle);
225 143379 : }
226 :
227 0 : static struct ntvfs_handle *smb2srv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key)
228 : {
229 0 : return NULL;
230 : }
231 :
232 0 : static DATA_BLOB smb2srv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx)
233 : {
234 0 : return data_blob(NULL, 0);
235 : }
236 :
237 1606 : static NTSTATUS smb2srv_tcon_backend(struct smb2srv_request *req, union smb_tcon *io)
238 : {
239 0 : struct smbsrv_tcon *tcon;
240 0 : NTSTATUS status;
241 0 : enum ntvfs_type type;
242 1606 : const char *service = io->smb2.in.path;
243 0 : struct share_config *scfg;
244 0 : char *sharetype;
245 1606 : uint64_t ntvfs_caps = 0;
246 :
247 1606 : if (strncmp(service, "\\\\", 2) == 0) {
248 1606 : const char *p = strchr(service+2, '\\');
249 1606 : if (p) {
250 1606 : service = p + 1;
251 : }
252 : }
253 :
254 1606 : status = share_get_config(req, req->smb_conn->share_context, service, &scfg);
255 1606 : if (!NT_STATUS_IS_OK(status)) {
256 4 : DEBUG(0,("smb2srv_tcon_backend: couldn't find service %s\n", service));
257 4 : return NT_STATUS_BAD_NETWORK_NAME;
258 : }
259 :
260 3204 : if (!socket_check_access(req->smb_conn->connection->socket,
261 1602 : scfg->name,
262 : share_string_list_option(req, scfg, SHARE_HOSTS_ALLOW),
263 : share_string_list_option(req, scfg, SHARE_HOSTS_DENY))) {
264 0 : return NT_STATUS_ACCESS_DENIED;
265 : }
266 :
267 : /* work out what sort of connection this is */
268 1602 : sharetype = share_string_option(req, scfg, SHARE_TYPE, "DISK");
269 1602 : if (sharetype && strcmp(sharetype, "IPC") == 0) {
270 1034 : type = NTVFS_IPC;
271 568 : } else if (sharetype && strcmp(sharetype, "PRINTER") == 0) {
272 0 : type = NTVFS_PRINT;
273 : } else {
274 568 : type = NTVFS_DISK;
275 : }
276 1602 : TALLOC_FREE(sharetype);
277 :
278 1602 : tcon = smbsrv_smb2_tcon_new(req->session, scfg->name);
279 1602 : if (!tcon) {
280 0 : DEBUG(0,("smb2srv_tcon_backend: Couldn't find free connection.\n"));
281 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
282 : }
283 1602 : req->tcon = tcon;
284 :
285 1602 : ntvfs_caps = NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS;
286 :
287 : /* init ntvfs function pointers */
288 1602 : status = ntvfs_init_connection(tcon, scfg, type,
289 1602 : req->smb_conn->negotiate.protocol,
290 : ntvfs_caps,
291 1602 : req->smb_conn->connection->event.ctx,
292 1602 : req->smb_conn->connection->msg_ctx,
293 1602 : req->smb_conn->lp_ctx,
294 1602 : req->smb_conn->connection->server_id,
295 : &tcon->ntvfs);
296 1602 : if (!NT_STATUS_IS_OK(status)) {
297 0 : DEBUG(0, ("smb2srv_tcon_backend: ntvfs_init_connection failed for service %s\n",
298 : scfg->name));
299 0 : goto failed;
300 : }
301 :
302 1602 : status = ntvfs_set_oplock_handler(tcon->ntvfs, smb2srv_send_oplock_break, tcon);
303 1602 : if (!NT_STATUS_IS_OK(status)) {
304 0 : DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the oplock handler!\n"));
305 0 : goto failed;
306 : }
307 :
308 1602 : status = ntvfs_set_addresses(tcon->ntvfs,
309 1602 : req->smb_conn->connection->local_address,
310 1602 : req->smb_conn->connection->remote_address);
311 1602 : if (!NT_STATUS_IS_OK(status)) {
312 0 : DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the address!\n"));
313 0 : goto failed;
314 : }
315 :
316 1602 : status = ntvfs_set_handle_callbacks(tcon->ntvfs,
317 : smb2srv_handle_create_new,
318 : smb2srv_handle_make_valid,
319 : smb2srv_handle_destroy,
320 : smb2srv_handle_search_by_wire_key,
321 : smb2srv_handle_get_wire_key,
322 : tcon);
323 1602 : if (!NT_STATUS_IS_OK(status)) {
324 0 : DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the handle callbacks!\n"));
325 0 : goto failed;
326 : }
327 :
328 3204 : req->ntvfs = ntvfs_request_create(req->tcon->ntvfs, req,
329 1602 : req->session->session_info,
330 1602 : SVAL(req->in.hdr, SMB2_HDR_PID),
331 : req->request_time,
332 : req, NULL, 0);
333 1602 : if (!req->ntvfs) {
334 0 : status = NT_STATUS_NO_MEMORY;
335 0 : goto failed;
336 : }
337 :
338 1602 : io->smb2.out.share_type = (unsigned)type; /* 1 - DISK, 2 - Print, 3 - IPC */
339 1602 : io->smb2.out.reserved = 0;
340 1602 : io->smb2.out.flags = 0x00000000;
341 1602 : io->smb2.out.capabilities = 0;
342 1602 : io->smb2.out.access_mask = SEC_RIGHTS_FILE_ALL;
343 :
344 1602 : io->smb2.out.tid = tcon->tid;
345 :
346 : /* Invoke NTVFS connection hook */
347 1602 : status = ntvfs_connect(req->ntvfs, io);
348 1602 : if (!NT_STATUS_IS_OK(status)) {
349 0 : DEBUG(0,("smb2srv_tcon_backend: NTVFS ntvfs_connect() failed: %s!\n", nt_errstr(status)));
350 0 : goto failed;
351 : }
352 :
353 1602 : return NT_STATUS_OK;
354 :
355 0 : failed:
356 0 : req->tcon = NULL;
357 0 : talloc_free(tcon);
358 0 : return status;
359 : }
360 :
361 1606 : static void smb2srv_tcon_send(struct smb2srv_request *req, union smb_tcon *io)
362 : {
363 1606 : if (!NT_STATUS_IS_OK(req->status)) {
364 4 : smb2srv_send_error(req, req->status);
365 4 : return;
366 : }
367 :
368 1602 : SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x10, false, 0));
369 :
370 1602 : SIVAL(req->out.hdr, SMB2_HDR_TID, io->smb2.out.tid);
371 :
372 1602 : SCVAL(req->out.body, 0x02, io->smb2.out.share_type);
373 1602 : SCVAL(req->out.body, 0x03, io->smb2.out.reserved);
374 1602 : SIVAL(req->out.body, 0x04, io->smb2.out.flags);
375 1602 : SIVAL(req->out.body, 0x08, io->smb2.out.capabilities);
376 1602 : SIVAL(req->out.body, 0x0C, io->smb2.out.access_mask);
377 :
378 1602 : smb2srv_send_reply(req);
379 : }
380 :
381 1606 : void smb2srv_tcon_recv(struct smb2srv_request *req)
382 : {
383 0 : union smb_tcon *io;
384 :
385 1606 : SMB2SRV_CHECK_BODY_SIZE(req, 0x08, true);
386 1606 : SMB2SRV_TALLOC_IO_PTR(io, union smb_tcon);
387 :
388 1606 : io->smb2.level = RAW_TCON_SMB2;
389 1606 : io->smb2.in.reserved = SVAL(req->in.body, 0x02);
390 1606 : SMB2SRV_CHECK(smb2_pull_o16s16_string(&req->in, io, req->in.body+0x04, &io->smb2.in.path));
391 :
392 : /* the VFS backend does not yet handle NULL paths */
393 1606 : if (io->smb2.in.path == NULL) {
394 0 : io->smb2.in.path = "";
395 : }
396 :
397 1606 : req->status = smb2srv_tcon_backend(req, io);
398 :
399 1606 : if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {
400 0 : talloc_free(req);
401 0 : return;
402 : }
403 1606 : smb2srv_tcon_send(req, io);
404 : }
405 :
406 445 : static NTSTATUS smb2srv_tdis_backend(struct smb2srv_request *req)
407 : {
408 : /* TODO: call ntvfs backends to close file of this tcon */
409 445 : talloc_free(req->tcon);
410 445 : req->tcon = NULL;
411 445 : return NT_STATUS_OK;
412 : }
413 :
414 445 : static void smb2srv_tdis_send(struct smb2srv_request *req)
415 : {
416 0 : NTSTATUS status;
417 :
418 445 : if (NT_STATUS_IS_ERR(req->status)) {
419 0 : smb2srv_send_error(req, req->status);
420 0 : return;
421 : }
422 :
423 445 : status = smb2srv_setup_reply(req, 0x04, false, 0);
424 445 : if (!NT_STATUS_IS_OK(status)) {
425 0 : smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
426 0 : talloc_free(req);
427 0 : return;
428 : }
429 :
430 445 : SSVAL(req->out.body, 0x02, 0);
431 :
432 445 : smb2srv_send_reply(req);
433 : }
434 :
435 445 : void smb2srv_tdis_recv(struct smb2srv_request *req)
436 : {
437 445 : SMB2SRV_CHECK_BODY_SIZE(req, 0x04, false);
438 :
439 445 : req->status = smb2srv_tdis_backend(req);
440 :
441 445 : if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {
442 0 : talloc_free(req);
443 0 : return;
444 : }
445 445 : smb2srv_tdis_send(req);
446 : }
|