10Sstevel@tonic-gate /*
2*2757Sjp161948  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate /*
60Sstevel@tonic-gate  * Author: Tatu Ylonen <ylo@cs.hut.fi>
70Sstevel@tonic-gate  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
80Sstevel@tonic-gate  *                    All rights reserved
90Sstevel@tonic-gate  * Auxiliary functions for storing and retrieving various data types to/from
100Sstevel@tonic-gate  * Buffers.
110Sstevel@tonic-gate  *
120Sstevel@tonic-gate  * As far as I am concerned, the code I have written for this software
130Sstevel@tonic-gate  * can be used freely for any purpose.  Any derived versions of this
140Sstevel@tonic-gate  * software must be clearly marked as such, and if the derived work is
150Sstevel@tonic-gate  * incompatible with the protocol description in the RFC file, it must be
160Sstevel@tonic-gate  * called by a name other than "ssh" or "Secure Shell".
170Sstevel@tonic-gate  *
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * SSH2 packet format added by Markus Friedl
200Sstevel@tonic-gate  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
210Sstevel@tonic-gate  *
220Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
230Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
240Sstevel@tonic-gate  * are met:
250Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
260Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
270Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
280Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
290Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
300Sstevel@tonic-gate  *
310Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
320Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
330Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
340Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
350Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
360Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
370Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
380Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
390Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
400Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
410Sstevel@tonic-gate  */
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include "includes.h"
440Sstevel@tonic-gate RCSID("$OpenBSD: bufaux.c,v 1.27 2002/06/26 08:53:12 markus Exp $");
450Sstevel@tonic-gate 
460Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #include <langinfo.h>
490Sstevel@tonic-gate #include <openssl/bn.h>
500Sstevel@tonic-gate #include "bufaux.h"
510Sstevel@tonic-gate #include "xmalloc.h"
520Sstevel@tonic-gate #include "getput.h"
530Sstevel@tonic-gate #include "log.h"
540Sstevel@tonic-gate #include "g11n.h"
550Sstevel@tonic-gate 
560Sstevel@tonic-gate /*
570Sstevel@tonic-gate  * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
580Sstevel@tonic-gate  * by (bits+7)/8 bytes of binary data, msb first.
590Sstevel@tonic-gate  */
60*2757Sjp161948 int
61*2757Sjp161948 buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value)
620Sstevel@tonic-gate {
630Sstevel@tonic-gate 	int bits = BN_num_bits(value);
640Sstevel@tonic-gate 	int bin_size = (bits + 7) / 8;
650Sstevel@tonic-gate 	u_char *buf = xmalloc(bin_size);
660Sstevel@tonic-gate 	int oi;
670Sstevel@tonic-gate 	char msg[2];
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	/* Get the value of in binary */
700Sstevel@tonic-gate 	oi = BN_bn2bin(value, buf);
71*2757Sjp161948 	if (oi != bin_size) {
72*2757Sjp161948 		error("buffer_put_bignum_ret: BN_bn2bin() failed: oi %d != bin_size %d",
730Sstevel@tonic-gate 		    oi, bin_size);
74*2757Sjp161948 		xfree(buf);
75*2757Sjp161948 		return (-1);
76*2757Sjp161948 	}
770Sstevel@tonic-gate 
780Sstevel@tonic-gate 	/* Store the number of bits in the buffer in two bytes, msb first. */
790Sstevel@tonic-gate 	PUT_16BIT(msg, bits);
800Sstevel@tonic-gate 	buffer_append(buffer, msg, 2);
810Sstevel@tonic-gate 	/* Store the binary data. */
820Sstevel@tonic-gate 	buffer_append(buffer, (char *)buf, oi);
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 	memset(buf, 0, bin_size);
850Sstevel@tonic-gate 	xfree(buf);
86*2757Sjp161948 
87*2757Sjp161948 	return (0);
88*2757Sjp161948 }
89*2757Sjp161948 
90*2757Sjp161948 void
91*2757Sjp161948 buffer_put_bignum(Buffer *buffer, const BIGNUM *value)
92*2757Sjp161948 {
93*2757Sjp161948 	if (buffer_put_bignum_ret(buffer, value) == -1)
94*2757Sjp161948 		fatal("buffer_put_bignum: buffer error");
950Sstevel@tonic-gate }
960Sstevel@tonic-gate 
970Sstevel@tonic-gate /*
980Sstevel@tonic-gate  * Retrieves an BIGNUM from the buffer.
990Sstevel@tonic-gate  */
100*2757Sjp161948 int
101*2757Sjp161948 buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value)
1020Sstevel@tonic-gate {
103*2757Sjp161948 	u_int bits, bytes;
1040Sstevel@tonic-gate 	u_char buf[2], *bin;
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 	/* Get the number for bits. */
107*2757Sjp161948 	if (buffer_get_ret(buffer, (char *) buf, 2) == -1) {
108*2757Sjp161948 		error("buffer_get_bignum_ret: invalid length");
109*2757Sjp161948 		return (-1);
110*2757Sjp161948 	}
1110Sstevel@tonic-gate 	bits = GET_16BIT(buf);
1120Sstevel@tonic-gate 	/* Compute the number of binary bytes that follow. */
1130Sstevel@tonic-gate 	bytes = (bits + 7) / 8;
114*2757Sjp161948 	if (bytes > 8 * 1024) {
115*2757Sjp161948 		error("buffer_get_bignum_ret: cannot handle BN of size %d", bytes);
116*2757Sjp161948 		return (-1);
117*2757Sjp161948 	}
118*2757Sjp161948 	if (buffer_len(buffer) < bytes) {
119*2757Sjp161948 		error("buffer_get_bignum_ret: input buffer too small");
120*2757Sjp161948 		return (-1);
121*2757Sjp161948 	}
1220Sstevel@tonic-gate 	bin = buffer_ptr(buffer);
1230Sstevel@tonic-gate 	BN_bin2bn(bin, bytes, value);
124*2757Sjp161948 	if (buffer_consume_ret(buffer, bytes) == -1) {
125*2757Sjp161948 		error("buffer_get_bignum_ret: buffer_consume failed");
126*2757Sjp161948 		return (-1);
127*2757Sjp161948 	}
128*2757Sjp161948 	return (0);
129*2757Sjp161948 }
130*2757Sjp161948 
131*2757Sjp161948 void
132*2757Sjp161948 buffer_get_bignum(Buffer *buffer, BIGNUM *value)
133*2757Sjp161948 {
134*2757Sjp161948 	if (buffer_get_bignum_ret(buffer, value) == -1)
135*2757Sjp161948 		fatal("buffer_get_bignum: buffer error");
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate /*
1390Sstevel@tonic-gate  * Stores an BIGNUM in the buffer in SSH2 format.
1400Sstevel@tonic-gate  */
141*2757Sjp161948 int
142*2757Sjp161948 buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value)
1430Sstevel@tonic-gate {
144*2757Sjp161948 	u_int bytes;
145*2757Sjp161948 	u_char *buf;
1460Sstevel@tonic-gate 	int oi;
147*2757Sjp161948 	u_int hasnohigh = 0;
1480Sstevel@tonic-gate 
149*2757Sjp161948 	if (BN_is_zero(value)) {
150*2757Sjp161948 		buffer_put_int(buffer, 0);
151*2757Sjp161948 		return 0;
152*2757Sjp161948 	}
153*2757Sjp161948 	if (value->neg) {
154*2757Sjp161948 		error("buffer_put_bignum2_ret: negative numbers not supported");
155*2757Sjp161948 		return (-1);
156*2757Sjp161948 	}
157*2757Sjp161948 	bytes = BN_num_bytes(value) + 1; /* extra padding byte */
158*2757Sjp161948 	if (bytes < 2) {
159*2757Sjp161948 		error("buffer_put_bignum2_ret: BN too small");
160*2757Sjp161948 		return (-1);
161*2757Sjp161948 	}
162*2757Sjp161948 	buf = xmalloc(bytes);
163*2757Sjp161948 	buf[0] = 0x00;
1640Sstevel@tonic-gate 	/* Get the value of in binary */
1650Sstevel@tonic-gate 	oi = BN_bn2bin(value, buf+1);
166*2757Sjp161948 	if (oi < 0 || (u_int)oi != bytes - 1) {
167*2757Sjp161948 		error("buffer_put_bignum2_ret: BN_bn2bin() failed: "
168*2757Sjp161948 		    "oi %d != bin_size %d", oi, bytes);
169*2757Sjp161948 		xfree(buf);
170*2757Sjp161948 		return (-1);
171*2757Sjp161948 	}
1720Sstevel@tonic-gate 	hasnohigh = (buf[1] & 0x80) ? 0 : 1;
1730Sstevel@tonic-gate 	buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh);
1740Sstevel@tonic-gate 	memset(buf, 0, bytes);
1750Sstevel@tonic-gate 	xfree(buf);
176*2757Sjp161948 	return (0);
177*2757Sjp161948 }
178*2757Sjp161948 
179*2757Sjp161948 void
180*2757Sjp161948 buffer_put_bignum2(Buffer *buffer, const BIGNUM *value)
181*2757Sjp161948 {
182*2757Sjp161948 	if (buffer_put_bignum2_ret(buffer, value) == -1)
183*2757Sjp161948 		fatal("buffer_put_bignum2: buffer error");
1840Sstevel@tonic-gate }
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate /* XXX does not handle negative BNs */
187*2757Sjp161948 int
188*2757Sjp161948 buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value)
189*2757Sjp161948 {
190*2757Sjp161948 	u_int len;
191*2757Sjp161948 	u_char *bin;
192*2757Sjp161948 
193*2757Sjp161948 	if ((bin = buffer_get_string_ret(buffer, &len)) == NULL) {
194*2757Sjp161948 		error("buffer_get_bignum2_ret: invalid bignum");
195*2757Sjp161948 		return (-1);
196*2757Sjp161948 	}
197*2757Sjp161948 
198*2757Sjp161948 	if (len > 0 && (bin[0] & 0x80)) {
199*2757Sjp161948 		error("buffer_get_bignum2_ret: negative numbers not supported");
200*2757Sjp161948 		xfree(bin);
201*2757Sjp161948 		return (-1);
202*2757Sjp161948 	}
203*2757Sjp161948 	if (len > 8 * 1024) {
204*2757Sjp161948 		error("buffer_get_bignum2_ret: cannot handle BN of size %d", len);
205*2757Sjp161948 		xfree(bin);
206*2757Sjp161948 		return (-1);
207*2757Sjp161948 	}
208*2757Sjp161948 	BN_bin2bn(bin, len, value);
209*2757Sjp161948 	xfree(bin);
210*2757Sjp161948 	return (0);
211*2757Sjp161948 }
212*2757Sjp161948 
2130Sstevel@tonic-gate void
2140Sstevel@tonic-gate buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
2150Sstevel@tonic-gate {
216*2757Sjp161948 	if (buffer_get_bignum2_ret(buffer, value) == -1)
217*2757Sjp161948 		fatal("buffer_get_bignum2: buffer error");
218*2757Sjp161948 }
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate /*
2210Sstevel@tonic-gate  * Returns integers from the buffer (msb first).
2220Sstevel@tonic-gate  */
2230Sstevel@tonic-gate 
224*2757Sjp161948 int
225*2757Sjp161948 buffer_get_short_ret(u_short *ret, Buffer *buffer)
226*2757Sjp161948 {
227*2757Sjp161948 	u_char buf[2];
228*2757Sjp161948 
229*2757Sjp161948 	if (buffer_get_ret(buffer, (char *) buf, 2) == -1)
230*2757Sjp161948 		return (-1);
231*2757Sjp161948 	*ret = GET_16BIT(buf);
232*2757Sjp161948 	return (0);
233*2757Sjp161948 }
234*2757Sjp161948 
2350Sstevel@tonic-gate u_short
2360Sstevel@tonic-gate buffer_get_short(Buffer *buffer)
2370Sstevel@tonic-gate {
238*2757Sjp161948 	u_short ret;
239*2757Sjp161948 
240*2757Sjp161948 	if (buffer_get_short_ret(&ret, buffer) == -1)
241*2757Sjp161948 		fatal("buffer_get_short: buffer error");
242*2757Sjp161948 
243*2757Sjp161948 	return (ret);
244*2757Sjp161948 }
2450Sstevel@tonic-gate 
246*2757Sjp161948 int
247*2757Sjp161948 buffer_get_int_ret(u_int *ret, Buffer *buffer)
248*2757Sjp161948 {
249*2757Sjp161948 	u_char buf[4];
250*2757Sjp161948 
251*2757Sjp161948 	if (buffer_get_ret(buffer, (char *) buf, 4) == -1)
252*2757Sjp161948 		return (-1);
253*2757Sjp161948 	*ret = GET_32BIT(buf);
254*2757Sjp161948 	return (0);
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate u_int
2580Sstevel@tonic-gate buffer_get_int(Buffer *buffer)
2590Sstevel@tonic-gate {
260*2757Sjp161948 	u_int ret;
2610Sstevel@tonic-gate 
262*2757Sjp161948 	if (buffer_get_int_ret(&ret, buffer) == -1)
263*2757Sjp161948 		fatal("buffer_get_int: buffer error");
264*2757Sjp161948 
265*2757Sjp161948 	return (ret);
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate #ifdef HAVE_U_INT64_T
269*2757Sjp161948 int
270*2757Sjp161948 buffer_get_int64_ret(u_int64_t *ret, Buffer *buffer)
271*2757Sjp161948 {
272*2757Sjp161948 	u_char buf[8];
273*2757Sjp161948 
274*2757Sjp161948 	if (buffer_get_ret(buffer, (char *) buf, 8) == -1)
275*2757Sjp161948 		return (-1);
276*2757Sjp161948 	*ret = GET_64BIT(buf);
277*2757Sjp161948 	return (0);
278*2757Sjp161948 }
279*2757Sjp161948 
2800Sstevel@tonic-gate u_int64_t
2810Sstevel@tonic-gate buffer_get_int64(Buffer *buffer)
2820Sstevel@tonic-gate {
283*2757Sjp161948 	u_int64_t ret;
2840Sstevel@tonic-gate 
285*2757Sjp161948 	if (buffer_get_int64_ret(&ret, buffer) == -1)
286*2757Sjp161948 		fatal("buffer_get_int: buffer error");
287*2757Sjp161948 
288*2757Sjp161948 	return (ret);
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate #endif
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate /*
2930Sstevel@tonic-gate  * Stores integers in the buffer, msb first.
2940Sstevel@tonic-gate  */
2950Sstevel@tonic-gate void
2960Sstevel@tonic-gate buffer_put_short(Buffer *buffer, u_short value)
2970Sstevel@tonic-gate {
2980Sstevel@tonic-gate 	char buf[2];
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	PUT_16BIT(buf, value);
3010Sstevel@tonic-gate 	buffer_append(buffer, buf, 2);
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate void
3050Sstevel@tonic-gate buffer_put_int(Buffer *buffer, u_int value)
3060Sstevel@tonic-gate {
3070Sstevel@tonic-gate 	char buf[4];
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	PUT_32BIT(buf, value);
3100Sstevel@tonic-gate 	buffer_append(buffer, buf, 4);
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate #ifdef HAVE_U_INT64_T
3140Sstevel@tonic-gate void
3150Sstevel@tonic-gate buffer_put_int64(Buffer *buffer, u_int64_t value)
3160Sstevel@tonic-gate {
3170Sstevel@tonic-gate 	char buf[8];
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	PUT_64BIT(buf, value);
3200Sstevel@tonic-gate 	buffer_append(buffer, buf, 8);
3210Sstevel@tonic-gate }
3220Sstevel@tonic-gate #endif
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate /*
3250Sstevel@tonic-gate  * Returns an arbitrary binary string from the buffer.  The string cannot
3260Sstevel@tonic-gate  * be longer than 256k.  The returned value points to memory allocated
3270Sstevel@tonic-gate  * with xmalloc; it is the responsibility of the calling function to free
3280Sstevel@tonic-gate  * the data.  If length_ptr is non-NULL, the length of the returned data
3290Sstevel@tonic-gate  * will be stored there.  A null character will be automatically appended
3300Sstevel@tonic-gate  * to the returned string, and is not counted in length.
3310Sstevel@tonic-gate  */
3320Sstevel@tonic-gate void *
333*2757Sjp161948 buffer_get_string_ret(Buffer *buffer, u_int *length_ptr)
3340Sstevel@tonic-gate {
3350Sstevel@tonic-gate 	u_char *value;
3360Sstevel@tonic-gate 	u_int len;
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	/* Get the length. */
3390Sstevel@tonic-gate 	len = buffer_get_int(buffer);
340*2757Sjp161948 	if (len > 256 * 1024) {
341*2757Sjp161948 		error("buffer_get_string_ret: bad string length %u", len);
342*2757Sjp161948 		return (NULL);
343*2757Sjp161948 	}
3440Sstevel@tonic-gate 	/* Allocate space for the string.  Add one byte for a null character. */
3450Sstevel@tonic-gate 	value = xmalloc(len + 1);
3460Sstevel@tonic-gate 	/* Get the string. */
347*2757Sjp161948 	if (buffer_get_ret(buffer, value, len) == -1) {
348*2757Sjp161948 		error("buffer_get_string_ret: buffer_get failed");
349*2757Sjp161948 		xfree(value);
350*2757Sjp161948 		return (NULL);
351*2757Sjp161948 	}
3520Sstevel@tonic-gate 	/* Append a null character to make processing easier. */
3530Sstevel@tonic-gate 	value[len] = 0;
3540Sstevel@tonic-gate 	/* Optionally return the length of the string. */
3550Sstevel@tonic-gate 	if (length_ptr)
3560Sstevel@tonic-gate 		*length_ptr = len;
357*2757Sjp161948 	return (value);
3580Sstevel@tonic-gate }
359*2757Sjp161948 
360*2757Sjp161948 void *
361*2757Sjp161948 buffer_get_string(Buffer *buffer, u_int *length_ptr)
362*2757Sjp161948 {
363*2757Sjp161948 	void *ret;
364*2757Sjp161948 
365*2757Sjp161948 	if ((ret = buffer_get_string_ret(buffer, length_ptr)) == NULL)
366*2757Sjp161948 		fatal("buffer_get_string: buffer error");
367*2757Sjp161948 	return (ret);
368*2757Sjp161948 }
369*2757Sjp161948 
3700Sstevel@tonic-gate char *
3710Sstevel@tonic-gate buffer_get_ascii_cstring(Buffer *buffer)
3720Sstevel@tonic-gate {
3730Sstevel@tonic-gate 	char *value;
3740Sstevel@tonic-gate 	u_char *p;
3750Sstevel@tonic-gate 	u_int len;
3760Sstevel@tonic-gate 	value = buffer_get_string(buffer, &len);
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	/* Look for NULL or high-bit set bytes */
3790Sstevel@tonic-gate 	for (p = (u_char *) value ;
3800Sstevel@tonic-gate 	     p && *p && (!(*p & 0x80)) && (p - (u_char *) value) < len ;
3810Sstevel@tonic-gate 	     p++) ;
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	/* If there were any, bomb */
3840Sstevel@tonic-gate 	if ((p - (u_char *) value) != len) {
3850Sstevel@tonic-gate 	    xfree(value);
3860Sstevel@tonic-gate 	    errno = EILSEQ;
3870Sstevel@tonic-gate 	    return NULL;
3880Sstevel@tonic-gate 	}
3890Sstevel@tonic-gate 	return value;
3900Sstevel@tonic-gate }
3910Sstevel@tonic-gate u_char *
3920Sstevel@tonic-gate buffer_get_utf8_cstring(Buffer *buffer)
3930Sstevel@tonic-gate {
3940Sstevel@tonic-gate 	u_char	*value, *converted, *estr;
3950Sstevel@tonic-gate 	u_int	len;
3960Sstevel@tonic-gate 	int	err;
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	if ((value = buffer_get_string(buffer, &len)) == NULL) {
3990Sstevel@tonic-gate 		return value;
4000Sstevel@tonic-gate 	}
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	converted = g11n_convert_from_utf8(value, &err, &estr);
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	if (converted != value) xfree(value);
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	if (err)
4070Sstevel@tonic-gate 	    fatal("invalid UTF-8 sequence; %s", estr);
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	return converted;
4100Sstevel@tonic-gate }
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate /*
4130Sstevel@tonic-gate  * Stores and arbitrary binary string in the buffer.
4140Sstevel@tonic-gate  */
4150Sstevel@tonic-gate void
4160Sstevel@tonic-gate buffer_put_string(Buffer *buffer, const void *buf, u_int len)
4170Sstevel@tonic-gate {
4180Sstevel@tonic-gate 	buffer_put_int(buffer, len);
4190Sstevel@tonic-gate 	buffer_append(buffer, buf, len);
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate void
4220Sstevel@tonic-gate buffer_put_cstring(Buffer *buffer, const char *s)
4230Sstevel@tonic-gate {
4240Sstevel@tonic-gate 	if (s == NULL)
4250Sstevel@tonic-gate 		fatal("buffer_put_cstring: s == NULL");
4260Sstevel@tonic-gate 	buffer_put_string(buffer, s, strlen(s));
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate /*
4300Sstevel@tonic-gate  * ASCII versions of the above
4310Sstevel@tonic-gate  */
4320Sstevel@tonic-gate #if 0
4330Sstevel@tonic-gate void
4340Sstevel@tonic-gate buffer_put_ascii_string(Buffer *buffer, const void *buf, u_int len)
4350Sstevel@tonic-gate {
4360Sstevel@tonic-gate 	u_char *p;
4370Sstevel@tonic-gate 	for (p = (u_char *) buf ;
4380Sstevel@tonic-gate 	     p && ((p - (u_char *) buf) < len) && *p && (!(*p & 0x80)) ;
4390Sstevel@tonic-gate 	     p++) ;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	if ((p - (u_char *) buf) != len)
4420Sstevel@tonic-gate 		verbose("buffer_put_ascii_string: storing a non-ASCII string");
4430Sstevel@tonic-gate 	buffer_put_int(buffer, len);
4440Sstevel@tonic-gate 	buffer_append(buffer, buf, len);
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate #endif
4470Sstevel@tonic-gate void
4480Sstevel@tonic-gate buffer_put_ascii_cstring(Buffer *buffer, const char *s)
4490Sstevel@tonic-gate {
4500Sstevel@tonic-gate 	u_char *estr;
4510Sstevel@tonic-gate 	if (s == NULL)
4520Sstevel@tonic-gate 		fatal("buffer_put_cstring: s == NULL");
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	if (!g11n_validate_ascii(s, strlen(s), &estr))
4550Sstevel@tonic-gate 	    verbose("buffer_put_ascii_cstring: non-ASCII string; %s", estr);
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	buffer_put_cstring(buffer, s);
4580Sstevel@tonic-gate }
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate /*
4610Sstevel@tonic-gate  * UTF-8 versions of the above.
4620Sstevel@tonic-gate  */
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate #if 0
4650Sstevel@tonic-gate void
4660Sstevel@tonic-gate buffer_put_utf8_string(Buffer *buffer, const void *buf, u_int len)
4670Sstevel@tonic-gate {
4680Sstevel@tonic-gate 	char *converted *estr;
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	converted = g11n_convert_to_utf8(buf, &err, &estr);
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	if (!converted && err)
4730Sstevel@tonic-gate 		fatal("buffer_put_utf8_string: input not a valid UTF-8 encoding; %s", estr);
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	if (err)
4760Sstevel@tonic-gate 		verbose("buffer_put_utf8_string: input not a valid UTF-8 encoding; %s", estr);
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	buffer_put_string(buffer, converted, strlen(converted));
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	if (converted != bug) xfree(converted);
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	return;
4830Sstevel@tonic-gate }
4840Sstevel@tonic-gate #endif
4850Sstevel@tonic-gate void
4860Sstevel@tonic-gate buffer_put_utf8_cstring(Buffer *buffer, const u_char *s)
4870Sstevel@tonic-gate {
4880Sstevel@tonic-gate 	u_char *converted, *estr;
4890Sstevel@tonic-gate 	int err;
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	if (s == NULL)
4920Sstevel@tonic-gate 		fatal("buffer_put_cstring: s == NULL");
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	converted = g11n_convert_to_utf8(s, &err, &estr);
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	if (!converted && err)
4970Sstevel@tonic-gate 		fatal("buffer_put_utf8_string: input not a valid UTF-8 encoding; %s", estr);
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	if (err)
5000Sstevel@tonic-gate 		verbose("buffer_put_utf8_string: input not a valid UTF-8 encoding; %s", estr);
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	buffer_put_cstring(buffer, (const char *) converted);
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	if (converted != s) xfree(converted);
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	return;
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate /*
5110Sstevel@tonic-gate  * Returns a character from the buffer (0 - 255).
5120Sstevel@tonic-gate  */
5130Sstevel@tonic-gate int
514*2757Sjp161948 buffer_get_char_ret(char *ret, Buffer *buffer)
515*2757Sjp161948 {
516*2757Sjp161948 	if (buffer_get_ret(buffer, ret, 1) == -1) {
517*2757Sjp161948 		error("buffer_get_char_ret: buffer_get_ret failed");
518*2757Sjp161948 		return (-1);
519*2757Sjp161948 	}
520*2757Sjp161948 	return (0);
521*2757Sjp161948 }
522*2757Sjp161948 
523*2757Sjp161948 int
5240Sstevel@tonic-gate buffer_get_char(Buffer *buffer)
5250Sstevel@tonic-gate {
5260Sstevel@tonic-gate 	char ch;
5270Sstevel@tonic-gate 
528*2757Sjp161948 	if (buffer_get_char_ret(&ch, buffer) == -1)
529*2757Sjp161948 		fatal("buffer_get_char: buffer error");
5300Sstevel@tonic-gate 	return (u_char) ch;
5310Sstevel@tonic-gate }
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate /*
5340Sstevel@tonic-gate  * Stores a character in the buffer.
5350Sstevel@tonic-gate  */
5360Sstevel@tonic-gate void
5370Sstevel@tonic-gate buffer_put_char(Buffer *buffer, int value)
5380Sstevel@tonic-gate {
5390Sstevel@tonic-gate 	char ch = value;
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	buffer_append(buffer, &ch, 1);
5420Sstevel@tonic-gate }
543