• 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
4   Copyright (C) Andrew Tridgell              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/*
21  this file implements functions for manipulating the 'struct smbsrv_request' structure in smbd
22*/
23
24#include "includes.h"
25#include "smb_server/smb_server.h"
26#include "smbd/service_stream.h"
27#include "lib/stream/packet.h"
28#include "ntvfs/ntvfs.h"
29
30
31/* we over allocate the data buffer to prevent too many realloc calls */
32#define REQ_OVER_ALLOCATION 0
33
34/* setup the bufinfo used for strings and range checking */
35void smbsrv_setup_bufinfo(struct smbsrv_request *req)
36{
37	req->in.bufinfo.mem_ctx    = req;
38	req->in.bufinfo.flags      = 0;
39	if (req->flags2 & FLAGS2_UNICODE_STRINGS) {
40		req->in.bufinfo.flags |= BUFINFO_FLAG_UNICODE;
41	}
42	req->in.bufinfo.align_base = req->in.buffer;
43	req->in.bufinfo.data       = req->in.data;
44	req->in.bufinfo.data_size  = req->in.data_size;
45}
46
47
48static int smbsrv_request_destructor(struct smbsrv_request *req)
49{
50	DLIST_REMOVE(req->smb_conn->requests, req);
51	return 0;
52}
53
54/****************************************************************************
55construct a basic request packet, mostly used to construct async packets
56such as change notify and oplock break requests
57****************************************************************************/
58struct smbsrv_request *smbsrv_init_request(struct smbsrv_connection *smb_conn)
59{
60	struct smbsrv_request *req;
61
62	req = talloc_zero(smb_conn, struct smbsrv_request);
63	if (!req) {
64		return NULL;
65	}
66
67	/* setup the request context */
68	req->smb_conn = smb_conn;
69
70	talloc_set_destructor(req, smbsrv_request_destructor);
71
72	return req;
73}
74
75
76/*
77  setup a chained reply in req->out with the given word count and initial data buffer size.
78*/
79static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
80{
81	uint32_t chain_base_size = req->out.size;
82
83	/* we need room for the wct value, the words, the buffer length and the buffer */
84	req->out.size += 1 + VWV(wct) + 2 + buflen;
85
86	/* over allocate by a small amount */
87	req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
88
89	req->out.buffer = talloc_realloc(req, req->out.buffer,
90					 uint8_t, req->out.allocated);
91	if (!req->out.buffer) {
92		smbsrv_terminate_connection(req->smb_conn, "allocation failed");
93		return;
94	}
95
96	req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
97	req->out.vwv = req->out.buffer + chain_base_size + 1;
98	req->out.wct = wct;
99	req->out.data = req->out.vwv + VWV(wct) + 2;
100	req->out.data_size = buflen;
101	req->out.ptr = req->out.data;
102
103	SCVAL(req->out.buffer, chain_base_size, wct);
104	SSVAL(req->out.vwv, VWV(wct), buflen);
105}
106
107
108/*
109  setup a reply in req->out with the given word count and initial data buffer size.
110  the caller will then fill in the command words and data before calling req_send_reply() to
111  send the reply on its way
112*/
113void smbsrv_setup_reply(struct smbsrv_request *req, uint_t wct, size_t buflen)
114{
115	uint16_t flags2;
116
117	if (req->chain_count != 0) {
118		req_setup_chain_reply(req, wct, buflen);
119		return;
120	}
121
122	req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + buflen;
123
124	/* over allocate by a small amount */
125	req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
126
127	req->out.buffer = talloc_size(req, req->out.allocated);
128	if (!req->out.buffer) {
129		smbsrv_terminate_connection(req->smb_conn, "allocation failed");
130		return;
131	}
132
133	flags2 = FLAGS2_LONG_PATH_COMPONENTS |
134		FLAGS2_EXTENDED_ATTRIBUTES |
135		FLAGS2_IS_LONG_NAME;
136#define _SMB_FLAGS2_ECHOED_FLAGS ( \
137	FLAGS2_UNICODE_STRINGS | \
138	FLAGS2_EXTENDED_SECURITY | \
139	FLAGS2_SMB_SECURITY_SIGNATURES \
140)
141	flags2 |= (req->flags2 & _SMB_FLAGS2_ECHOED_FLAGS);
142	if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
143		flags2 |= FLAGS2_32_BIT_ERROR_CODES;
144	}
145
146	req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
147	req->out.vwv = req->out.hdr + HDR_VWV;
148	req->out.wct = wct;
149	req->out.data = req->out.vwv + VWV(wct) + 2;
150	req->out.data_size = buflen;
151	req->out.ptr = req->out.data;
152
153	SIVAL(req->out.hdr, HDR_RCLS, 0);
154
155	SCVAL(req->out.hdr, HDR_WCT, wct);
156	SSVAL(req->out.vwv, VWV(wct), buflen);
157
158	memcpy(req->out.hdr, "\377SMB", 4);
159	SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
160	SSVAL(req->out.hdr,HDR_FLG2, flags2);
161	SSVAL(req->out.hdr,HDR_PIDHIGH,0);
162	memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
163
164	if (req->in.hdr) {
165		/* copy the cmd, tid, pid, uid and mid from the request */
166		SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));
167		SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
168		SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
169		SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
170		SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
171	} else {
172		SCVAL(req->out.hdr,HDR_COM,0);
173		SSVAL(req->out.hdr,HDR_TID,0);
174		SSVAL(req->out.hdr,HDR_PID,0);
175		SSVAL(req->out.hdr,HDR_UID,0);
176		SSVAL(req->out.hdr,HDR_MID,0);
177	}
178}
179
180
181/*
182  setup a copy of a request, used when the server needs to send
183  more than one reply for a single request packet
184*/
185struct smbsrv_request *smbsrv_setup_secondary_request(struct smbsrv_request *old_req)
186{
187	struct smbsrv_request *req;
188	ptrdiff_t diff;
189
190	req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
191	if (req == NULL) {
192		return NULL;
193	}
194
195	req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
196	if (req->out.buffer == NULL) {
197		talloc_free(req);
198		return NULL;
199	}
200
201	diff = req->out.buffer - old_req->out.buffer;
202
203	req->out.hdr  += diff;
204	req->out.vwv  += diff;
205	req->out.data += diff;
206	req->out.ptr  += diff;
207
208	return req;
209}
210
211/*
212  work out the maximum data size we will allow for this reply, given
213  the negotiated max_xmit. The basic reply packet must be setup before
214  this call
215
216  note that this is deliberately a signed integer reply
217*/
218int req_max_data(struct smbsrv_request *req)
219{
220	int ret;
221	ret = req->smb_conn->negotiate.max_send;
222	ret -= PTR_DIFF(req->out.data, req->out.hdr);
223	if (ret < 0) ret = 0;
224	return ret;
225}
226
227
228/*
229  grow the allocation of the data buffer portion of a reply
230  packet. Note that as this can reallocate the packet buffer this
231  invalidates any local pointers into the packet.
232
233  To cope with this req->out.ptr is supplied. This will be updated to
234  point at the same offset into the packet as before this call
235*/
236static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
237{
238	int delta;
239	uint8_t *buf2;
240
241	delta = new_size - req->out.data_size;
242	if (delta + req->out.size <= req->out.allocated) {
243		/* it fits in the preallocation */
244		return;
245	}
246
247	/* we need to realloc */
248	req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
249	buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
250	if (buf2 == NULL) {
251		smb_panic("out of memory in req_grow_allocation");
252	}
253
254	if (buf2 == req->out.buffer) {
255		/* the malloc library gave us the same pointer */
256		return;
257	}
258
259	/* update the pointers into the packet */
260	req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
261	req->out.ptr  = buf2 + PTR_DIFF(req->out.ptr,  req->out.buffer);
262	req->out.vwv  = buf2 + PTR_DIFF(req->out.vwv,  req->out.buffer);
263	req->out.hdr  = buf2 + PTR_DIFF(req->out.hdr,  req->out.buffer);
264
265	req->out.buffer = buf2;
266}
267
268
269/*
270  grow the data buffer portion of a reply packet. Note that as this
271  can reallocate the packet buffer this invalidates any local pointers
272  into the packet.
273
274  To cope with this req->out.ptr is supplied. This will be updated to
275  point at the same offset into the packet as before this call
276*/
277void req_grow_data(struct smbsrv_request *req, size_t new_size)
278{
279	int delta;
280
281	if (!(req->control_flags & SMBSRV_REQ_CONTROL_LARGE) && new_size > req_max_data(req)) {
282		smb_panic("reply buffer too large!");
283	}
284
285	req_grow_allocation(req, new_size);
286
287	delta = new_size - req->out.data_size;
288
289	req->out.size += delta;
290	req->out.data_size += delta;
291
292	/* set the BCC to the new data size */
293	SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
294}
295
296/*
297  send a reply and destroy the request buffer
298
299  note that this only looks at req->out.buffer and req->out.size, allowing manually
300  constructed packets to be sent
301*/
302void smbsrv_send_reply_nosign(struct smbsrv_request *req)
303{
304	DATA_BLOB blob;
305	NTSTATUS status;
306
307	if (req->smb_conn->connection->event.fde == NULL) {
308		/* we are in the process of shutting down this connection */
309		talloc_free(req);
310		return;
311	}
312
313	if (req->out.size > NBT_HDR_SIZE) {
314		_smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
315	}
316
317	blob = data_blob_const(req->out.buffer, req->out.size);
318	status = packet_send(req->smb_conn->packet, blob);
319	if (!NT_STATUS_IS_OK(status)) {
320		smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
321	}
322	talloc_free(req);
323}
324
325/*
326  possibly sign a message then send a reply and destroy the request buffer
327
328  note that this only looks at req->out.buffer and req->out.size, allowing manually
329  constructed packets to be sent
330*/
331void smbsrv_send_reply(struct smbsrv_request *req)
332{
333	if (req->smb_conn->connection->event.fde == NULL) {
334		/* we are in the process of shutting down this connection */
335		talloc_free(req);
336		return;
337	}
338	smbsrv_sign_packet(req);
339
340	smbsrv_send_reply_nosign(req);
341}
342
343/*
344   setup the header of a reply to include an NTSTATUS code
345*/
346void smbsrv_setup_error(struct smbsrv_request *req, NTSTATUS status)
347{
348	if (!req->smb_conn->config.nt_status_support || !(req->smb_conn->negotiate.client_caps & CAP_STATUS32)) {
349		/* convert to DOS error codes */
350		uint8_t eclass;
351		uint32_t ecode;
352		ntstatus_to_dos(status, &eclass, &ecode);
353		SCVAL(req->out.hdr, HDR_RCLS, eclass);
354		SSVAL(req->out.hdr, HDR_ERR, ecode);
355		SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
356		return;
357	}
358
359	if (NT_STATUS_IS_DOS(status)) {
360		/* its a encoded DOS error, using the reserved range */
361		SSVAL(req->out.hdr, HDR_RCLS, NT_STATUS_DOS_CLASS(status));
362		SSVAL(req->out.hdr, HDR_ERR,  NT_STATUS_DOS_CODE(status));
363		SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) & ~FLAGS2_32_BIT_ERROR_CODES);
364	} else {
365		SIVAL(req->out.hdr, HDR_RCLS, NT_STATUS_V(status));
366		SSVAL(req->out.hdr, HDR_FLG2, SVAL(req->out.hdr, HDR_FLG2) | FLAGS2_32_BIT_ERROR_CODES);
367	}
368}
369
370/*
371   construct and send an error packet, then destroy the request
372   auto-converts to DOS error format when appropriate
373*/
374void smbsrv_send_error(struct smbsrv_request *req, NTSTATUS status)
375{
376	if (req->smb_conn->connection->event.fde == NULL) {
377		/* the socket has been destroyed - no point trying to send an error! */
378		talloc_free(req);
379		return;
380	}
381	smbsrv_setup_reply(req, 0, 0);
382
383	/* error returns never have any data */
384	req_grow_data(req, 0);
385
386	smbsrv_setup_error(req, status);
387	smbsrv_send_reply(req);
388}
389
390
391/*
392  push a string into the data portion of the request packet, growing it if necessary
393  this gets quite tricky - please be very careful to cover all cases when modifying this
394
395  if dest is NULL, then put the string at the end of the data portion of the packet
396
397  if dest_len is -1 then no limit applies
398*/
399size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, size_t flags)
400{
401	size_t len;
402	uint_t grow_size;
403	uint8_t *buf0;
404	const int max_bytes_per_char = 3;
405
406	if (!(flags & (STR_ASCII|STR_UNICODE))) {
407		flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
408	}
409
410	if (dest == NULL) {
411		dest = req->out.data + req->out.data_size;
412	}
413
414	if (dest_len != -1) {
415		len = dest_len;
416	} else {
417		len = (strlen(str)+2) * max_bytes_per_char;
418	}
419
420	grow_size = len + PTR_DIFF(dest, req->out.data);
421	buf0 = req->out.buffer;
422
423	req_grow_allocation(req, grow_size);
424
425	if (buf0 != req->out.buffer) {
426		dest = req->out.buffer + PTR_DIFF(dest, buf0);
427	}
428
429	len = push_string(dest, str, len, flags);
430
431	grow_size = len + PTR_DIFF(dest, req->out.data);
432
433	if (grow_size > req->out.data_size) {
434		req_grow_data(req, grow_size);
435	}
436
437	return len;
438}
439
440/*
441  append raw bytes into the data portion of the request packet
442  return the number of bytes added
443*/
444size_t req_append_bytes(struct smbsrv_request *req,
445			const uint8_t *bytes, size_t byte_len)
446{
447	req_grow_allocation(req, byte_len + req->out.data_size);
448	memcpy(req->out.data + req->out.data_size, bytes, byte_len);
449	req_grow_data(req, byte_len + req->out.data_size);
450	return byte_len;
451}
452/*
453  append variable block (type 5 buffer) into the data portion of the request packet
454  return the number of bytes added
455*/
456size_t req_append_var_block(struct smbsrv_request *req,
457		const uint8_t *bytes, uint16_t byte_len)
458{
459	req_grow_allocation(req, byte_len + 3 + req->out.data_size);
460	SCVAL(req->out.data + req->out.data_size, 0, 5);
461	SSVAL(req->out.data + req->out.data_size, 1, byte_len);		/* add field length */
462	if (byte_len > 0) {
463		memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
464	}
465	req_grow_data(req, byte_len + 3 + req->out.data_size);
466	return byte_len + 3;
467}
468/**
469  pull a UCS2 string from a request packet, returning a talloced unix string
470
471  the string length is limited by the 3 things:
472   - the data size in the request (end of packet)
473   - the passed 'byte_len' if it is not -1
474   - the end of string (null termination)
475
476  Note that 'byte_len' is the number of bytes in the packet
477
478  on failure zero is returned and *dest is set to NULL, otherwise the number
479  of bytes consumed in the packet is returned
480*/
481static size_t req_pull_ucs2(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
482{
483	int src_len, src_len2, alignment=0;
484	bool ret;
485	char *dest2;
486
487	if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
488		src++;
489		alignment=1;
490		if (byte_len != -1) {
491			byte_len--;
492		}
493	}
494
495	if (flags & STR_NO_RANGE_CHECK) {
496		src_len = byte_len;
497	} else {
498		src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
499		if (byte_len != -1 && src_len > byte_len) {
500			src_len = byte_len;
501		}
502	}
503
504	if (src_len < 0) {
505		*dest = NULL;
506		return 0;
507	}
508
509	src_len2 = utf16_len_n(src, src_len);
510	if (src_len2 == 0) {
511		*dest = talloc_strdup(bufinfo->mem_ctx, "");
512		return src_len2 + alignment;
513	}
514
515	ret = convert_string_talloc(bufinfo->mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2, NULL, false);
516
517	if (!ret) {
518		*dest = NULL;
519		return 0;
520	}
521	*dest = dest2;
522
523	return src_len2 + alignment;
524}
525
526/**
527  pull a ascii string from a request packet, returning a talloced string
528
529  the string length is limited by the 3 things:
530   - the data size in the request (end of packet)
531   - the passed 'byte_len' if it is not -1
532   - the end of string (null termination)
533
534  Note that 'byte_len' is the number of bytes in the packet
535
536  on failure zero is returned and *dest is set to NULL, otherwise the number
537  of bytes consumed in the packet is returned
538*/
539static size_t req_pull_ascii(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
540{
541	int src_len, src_len2;
542	bool ret;
543	char *dest2;
544
545	if (flags & STR_NO_RANGE_CHECK) {
546		src_len = byte_len;
547	} else {
548		src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
549		if (src_len < 0) {
550			*dest = NULL;
551			return 0;
552		}
553		if (byte_len != -1 && src_len > byte_len) {
554			src_len = byte_len;
555		}
556	}
557
558	src_len2 = strnlen((const char *)src, src_len);
559	if (src_len2 <= src_len - 1) {
560		/* include the termination if we didn't reach the end of the packet */
561		src_len2++;
562	}
563
564	ret = convert_string_talloc(bufinfo->mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2, NULL, false);
565
566	if (!ret) {
567		*dest = NULL;
568		return 0;
569	}
570	*dest = dest2;
571
572	return src_len2;
573}
574
575/**
576  pull a string from a request packet, returning a talloced string
577
578  the string length is limited by the 3 things:
579   - the data size in the request (end of packet)
580   - the passed 'byte_len' if it is not -1
581   - the end of string (null termination)
582
583  Note that 'byte_len' is the number of bytes in the packet
584
585  on failure zero is returned and *dest is set to NULL, otherwise the number
586  of bytes consumed in the packet is returned
587*/
588size_t req_pull_string(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
589{
590	if (!(flags & STR_ASCII) &&
591	    (((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) {
592		return req_pull_ucs2(bufinfo, dest, src, byte_len, flags);
593	}
594
595	return req_pull_ascii(bufinfo, dest, src, byte_len, flags);
596}
597
598
599/**
600  pull a ASCII4 string buffer from a request packet, returning a talloced string
601
602  an ASCII4 buffer is a null terminated string that has a prefix
603  of the character 0x4. It tends to be used in older parts of the protocol.
604
605  on failure *dest is set to the zero length string. This seems to
606  match win2000 behaviour
607*/
608size_t req_pull_ascii4(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, uint_t flags)
609{
610	ssize_t ret;
611
612	if (PTR_DIFF(src, bufinfo->data) + 1 > bufinfo->data_size) {
613		/* win2000 treats this as the empty string! */
614		(*dest) = talloc_strdup(bufinfo->mem_ctx, "");
615		return 0;
616	}
617
618	/* this consumes the 0x4 byte. We don't check whether the byte
619	   is actually 0x4 or not. This matches win2000 server
620	   behaviour */
621	src++;
622
623	ret = req_pull_string(bufinfo, dest, src, -1, flags);
624	if (ret == -1) {
625		(*dest) = talloc_strdup(bufinfo->mem_ctx, "");
626		return 1;
627	}
628
629	return ret + 1;
630}
631
632/**
633  pull a DATA_BLOB from a request packet, returning a talloced blob
634
635  return false if any part is outside the data portion of the packet
636*/
637bool req_pull_blob(struct request_bufinfo *bufinfo, const uint8_t *src, int len, DATA_BLOB *blob)
638{
639	if (len != 0 && req_data_oob(bufinfo, src, len)) {
640		return false;
641	}
642
643	(*blob) = data_blob_talloc(bufinfo->mem_ctx, src, len);
644
645	return true;
646}
647
648/* check that a lump of data in a request is within the bounds of the data section of
649   the packet */
650bool req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count)
651{
652	if (count == 0) {
653		return false;
654	}
655
656	/* be careful with wraparound! */
657	if ((uintptr_t)ptr < (uintptr_t)bufinfo->data ||
658	    (uintptr_t)ptr >= (uintptr_t)bufinfo->data + bufinfo->data_size ||
659	    count > bufinfo->data_size ||
660	    (uintptr_t)ptr + count > (uintptr_t)bufinfo->data + bufinfo->data_size) {
661		return true;
662	}
663	return false;
664}
665
666
667/*
668   pull an open file handle from a packet, taking account of the chained_fnum
669*/
670static uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
671{
672	if (req->chained_fnum != -1) {
673		return req->chained_fnum;
674	}
675	return SVAL(base, offset);
676}
677
678struct ntvfs_handle *smbsrv_pull_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
679{
680	struct smbsrv_handle *handle;
681	uint16_t fnum = req_fnum(req, base, offset);
682
683	handle = smbsrv_smb_handle_find(req->tcon, fnum, req->request_time);
684	if (!handle) {
685		return NULL;
686	}
687
688	/*
689	 * For SMB tcons and sessions can be mixed!
690	 * But we need to make sure that file handles
691	 * are only accessed by the opening session!
692	 *
693	 * So check if the handle is valid for the given session!
694	 */
695	if (handle->session != req->session) {
696		return NULL;
697	}
698
699	return handle->ntvfs;
700}
701
702void smbsrv_push_fnum(uint8_t *base, uint_t offset, struct ntvfs_handle *ntvfs)
703{
704	struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
705				       struct smbsrv_handle);
706	SSVAL(base, offset, handle->hid);
707}
708
709NTSTATUS smbsrv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h)
710{
711	struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
712				     struct smbsrv_request);
713	struct smbsrv_handle *handle;
714	struct ntvfs_handle *h;
715
716	handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time);
717	if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
718
719	h = talloc_zero(handle, struct ntvfs_handle);
720	if (!h) goto nomem;
721
722	/*
723	 * note: we don't set handle->ntvfs yet,
724	 *       this will be done by smbsrv_handle_make_valid()
725	 *       this makes sure the handle is invalid for clients
726	 *       until the ntvfs subsystem has made it valid
727	 */
728	h->ctx		= ntvfs->ctx;
729	h->session_info	= ntvfs->session_info;
730	h->smbpid	= ntvfs->smbpid;
731
732	h->frontend_data.private_data = handle;
733
734	*_h = h;
735	return NT_STATUS_OK;
736nomem:
737	talloc_free(handle);
738	return NT_STATUS_NO_MEMORY;
739}
740
741NTSTATUS smbsrv_handle_make_valid(void *private_data, struct ntvfs_handle *h)
742{
743	struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon);
744	struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
745						       struct smbsrv_handle);
746	/* this tells the frontend that the handle is valid */
747	handle->ntvfs = h;
748	/* this moves the smbsrv_request to the smbsrv_tcon memory context */
749	talloc_steal(tcon, handle);
750	return NT_STATUS_OK;
751}
752
753void smbsrv_handle_destroy(void *private_data, struct ntvfs_handle *h)
754{
755	struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
756						       struct smbsrv_handle);
757	talloc_free(handle);
758}
759
760struct ntvfs_handle *smbsrv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key)
761{
762	struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
763				     struct smbsrv_request);
764
765	if (key->length != 2) return NULL;
766
767	return smbsrv_pull_fnum(req, key->data, 0);
768}
769
770DATA_BLOB smbsrv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx)
771{
772	uint8_t key[2];
773
774	smbsrv_push_fnum(key, 0, handle);
775
776	return data_blob_talloc(mem_ctx, key, sizeof(key));
777}
778