xref: /titanic_44/usr/src/cmd/ssh/libssh/common/bufaux.c (revision 6f786ace10b9c0c7c5515e525fb660fbccfda6a3)
17c478bd9Sstevel@tonic-gate /*
2*6f786aceSNobutomo Nakano  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate /*
67c478bd9Sstevel@tonic-gate  * Author: Tatu Ylonen <ylo@cs.hut.fi>
77c478bd9Sstevel@tonic-gate  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
87c478bd9Sstevel@tonic-gate  *                    All rights reserved
97c478bd9Sstevel@tonic-gate  * Auxiliary functions for storing and retrieving various data types to/from
107c478bd9Sstevel@tonic-gate  * Buffers.
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  * As far as I am concerned, the code I have written for this software
137c478bd9Sstevel@tonic-gate  * can be used freely for any purpose.  Any derived versions of this
147c478bd9Sstevel@tonic-gate  * software must be clearly marked as such, and if the derived work is
157c478bd9Sstevel@tonic-gate  * incompatible with the protocol description in the RFC file, it must be
167c478bd9Sstevel@tonic-gate  * called by a name other than "ssh" or "Secure Shell".
177c478bd9Sstevel@tonic-gate  *
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * SSH2 packet format added by Markus Friedl
207c478bd9Sstevel@tonic-gate  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
217c478bd9Sstevel@tonic-gate  *
227c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
237c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
247c478bd9Sstevel@tonic-gate  * are met:
257c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
267c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
277c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
287c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
297c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
307c478bd9Sstevel@tonic-gate  *
317c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
327c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
337c478bd9Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
347c478bd9Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
357c478bd9Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
367c478bd9Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
377c478bd9Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
387c478bd9Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
397c478bd9Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
407c478bd9Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
417c478bd9Sstevel@tonic-gate  */
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include "includes.h"
447c478bd9Sstevel@tonic-gate RCSID("$OpenBSD: bufaux.c,v 1.27 2002/06/26 08:53:12 markus Exp $");
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include <langinfo.h>
477c478bd9Sstevel@tonic-gate #include <openssl/bn.h>
487c478bd9Sstevel@tonic-gate #include "bufaux.h"
497c478bd9Sstevel@tonic-gate #include "xmalloc.h"
507c478bd9Sstevel@tonic-gate #include "getput.h"
517c478bd9Sstevel@tonic-gate #include "log.h"
527c478bd9Sstevel@tonic-gate #include "g11n.h"
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate /*
557c478bd9Sstevel@tonic-gate  * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
567c478bd9Sstevel@tonic-gate  * by (bits+7)/8 bytes of binary data, msb first.
577c478bd9Sstevel@tonic-gate  */
5826ba1984Sjp161948 int
buffer_put_bignum_ret(Buffer * buffer,const BIGNUM * value)5926ba1984Sjp161948 buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value)
607c478bd9Sstevel@tonic-gate {
617c478bd9Sstevel@tonic-gate 	int bits = BN_num_bits(value);
627c478bd9Sstevel@tonic-gate 	int bin_size = (bits + 7) / 8;
637c478bd9Sstevel@tonic-gate 	u_char *buf = xmalloc(bin_size);
647c478bd9Sstevel@tonic-gate 	int oi;
657c478bd9Sstevel@tonic-gate 	char msg[2];
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 	/* Get the value of in binary */
687c478bd9Sstevel@tonic-gate 	oi = BN_bn2bin(value, buf);
6926ba1984Sjp161948 	if (oi != bin_size) {
7026ba1984Sjp161948 		error("buffer_put_bignum_ret: BN_bn2bin() failed: oi %d != bin_size %d",
717c478bd9Sstevel@tonic-gate 		    oi, bin_size);
7226ba1984Sjp161948 		xfree(buf);
7326ba1984Sjp161948 		return (-1);
7426ba1984Sjp161948 	}
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	/* Store the number of bits in the buffer in two bytes, msb first. */
777c478bd9Sstevel@tonic-gate 	PUT_16BIT(msg, bits);
787c478bd9Sstevel@tonic-gate 	buffer_append(buffer, msg, 2);
797c478bd9Sstevel@tonic-gate 	/* Store the binary data. */
807c478bd9Sstevel@tonic-gate 	buffer_append(buffer, (char *)buf, oi);
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	memset(buf, 0, bin_size);
837c478bd9Sstevel@tonic-gate 	xfree(buf);
8426ba1984Sjp161948 
8526ba1984Sjp161948 	return (0);
8626ba1984Sjp161948 }
8726ba1984Sjp161948 
8826ba1984Sjp161948 void
buffer_put_bignum(Buffer * buffer,const BIGNUM * value)8926ba1984Sjp161948 buffer_put_bignum(Buffer *buffer, const BIGNUM *value)
9026ba1984Sjp161948 {
9126ba1984Sjp161948 	if (buffer_put_bignum_ret(buffer, value) == -1)
9226ba1984Sjp161948 		fatal("buffer_put_bignum: buffer error");
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate  * Retrieves an BIGNUM from the buffer.
977c478bd9Sstevel@tonic-gate  */
9826ba1984Sjp161948 int
buffer_get_bignum_ret(Buffer * buffer,BIGNUM * value)9926ba1984Sjp161948 buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value)
1007c478bd9Sstevel@tonic-gate {
10126ba1984Sjp161948 	u_int bits, bytes;
1027c478bd9Sstevel@tonic-gate 	u_char buf[2], *bin;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	/* Get the number for bits. */
10526ba1984Sjp161948 	if (buffer_get_ret(buffer, (char *) buf, 2) == -1) {
10626ba1984Sjp161948 		error("buffer_get_bignum_ret: invalid length");
10726ba1984Sjp161948 		return (-1);
10826ba1984Sjp161948 	}
1097c478bd9Sstevel@tonic-gate 	bits = GET_16BIT(buf);
1107c478bd9Sstevel@tonic-gate 	/* Compute the number of binary bytes that follow. */
1117c478bd9Sstevel@tonic-gate 	bytes = (bits + 7) / 8;
11226ba1984Sjp161948 	if (bytes > 8 * 1024) {
11326ba1984Sjp161948 		error("buffer_get_bignum_ret: cannot handle BN of size %d", bytes);
11426ba1984Sjp161948 		return (-1);
11526ba1984Sjp161948 	}
11626ba1984Sjp161948 	if (buffer_len(buffer) < bytes) {
11726ba1984Sjp161948 		error("buffer_get_bignum_ret: input buffer too small");
11826ba1984Sjp161948 		return (-1);
11926ba1984Sjp161948 	}
1207c478bd9Sstevel@tonic-gate 	bin = buffer_ptr(buffer);
1217c478bd9Sstevel@tonic-gate 	BN_bin2bn(bin, bytes, value);
12226ba1984Sjp161948 	if (buffer_consume_ret(buffer, bytes) == -1) {
12326ba1984Sjp161948 		error("buffer_get_bignum_ret: buffer_consume failed");
12426ba1984Sjp161948 		return (-1);
12526ba1984Sjp161948 	}
12626ba1984Sjp161948 	return (0);
12726ba1984Sjp161948 }
12826ba1984Sjp161948 
12926ba1984Sjp161948 void
buffer_get_bignum(Buffer * buffer,BIGNUM * value)13026ba1984Sjp161948 buffer_get_bignum(Buffer *buffer, BIGNUM *value)
13126ba1984Sjp161948 {
13226ba1984Sjp161948 	if (buffer_get_bignum_ret(buffer, value) == -1)
13326ba1984Sjp161948 		fatal("buffer_get_bignum: buffer error");
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate /*
1377c478bd9Sstevel@tonic-gate  * Stores an BIGNUM in the buffer in SSH2 format.
1387c478bd9Sstevel@tonic-gate  */
13926ba1984Sjp161948 int
buffer_put_bignum2_ret(Buffer * buffer,const BIGNUM * value)14026ba1984Sjp161948 buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value)
1417c478bd9Sstevel@tonic-gate {
14226ba1984Sjp161948 	u_int bytes;
14326ba1984Sjp161948 	u_char *buf;
1447c478bd9Sstevel@tonic-gate 	int oi;
14526ba1984Sjp161948 	u_int hasnohigh = 0;
1467c478bd9Sstevel@tonic-gate 
14726ba1984Sjp161948 	if (BN_is_zero(value)) {
14826ba1984Sjp161948 		buffer_put_int(buffer, 0);
14926ba1984Sjp161948 		return 0;
15026ba1984Sjp161948 	}
15126ba1984Sjp161948 	if (value->neg) {
15226ba1984Sjp161948 		error("buffer_put_bignum2_ret: negative numbers not supported");
15326ba1984Sjp161948 		return (-1);
15426ba1984Sjp161948 	}
15526ba1984Sjp161948 	bytes = BN_num_bytes(value) + 1; /* extra padding byte */
15626ba1984Sjp161948 	if (bytes < 2) {
15726ba1984Sjp161948 		error("buffer_put_bignum2_ret: BN too small");
15826ba1984Sjp161948 		return (-1);
15926ba1984Sjp161948 	}
16026ba1984Sjp161948 	buf = xmalloc(bytes);
16126ba1984Sjp161948 	buf[0] = 0x00;
1627c478bd9Sstevel@tonic-gate 	/* Get the value of in binary */
1637c478bd9Sstevel@tonic-gate 	oi = BN_bn2bin(value, buf+1);
16426ba1984Sjp161948 	if (oi < 0 || (u_int)oi != bytes - 1) {
16526ba1984Sjp161948 		error("buffer_put_bignum2_ret: BN_bn2bin() failed: "
16626ba1984Sjp161948 		    "oi %d != bin_size %d", oi, bytes);
16726ba1984Sjp161948 		xfree(buf);
16826ba1984Sjp161948 		return (-1);
16926ba1984Sjp161948 	}
1707c478bd9Sstevel@tonic-gate 	hasnohigh = (buf[1] & 0x80) ? 0 : 1;
1717c478bd9Sstevel@tonic-gate 	buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh);
1727c478bd9Sstevel@tonic-gate 	memset(buf, 0, bytes);
1737c478bd9Sstevel@tonic-gate 	xfree(buf);
17426ba1984Sjp161948 	return (0);
17526ba1984Sjp161948 }
17626ba1984Sjp161948 
17726ba1984Sjp161948 void
buffer_put_bignum2(Buffer * buffer,const BIGNUM * value)17826ba1984Sjp161948 buffer_put_bignum2(Buffer *buffer, const BIGNUM *value)
17926ba1984Sjp161948 {
18026ba1984Sjp161948 	if (buffer_put_bignum2_ret(buffer, value) == -1)
18126ba1984Sjp161948 		fatal("buffer_put_bignum2: buffer error");
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate /* XXX does not handle negative BNs */
18526ba1984Sjp161948 int
buffer_get_bignum2_ret(Buffer * buffer,BIGNUM * value)18626ba1984Sjp161948 buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value)
18726ba1984Sjp161948 {
18826ba1984Sjp161948 	u_int len;
18926ba1984Sjp161948 	u_char *bin;
19026ba1984Sjp161948 
19126ba1984Sjp161948 	if ((bin = buffer_get_string_ret(buffer, &len)) == NULL) {
19226ba1984Sjp161948 		error("buffer_get_bignum2_ret: invalid bignum");
19326ba1984Sjp161948 		return (-1);
19426ba1984Sjp161948 	}
19526ba1984Sjp161948 
19626ba1984Sjp161948 	if (len > 0 && (bin[0] & 0x80)) {
19726ba1984Sjp161948 		error("buffer_get_bignum2_ret: negative numbers not supported");
19826ba1984Sjp161948 		xfree(bin);
19926ba1984Sjp161948 		return (-1);
20026ba1984Sjp161948 	}
20126ba1984Sjp161948 	if (len > 8 * 1024) {
20226ba1984Sjp161948 		error("buffer_get_bignum2_ret: cannot handle BN of size %d", len);
20326ba1984Sjp161948 		xfree(bin);
20426ba1984Sjp161948 		return (-1);
20526ba1984Sjp161948 	}
20626ba1984Sjp161948 	BN_bin2bn(bin, len, value);
20726ba1984Sjp161948 	xfree(bin);
20826ba1984Sjp161948 	return (0);
20926ba1984Sjp161948 }
21026ba1984Sjp161948 
2117c478bd9Sstevel@tonic-gate void
buffer_get_bignum2(Buffer * buffer,BIGNUM * value)2127c478bd9Sstevel@tonic-gate buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
2137c478bd9Sstevel@tonic-gate {
21426ba1984Sjp161948 	if (buffer_get_bignum2_ret(buffer, value) == -1)
21526ba1984Sjp161948 		fatal("buffer_get_bignum2: buffer error");
2167c478bd9Sstevel@tonic-gate }
21726ba1984Sjp161948 
2187c478bd9Sstevel@tonic-gate /*
2197c478bd9Sstevel@tonic-gate  * Returns integers from the buffer (msb first).
2207c478bd9Sstevel@tonic-gate  */
2217c478bd9Sstevel@tonic-gate 
22226ba1984Sjp161948 int
buffer_get_short_ret(u_short * ret,Buffer * buffer)22326ba1984Sjp161948 buffer_get_short_ret(u_short *ret, Buffer *buffer)
2247c478bd9Sstevel@tonic-gate {
2257c478bd9Sstevel@tonic-gate 	u_char buf[2];
2267c478bd9Sstevel@tonic-gate 
22726ba1984Sjp161948 	if (buffer_get_ret(buffer, (char *) buf, 2) == -1)
22826ba1984Sjp161948 		return (-1);
22926ba1984Sjp161948 	*ret = GET_16BIT(buf);
23026ba1984Sjp161948 	return (0);
23126ba1984Sjp161948 }
23226ba1984Sjp161948 
23326ba1984Sjp161948 u_short
buffer_get_short(Buffer * buffer)23426ba1984Sjp161948 buffer_get_short(Buffer *buffer)
23526ba1984Sjp161948 {
23626ba1984Sjp161948 	u_short ret;
23726ba1984Sjp161948 
23826ba1984Sjp161948 	if (buffer_get_short_ret(&ret, buffer) == -1)
23926ba1984Sjp161948 		fatal("buffer_get_short: buffer error");
24026ba1984Sjp161948 
24126ba1984Sjp161948 	return (ret);
24226ba1984Sjp161948 }
24326ba1984Sjp161948 
24426ba1984Sjp161948 int
buffer_get_int_ret(u_int * ret,Buffer * buffer)24526ba1984Sjp161948 buffer_get_int_ret(u_int *ret, Buffer *buffer)
24626ba1984Sjp161948 {
24726ba1984Sjp161948 	u_char buf[4];
24826ba1984Sjp161948 
24926ba1984Sjp161948 	if (buffer_get_ret(buffer, (char *) buf, 4) == -1)
25026ba1984Sjp161948 		return (-1);
25126ba1984Sjp161948 	*ret = GET_32BIT(buf);
25226ba1984Sjp161948 	return (0);
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate u_int
buffer_get_int(Buffer * buffer)2567c478bd9Sstevel@tonic-gate buffer_get_int(Buffer *buffer)
2577c478bd9Sstevel@tonic-gate {
25826ba1984Sjp161948 	u_int ret;
2597c478bd9Sstevel@tonic-gate 
26026ba1984Sjp161948 	if (buffer_get_int_ret(&ret, buffer) == -1)
26126ba1984Sjp161948 		fatal("buffer_get_int: buffer error");
26226ba1984Sjp161948 
26326ba1984Sjp161948 	return (ret);
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate #ifdef HAVE_U_INT64_T
26726ba1984Sjp161948 int
buffer_get_int64_ret(u_int64_t * ret,Buffer * buffer)26826ba1984Sjp161948 buffer_get_int64_ret(u_int64_t *ret, Buffer *buffer)
2697c478bd9Sstevel@tonic-gate {
2707c478bd9Sstevel@tonic-gate 	u_char buf[8];
2717c478bd9Sstevel@tonic-gate 
27226ba1984Sjp161948 	if (buffer_get_ret(buffer, (char *) buf, 8) == -1)
27326ba1984Sjp161948 		return (-1);
27426ba1984Sjp161948 	*ret = GET_64BIT(buf);
27526ba1984Sjp161948 	return (0);
27626ba1984Sjp161948 }
27726ba1984Sjp161948 
27826ba1984Sjp161948 u_int64_t
buffer_get_int64(Buffer * buffer)27926ba1984Sjp161948 buffer_get_int64(Buffer *buffer)
28026ba1984Sjp161948 {
28126ba1984Sjp161948 	u_int64_t ret;
28226ba1984Sjp161948 
28326ba1984Sjp161948 	if (buffer_get_int64_ret(&ret, buffer) == -1)
28426ba1984Sjp161948 		fatal("buffer_get_int: buffer error");
28526ba1984Sjp161948 
28626ba1984Sjp161948 	return (ret);
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate #endif
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate /*
2917c478bd9Sstevel@tonic-gate  * Stores integers in the buffer, msb first.
2927c478bd9Sstevel@tonic-gate  */
2937c478bd9Sstevel@tonic-gate void
buffer_put_short(Buffer * buffer,u_short value)2947c478bd9Sstevel@tonic-gate buffer_put_short(Buffer *buffer, u_short value)
2957c478bd9Sstevel@tonic-gate {
2967c478bd9Sstevel@tonic-gate 	char buf[2];
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	PUT_16BIT(buf, value);
2997c478bd9Sstevel@tonic-gate 	buffer_append(buffer, buf, 2);
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate void
buffer_put_int(Buffer * buffer,u_int value)3037c478bd9Sstevel@tonic-gate buffer_put_int(Buffer *buffer, u_int value)
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate 	char buf[4];
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	PUT_32BIT(buf, value);
3087c478bd9Sstevel@tonic-gate 	buffer_append(buffer, buf, 4);
3097c478bd9Sstevel@tonic-gate }
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate #ifdef HAVE_U_INT64_T
3127c478bd9Sstevel@tonic-gate void
buffer_put_int64(Buffer * buffer,u_int64_t value)3137c478bd9Sstevel@tonic-gate buffer_put_int64(Buffer *buffer, u_int64_t value)
3147c478bd9Sstevel@tonic-gate {
3157c478bd9Sstevel@tonic-gate 	char buf[8];
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	PUT_64BIT(buf, value);
3187c478bd9Sstevel@tonic-gate 	buffer_append(buffer, buf, 8);
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate #endif
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate /*
3237c478bd9Sstevel@tonic-gate  * Returns an arbitrary binary string from the buffer.  The string cannot
3247c478bd9Sstevel@tonic-gate  * be longer than 256k.  The returned value points to memory allocated
3257c478bd9Sstevel@tonic-gate  * with xmalloc; it is the responsibility of the calling function to free
3267c478bd9Sstevel@tonic-gate  * the data.  If length_ptr is non-NULL, the length of the returned data
3277c478bd9Sstevel@tonic-gate  * will be stored there.  A null character will be automatically appended
3287c478bd9Sstevel@tonic-gate  * to the returned string, and is not counted in length.
3297c478bd9Sstevel@tonic-gate  */
3307c478bd9Sstevel@tonic-gate void *
buffer_get_string_ret(Buffer * buffer,u_int * length_ptr)33126ba1984Sjp161948 buffer_get_string_ret(Buffer *buffer, u_int *length_ptr)
3327c478bd9Sstevel@tonic-gate {
3337c478bd9Sstevel@tonic-gate 	u_char *value;
3347c478bd9Sstevel@tonic-gate 	u_int len;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	/* Get the length. */
3377c478bd9Sstevel@tonic-gate 	len = buffer_get_int(buffer);
33826ba1984Sjp161948 	if (len > 256 * 1024) {
33926ba1984Sjp161948 		error("buffer_get_string_ret: bad string length %u", len);
34026ba1984Sjp161948 		return (NULL);
34126ba1984Sjp161948 	}
3427c478bd9Sstevel@tonic-gate 	/* Allocate space for the string.  Add one byte for a null character. */
3437c478bd9Sstevel@tonic-gate 	value = xmalloc(len + 1);
3447c478bd9Sstevel@tonic-gate 	/* Get the string. */
34526ba1984Sjp161948 	if (buffer_get_ret(buffer, value, len) == -1) {
34626ba1984Sjp161948 		error("buffer_get_string_ret: buffer_get failed");
34726ba1984Sjp161948 		xfree(value);
34826ba1984Sjp161948 		return (NULL);
34926ba1984Sjp161948 	}
3507c478bd9Sstevel@tonic-gate 	/* Append a null character to make processing easier. */
3517c478bd9Sstevel@tonic-gate 	value[len] = 0;
3527c478bd9Sstevel@tonic-gate 	/* Optionally return the length of the string. */
3537c478bd9Sstevel@tonic-gate 	if (length_ptr)
3547c478bd9Sstevel@tonic-gate 		*length_ptr = len;
35526ba1984Sjp161948 	return (value);
3567c478bd9Sstevel@tonic-gate }
35726ba1984Sjp161948 
35826ba1984Sjp161948 void *
buffer_get_string(Buffer * buffer,u_int * length_ptr)35926ba1984Sjp161948 buffer_get_string(Buffer *buffer, u_int *length_ptr)
36026ba1984Sjp161948 {
36126ba1984Sjp161948 	void *ret;
36226ba1984Sjp161948 
36326ba1984Sjp161948 	if ((ret = buffer_get_string_ret(buffer, length_ptr)) == NULL)
36426ba1984Sjp161948 		fatal("buffer_get_string: buffer error");
36526ba1984Sjp161948 	return (ret);
36626ba1984Sjp161948 }
36726ba1984Sjp161948 
3687c478bd9Sstevel@tonic-gate char *
buffer_get_utf8_string(Buffer * buffer,uint_t * length_ptr)369*6f786aceSNobutomo Nakano buffer_get_utf8_string(Buffer *buffer, uint_t *length_ptr)
3707c478bd9Sstevel@tonic-gate {
371*6f786aceSNobutomo Nakano 	char	*value, *converted, *estr;
372*6f786aceSNobutomo Nakano 	uint_t	len;
3737c478bd9Sstevel@tonic-gate 
374*6f786aceSNobutomo Nakano 	if ((value = buffer_get_string(buffer, &len)) == NULL)
375*6f786aceSNobutomo Nakano 		return (value);
3767c478bd9Sstevel@tonic-gate 
377*6f786aceSNobutomo Nakano 	converted = g11n_convert_from_utf8(value, &len, &estr);
378*6f786aceSNobutomo Nakano 	if (converted == NULL) {
379*6f786aceSNobutomo Nakano 		if (estr != NULL)
380*6f786aceSNobutomo Nakano 			error("invalid UTF-8 sequence: %s", estr);
381*6f786aceSNobutomo Nakano 		converted = value;
382*6f786aceSNobutomo Nakano 	} else {
3837c478bd9Sstevel@tonic-gate 		xfree(value);
3847c478bd9Sstevel@tonic-gate 	}
3857c478bd9Sstevel@tonic-gate 
386*6f786aceSNobutomo Nakano 	if (length_ptr != NULL)
387*6f786aceSNobutomo Nakano 		*length_ptr = len;
3887c478bd9Sstevel@tonic-gate 
389*6f786aceSNobutomo Nakano 	return (converted);
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate /*
3937c478bd9Sstevel@tonic-gate  * Stores and arbitrary binary string in the buffer.
3947c478bd9Sstevel@tonic-gate  */
3957c478bd9Sstevel@tonic-gate void
buffer_put_string(Buffer * buffer,const void * buf,u_int len)3967c478bd9Sstevel@tonic-gate buffer_put_string(Buffer *buffer, const void *buf, u_int len)
3977c478bd9Sstevel@tonic-gate {
3987c478bd9Sstevel@tonic-gate 	buffer_put_int(buffer, len);
3997c478bd9Sstevel@tonic-gate 	buffer_append(buffer, buf, len);
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate void
buffer_put_cstring(Buffer * buffer,const char * s)4027c478bd9Sstevel@tonic-gate buffer_put_cstring(Buffer *buffer, const char *s)
4037c478bd9Sstevel@tonic-gate {
4047c478bd9Sstevel@tonic-gate 	if (s == NULL)
4057c478bd9Sstevel@tonic-gate 		fatal("buffer_put_cstring: s == NULL");
4067c478bd9Sstevel@tonic-gate 	buffer_put_string(buffer, s, strlen(s));
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate /*
4107c478bd9Sstevel@tonic-gate  * UTF-8 versions of the above.
4117c478bd9Sstevel@tonic-gate  */
4127c478bd9Sstevel@tonic-gate void
buffer_put_utf8_string(Buffer * buffer,const char * s,uint_t len)413*6f786aceSNobutomo Nakano buffer_put_utf8_string(Buffer *buffer, const char *s, uint_t len)
4147c478bd9Sstevel@tonic-gate {
415*6f786aceSNobutomo Nakano 	char	*converted, *estr;
416*6f786aceSNobutomo Nakano 	uint_t	nlen = len;
4177c478bd9Sstevel@tonic-gate 
418*6f786aceSNobutomo Nakano 	converted = g11n_convert_to_utf8(s, &nlen, 0, &estr);
419*6f786aceSNobutomo Nakano 	if (converted == NULL) {
420*6f786aceSNobutomo Nakano 		if (estr != NULL)
421*6f786aceSNobutomo Nakano 			error("Can't convert to UTF-8: %s", estr);
422*6f786aceSNobutomo Nakano 		converted = (char *)s;
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 
425*6f786aceSNobutomo Nakano 	buffer_put_string(buffer, converted, nlen);
426*6f786aceSNobutomo Nakano 
427*6f786aceSNobutomo Nakano 	if (converted != s)
428*6f786aceSNobutomo Nakano 		xfree(converted);
429*6f786aceSNobutomo Nakano }
430*6f786aceSNobutomo Nakano 
431*6f786aceSNobutomo Nakano void
buffer_put_utf8_cstring(Buffer * buffer,const char * s)432*6f786aceSNobutomo Nakano buffer_put_utf8_cstring(Buffer *buffer, const char *s)
433*6f786aceSNobutomo Nakano {
434*6f786aceSNobutomo Nakano 	buffer_put_utf8_string(buffer, s, strlen(s));
435*6f786aceSNobutomo Nakano }
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate /*
4387c478bd9Sstevel@tonic-gate  * Returns a character from the buffer (0 - 255).
4397c478bd9Sstevel@tonic-gate  */
4407c478bd9Sstevel@tonic-gate int
buffer_get_char_ret(char * ret,Buffer * buffer)44126ba1984Sjp161948 buffer_get_char_ret(char *ret, Buffer *buffer)
44226ba1984Sjp161948 {
44326ba1984Sjp161948 	if (buffer_get_ret(buffer, ret, 1) == -1) {
44426ba1984Sjp161948 		error("buffer_get_char_ret: buffer_get_ret failed");
44526ba1984Sjp161948 		return (-1);
44626ba1984Sjp161948 	}
44726ba1984Sjp161948 	return (0);
44826ba1984Sjp161948 }
44926ba1984Sjp161948 
45026ba1984Sjp161948 int
buffer_get_char(Buffer * buffer)4517c478bd9Sstevel@tonic-gate buffer_get_char(Buffer *buffer)
4527c478bd9Sstevel@tonic-gate {
4537c478bd9Sstevel@tonic-gate 	char ch;
4547c478bd9Sstevel@tonic-gate 
45526ba1984Sjp161948 	if (buffer_get_char_ret(&ch, buffer) == -1)
45626ba1984Sjp161948 		fatal("buffer_get_char: buffer error");
4577c478bd9Sstevel@tonic-gate 	return (u_char) ch;
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate /*
4617c478bd9Sstevel@tonic-gate  * Stores a character in the buffer.
4627c478bd9Sstevel@tonic-gate  */
4637c478bd9Sstevel@tonic-gate void
buffer_put_char(Buffer * buffer,int value)4647c478bd9Sstevel@tonic-gate buffer_put_char(Buffer *buffer, int value)
4657c478bd9Sstevel@tonic-gate {
4667c478bd9Sstevel@tonic-gate 	char ch = value;
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	buffer_append(buffer, &ch, 1);
4697c478bd9Sstevel@tonic-gate }
470