Home | History | Annotate | Download | only in smbsrv
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * SMB mbuf marshaling encode/decode.
     28  */
     29 
     30 #include <smbsrv/smb_kproto.h>
     31 
     32 
     33 #define	MALLOC_QUANTUM	80
     34 
     35 #define	DECODE_NO_ERROR		0
     36 #define	DECODE_NO_MORE_DATA	1
     37 #define	DECODE_ALLOCATION_ERROR	2
     38 #define	DECODE_CONVERSION_ERROR	3
     39 
     40 static int mbc_marshal_cstou8(char *, char *, size_t, char *, size_t);
     41 static int mbc_marshal_make_room(mbuf_chain_t *, int32_t);
     42 static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t);
     43 static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t);
     44 static int mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t);
     45 static int mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t);
     46 static int mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t);
     47 static int mbc_marshal_put_ascii_string(mbuf_chain_t *, char *, int);
     48 static int mbc_marshal_put_unicode_string(mbuf_chain_t *, char *, int);
     49 static int mbc_marshal_put_uio(mbuf_chain_t *, struct uio *);
     50 static int mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m);
     51 static int mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc);
     52 static uint8_t mbc_marshal_fetch_byte(mbuf_chain_t *mbc);
     53 static int mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data);
     54 static int mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data);
     55 static int mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data);
     56 static uint64_t qswap(uint64_t ll);
     57 static int mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data);
     58 static int mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data);
     59 static int mbc_marshal_get_ascii_string(smb_request_t *, mbuf_chain_t *,
     60     uint8_t **ascii, int);
     61 static int mbc_marshal_get_unicode_string(smb_request_t *, mbuf_chain_t *,
     62     uint8_t **, int);
     63 static int mbc_marshal_get_mbufs(mbuf_chain_t *, int32_t, mbuf_t **);
     64 static int mbc_marshal_get_mbuf_chain(mbuf_chain_t *, int32_t, mbuf_chain_t *);
     65 static int mbc_marshal_get_uio(mbuf_chain_t *, struct uio *);
     66 static int mbc_marshal_get_skip(mbuf_chain_t *, uint_t);
     67 
     68 /*
     69  * smb_mbc_vdecodef
     70  *
     71  * This function reads the contents of the mbc chain passed in under the list
     72  * of arguments passed in.
     73  *
     74  * The format string provides a description of the parameters passed in as well
     75  * as an action to be taken by smb_mbc_vdecodef().
     76  *
     77  *	%	Pointer to an SMB request structure (smb_request_t *). There
     78  *		should be only one of these in the string.
     79  *
     80  *	C	Pointer to an mbuf chain. Copy to that mbuf chain the number of
     81  *		bytes specified (number preceding C).
     82  *
     83  *	m	Pointer to an mbuf. Copy to that mbuf the number of bytes
     84  *		specified (number preceding m).
     85  *
     86  *	M	Read the 32 bit value at the current location of the mbuf chain
     87  *		and check if it matches the signature of an SMB request (SMBX).
     88  *
     89  *	b	Pointer to a buffer. Copy to that buffer the number of bytes
     90  *		specified (number preceding b).
     91  *
     92  *	c	Same as 'b'.
     93  *
     94  *	w	Pointer to a word (16bit value). Copy the next 16bit value into
     95  *		that location.
     96  *
     97  *	l	Pointer to a long (32bit value). Copy the next 32bit value into
     98  *		that location.
     99  *
    100  *	q	Pointer to a quad (64bit value). Copy the next 64bit value into
    101  *		that location.
    102  *
    103  *	Q	Same as above with a call to qswap().
    104  *
    105  *	B	Pointer to a vardata_block structure. That structure is used to
    106  *		retrieve data from the mbuf chain (an iovec type structure is
    107  *		embedded in a vardata_block).
    108  *
    109  *	D	Pointer to a vardata_block structure. That structure is used to
    110  *		retrieve data from the mbuf chain, however, two fields of the
    111  *		vardata_block structure (tag and len) are first initialized
    112  *		using the mbuf chain itself.
    113  *
    114  *	V	Same as 'D'.
    115  *
    116  *	L
    117  *
    118  *	A
    119  *
    120  *	P	Same as 'A'
    121  *
    122  *	S	Same as 'A'
    123  *
    124  *	u	Pointer to a string pointer. Allocate memory and retrieve the
    125  *		string at the current location in the mbuf chain. Store the
    126  *		address to the buffer allocated at the address specified by
    127  *		the pointer. In addition if an sr was passed and it indicates
    128  *		that the string is an unicode string, convert it.
    129  *
    130  *	s	Same as 'u' without convertion.
    131  *
    132  *	U	Same as 'u'. The string to retrieve is unicode.
    133  *
    134  *	y	Pointer to a 32bit value. Read the dos time at the current mbuf
    135  *		chain location, convert it to unix time and store it at the
    136  *		location indicated by the pointer.
    137  *
    138  *	Y	Same as 'y' bt the dos time coded in the mbuf chain is inverted.
    139  *
    140  *	.	Skip the number of bytes indicated by the number preceding '.'.
    141  *
    142  *	,	Same as '.' but take in account it is an unicode string.
    143  */
    144 int
    145 smb_mbc_vdecodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
    146 {
    147 	uint8_t		c;
    148 	uint8_t		cval;
    149 	uint8_t		*cvalp;
    150 	uint8_t		**cvalpp;
    151 	uint16_t	wval;
    152 	uint16_t	*wvalp;
    153 	uint32_t	*lvalp;
    154 	uint64_t	*llvalp;
    155 	smb_vdb_t	*vdp;
    156 	smb_request_t	*sr = NULL;
    157 	uint32_t	lval;
    158 	int		unicode = 0;
    159 	int		repc;
    160 
    161 	while ((c = *fmt++) != 0) {
    162 		repc = 1;
    163 
    164 		if ('0' <= c && c <= '9') {
    165 			repc = 0;
    166 			do {
    167 				repc = repc * 10 + c - '0';
    168 				c = *fmt++;
    169 			} while ('0' <= c && c <= '9');
    170 		} else if (c == '#') {
    171 			repc = va_arg(ap, int);
    172 			c = *fmt++;
    173 		}
    174 
    175 		switch (c) {
    176 		case '%':
    177 			sr = va_arg(ap, struct smb_request *);
    178 			unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
    179 			break;
    180 
    181 		case 'C':	/* Mbuf_chain */
    182 			if (mbc_marshal_get_mbuf_chain(mbc, repc,
    183 			    va_arg(ap, mbuf_chain_t *)) != 0)
    184 				return (-1);
    185 			break;
    186 
    187 		case 'm':	/* struct_mbuf */
    188 			if (mbc_marshal_get_mbufs(mbc, repc,
    189 			    va_arg(ap, mbuf_t **)) != 0)
    190 				return (-1);
    191 			break;
    192 
    193 		case 'M':
    194 			if (mbc_marshal_get_long(mbc, &lval) != 0)
    195 				/* Data will never be available */
    196 				return (-1);
    197 
    198 			if (lval != 0x424D53FF) /* 0xFF S M B */
    199 				return (-1);
    200 			break;
    201 
    202 		case 'b':
    203 		case 'c':
    204 			cvalp = va_arg(ap, uint8_t *);
    205 			if (MBC_ROOM_FOR(mbc, repc) == 0)
    206 				/* Data will never be available */
    207 				return (-1);
    208 
    209 			while (repc-- > 0)
    210 				*cvalp++ = mbc_marshal_fetch_byte(mbc);
    211 			break;
    212 
    213 		case 'w':
    214 			wvalp = va_arg(ap, uint16_t *);
    215 			while (repc-- > 0)
    216 				if (mbc_marshal_get_short(mbc, wvalp++) != 0)
    217 					return (-1);
    218 			break;
    219 
    220 		case 'l':
    221 			lvalp = va_arg(ap, uint32_t *);
    222 			while (repc-- > 0)
    223 				if (mbc_marshal_get_long(mbc, lvalp++) != 0)
    224 					return (-1);
    225 			break;
    226 
    227 		case 'q':
    228 			llvalp = va_arg(ap, uint64_t *);
    229 			while (repc-- > 0)
    230 				if (mbc_marshal_get_long_long(
    231 				    mbc, llvalp++) != 0)
    232 					return (-1);
    233 			break;
    234 
    235 		case 'Q':
    236 			llvalp = va_arg(ap, uint64_t *);
    237 			while (repc-- > 0)
    238 				if (mbc_marshal_get_odd_long_long(
    239 				    mbc, llvalp++) != 0)
    240 					return (-1);
    241 			break;
    242 
    243 		case 'B':
    244 			vdp = va_arg(ap, struct vardata_block *);
    245 			vdp->vdb_tag = 0;
    246 			vdp->vdb_len = repc;
    247 			vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0];
    248 			vdp->vdb_uio.uio_iovcnt = MAX_IOVEC;
    249 			vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
    250 			vdp->vdb_uio.uio_resid = repc;
    251 			if (mbc_marshal_get_uio(mbc, &vdp->vdb_uio) != 0)
    252 				return (-1);
    253 			break;
    254 
    255 		case 'D':
    256 		case 'V':
    257 			vdp = va_arg(ap, struct vardata_block *);
    258 			if (mbc_marshal_get_char(mbc, &vdp->vdb_tag) != 0)
    259 				return (-1);
    260 			if (mbc_marshal_get_short(mbc, &wval) != 0)
    261 				return (-1);
    262 			vdp->vdb_len = (uint32_t)wval;
    263 			vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0];
    264 			vdp->vdb_uio.uio_iovcnt = MAX_IOVEC;
    265 			vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
    266 			vdp->vdb_uio.uio_resid = vdp->vdb_len;
    267 			if (vdp->vdb_len != 0) {
    268 				if (mbc_marshal_get_uio(mbc,
    269 				    &vdp->vdb_uio) != 0)
    270 					return (-1);
    271 			}
    272 			break;
    273 
    274 		case 'L':
    275 			if (mbc_marshal_get_char(mbc, &cval) != 0)
    276 				return (-1);
    277 			if (cval != 2)
    278 				return (-1);
    279 			goto ascii_conversion;
    280 
    281 		case 'A':
    282 		case 'S':
    283 			if (mbc_marshal_get_char(mbc, &cval) != 0)
    284 				return (-1);
    285 			if (((c == 'A' || c == 'S') && cval != 4) ||
    286 			    (c == 'L' && cval != 2))
    287 				return (-1);
    288 			/* FALLTHROUGH */
    289 
    290 		case 'u': /* Convert from unicode if flags are set */
    291 			if (unicode)
    292 				goto unicode_translation;
    293 			/* FALLTHROUGH */
    294 
    295 		case 's':
    296 ascii_conversion:
    297 			ASSERT(sr != NULL);
    298 			cvalpp = va_arg(ap, uint8_t **);
    299 			if (repc <= 1)
    300 				repc = 0;
    301 			if (mbc_marshal_get_ascii_string(sr,
    302 			    mbc, cvalpp, repc) != 0)
    303 				return (-1);
    304 			break;
    305 
    306 		case 'U': /* Convert from unicode */
    307 unicode_translation:
    308 			ASSERT(sr != 0);
    309 			cvalpp = va_arg(ap, uint8_t **);
    310 			if (repc <= 1)
    311 				repc = 0;
    312 			if (mbc->chain_offset & 1)
    313 				mbc->chain_offset++;
    314 			if (mbc_marshal_get_unicode_string(sr,
    315 			    mbc, cvalpp, repc) != 0)
    316 				return (-1);
    317 			break;
    318 
    319 		case 'Y': /* dos time to unix time tt/dd */
    320 			lvalp = va_arg(ap, uint32_t *);
    321 			while (repc-- > 0) {
    322 				short	d, t;
    323 
    324 				if (mbc_marshal_get_short(mbc,
    325 				    (uint16_t *)&t) != 0)
    326 					return (-1);
    327 				if (mbc_marshal_get_short(mbc,
    328 				    (uint16_t *)&d) != 0)
    329 					return (-1);
    330 				*lvalp++ = smb_time_dos_to_unix(d, t);
    331 			}
    332 			break;
    333 
    334 		case 'y': /* dos time to unix time dd/tt */
    335 			lvalp = va_arg(ap, uint32_t *);
    336 			while (repc-- > 0) {
    337 				short	d, t;
    338 
    339 				if (mbc_marshal_get_short(mbc,
    340 				    (uint16_t *)&d) != 0)
    341 					return (-1);
    342 				if (mbc_marshal_get_short(mbc,
    343 				    (uint16_t *)&t) != 0)
    344 					return (-1);
    345 				*lvalp++ = smb_time_dos_to_unix(d, t);
    346 			}
    347 			break;
    348 
    349 		case ',':
    350 			if (unicode)
    351 				repc *= 2;
    352 			/* FALLTHROUGH */
    353 
    354 		case '.':
    355 			if (mbc_marshal_get_skip(mbc, repc) != 0)
    356 				return (-1);
    357 			break;
    358 
    359 		default:
    360 			ASSERT(0);
    361 			return (-1);
    362 		}
    363 	}
    364 	return (0);
    365 }
    366 
    367 /*
    368  * smb_mbc_decodef
    369  *
    370  * This function reads the contents of the mbc chain passed in under the
    371  * control of the format fmt.
    372  *
    373  * (for a description of the format string see smb_mbc_vencodef()).
    374  */
    375 int
    376 smb_mbc_decodef(mbuf_chain_t *mbc, char *fmt, ...)
    377 {
    378 	int	xx;
    379 	va_list	ap;
    380 
    381 	va_start(ap, fmt);
    382 	xx = smb_mbc_vdecodef(mbc, fmt, ap);
    383 	va_end(ap);
    384 	return (xx);
    385 }
    386 
    387 /*
    388  * smb_mbc_peek
    389  *
    390  * This function reads the contents of the mbc passed in at the specified offset
    391  * under the control of the format fmt. The offset of the chain passed in is not
    392  * modified.
    393  *
    394  * (for a description of the format string see smb_mbc_vdecodef()).
    395  */
    396 int
    397 smb_mbc_peek(mbuf_chain_t *mbc, int offset, char *fmt, ...)
    398 {
    399 	mbuf_chain_t	tmp;
    400 	va_list		ap;
    401 	int		xx;
    402 
    403 	va_start(ap, fmt);
    404 
    405 	(void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset);
    406 	xx = smb_mbc_vdecodef(&tmp, fmt, ap);
    407 	va_end(ap);
    408 	return (xx);
    409 }
    410 
    411 /*
    412  * smb_mbc_vencodef
    413  *
    414  * This function builds a stream of bytes in the mbc chain passed in under the
    415  * control of the list of arguments passed in.
    416  *
    417  * The format string provides a description of the parameters passed in as well
    418  * as an action to be taken by smb_mbc_vencodef().
    419  *
    420  *	\b	Restore the mbuf chain offset to its initial value.
    421  *
    422  *	%	Pointer to an SMB request structure (smb_request_t *). There
    423  *		should be only one of these in the string. If an sr in present
    424  *		it will be used to determine if unicode conversion should be
    425  *		applied to the strings.
    426  *
    427  *	C	Pointer to an mbuf chain. Copy that mbuf chain into the
    428  *		destination mbuf chain.
    429  *
    430  *	D	Pointer to a vardata_block structure. Copy the data described
    431  *		by that structure into the mbuf chain. The tag field is hard
    432  *		coded to '1'.
    433  *
    434  *	M	Write the SMB request signature ('SMBX') into the mbuf chain.
    435  *
    436  *	T	Pointer to a timestruc_t. Convert the content of the structure
    437  *		into NT time and store the result of the conversion in the
    438  *		mbuf chain.
    439  *
    440  *	V	Same as 'D' but the tag field is hard coded to '5'.
    441  *
    442  *	b	Byte. Store the byte or the nymber of bytes specified into the
    443  *		the mbuf chain. A format string like this "2b" would require 2
    444  *		bytes to be passed in.
    445  *
    446  *	m	Pointer to an mbuf. Copy the contents of the mbuf into the mbuf
    447  *		chain.
    448  *
    449  *	c	Pointer to a buffer. Copy the buffer into the mbuf chain. The
    450  *		size of the buffer is indicated by the number preceding 'c'.
    451  *
    452  *	w	Word (16bit value). Store the word or the number of words
    453  *              specified into the the mbuf chain. A format string like this
    454  *		"2w" would require 2 words to be passed in.
    455  *
    456  *	l	Long (32bit value). Store the long or the number of longs
    457  *		specified into the the mbuf chain. A format string like this
    458  *		"2l" would require 2 longs to be passed in.
    459  *
    460  *	q	Quad (64bit value). Store the quad or the number of quads
    461  *		specified into the the mbuf chain. A format string like this
    462  *		"2q" would require 2 quads to be passed in.
    463  *
    464  *	L	Pointer to a string. Store the string passed in into the mbuf
    465  *		chain preceded with a tag value of '2'.
    466  *
    467  *	S	Pointer to a string. Store the string passed in into the mbuf
    468  *		chain preceded with a tag value of '4'. Applied a unicode
    469  *		conversion is appropriate.
    470  *
    471  *	A	Same as 'S'
    472  *
    473  *	P	Pointer to a string. Store the string passed in into the mbuf
    474  *		chain preceded with a tag value of '5'. Applied a unicode
    475  *		conversion is appropriate.
    476  *
    477  *	u	Pointer to a string. Store the string passed in into the mbuf
    478  *		chain. Applied a unicode conversion is appropriate.
    479  *
    480  *	s	Pointer to a string. Store the string passed in into the mbuf
    481  *		chain.
    482  *
    483  *	Y	Date/Time.  Store the Date/Time or the number of Date/Time(s)
    484  *		specified into the the mbuf chain. A format string like this
    485  *		"2Y" would require 2 Date/Time values. The Date/Time is
    486  *		converted to DOS before storing.
    487  *
    488  *	y	Same as 'Y'. The order of Date and Time is reversed.
    489  *
    490  *	,	Character. Store the character or number of character specified
    491  *		into the mbuf chain.  A format string like this "2c" would
    492  *		require 2 characters to be passed in. A unicode conversion is
    493  *		applied if appropriate.
    494  *
    495  *	.	Same as '`' without unicode conversion.
    496  *
    497  *	U	Align the offset of the mbuf chain on a 16bit boundary.
    498  */
    499 int
    500 smb_mbc_vencodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
    501 {
    502 	uint8_t		*cvalp;
    503 	timestruc_t	*tvp;
    504 	smb_vdb_t	*vdp;
    505 	smb_request_t	*sr = NULL;
    506 	uint64_t	llval;
    507 	int64_t		nt_time;
    508 	uint32_t	lval;
    509 	uint_t		tag;
    510 	int		unicode = 0;
    511 	int		repc = 1;
    512 	uint16_t	wval;
    513 	uint8_t		cval;
    514 	uint8_t		c;
    515 
    516 	while ((c = *fmt++) != 0) {
    517 		repc = 1;
    518 
    519 		if ('0' <= c && c <= '9') {
    520 			repc = 0;
    521 			do {
    522 				repc = repc * 10 + c - '0';
    523 				c = *fmt++;
    524 			} while ('0' <= c && c <= '9');
    525 		} else if (c == '#') {
    526 			repc = va_arg(ap, int);
    527 			c = *fmt++;
    528 		}
    529 
    530 		switch (c) {
    531 		case '%':
    532 			sr = va_arg(ap, struct smb_request *);
    533 			unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
    534 			break;
    535 
    536 		case 'C':	/* Mbuf_chain */
    537 			if (mbc_marshal_put_mbuf_chain(mbc,
    538 			    va_arg(ap, mbuf_chain_t *)) != 0)
    539 				return (DECODE_NO_MORE_DATA);
    540 			break;
    541 
    542 		case 'D':
    543 			vdp = va_arg(ap, struct vardata_block *);
    544 
    545 			if (mbc_marshal_put_char(mbc, 1) != 0)
    546 				return (DECODE_NO_MORE_DATA);
    547 			if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0)
    548 				return (DECODE_NO_MORE_DATA);
    549 			if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0)
    550 				return (DECODE_NO_MORE_DATA);
    551 			break;
    552 
    553 		case 'M':
    554 			/* 0xFF S M B */
    555 			if (mbc_marshal_put_long(mbc, 0x424D53FF))
    556 				return (DECODE_NO_MORE_DATA);
    557 			break;
    558 
    559 		case 'T':
    560 			tvp = va_arg(ap, timestruc_t *);
    561 			nt_time = smb_time_unix_to_nt(tvp);
    562 			if (mbc_marshal_put_long_long(mbc, nt_time) != 0)
    563 				return (DECODE_NO_MORE_DATA);
    564 			break;
    565 
    566 		case 'V':
    567 			vdp = va_arg(ap, struct vardata_block *);
    568 
    569 			if (mbc_marshal_put_char(mbc, 5) != 0)
    570 				return (DECODE_NO_MORE_DATA);
    571 			if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0)
    572 				return (DECODE_NO_MORE_DATA);
    573 			if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0)
    574 				return (DECODE_NO_MORE_DATA);
    575 			break;
    576 
    577 		case 'b':
    578 			while (repc-- > 0) {
    579 				cval = va_arg(ap, int);
    580 				if (mbc_marshal_put_char(mbc, cval) != 0)
    581 					return (DECODE_NO_MORE_DATA);
    582 			}
    583 			break;
    584 
    585 		case 'm':	/* struct_mbuf */
    586 			if (mbc_marshal_put_mbufs(mbc,
    587 			    va_arg(ap, mbuf_t *)) != 0)
    588 				return (DECODE_NO_MORE_DATA);
    589 			break;
    590 
    591 		case 'c':
    592 			cvalp = va_arg(ap, uint8_t *);
    593 			while (repc-- > 0) {
    594 				if (mbc_marshal_put_char(mbc,
    595 				    *cvalp++) != 0)
    596 					return (DECODE_NO_MORE_DATA);
    597 			}
    598 			break;
    599 
    600 		case 'w':
    601 			while (repc-- > 0) {
    602 				wval = va_arg(ap, int);
    603 				if (mbc_marshal_put_short(mbc, wval) != 0)
    604 					return (DECODE_NO_MORE_DATA);
    605 			}
    606 			break;
    607 
    608 		case 'l':
    609 			while (repc-- > 0) {
    610 				lval = va_arg(ap, uint32_t);
    611 				if (mbc_marshal_put_long(mbc, lval) != 0)
    612 					return (DECODE_NO_MORE_DATA);
    613 			}
    614 			break;
    615 
    616 		case 'q':
    617 			while (repc-- > 0) {
    618 				llval = va_arg(ap, uint64_t);
    619 				if (mbc_marshal_put_long_long(mbc, llval) != 0)
    620 					return (DECODE_NO_MORE_DATA);
    621 			}
    622 			break;
    623 
    624 
    625 		case 'L':
    626 			tag = 2;
    627 			goto ascii_conversion;
    628 
    629 		case 'S':
    630 		case 'A':
    631 			tag = 4;
    632 			goto tagged_str;
    633 
    634 		case 'P':
    635 			tag = 3;
    636 			goto tagged_str;
    637 
    638 		tagged_str:
    639 			if (mbc_marshal_put_char(mbc, tag) != 0)
    640 				return (DECODE_NO_MORE_DATA);
    641 			/* FALLTHROUGH */
    642 
    643 		case 'u':	/* Convert from unicode if flags are set */
    644 			if (unicode)
    645 				goto unicode_translation;
    646 			/* FALLTHROUGH */
    647 
    648 		case 's':	/* ASCII/multibyte string */
    649 ascii_conversion:	cvalp = va_arg(ap, uint8_t *);
    650 			if (mbc_marshal_put_ascii_string(mbc,
    651 			    (char *)cvalp, repc) != 0)
    652 				return (DECODE_NO_MORE_DATA);
    653 			break;
    654 
    655 		case 'Y':		/* int32_t, encode dos date/time */
    656 			while (repc-- > 0) {
    657 				uint16_t	d, t;
    658 
    659 				lval = va_arg(ap, uint32_t);
    660 				smb_time_unix_to_dos(lval,
    661 				    (short *)&d, (short *)&t);
    662 				if (mbc_marshal_put_short(mbc, t) != 0)
    663 					return (DECODE_NO_MORE_DATA);
    664 				if (mbc_marshal_put_short(mbc, d) != 0)
    665 					return (DECODE_NO_MORE_DATA);
    666 			}
    667 			break;
    668 
    669 		case 'y':		/* int32_t, encode dos date/time */
    670 			while (repc-- > 0) {
    671 				uint16_t	d, t;
    672 
    673 				lval = va_arg(ap, uint32_t);
    674 				smb_time_unix_to_dos(lval,
    675 				    (short *)&d, (short *)&t);
    676 				if (mbc_marshal_put_short(mbc, d) != 0)
    677 					return (DECODE_NO_MORE_DATA);
    678 				if (mbc_marshal_put_short(mbc, t) != 0)
    679 					return (DECODE_NO_MORE_DATA);
    680 			}
    681 			break;
    682 
    683 		case ',':
    684 			if (unicode)
    685 				repc *= 2;
    686 			/* FALLTHROUGH */
    687 
    688 		case '.':
    689 			while (repc-- > 0)
    690 				if (mbc_marshal_put_char(mbc, 0) != 0)
    691 					return (DECODE_NO_MORE_DATA);
    692 			break;
    693 
    694 		case 'U': /* Convert to unicode, align to word boundary */
    695 unicode_translation:
    696 			if (mbc->chain_offset & 1)
    697 				mbc->chain_offset++;
    698 			cvalp = va_arg(ap, uint8_t *);
    699 			if (mbc_marshal_put_unicode_string(mbc,
    700 			    (char *)cvalp, repc) != 0)
    701 				return (DECODE_NO_MORE_DATA);
    702 			break;
    703 
    704 		default:
    705 			ASSERT(0);
    706 			return (-1);
    707 		}
    708 	}
    709 	return (0);
    710 }
    711 
    712 /*
    713  * smb_mbc_encodef
    714  *
    715  * This function builds a stream of bytes in the mbc chain passed in under the
    716  * control of the format fmt.
    717  *
    718  * (for a description of the format string see smb_mbc_vencodef()).
    719  */
    720 int
    721 smb_mbc_encodef(mbuf_chain_t *mbc, char *fmt, ...)
    722 {
    723 	int	rc;
    724 	va_list	ap;
    725 
    726 	va_start(ap, fmt);
    727 	rc = smb_mbc_vencodef(mbc, fmt, ap);
    728 	va_end(ap);
    729 	return (rc);
    730 }
    731 
    732 /*
    733  * smb_mbc_poke
    734  *
    735  * This function writes a stream of bytes in the mbc passed in at the specified
    736  * offset under the control of the format fmt. The offset of the chain passed in
    737  * is not modified.
    738  *
    739  * (for a description of the format string see smb_mbc_vencodef()).
    740  */
    741 int
    742 smb_mbc_poke(mbuf_chain_t *mbc, int offset, char *fmt, ...)
    743 {
    744 	int		xx;
    745 	mbuf_chain_t	tmp;
    746 	va_list		ap;
    747 
    748 	(void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset);
    749 	va_start(ap, fmt);
    750 	xx = smb_mbc_vencodef(&tmp, fmt, ap);
    751 	va_end(ap);
    752 	return (xx);
    753 }
    754 
    755 /*
    756  * Put data into mbuf chain allocating as needed.
    757  * Adds room to end of mbuf chain if needed.
    758  */
    759 static int
    760 mbc_marshal_make_room(mbuf_chain_t *mbc, int32_t bytes_needed)
    761 {
    762 	mbuf_t	*m;
    763 	mbuf_t	*l;
    764 	int32_t	bytes_available;
    765 
    766 	bytes_needed += mbc->chain_offset;
    767 	if (bytes_needed > mbc->max_bytes)
    768 		return (EMSGSIZE);
    769 
    770 	if ((m = mbc->chain) == 0) {
    771 		MGET(m, M_WAIT, MT_DATA);
    772 		m->m_len = 0;
    773 		if (mbc->max_bytes > MLEN)
    774 			MCLGET(m, M_WAIT);
    775 		mbc->chain = m;
    776 		/* xxxx */
    777 		/* ^    */
    778 	}
    779 
    780 	/* ---- ----- --xx ---xxx */
    781 	/* ^			  */
    782 
    783 	l = 0;
    784 	while ((m != 0) && (bytes_needed >= m->m_len)) {
    785 		l = m;
    786 		bytes_needed -= m->m_len;
    787 		m = m->m_next;
    788 	}
    789 
    790 	if ((bytes_needed == 0) || (m != 0)) {
    791 		/* We have enough room already */
    792 		return (0);
    793 	}
    794 
    795 	/* ---- ----- --xx ---xxx */
    796 	/*			 ^ */
    797 	/* Back up to start of last mbuf */
    798 	m = l;
    799 	bytes_needed += m->m_len;
    800 
    801 	/* ---- ----- --xx ---xxx */
    802 	/*		   ^	  */
    803 
    804 	bytes_available = (m->m_flags & M_EXT) ?
    805 	    m->m_ext.ext_size : MLEN;
    806 
    807 	/* ---- ----- --xx ---xxx */
    808 	/*		   ^	  */
    809 	while ((bytes_needed != 0) && (bytes_needed > bytes_available)) {
    810 		m->m_len = bytes_available;
    811 		bytes_needed -= m->m_len;
    812 		/* ---- ----- --xx ------ */
    813 		/*		   ^	  */
    814 
    815 		MGET(m->m_next, M_WAIT, MT_DATA);
    816 		m = m->m_next;
    817 		m->m_len = 0;
    818 		if (bytes_needed > MLEN)
    819 			MCLGET(m, M_WAIT);
    820 
    821 		bytes_available = (m->m_flags & M_EXT) ?
    822 		    m->m_ext.ext_size : MLEN;
    823 
    824 		/* ---- ----- --xx ------ xxxx */
    825 		/*			  ^    */
    826 	}
    827 
    828 	/* ---- ----- --xx ------ xxxx */
    829 	/*			  ^    */
    830 	/* Expand last tail as needed */
    831 	if (m->m_len <= bytes_needed) {
    832 		m->m_len = bytes_needed;
    833 		/* ---- ----- --xx ------ --xx */
    834 		/*			   ^   */
    835 	}
    836 
    837 	return (0);
    838 }
    839 
    840 static void
    841 mbc_marshal_store_byte(mbuf_chain_t *mbc, uint8_t data)
    842 {
    843 	mbuf_t	*m = mbc->chain;
    844 	int32_t	cur_offset = mbc->chain_offset;
    845 
    846 	/*
    847 	 * Scan forward looking for the last data currently in chain.
    848 	 */
    849 	while (cur_offset >= m->m_len) {
    850 		cur_offset -= m->m_len;
    851 		m = m->m_next;
    852 	}
    853 	((char *)m->m_data)[cur_offset] = data;
    854 	mbc->chain_offset++;
    855 }
    856 
    857 static int
    858 mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t data)
    859 {
    860 	if (mbc_marshal_make_room(mbc, sizeof (char)) != 0)
    861 		return (DECODE_NO_MORE_DATA);
    862 	mbc_marshal_store_byte(mbc, data);
    863 	return (0);
    864 }
    865 
    866 static int
    867 mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t data)
    868 {
    869 	if (mbc_marshal_make_room(mbc, sizeof (short)))
    870 		return (DECODE_NO_MORE_DATA);
    871 	mbc_marshal_store_byte(mbc, data);
    872 	mbc_marshal_store_byte(mbc, data >> 8);
    873 	return (0);
    874 }
    875 
    876 static int
    877 mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t data)
    878 {
    879 	if (mbc_marshal_make_room(mbc, sizeof (int32_t)))
    880 		return (DECODE_NO_MORE_DATA);
    881 	mbc_marshal_store_byte(mbc, data);
    882 	mbc_marshal_store_byte(mbc, data >> 8);
    883 	mbc_marshal_store_byte(mbc, data >> 16);
    884 	mbc_marshal_store_byte(mbc, data >> 24);
    885 	return (0);
    886 }
    887 
    888 static int
    889 mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t data)
    890 {
    891 	if (mbc_marshal_make_room(mbc, sizeof (int64_t)))
    892 		return (DECODE_NO_MORE_DATA);
    893 
    894 	mbc_marshal_store_byte(mbc, data);
    895 	mbc_marshal_store_byte(mbc, data >> 8);
    896 	mbc_marshal_store_byte(mbc, data >> 16);
    897 	mbc_marshal_store_byte(mbc, data >> 24);
    898 	mbc_marshal_store_byte(mbc, data >> 32);
    899 	mbc_marshal_store_byte(mbc, data >> 40);
    900 	mbc_marshal_store_byte(mbc, data >> 48);
    901 	mbc_marshal_store_byte(mbc, data >> 56);
    902 	return (0);
    903 }
    904 
    905 /*
    906  * When need to convert from UTF-8 (internal format) to a single
    907  * byte string (external format ) when marshalling a string.
    908  */
    909 static int
    910 mbc_marshal_put_ascii_string(mbuf_chain_t *mbc, char *mbs, int repc)
    911 {
    912 	smb_wchar_t	wide_char;
    913 	int		nbytes;
    914 	int		length;
    915 
    916 	if ((length = smb_sbequiv_strlen(mbs)) == -1)
    917 		return (DECODE_NO_MORE_DATA);
    918 
    919 	length += sizeof (char);
    920 
    921 	if ((repc > 1) && (repc < length))
    922 		length = repc;
    923 	if (mbc_marshal_make_room(mbc, length))
    924 		return (DECODE_NO_MORE_DATA);
    925 
    926 	while (*mbs) {
    927 		/*
    928 		 * We should restore oem chars here.
    929 		 */
    930 		nbytes = smb_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX);
    931 		if (nbytes == -1)
    932 			return (DECODE_NO_MORE_DATA);
    933 
    934 		mbc_marshal_store_byte(mbc, (uint8_t)wide_char);
    935 
    936 		if (wide_char & 0xFF00)
    937 			mbc_marshal_store_byte(mbc, wide_char >> 8);
    938 
    939 		mbs += nbytes;
    940 	}
    941 
    942 	mbc_marshal_store_byte(mbc, 0);
    943 	return (0);
    944 }
    945 
    946 static int
    947 mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *ascii, int repc)
    948 {
    949 	smb_wchar_t	wchar;
    950 	int		consumed;
    951 	int		length;
    952 
    953 	if ((length = smb_wcequiv_strlen(ascii)) == -1)
    954 		return (DECODE_NO_MORE_DATA);
    955 
    956 	length += sizeof (smb_wchar_t);
    957 
    958 	if ((repc > 1) && (repc < length))
    959 		length = repc;
    960 
    961 	if (mbc_marshal_make_room(mbc, length))
    962 		return (DECODE_NO_MORE_DATA);
    963 	while (length > 0) {
    964 		consumed = smb_mbtowc(&wchar, ascii, MTS_MB_CHAR_MAX);
    965 		if (consumed == -1)
    966 			break;	/* Invalid sequence */
    967 		/*
    968 		 * Note that consumed will be 0 when the null terminator
    969 		 * is encountered and ascii will not be advanced beyond
    970 		 * that point. Length will continue to be decremented so
    971 		 * we won't get stuck here.
    972 		 */
    973 		ascii += consumed;
    974 		mbc_marshal_store_byte(mbc, wchar);
    975 		mbc_marshal_store_byte(mbc, wchar >> 8);
    976 		length -= sizeof (smb_wchar_t);
    977 	}
    978 	return (0);
    979 }
    980 
    981 static int
    982 mbc_marshal_put_uio(mbuf_chain_t *mbc, struct uio *uio)
    983 {
    984 	mbuf_t		**t;
    985 	mbuf_t		*m = NULL;
    986 	struct iovec	*iov = uio->uio_iov;
    987 	int32_t		i, iov_cnt = uio->uio_iovcnt;
    988 
    989 	iov = uio->uio_iov;
    990 	t = &mbc->chain;
    991 	for (i = 0; i < iov_cnt; i++) {
    992 		MGET(m, M_WAIT, MT_DATA);
    993 		m->m_ext.ext_buf = iov->iov_base;
    994 		m->m_ext.ext_ref = smb_noop;
    995 		m->m_data = m->m_ext.ext_buf;
    996 		m->m_flags |= M_EXT;
    997 		m->m_len = m->m_ext.ext_size = iov->iov_len;
    998 		mbc->max_bytes += m->m_len;
    999 		m->m_next = 0;
   1000 		*t = m;
   1001 		t = &m->m_next;
   1002 		iov++;
   1003 	}
   1004 	return (0);
   1005 }
   1006 
   1007 static int
   1008 mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m)
   1009 {
   1010 	mbuf_t	*mt;
   1011 	mbuf_t	**t;
   1012 	int	bytes;
   1013 
   1014 	if (m != NULL) {
   1015 		mt = m;
   1016 		bytes = mt->m_len;
   1017 		while (mt->m_next != 0) {
   1018 			mt = mt->m_next;
   1019 			bytes += mt->m_len;
   1020 		}
   1021 		if (bytes != 0) {
   1022 			t = &mbc->chain;
   1023 			while (*t != 0) {
   1024 				bytes += (*t)->m_len;
   1025 				t = &(*t)->m_next;
   1026 			}
   1027 			*t = m;
   1028 			mbc->chain_offset = bytes;
   1029 		} else {
   1030 			m_freem(m);
   1031 		}
   1032 	}
   1033 	return (0);
   1034 }
   1035 
   1036 static int
   1037 mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc)
   1038 {
   1039 	if (nmbc->chain != 0) {
   1040 		if (mbc_marshal_put_mbufs(mbc, nmbc->chain))
   1041 			return (DECODE_NO_MORE_DATA);
   1042 		MBC_SETUP(nmbc, nmbc->max_bytes);
   1043 	}
   1044 	return (0);
   1045 }
   1046 
   1047 static uint8_t
   1048 mbc_marshal_fetch_byte(mbuf_chain_t *mbc)
   1049 {
   1050 	uint8_t	data;
   1051 	mbuf_t	*m = mbc->chain;
   1052 	int32_t	offset = mbc->chain_offset;
   1053 
   1054 	while (offset >= m->m_len) {
   1055 		offset -= m->m_len;
   1056 		m = m->m_next;
   1057 	}
   1058 	data = ((uint8_t *)m->m_data)[offset];
   1059 	mbc->chain_offset++;
   1060 	return (data);
   1061 }
   1062 
   1063 static int
   1064 mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data)
   1065 {
   1066 	if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
   1067 		/* Data will never be available */
   1068 		return (DECODE_NO_MORE_DATA);
   1069 	}
   1070 	*data = mbc_marshal_fetch_byte(mbc);
   1071 	return (0);
   1072 }
   1073 
   1074 static int
   1075 mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data)
   1076 {
   1077 	uint16_t	tmp;
   1078 	mbuf_t		*m = mbc->chain;
   1079 	int32_t		offset = mbc->chain_offset;
   1080 
   1081 	if (MBC_ROOM_FOR(mbc, sizeof (short)) == 0) {
   1082 		/* Data will never be available */
   1083 		return (DECODE_NO_MORE_DATA);
   1084 	}
   1085 
   1086 	while (offset >= m->m_len) {
   1087 		offset -= m->m_len;
   1088 		m = m->m_next;
   1089 	}
   1090 	if ((m->m_len - offset) >= sizeof (short)) {
   1091 		*data = LE_IN16(m->m_data + offset);
   1092 		mbc->chain_offset += sizeof (short);
   1093 	} else {
   1094 		tmp = (uint16_t)mbc_marshal_fetch_byte(mbc);
   1095 		tmp |= ((uint16_t)mbc_marshal_fetch_byte(mbc)) << 8;
   1096 		*data = tmp;
   1097 	}
   1098 	return (0);
   1099 }
   1100 
   1101 static int
   1102 mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data)
   1103 {
   1104 	uint32_t	tmp;
   1105 	mbuf_t		*m = mbc->chain;
   1106 	int32_t		offset = mbc->chain_offset;
   1107 
   1108 	if (MBC_ROOM_FOR(mbc, sizeof (int32_t)) == 0) {
   1109 		/* Data will never be available */
   1110 		return (DECODE_NO_MORE_DATA);
   1111 	}
   1112 	while (offset >= m->m_len) {
   1113 		offset -= m->m_len;
   1114 		m = m->m_next;
   1115 	}
   1116 	if ((m->m_len - offset) >= sizeof (int32_t)) {
   1117 		*data = LE_IN32(m->m_data + offset);
   1118 		mbc->chain_offset += sizeof (int32_t);
   1119 	} else {
   1120 		tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
   1121 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 8;
   1122 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 16;
   1123 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 24;
   1124 		*data = tmp;
   1125 	}
   1126 	return (0);
   1127 }
   1128 
   1129 static uint64_t
   1130 qswap(uint64_t ll)
   1131 {
   1132 	uint64_t v;
   1133 
   1134 	v = ll >> 32;
   1135 	v |= ll << 32;
   1136 
   1137 	return (v);
   1138 }
   1139 
   1140 static int
   1141 mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data)
   1142 {
   1143 	uint64_t	tmp;
   1144 	mbuf_t		*m = mbc->chain;
   1145 	int32_t		offset = mbc->chain_offset;
   1146 
   1147 	if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
   1148 		/* Data will never be available */
   1149 		return (DECODE_NO_MORE_DATA);
   1150 	}
   1151 	while (offset >= m->m_len) {
   1152 		offset -= m->m_len;
   1153 		m = m->m_next;
   1154 	}
   1155 
   1156 	if ((m->m_len - offset) >= sizeof (int64_t)) {
   1157 		*data = qswap(LE_IN64(m->m_data + offset));
   1158 		mbc->chain_offset += sizeof (int64_t);
   1159 	} else {
   1160 		tmp = (uint64_t)mbc_marshal_fetch_byte(mbc) << 32;
   1161 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 40;
   1162 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 48;
   1163 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 56;
   1164 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc);
   1165 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 8;
   1166 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 16;
   1167 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 24;
   1168 
   1169 		*(uint64_t *)data = tmp;
   1170 	}
   1171 	return (0);
   1172 }
   1173 
   1174 static int
   1175 mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data)
   1176 {
   1177 	uint64_t	tmp;
   1178 	mbuf_t		*m = mbc->chain;
   1179 	int32_t		offset = mbc->chain_offset;
   1180 
   1181 	if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
   1182 		/* Data will never be available */
   1183 		return (DECODE_NO_MORE_DATA);
   1184 	}
   1185 	while (offset >= m->m_len) {
   1186 		offset -= m->m_len;
   1187 		m = m->m_next;
   1188 	}
   1189 	if ((m->m_len - offset) >= sizeof (int64_t)) {
   1190 		*data = LE_IN64(m->m_data + offset);
   1191 		mbc->chain_offset += sizeof (int64_t);
   1192 	} else {
   1193 		tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
   1194 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 8;
   1195 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 16;
   1196 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 24;
   1197 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32;
   1198 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40;
   1199 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48;
   1200 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56;
   1201 		*(uint64_t *)data = tmp;
   1202 	}
   1203 	return (0);
   1204 }
   1205 
   1206 /*
   1207  * mbc_marshal_get_ascii_string
   1208  *
   1209  * The ascii string in smb includes oem chars. Since the
   1210  * system needs utf8 encodes unicode char, conversion is
   1211  * required to convert the oem char to unicode and then
   1212  * to encode the converted wchars to utf8 format.
   1213  * Therefore, the **ascii returned will be in such format
   1214  * instead of the real ASCII format.
   1215  */
   1216 static int
   1217 mbc_marshal_get_ascii_string(
   1218     smb_request_t	*sr,
   1219     mbuf_chain_t	*mbc,
   1220     uint8_t		**ascii,
   1221     int			max_ascii)
   1222 {
   1223 	char		*rcvbuf;
   1224 	char		*ch;
   1225 	int		max;
   1226 	int		length = 0;
   1227 
   1228 	max = MALLOC_QUANTUM;
   1229 	rcvbuf = smb_srm_alloc(sr, max);
   1230 
   1231 	if (max_ascii == 0)
   1232 		max_ascii = 0xffff;
   1233 
   1234 	ch = rcvbuf;
   1235 	for (;;) {
   1236 		while (length < max) {
   1237 			if (max_ascii-- <= 0) {
   1238 				*ch++ = 0;
   1239 				goto multibyte_encode;
   1240 			}
   1241 			if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
   1242 				/* Data will never be available */
   1243 				return (DECODE_NO_MORE_DATA);
   1244 			}
   1245 			if ((*ch++ = mbc_marshal_fetch_byte(mbc)) == 0)
   1246 				goto multibyte_encode;
   1247 			length++;
   1248 		}
   1249 		max += MALLOC_QUANTUM;
   1250 		rcvbuf = smb_srm_realloc(sr, rcvbuf, max);
   1251 		ch = rcvbuf + length;
   1252 	}
   1253 
   1254 multibyte_encode:
   1255 	/*
   1256 	 * UTF-8 encode the string for internal system use.
   1257 	 */
   1258 	length = strlen(rcvbuf) + 1;
   1259 	*ascii = smb_srm_alloc(sr, length * MTS_MB_CHAR_MAX);
   1260 	return (mbc_marshal_cstou8("CP850", (char *)*ascii,
   1261 	    (size_t)length * MTS_MB_CHAR_MAX, rcvbuf, (size_t)length));
   1262 }
   1263 
   1264 static int
   1265 mbc_marshal_get_unicode_string(smb_request_t *sr,
   1266     mbuf_chain_t *mbc, uint8_t **ascii, int max_unicode)
   1267 {
   1268 	int		max;
   1269 	uint16_t	wchar;
   1270 	char		*ch;
   1271 	int		emitted;
   1272 	int		length = 0;
   1273 
   1274 	if (max_unicode == 0)
   1275 		max_unicode = 0xffff;
   1276 
   1277 	max = MALLOC_QUANTUM;
   1278 	*ascii = smb_srm_alloc(sr, max);
   1279 
   1280 	ch = (char *)*ascii;
   1281 	for (;;) {
   1282 		while ((length + MTS_MB_CHAR_MAX) < max) {
   1283 			if (max_unicode <= 0)
   1284 				goto done;
   1285 			max_unicode -= 2;
   1286 
   1287 			if (mbc_marshal_get_short(mbc, &wchar) != 0)
   1288 				return (DECODE_NO_MORE_DATA);
   1289 
   1290 			if (wchar == 0)	goto done;
   1291 
   1292 			emitted = smb_wctomb(ch, wchar);
   1293 			length += emitted;
   1294 			ch += emitted;
   1295 		}
   1296 		max += MALLOC_QUANTUM;
   1297 		*ascii = smb_srm_realloc(sr, *ascii, max);
   1298 		ch = (char *)*ascii + length;
   1299 	}
   1300 done:	*ch = 0;
   1301 	return (0);
   1302 }
   1303 
   1304 static int /*ARGSUSED*/
   1305 mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m)
   1306 {
   1307 	if (MBC_ROOM_FOR(mbc, bytes) == 0) {
   1308 		/* Data will never be available */
   1309 		return (DECODE_NO_MORE_DATA);
   1310 	}
   1311 	return (0);
   1312 }
   1313 
   1314 static int
   1315 mbc_marshal_get_mbuf_chain(mbuf_chain_t *mbc, int32_t bytes, mbuf_chain_t *nmbc)
   1316 {
   1317 	int	rc;
   1318 	mbuf_t	*m;
   1319 
   1320 	if (bytes == 0) {
   1321 		/* Get all the rest */
   1322 		bytes = mbc->max_bytes - mbc->chain_offset;
   1323 	}
   1324 
   1325 	MBC_SETUP(nmbc, mbc->max_bytes);
   1326 	if ((rc = mbc_marshal_get_mbufs(mbc, bytes, &m)) != 0) {
   1327 		if (m)
   1328 			m_freem(m);
   1329 		return (rc);
   1330 	}
   1331 	nmbc->chain = m;
   1332 	while (m != 0) {
   1333 		bytes += m->m_len;
   1334 		m = m->m_next;
   1335 	}
   1336 	nmbc->max_bytes = bytes;
   1337 	return (0);
   1338 }
   1339 
   1340 static int
   1341 mbc_marshal_get_uio(mbuf_chain_t *mbc, struct uio *uio)
   1342 {
   1343 	int		i, offset;
   1344 	int32_t		bytes = uio->uio_resid;
   1345 	int32_t		remainder;
   1346 	struct iovec	*iov;
   1347 	mbuf_t		*m;
   1348 
   1349 	/*
   1350 	 * The residual count is tested because in the case of write requests
   1351 	 * with no data (smbtorture RAW-WRITE test will generate that type of
   1352 	 * request) this function is called with a residual count of zero
   1353 	 * bytes.
   1354 	 */
   1355 	if (bytes != 0) {
   1356 		iov = uio->uio_iov;
   1357 		uio->uio_segflg = UIO_SYSSPACE;
   1358 		uio->uio_extflg = UIO_COPY_DEFAULT;
   1359 
   1360 		if (MBC_ROOM_FOR(mbc, bytes) == 0) {
   1361 			/* Data will never be available */
   1362 			return (DECODE_NO_MORE_DATA);
   1363 		}
   1364 
   1365 		m = mbc->chain;
   1366 		offset = mbc->chain_offset;
   1367 		while (offset >= m->m_len) {
   1368 			offset -= m->m_len;
   1369 			m = m->m_next;
   1370 			ASSERT((offset == 0) || (offset && m));
   1371 		}
   1372 
   1373 		for (i = 0; (bytes > 0) && (i < uio->uio_iovcnt); i++) {
   1374 			iov[i].iov_base = &m->m_data[offset];
   1375 			remainder = m->m_len - offset;
   1376 			if (remainder >= bytes) {
   1377 				iov[i].iov_len = bytes;
   1378 				mbc->chain_offset += bytes;
   1379 				uio->uio_iovcnt = i + 1;
   1380 				return (0);
   1381 			}
   1382 			iov[i].iov_len = remainder;
   1383 			mbc->chain_offset += remainder;
   1384 			bytes -= remainder;
   1385 			m = m->m_next;
   1386 			offset = 0;
   1387 		}
   1388 		return (DECODE_NO_MORE_DATA);
   1389 	}
   1390 	return (0);
   1391 }
   1392 
   1393 static int
   1394 mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip)
   1395 {
   1396 	if (MBC_ROOM_FOR(mbc, skip) == 0)
   1397 		return (DECODE_NO_MORE_DATA);
   1398 	mbc->chain_offset += skip;
   1399 	return (0);
   1400 }
   1401 
   1402 /*
   1403  * Converts oem string to UTF-8 string with an output string of max
   1404  * maxconv bytes.  The string may be truncated or not null-terminated if
   1405  * there is not enough room.
   1406  *
   1407  * returns -1, cnt (partial conversion)  or 0 (success)
   1408  */
   1409 
   1410 static int
   1411 mbc_marshal_cstou8(char *cs, char *outbuf, size_t maxconv,
   1412     char *inbuf, size_t srcbytes)
   1413 {
   1414 	kiconv_t	t2u;
   1415 	size_t		inlen = srcbytes;
   1416 	size_t		outlen = maxconv;
   1417 	int		err = 0;
   1418 	size_t		rc;
   1419 
   1420 	if ((t2u = kiconv_open("UTF-8", cs)) == (kiconv_t)-1)
   1421 		return (-1);
   1422 
   1423 	rc = kiconv(t2u, &inbuf, &inlen, &outbuf, &outlen, &err);
   1424 	(void) kiconv_close(t2u);
   1425 	return ((int)rc);
   1426 }
   1427