xref: /onnv-gate/usr/src/cmd/ssh/libssh/common/bufaux.c (revision 9600:113cf06ae502)
10Sstevel@tonic-gate /*
2*9600SNobutomo.Nakano@Sun.COM  * Copyright 2009 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 #include <langinfo.h>
470Sstevel@tonic-gate #include <openssl/bn.h>
480Sstevel@tonic-gate #include "bufaux.h"
490Sstevel@tonic-gate #include "xmalloc.h"
500Sstevel@tonic-gate #include "getput.h"
510Sstevel@tonic-gate #include "log.h"
520Sstevel@tonic-gate #include "g11n.h"
530Sstevel@tonic-gate 
540Sstevel@tonic-gate /*
550Sstevel@tonic-gate  * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
560Sstevel@tonic-gate  * by (bits+7)/8 bytes of binary data, msb first.
570Sstevel@tonic-gate  */
582757Sjp161948 int
buffer_put_bignum_ret(Buffer * buffer,const BIGNUM * value)592757Sjp161948 buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value)
600Sstevel@tonic-gate {
610Sstevel@tonic-gate 	int bits = BN_num_bits(value);
620Sstevel@tonic-gate 	int bin_size = (bits + 7) / 8;
630Sstevel@tonic-gate 	u_char *buf = xmalloc(bin_size);
640Sstevel@tonic-gate 	int oi;
650Sstevel@tonic-gate 	char msg[2];
660Sstevel@tonic-gate 
670Sstevel@tonic-gate 	/* Get the value of in binary */
680Sstevel@tonic-gate 	oi = BN_bn2bin(value, buf);
692757Sjp161948 	if (oi != bin_size) {
702757Sjp161948 		error("buffer_put_bignum_ret: BN_bn2bin() failed: oi %d != bin_size %d",
710Sstevel@tonic-gate 		    oi, bin_size);
722757Sjp161948 		xfree(buf);
732757Sjp161948 		return (-1);
742757Sjp161948 	}
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	/* Store the number of bits in the buffer in two bytes, msb first. */
770Sstevel@tonic-gate 	PUT_16BIT(msg, bits);
780Sstevel@tonic-gate 	buffer_append(buffer, msg, 2);
790Sstevel@tonic-gate 	/* Store the binary data. */
800Sstevel@tonic-gate 	buffer_append(buffer, (char *)buf, oi);
810Sstevel@tonic-gate 
820Sstevel@tonic-gate 	memset(buf, 0, bin_size);
830Sstevel@tonic-gate 	xfree(buf);
842757Sjp161948 
852757Sjp161948 	return (0);
862757Sjp161948 }
872757Sjp161948 
882757Sjp161948 void
buffer_put_bignum(Buffer * buffer,const BIGNUM * value)892757Sjp161948 buffer_put_bignum(Buffer *buffer, const BIGNUM *value)
902757Sjp161948 {
912757Sjp161948 	if (buffer_put_bignum_ret(buffer, value) == -1)
922757Sjp161948 		fatal("buffer_put_bignum: buffer error");
930Sstevel@tonic-gate }
940Sstevel@tonic-gate 
950Sstevel@tonic-gate /*
960Sstevel@tonic-gate  * Retrieves an BIGNUM from the buffer.
970Sstevel@tonic-gate  */
982757Sjp161948 int
buffer_get_bignum_ret(Buffer * buffer,BIGNUM * value)992757Sjp161948 buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value)
1000Sstevel@tonic-gate {
1012757Sjp161948 	u_int bits, bytes;
1020Sstevel@tonic-gate 	u_char buf[2], *bin;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 	/* Get the number for bits. */
1052757Sjp161948 	if (buffer_get_ret(buffer, (char *) buf, 2) == -1) {
1062757Sjp161948 		error("buffer_get_bignum_ret: invalid length");
1072757Sjp161948 		return (-1);
1082757Sjp161948 	}
1090Sstevel@tonic-gate 	bits = GET_16BIT(buf);
1100Sstevel@tonic-gate 	/* Compute the number of binary bytes that follow. */
1110Sstevel@tonic-gate 	bytes = (bits + 7) / 8;
1122757Sjp161948 	if (bytes > 8 * 1024) {
1132757Sjp161948 		error("buffer_get_bignum_ret: cannot handle BN of size %d", bytes);
1142757Sjp161948 		return (-1);
1152757Sjp161948 	}
1162757Sjp161948 	if (buffer_len(buffer) < bytes) {
1172757Sjp161948 		error("buffer_get_bignum_ret: input buffer too small");
1182757Sjp161948 		return (-1);
1192757Sjp161948 	}
1200Sstevel@tonic-gate 	bin = buffer_ptr(buffer);
1210Sstevel@tonic-gate 	BN_bin2bn(bin, bytes, value);
1222757Sjp161948 	if (buffer_consume_ret(buffer, bytes) == -1) {
1232757Sjp161948 		error("buffer_get_bignum_ret: buffer_consume failed");
1242757Sjp161948 		return (-1);
1252757Sjp161948 	}
1262757Sjp161948 	return (0);
1272757Sjp161948 }
1282757Sjp161948 
1292757Sjp161948 void
buffer_get_bignum(Buffer * buffer,BIGNUM * value)1302757Sjp161948 buffer_get_bignum(Buffer *buffer, BIGNUM *value)
1312757Sjp161948 {
1322757Sjp161948 	if (buffer_get_bignum_ret(buffer, value) == -1)
1332757Sjp161948 		fatal("buffer_get_bignum: buffer error");
1340Sstevel@tonic-gate }
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate /*
1370Sstevel@tonic-gate  * Stores an BIGNUM in the buffer in SSH2 format.
1380Sstevel@tonic-gate  */
1392757Sjp161948 int
buffer_put_bignum2_ret(Buffer * buffer,const BIGNUM * value)1402757Sjp161948 buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value)
1410Sstevel@tonic-gate {
1422757Sjp161948 	u_int bytes;
1432757Sjp161948 	u_char *buf;
1440Sstevel@tonic-gate 	int oi;
1452757Sjp161948 	u_int hasnohigh = 0;
1460Sstevel@tonic-gate 
1472757Sjp161948 	if (BN_is_zero(value)) {
1482757Sjp161948 		buffer_put_int(buffer, 0);
1492757Sjp161948 		return 0;
1502757Sjp161948 	}
1512757Sjp161948 	if (value->neg) {
1522757Sjp161948 		error("buffer_put_bignum2_ret: negative numbers not supported");
1532757Sjp161948 		return (-1);
1542757Sjp161948 	}
1552757Sjp161948 	bytes = BN_num_bytes(value) + 1; /* extra padding byte */
1562757Sjp161948 	if (bytes < 2) {
1572757Sjp161948 		error("buffer_put_bignum2_ret: BN too small");
1582757Sjp161948 		return (-1);
1592757Sjp161948 	}
1602757Sjp161948 	buf = xmalloc(bytes);
1612757Sjp161948 	buf[0] = 0x00;
1620Sstevel@tonic-gate 	/* Get the value of in binary */
1630Sstevel@tonic-gate 	oi = BN_bn2bin(value, buf+1);
1642757Sjp161948 	if (oi < 0 || (u_int)oi != bytes - 1) {
1652757Sjp161948 		error("buffer_put_bignum2_ret: BN_bn2bin() failed: "
1662757Sjp161948 		    "oi %d != bin_size %d", oi, bytes);
1672757Sjp161948 		xfree(buf);
1682757Sjp161948 		return (-1);
1692757Sjp161948 	}
1700Sstevel@tonic-gate 	hasnohigh = (buf[1] & 0x80) ? 0 : 1;
1710Sstevel@tonic-gate 	buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh);
1720Sstevel@tonic-gate 	memset(buf, 0, bytes);
1730Sstevel@tonic-gate 	xfree(buf);
1742757Sjp161948 	return (0);
1752757Sjp161948 }
1762757Sjp161948 
1772757Sjp161948 void
buffer_put_bignum2(Buffer * buffer,const BIGNUM * value)1782757Sjp161948 buffer_put_bignum2(Buffer *buffer, const BIGNUM *value)
1792757Sjp161948 {
1802757Sjp161948 	if (buffer_put_bignum2_ret(buffer, value) == -1)
1812757Sjp161948 		fatal("buffer_put_bignum2: buffer error");
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate /* XXX does not handle negative BNs */
1852757Sjp161948 int
buffer_get_bignum2_ret(Buffer * buffer,BIGNUM * value)1862757Sjp161948 buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value)
1872757Sjp161948 {
1882757Sjp161948 	u_int len;
1892757Sjp161948 	u_char *bin;
1902757Sjp161948 
1912757Sjp161948 	if ((bin = buffer_get_string_ret(buffer, &len)) == NULL) {
1922757Sjp161948 		error("buffer_get_bignum2_ret: invalid bignum");
1932757Sjp161948 		return (-1);
1942757Sjp161948 	}
1952757Sjp161948 
1962757Sjp161948 	if (len > 0 && (bin[0] & 0x80)) {
1972757Sjp161948 		error("buffer_get_bignum2_ret: negative numbers not supported");
1982757Sjp161948 		xfree(bin);
1992757Sjp161948 		return (-1);
2002757Sjp161948 	}
2012757Sjp161948 	if (len > 8 * 1024) {
2022757Sjp161948 		error("buffer_get_bignum2_ret: cannot handle BN of size %d", len);
2032757Sjp161948 		xfree(bin);
2042757Sjp161948 		return (-1);
2052757Sjp161948 	}
2062757Sjp161948 	BN_bin2bn(bin, len, value);
2072757Sjp161948 	xfree(bin);
2082757Sjp161948 	return (0);
2092757Sjp161948 }
2102757Sjp161948 
2110Sstevel@tonic-gate void
buffer_get_bignum2(Buffer * buffer,BIGNUM * value)2120Sstevel@tonic-gate buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
2130Sstevel@tonic-gate {
2142757Sjp161948 	if (buffer_get_bignum2_ret(buffer, value) == -1)
2152757Sjp161948 		fatal("buffer_get_bignum2: buffer error");
2162757Sjp161948 }
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate /*
2190Sstevel@tonic-gate  * Returns integers from the buffer (msb first).
2200Sstevel@tonic-gate  */
2210Sstevel@tonic-gate 
2222757Sjp161948 int
buffer_get_short_ret(u_short * ret,Buffer * buffer)2232757Sjp161948 buffer_get_short_ret(u_short *ret, Buffer *buffer)
2242757Sjp161948 {
2252757Sjp161948 	u_char buf[2];
2262757Sjp161948 
2272757Sjp161948 	if (buffer_get_ret(buffer, (char *) buf, 2) == -1)
2282757Sjp161948 		return (-1);
2292757Sjp161948 	*ret = GET_16BIT(buf);
2302757Sjp161948 	return (0);
2312757Sjp161948 }
2322757Sjp161948 
2330Sstevel@tonic-gate u_short
buffer_get_short(Buffer * buffer)2340Sstevel@tonic-gate buffer_get_short(Buffer *buffer)
2350Sstevel@tonic-gate {
2362757Sjp161948 	u_short ret;
2372757Sjp161948 
2382757Sjp161948 	if (buffer_get_short_ret(&ret, buffer) == -1)
2392757Sjp161948 		fatal("buffer_get_short: buffer error");
2402757Sjp161948 
2412757Sjp161948 	return (ret);
2422757Sjp161948 }
2430Sstevel@tonic-gate 
2442757Sjp161948 int
buffer_get_int_ret(u_int * ret,Buffer * buffer)2452757Sjp161948 buffer_get_int_ret(u_int *ret, Buffer *buffer)
2462757Sjp161948 {
2472757Sjp161948 	u_char buf[4];
2482757Sjp161948 
2492757Sjp161948 	if (buffer_get_ret(buffer, (char *) buf, 4) == -1)
2502757Sjp161948 		return (-1);
2512757Sjp161948 	*ret = GET_32BIT(buf);
2522757Sjp161948 	return (0);
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate u_int
buffer_get_int(Buffer * buffer)2560Sstevel@tonic-gate buffer_get_int(Buffer *buffer)
2570Sstevel@tonic-gate {
2582757Sjp161948 	u_int ret;
2590Sstevel@tonic-gate 
2602757Sjp161948 	if (buffer_get_int_ret(&ret, buffer) == -1)
2612757Sjp161948 		fatal("buffer_get_int: buffer error");
2622757Sjp161948 
2632757Sjp161948 	return (ret);
2640Sstevel@tonic-gate }
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate #ifdef HAVE_U_INT64_T
2672757Sjp161948 int
buffer_get_int64_ret(u_int64_t * ret,Buffer * buffer)2682757Sjp161948 buffer_get_int64_ret(u_int64_t *ret, Buffer *buffer)
2692757Sjp161948 {
2702757Sjp161948 	u_char buf[8];
2712757Sjp161948 
2722757Sjp161948 	if (buffer_get_ret(buffer, (char *) buf, 8) == -1)
2732757Sjp161948 		return (-1);
2742757Sjp161948 	*ret = GET_64BIT(buf);
2752757Sjp161948 	return (0);
2762757Sjp161948 }
2772757Sjp161948 
2780Sstevel@tonic-gate u_int64_t
buffer_get_int64(Buffer * buffer)2790Sstevel@tonic-gate buffer_get_int64(Buffer *buffer)
2800Sstevel@tonic-gate {
2812757Sjp161948 	u_int64_t ret;
2820Sstevel@tonic-gate 
2832757Sjp161948 	if (buffer_get_int64_ret(&ret, buffer) == -1)
2842757Sjp161948 		fatal("buffer_get_int: buffer error");
2852757Sjp161948 
2862757Sjp161948 	return (ret);
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate #endif
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate /*
2910Sstevel@tonic-gate  * Stores integers in the buffer, msb first.
2920Sstevel@tonic-gate  */
2930Sstevel@tonic-gate void
buffer_put_short(Buffer * buffer,u_short value)2940Sstevel@tonic-gate buffer_put_short(Buffer *buffer, u_short value)
2950Sstevel@tonic-gate {
2960Sstevel@tonic-gate 	char buf[2];
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	PUT_16BIT(buf, value);
2990Sstevel@tonic-gate 	buffer_append(buffer, buf, 2);
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate void
buffer_put_int(Buffer * buffer,u_int value)3030Sstevel@tonic-gate buffer_put_int(Buffer *buffer, u_int value)
3040Sstevel@tonic-gate {
3050Sstevel@tonic-gate 	char buf[4];
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	PUT_32BIT(buf, value);
3080Sstevel@tonic-gate 	buffer_append(buffer, buf, 4);
3090Sstevel@tonic-gate }
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate #ifdef HAVE_U_INT64_T
3120Sstevel@tonic-gate void
buffer_put_int64(Buffer * buffer,u_int64_t value)3130Sstevel@tonic-gate buffer_put_int64(Buffer *buffer, u_int64_t value)
3140Sstevel@tonic-gate {
3150Sstevel@tonic-gate 	char buf[8];
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	PUT_64BIT(buf, value);
3180Sstevel@tonic-gate 	buffer_append(buffer, buf, 8);
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate #endif
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate /*
3230Sstevel@tonic-gate  * Returns an arbitrary binary string from the buffer.  The string cannot
3240Sstevel@tonic-gate  * be longer than 256k.  The returned value points to memory allocated
3250Sstevel@tonic-gate  * with xmalloc; it is the responsibility of the calling function to free
3260Sstevel@tonic-gate  * the data.  If length_ptr is non-NULL, the length of the returned data
3270Sstevel@tonic-gate  * will be stored there.  A null character will be automatically appended
3280Sstevel@tonic-gate  * to the returned string, and is not counted in length.
3290Sstevel@tonic-gate  */
3300Sstevel@tonic-gate void *
buffer_get_string_ret(Buffer * buffer,u_int * length_ptr)3312757Sjp161948 buffer_get_string_ret(Buffer *buffer, u_int *length_ptr)
3320Sstevel@tonic-gate {
3330Sstevel@tonic-gate 	u_char *value;
3340Sstevel@tonic-gate 	u_int len;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	/* Get the length. */
3370Sstevel@tonic-gate 	len = buffer_get_int(buffer);
3382757Sjp161948 	if (len > 256 * 1024) {
3392757Sjp161948 		error("buffer_get_string_ret: bad string length %u", len);
3402757Sjp161948 		return (NULL);
3412757Sjp161948 	}
3420Sstevel@tonic-gate 	/* Allocate space for the string.  Add one byte for a null character. */
3430Sstevel@tonic-gate 	value = xmalloc(len + 1);
3440Sstevel@tonic-gate 	/* Get the string. */
3452757Sjp161948 	if (buffer_get_ret(buffer, value, len) == -1) {
3462757Sjp161948 		error("buffer_get_string_ret: buffer_get failed");
3472757Sjp161948 		xfree(value);
3482757Sjp161948 		return (NULL);
3492757Sjp161948 	}
3500Sstevel@tonic-gate 	/* Append a null character to make processing easier. */
3510Sstevel@tonic-gate 	value[len] = 0;
3520Sstevel@tonic-gate 	/* Optionally return the length of the string. */
3530Sstevel@tonic-gate 	if (length_ptr)
3540Sstevel@tonic-gate 		*length_ptr = len;
3552757Sjp161948 	return (value);
3560Sstevel@tonic-gate }
3572757Sjp161948 
3582757Sjp161948 void *
buffer_get_string(Buffer * buffer,u_int * length_ptr)3592757Sjp161948 buffer_get_string(Buffer *buffer, u_int *length_ptr)
3602757Sjp161948 {
3612757Sjp161948 	void *ret;
3622757Sjp161948 
3632757Sjp161948 	if ((ret = buffer_get_string_ret(buffer, length_ptr)) == NULL)
3642757Sjp161948 		fatal("buffer_get_string: buffer error");
3652757Sjp161948 	return (ret);
3662757Sjp161948 }
3672757Sjp161948 
3680Sstevel@tonic-gate char *
buffer_get_utf8_string(Buffer * buffer,uint_t * length_ptr)369*9600SNobutomo.Nakano@Sun.COM buffer_get_utf8_string(Buffer *buffer, uint_t *length_ptr)
3700Sstevel@tonic-gate {
371*9600SNobutomo.Nakano@Sun.COM 	char	*value, *converted, *estr;
372*9600SNobutomo.Nakano@Sun.COM 	uint_t	len;
3730Sstevel@tonic-gate 
374*9600SNobutomo.Nakano@Sun.COM 	if ((value = buffer_get_string(buffer, &len)) == NULL)
375*9600SNobutomo.Nakano@Sun.COM 		return (value);
3760Sstevel@tonic-gate 
377*9600SNobutomo.Nakano@Sun.COM 	converted = g11n_convert_from_utf8(value, &len, &estr);
378*9600SNobutomo.Nakano@Sun.COM 	if (converted == NULL) {
379*9600SNobutomo.Nakano@Sun.COM 		if (estr != NULL)
380*9600SNobutomo.Nakano@Sun.COM 			error("invalid UTF-8 sequence: %s", estr);
381*9600SNobutomo.Nakano@Sun.COM 		converted = value;
382*9600SNobutomo.Nakano@Sun.COM 	} else {
383*9600SNobutomo.Nakano@Sun.COM 		xfree(value);
3840Sstevel@tonic-gate 	}
3850Sstevel@tonic-gate 
386*9600SNobutomo.Nakano@Sun.COM 	if (length_ptr != NULL)
387*9600SNobutomo.Nakano@Sun.COM 		*length_ptr = len;
3880Sstevel@tonic-gate 
389*9600SNobutomo.Nakano@Sun.COM 	return (converted);
3900Sstevel@tonic-gate }
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate /*
3930Sstevel@tonic-gate  * Stores and arbitrary binary string in the buffer.
3940Sstevel@tonic-gate  */
3950Sstevel@tonic-gate void
buffer_put_string(Buffer * buffer,const void * buf,u_int len)3960Sstevel@tonic-gate buffer_put_string(Buffer *buffer, const void *buf, u_int len)
3970Sstevel@tonic-gate {
3980Sstevel@tonic-gate 	buffer_put_int(buffer, len);
3990Sstevel@tonic-gate 	buffer_append(buffer, buf, len);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate void
buffer_put_cstring(Buffer * buffer,const char * s)4020Sstevel@tonic-gate buffer_put_cstring(Buffer *buffer, const char *s)
4030Sstevel@tonic-gate {
4040Sstevel@tonic-gate 	if (s == NULL)
4050Sstevel@tonic-gate 		fatal("buffer_put_cstring: s == NULL");
4060Sstevel@tonic-gate 	buffer_put_string(buffer, s, strlen(s));
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate /*
4100Sstevel@tonic-gate  * UTF-8 versions of the above.
4110Sstevel@tonic-gate  */
4120Sstevel@tonic-gate void
buffer_put_utf8_string(Buffer * buffer,const char * s,uint_t len)413*9600SNobutomo.Nakano@Sun.COM buffer_put_utf8_string(Buffer *buffer, const char *s, uint_t len)
4140Sstevel@tonic-gate {
415*9600SNobutomo.Nakano@Sun.COM 	char	*converted, *estr;
416*9600SNobutomo.Nakano@Sun.COM 	uint_t	nlen = len;
4170Sstevel@tonic-gate 
418*9600SNobutomo.Nakano@Sun.COM 	converted = g11n_convert_to_utf8(s, &nlen, 0, &estr);
419*9600SNobutomo.Nakano@Sun.COM 	if (converted == NULL) {
420*9600SNobutomo.Nakano@Sun.COM 		if (estr != NULL)
421*9600SNobutomo.Nakano@Sun.COM 			error("Can't convert to UTF-8: %s", estr);
422*9600SNobutomo.Nakano@Sun.COM 		converted = (char *)s;
423*9600SNobutomo.Nakano@Sun.COM 	}
4240Sstevel@tonic-gate 
425*9600SNobutomo.Nakano@Sun.COM 	buffer_put_string(buffer, converted, nlen);
4260Sstevel@tonic-gate 
427*9600SNobutomo.Nakano@Sun.COM 	if (converted != s)
428*9600SNobutomo.Nakano@Sun.COM 		xfree(converted);
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate 
431*9600SNobutomo.Nakano@Sun.COM void
buffer_put_utf8_cstring(Buffer * buffer,const char * s)432*9600SNobutomo.Nakano@Sun.COM buffer_put_utf8_cstring(Buffer *buffer, const char *s)
433*9600SNobutomo.Nakano@Sun.COM {
434*9600SNobutomo.Nakano@Sun.COM 	buffer_put_utf8_string(buffer, s, strlen(s));
435*9600SNobutomo.Nakano@Sun.COM }
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate /*
4380Sstevel@tonic-gate  * Returns a character from the buffer (0 - 255).
4390Sstevel@tonic-gate  */
4400Sstevel@tonic-gate int
buffer_get_char_ret(char * ret,Buffer * buffer)4412757Sjp161948 buffer_get_char_ret(char *ret, Buffer *buffer)
4422757Sjp161948 {
4432757Sjp161948 	if (buffer_get_ret(buffer, ret, 1) == -1) {
4442757Sjp161948 		error("buffer_get_char_ret: buffer_get_ret failed");
4452757Sjp161948 		return (-1);
4462757Sjp161948 	}
4472757Sjp161948 	return (0);
4482757Sjp161948 }
4492757Sjp161948 
4502757Sjp161948 int
buffer_get_char(Buffer * buffer)4510Sstevel@tonic-gate buffer_get_char(Buffer *buffer)
4520Sstevel@tonic-gate {
4530Sstevel@tonic-gate 	char ch;
4540Sstevel@tonic-gate 
4552757Sjp161948 	if (buffer_get_char_ret(&ch, buffer) == -1)
4562757Sjp161948 		fatal("buffer_get_char: buffer error");
4570Sstevel@tonic-gate 	return (u_char) ch;
4580Sstevel@tonic-gate }
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate /*
4610Sstevel@tonic-gate  * Stores a character in the buffer.
4620Sstevel@tonic-gate  */
4630Sstevel@tonic-gate void
buffer_put_char(Buffer * buffer,int value)4640Sstevel@tonic-gate buffer_put_char(Buffer *buffer, int value)
4650Sstevel@tonic-gate {
4660Sstevel@tonic-gate 	char ch = value;
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	buffer_append(buffer, &ch, 1);
4690Sstevel@tonic-gate }
470