1255767Sdes/* $OpenBSD: bufaux.c,v 1.52 2013/07/12 00:19:58 djm Exp $ */
257429Smarkm/*
357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi>
457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
557429Smarkm *                    All rights reserved
657429Smarkm * Auxiliary functions for storing and retrieving various data types to/from
757429Smarkm * Buffers.
857429Smarkm *
965674Skris * As far as I am concerned, the code I have written for this software
1065674Skris * can be used freely for any purpose.  Any derived versions of this
1165674Skris * software must be clearly marked as such, and if the derived work is
1265674Skris * incompatible with the protocol description in the RFC file, it must be
1365674Skris * called by a name other than "ssh" or "Secure Shell".
1465674Skris *
1565674Skris *
1660576Skris * SSH2 packet format added by Markus Friedl
1765674Skris * Copyright (c) 2000 Markus Friedl.  All rights reserved.
1860576Skris *
1965674Skris * Redistribution and use in source and binary forms, with or without
2065674Skris * modification, are permitted provided that the following conditions
2165674Skris * are met:
2265674Skris * 1. Redistributions of source code must retain the above copyright
2365674Skris *    notice, this list of conditions and the following disclaimer.
2465674Skris * 2. Redistributions in binary form must reproduce the above copyright
2565674Skris *    notice, this list of conditions and the following disclaimer in the
2665674Skris *    documentation and/or other materials provided with the distribution.
2765674Skris *
2865674Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2965674Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
3065674Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
3165674Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
3265674Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
3365674Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3465674Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3565674Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3665674Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3765674Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3857429Smarkm */
3957429Smarkm
4057429Smarkm#include "includes.h"
4157429Smarkm
42162856Sdes#include <sys/types.h>
43162856Sdes
4457464Sgreen#include <openssl/bn.h>
45162856Sdes
46162856Sdes#include <string.h>
47162856Sdes#include <stdarg.h>
48162856Sdes
4957429Smarkm#include "xmalloc.h"
50162856Sdes#include "buffer.h"
5176262Sgreen#include "log.h"
52162856Sdes#include "misc.h"
5357429Smarkm
5457429Smarkm/*
5598684Sdes * Returns integers from the buffer (msb first).
5657429Smarkm */
5798684Sdes
58147005Sdesint
59147005Sdesbuffer_get_short_ret(u_short *ret, Buffer *buffer)
60147005Sdes{
61147005Sdes	u_char buf[2];
62147005Sdes
63147005Sdes	if (buffer_get_ret(buffer, (char *) buf, 2) == -1)
64147005Sdes		return (-1);
65162856Sdes	*ret = get_u16(buf);
66147005Sdes	return (0);
67147005Sdes}
68147005Sdes
6998684Sdesu_short
7098684Sdesbuffer_get_short(Buffer *buffer)
7198684Sdes{
72147005Sdes	u_short ret;
7399063Sdes
74147005Sdes	if (buffer_get_short_ret(&ret, buffer) == -1)
75147005Sdes		fatal("buffer_get_short: buffer error");
76147005Sdes
77147005Sdes	return (ret);
7898684Sdes}
7998684Sdes
80147005Sdesint
81147005Sdesbuffer_get_int_ret(u_int *ret, Buffer *buffer)
82147005Sdes{
83147005Sdes	u_char buf[4];
84147005Sdes
85147005Sdes	if (buffer_get_ret(buffer, (char *) buf, 4) == -1)
86147005Sdes		return (-1);
87215116Sdes	if (ret != NULL)
88215116Sdes		*ret = get_u32(buf);
89147005Sdes	return (0);
90147005Sdes}
91147005Sdes
9276262Sgreenu_int
9357429Smarkmbuffer_get_int(Buffer *buffer)
9457429Smarkm{
95147005Sdes	u_int ret;
9699063Sdes
97147005Sdes	if (buffer_get_int_ret(&ret, buffer) == -1)
98147005Sdes		fatal("buffer_get_int: buffer error");
99147005Sdes
100147005Sdes	return (ret);
10157429Smarkm}
10257429Smarkm
103147005Sdesint
104147005Sdesbuffer_get_int64_ret(u_int64_t *ret, Buffer *buffer)
105147005Sdes{
106147005Sdes	u_char buf[8];
107147005Sdes
108147005Sdes	if (buffer_get_ret(buffer, (char *) buf, 8) == -1)
109147005Sdes		return (-1);
110215116Sdes	if (ret != NULL)
111215116Sdes		*ret = get_u64(buf);
112147005Sdes	return (0);
113147005Sdes}
114147005Sdes
11576262Sgreenu_int64_t
11676262Sgreenbuffer_get_int64(Buffer *buffer)
11776262Sgreen{
118147005Sdes	u_int64_t ret;
11999063Sdes
120147005Sdes	if (buffer_get_int64_ret(&ret, buffer) == -1)
121147005Sdes		fatal("buffer_get_int: buffer error");
122147005Sdes
123147005Sdes	return (ret);
12476262Sgreen}
12576262Sgreen
12657429Smarkm/*
12798684Sdes * Stores integers in the buffer, msb first.
12857429Smarkm */
12960576Skrisvoid
13098684Sdesbuffer_put_short(Buffer *buffer, u_short value)
13198684Sdes{
13298684Sdes	char buf[2];
13399063Sdes
134162856Sdes	put_u16(buf, value);
13598684Sdes	buffer_append(buffer, buf, 2);
13698684Sdes}
13798684Sdes
13898684Sdesvoid
13976262Sgreenbuffer_put_int(Buffer *buffer, u_int value)
14057429Smarkm{
14157429Smarkm	char buf[4];
14299063Sdes
143162856Sdes	put_u32(buf, value);
14457429Smarkm	buffer_append(buffer, buf, 4);
14557429Smarkm}
14657429Smarkm
14776262Sgreenvoid
14876262Sgreenbuffer_put_int64(Buffer *buffer, u_int64_t value)
14976262Sgreen{
15076262Sgreen	char buf[8];
15199063Sdes
152162856Sdes	put_u64(buf, value);
15376262Sgreen	buffer_append(buffer, buf, 8);
15476262Sgreen}
15576262Sgreen
15657429Smarkm/*
15757429Smarkm * Returns an arbitrary binary string from the buffer.  The string cannot
15857429Smarkm * be longer than 256k.  The returned value points to memory allocated
15957429Smarkm * with xmalloc; it is the responsibility of the calling function to free
16057429Smarkm * the data.  If length_ptr is non-NULL, the length of the returned data
16157429Smarkm * will be stored there.  A null character will be automatically appended
16257429Smarkm * to the returned string, and is not counted in length.
16357429Smarkm */
16492559Sdesvoid *
165147005Sdesbuffer_get_string_ret(Buffer *buffer, u_int *length_ptr)
16657429Smarkm{
16799063Sdes	u_char *value;
16876262Sgreen	u_int len;
16999063Sdes
17057429Smarkm	/* Get the length. */
171204917Sdes	if (buffer_get_int_ret(&len, buffer) != 0) {
172204917Sdes		error("buffer_get_string_ret: cannot extract length");
173204917Sdes		return (NULL);
174204917Sdes	}
175147005Sdes	if (len > 256 * 1024) {
176147005Sdes		error("buffer_get_string_ret: bad string length %u", len);
177147005Sdes		return (NULL);
178147005Sdes	}
17957429Smarkm	/* Allocate space for the string.  Add one byte for a null character. */
18057429Smarkm	value = xmalloc(len + 1);
18157429Smarkm	/* Get the string. */
182147005Sdes	if (buffer_get_ret(buffer, value, len) == -1) {
183147005Sdes		error("buffer_get_string_ret: buffer_get failed");
184255767Sdes		free(value);
185147005Sdes		return (NULL);
186147005Sdes	}
18757429Smarkm	/* Append a null character to make processing easier. */
188181111Sdes	value[len] = '\0';
18957429Smarkm	/* Optionally return the length of the string. */
19057429Smarkm	if (length_ptr)
19157429Smarkm		*length_ptr = len;
192147005Sdes	return (value);
19357429Smarkm}
19457429Smarkm
195147005Sdesvoid *
196147005Sdesbuffer_get_string(Buffer *buffer, u_int *length_ptr)
197147005Sdes{
198147005Sdes	void *ret;
199147005Sdes
200147005Sdes	if ((ret = buffer_get_string_ret(buffer, length_ptr)) == NULL)
201147005Sdes		fatal("buffer_get_string: buffer error");
202147005Sdes	return (ret);
203147005Sdes}
204147005Sdes
205221420Sdeschar *
206221420Sdesbuffer_get_cstring_ret(Buffer *buffer, u_int *length_ptr)
207221420Sdes{
208221420Sdes	u_int length;
209221420Sdes	char *cp, *ret = buffer_get_string_ret(buffer, &length);
210221420Sdes
211221420Sdes	if (ret == NULL)
212221420Sdes		return NULL;
213221420Sdes	if ((cp = memchr(ret, '\0', length)) != NULL) {
214221420Sdes		/* XXX allow \0 at end-of-string for a while, remove later */
215221420Sdes		if (cp == ret + length - 1)
216221420Sdes			error("buffer_get_cstring_ret: string contains \\0");
217221420Sdes		else {
218221420Sdes			bzero(ret, length);
219255767Sdes			free(ret);
220221420Sdes			return NULL;
221221420Sdes		}
222221420Sdes	}
223221420Sdes	if (length_ptr != NULL)
224221420Sdes		*length_ptr = length;
225221420Sdes	return ret;
226221420Sdes}
227221420Sdes
228221420Sdeschar *
229221420Sdesbuffer_get_cstring(Buffer *buffer, u_int *length_ptr)
230221420Sdes{
231221420Sdes	char *ret;
232221420Sdes
233221420Sdes	if ((ret = buffer_get_cstring_ret(buffer, length_ptr)) == NULL)
234221420Sdes		fatal("buffer_get_cstring: buffer error");
235221420Sdes	return ret;
236221420Sdes}
237221420Sdes
238181111Sdesvoid *
239204917Sdesbuffer_get_string_ptr_ret(Buffer *buffer, u_int *length_ptr)
240181111Sdes{
241181111Sdes	void *ptr;
242181111Sdes	u_int len;
243181111Sdes
244204917Sdes	if (buffer_get_int_ret(&len, buffer) != 0)
245204917Sdes		return NULL;
246204917Sdes	if (len > 256 * 1024) {
247204917Sdes		error("buffer_get_string_ptr: bad string length %u", len);
248204917Sdes		return NULL;
249204917Sdes	}
250181111Sdes	ptr = buffer_ptr(buffer);
251181111Sdes	buffer_consume(buffer, len);
252181111Sdes	if (length_ptr)
253181111Sdes		*length_ptr = len;
254181111Sdes	return (ptr);
255181111Sdes}
256181111Sdes
257204917Sdesvoid *
258204917Sdesbuffer_get_string_ptr(Buffer *buffer, u_int *length_ptr)
259204917Sdes{
260204917Sdes	void *ret;
261204917Sdes
262204917Sdes	if ((ret = buffer_get_string_ptr_ret(buffer, length_ptr)) == NULL)
263204917Sdes		fatal("buffer_get_string_ptr: buffer error");
264204917Sdes	return (ret);
265204917Sdes}
266204917Sdes
26757429Smarkm/*
26857429Smarkm * Stores and arbitrary binary string in the buffer.
26957429Smarkm */
27060576Skrisvoid
27176262Sgreenbuffer_put_string(Buffer *buffer, const void *buf, u_int len)
27257429Smarkm{
27357429Smarkm	buffer_put_int(buffer, len);
27457429Smarkm	buffer_append(buffer, buf, len);
27557429Smarkm}
27660576Skrisvoid
27760576Skrisbuffer_put_cstring(Buffer *buffer, const char *s)
27860576Skris{
27998684Sdes	if (s == NULL)
28098684Sdes		fatal("buffer_put_cstring: s == NULL");
28160576Skris	buffer_put_string(buffer, s, strlen(s));
28260576Skris}
28357429Smarkm
28457429Smarkm/*
28557429Smarkm * Returns a character from the buffer (0 - 255).
28657429Smarkm */
28760576Skrisint
288255767Sdesbuffer_get_char_ret(u_char *ret, Buffer *buffer)
289147005Sdes{
290147005Sdes	if (buffer_get_ret(buffer, ret, 1) == -1) {
291147005Sdes		error("buffer_get_char_ret: buffer_get_ret failed");
292147005Sdes		return (-1);
293147005Sdes	}
294147005Sdes	return (0);
295147005Sdes}
296147005Sdes
297147005Sdesint
29857429Smarkmbuffer_get_char(Buffer *buffer)
29957429Smarkm{
300255767Sdes	u_char ch;
30199063Sdes
302147005Sdes	if (buffer_get_char_ret(&ch, buffer) == -1)
303147005Sdes		fatal("buffer_get_char: buffer error");
304255767Sdes	return ch;
30557429Smarkm}
30657429Smarkm
30757429Smarkm/*
30857429Smarkm * Stores a character in the buffer.
30957429Smarkm */
31060576Skrisvoid
31157429Smarkmbuffer_put_char(Buffer *buffer, int value)
31257429Smarkm{
31357429Smarkm	char ch = value;
31499063Sdes
31557429Smarkm	buffer_append(buffer, &ch, 1);
31657429Smarkm}
317