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 */
smbsrv_setup_bufinfo(struct smbsrv_request * req)35 void 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 
smbsrv_request_destructor(struct smbsrv_request * req)48 static int smbsrv_request_destructor(struct smbsrv_request *req)
49 {
50 	DLIST_REMOVE(req->smb_conn->requests, req);
51 	return 0;
52 }
53 
54 /****************************************************************************
55 construct a basic request packet, mostly used to construct async packets
56 such as change notify and oplock break requests
57 ****************************************************************************/
smbsrv_init_request(struct smbsrv_connection * smb_conn)58 struct 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 */
req_setup_chain_reply(struct smbsrv_request * req,unsigned int wct,unsigned int buflen)79 static void req_setup_chain_reply(struct smbsrv_request *req, unsigned int wct, unsigned int 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 */
smbsrv_setup_reply(struct smbsrv_request * req,unsigned int wct,size_t buflen)113 void smbsrv_setup_reply(struct smbsrv_request *req, unsigned int 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 */
smbsrv_setup_secondary_request(struct smbsrv_request * old_req)185 struct 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 */
req_max_data(struct smbsrv_request * req)218 int 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 */
req_grow_allocation(struct smbsrv_request * req,unsigned int new_size)236 static void req_grow_allocation(struct smbsrv_request *req, unsigned int 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 */
req_grow_data(struct smbsrv_request * req,size_t new_size)277 void 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 */
smbsrv_send_reply_nosign(struct smbsrv_request * req)302 void 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_nbt(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 */
smbsrv_send_reply(struct smbsrv_request * req)331 void 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 */
smbsrv_setup_error(struct smbsrv_request * req,NTSTATUS status)346 void 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 */
smbsrv_send_error(struct smbsrv_request * req,NTSTATUS status)374 void 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 */
req_push_str(struct smbsrv_request * req,uint8_t * dest,const char * str,int dest_len,size_t flags)399 size_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 	unsigned int 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 */
req_append_bytes(struct smbsrv_request * req,const uint8_t * bytes,size_t byte_len)444 size_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 */
req_append_var_block(struct smbsrv_request * req,const uint8_t * bytes,uint16_t byte_len)456 size_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 */
req_pull_ucs2(struct request_bufinfo * bufinfo,const char ** dest,const uint8_t * src,int byte_len,unsigned int flags)481 static size_t req_pull_ucs2(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, unsigned int flags)
482 {
483 	int src_len, src_len2, alignment=0;
484 	bool ret;
485 	char *dest2;
486 	size_t converted_size = 0;
487 
488 	if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
489 		src++;
490 		alignment=1;
491 		if (byte_len != -1) {
492 			byte_len--;
493 		}
494 	}
495 
496 	if (flags & STR_NO_RANGE_CHECK) {
497 		src_len = byte_len;
498 	} else {
499 		src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
500 		if (byte_len != -1 && src_len > byte_len) {
501 			src_len = byte_len;
502 		}
503 	}
504 
505 	if (src_len < 0) {
506 		*dest = NULL;
507 		return 0;
508 	}
509 
510 	src_len2 = utf16_len_n(src, src_len);
511 	if (src_len2 == 0) {
512 		*dest = talloc_strdup(bufinfo->mem_ctx, "");
513 		return src_len2 + alignment;
514 	}
515 
516 	ret = convert_string_talloc(bufinfo->mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2, &converted_size);
517 
518 	if (!ret) {
519 		*dest = NULL;
520 		return 0;
521 	}
522 	*dest = dest2;
523 
524 	return src_len2 + alignment;
525 }
526 
527 /**
528   pull a ascii string from a request packet, returning a talloced string
529 
530   the string length is limited by the 3 things:
531    - the data size in the request (end of packet)
532    - the passed 'byte_len' if it is not -1
533    - the end of string (null termination)
534 
535   Note that 'byte_len' is the number of bytes in the packet
536 
537   on failure zero is returned and *dest is set to NULL, otherwise the number
538   of bytes consumed in the packet is returned
539 */
req_pull_ascii(struct request_bufinfo * bufinfo,const char ** dest,const uint8_t * src,int byte_len,unsigned int flags)540 static size_t req_pull_ascii(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, unsigned int flags)
541 {
542 	int src_len, src_len2;
543 	bool ret;
544 	char *dest2;
545 	size_t converted_size = 0;
546 
547 	if (flags & STR_NO_RANGE_CHECK) {
548 		src_len = byte_len;
549 	} else {
550 		src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
551 		if (src_len < 0) {
552 			*dest = NULL;
553 			return 0;
554 		}
555 		if (byte_len != -1 && src_len > byte_len) {
556 			src_len = byte_len;
557 		}
558 	}
559 
560 	src_len2 = strnlen((const char *)src, src_len);
561 	if (src_len2 <= src_len - 1) {
562 		/* include the termination if we didn't reach the end of the packet */
563 		src_len2++;
564 	}
565 
566 	ret = convert_string_talloc(bufinfo->mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2, &converted_size);
567 
568 	if (!ret) {
569 		*dest = NULL;
570 		return 0;
571 	}
572 	*dest = dest2;
573 
574 	return src_len2;
575 }
576 
577 /**
578   pull a string from a request packet, returning a talloced string
579 
580   the string length is limited by the 3 things:
581    - the data size in the request (end of packet)
582    - the passed 'byte_len' if it is not -1
583    - the end of string (null termination)
584 
585   Note that 'byte_len' is the number of bytes in the packet
586 
587   on failure zero is returned and *dest is set to NULL, otherwise the number
588   of bytes consumed in the packet is returned
589 */
req_pull_string(struct request_bufinfo * bufinfo,const char ** dest,const uint8_t * src,int byte_len,unsigned int flags)590 size_t req_pull_string(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, unsigned int flags)
591 {
592 	if (!(flags & STR_ASCII) &&
593 	    (((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) {
594 		return req_pull_ucs2(bufinfo, dest, src, byte_len, flags);
595 	}
596 
597 	return req_pull_ascii(bufinfo, dest, src, byte_len, flags);
598 }
599 
600 
601 /**
602   pull a ASCII4 string buffer from a request packet, returning a talloced string
603 
604   an ASCII4 buffer is a null terminated string that has a prefix
605   of the character 0x4. It tends to be used in older parts of the protocol.
606 
607   on failure *dest is set to the zero length string. This seems to
608   match win2000 behaviour
609 */
req_pull_ascii4(struct request_bufinfo * bufinfo,const char ** dest,const uint8_t * src,unsigned int flags)610 size_t req_pull_ascii4(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, unsigned int flags)
611 {
612 	ssize_t ret;
613 
614 	if (PTR_DIFF(src, bufinfo->data) + 1 > bufinfo->data_size) {
615 		/* win2000 treats this as the empty string! */
616 		(*dest) = talloc_strdup(bufinfo->mem_ctx, "");
617 		return 0;
618 	}
619 
620 	/* this consumes the 0x4 byte. We don't check whether the byte
621 	   is actually 0x4 or not. This matches win2000 server
622 	   behaviour */
623 	src++;
624 
625 	ret = req_pull_string(bufinfo, dest, src, -1, flags);
626 	if (ret == -1) {
627 		(*dest) = talloc_strdup(bufinfo->mem_ctx, "");
628 		return 1;
629 	}
630 
631 	return ret + 1;
632 }
633 
634 /**
635   pull a DATA_BLOB from a request packet, returning a talloced blob
636 
637   return false if any part is outside the data portion of the packet
638 */
req_pull_blob(struct request_bufinfo * bufinfo,const uint8_t * src,int len,DATA_BLOB * blob)639 bool req_pull_blob(struct request_bufinfo *bufinfo, const uint8_t *src, int len, DATA_BLOB *blob)
640 {
641 	if (len != 0 && req_data_oob(bufinfo, src, len)) {
642 		return false;
643 	}
644 
645 	(*blob) = data_blob_talloc(bufinfo->mem_ctx, src, len);
646 
647 	return true;
648 }
649 
650 /* check that a lump of data in a request is within the bounds of the data section of
651    the packet */
req_data_oob(struct request_bufinfo * bufinfo,const uint8_t * ptr,uint32_t count)652 bool req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count)
653 {
654 	if (count == 0) {
655 		return false;
656 	}
657 
658 	/* be careful with wraparound! */
659 	if ((uintptr_t)ptr < (uintptr_t)bufinfo->data ||
660 	    (uintptr_t)ptr >= (uintptr_t)bufinfo->data + bufinfo->data_size ||
661 	    count > bufinfo->data_size ||
662 	    (uintptr_t)ptr + count > (uintptr_t)bufinfo->data + bufinfo->data_size) {
663 		return true;
664 	}
665 	return false;
666 }
667 
668 
669 /*
670    pull an open file handle from a packet, taking account of the chained_fnum
671 */
req_fnum(struct smbsrv_request * req,const uint8_t * base,unsigned int offset)672 static uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, unsigned int offset)
673 {
674 	if (req->chained_fnum != -1) {
675 		return req->chained_fnum;
676 	}
677 	return SVAL(base, offset);
678 }
679 
smbsrv_pull_fnum(struct smbsrv_request * req,const uint8_t * base,unsigned int offset)680 struct ntvfs_handle *smbsrv_pull_fnum(struct smbsrv_request *req, const uint8_t *base, unsigned int offset)
681 {
682 	struct smbsrv_handle *handle;
683 	uint16_t fnum = req_fnum(req, base, offset);
684 
685 	handle = smbsrv_smb_handle_find(req->tcon, fnum, req->request_time);
686 	if (!handle) {
687 		return NULL;
688 	}
689 
690 	/*
691 	 * For SMB tcons and sessions can be mixed!
692 	 * But we need to make sure that file handles
693 	 * are only accessed by the opening session!
694 	 *
695 	 * So check if the handle is valid for the given session!
696 	 */
697 	if (handle->session != req->session) {
698 		return NULL;
699 	}
700 
701 	return handle->ntvfs;
702 }
703 
smbsrv_push_fnum(uint8_t * base,unsigned int offset,struct ntvfs_handle * ntvfs)704 void smbsrv_push_fnum(uint8_t *base, unsigned int offset, struct ntvfs_handle *ntvfs)
705 {
706 	struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
707 				       struct smbsrv_handle);
708 	SSVAL(base, offset, handle->hid);
709 }
710 
smbsrv_handle_create_new(void * private_data,struct ntvfs_request * ntvfs,struct ntvfs_handle ** _h)711 NTSTATUS smbsrv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h)
712 {
713 	struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
714 				     struct smbsrv_request);
715 	struct smbsrv_handle *handle;
716 	struct ntvfs_handle *h;
717 
718 	handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time);
719 	if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
720 
721 	h = talloc_zero(handle, struct ntvfs_handle);
722 	if (!h) goto nomem;
723 
724 	/*
725 	 * note: we don't set handle->ntvfs yet,
726 	 *       this will be done by smbsrv_handle_make_valid()
727 	 *       this makes sure the handle is invalid for clients
728 	 *       until the ntvfs subsystem has made it valid
729 	 */
730 	h->ctx		= ntvfs->ctx;
731 	h->session_info	= ntvfs->session_info;
732 	h->smbpid	= ntvfs->smbpid;
733 
734 	h->frontend_data.private_data = handle;
735 
736 	*_h = h;
737 	return NT_STATUS_OK;
738 nomem:
739 	talloc_free(handle);
740 	return NT_STATUS_NO_MEMORY;
741 }
742 
smbsrv_handle_make_valid(void * private_data,struct ntvfs_handle * h)743 NTSTATUS smbsrv_handle_make_valid(void *private_data, struct ntvfs_handle *h)
744 {
745 	struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon);
746 	struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
747 						       struct smbsrv_handle);
748 	/* this tells the frontend that the handle is valid */
749 	handle->ntvfs = h;
750 	/* this moves the smbsrv_request to the smbsrv_tcon memory context */
751 	talloc_steal(tcon, handle);
752 	return NT_STATUS_OK;
753 }
754 
smbsrv_handle_destroy(void * private_data,struct ntvfs_handle * h)755 void smbsrv_handle_destroy(void *private_data, struct ntvfs_handle *h)
756 {
757 	struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
758 						       struct smbsrv_handle);
759 	talloc_free(handle);
760 }
761 
smbsrv_handle_search_by_wire_key(void * private_data,struct ntvfs_request * ntvfs,const DATA_BLOB * key)762 struct ntvfs_handle *smbsrv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key)
763 {
764 	struct smbsrv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
765 				     struct smbsrv_request);
766 
767 	if (key->length != 2) return NULL;
768 
769 	return smbsrv_pull_fnum(req, key->data, 0);
770 }
771 
smbsrv_handle_get_wire_key(void * private_data,struct ntvfs_handle * handle,TALLOC_CTX * mem_ctx)772 DATA_BLOB smbsrv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx)
773 {
774 	uint8_t key[2];
775 
776 	smbsrv_push_fnum(key, 0, handle);
777 
778 	return data_blob_talloc(mem_ctx, key, sizeof(key));
779 }
780