xref: /titanic_44/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c (revision 7f3ef643e446c82e27a9386991b140b128baf22c)
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
smb_mbc_vdecodef(mbuf_chain_t * mbc,char * fmt,va_list ap)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
smb_mbc_decodef(mbuf_chain_t * mbc,char * fmt,...)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
smb_mbc_peek(mbuf_chain_t * mbc,int offset,char * fmt,...)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
smb_mbc_vencodef(mbuf_chain_t * mbc,char * fmt,va_list ap)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
smb_mbc_encodef(mbuf_chain_t * mbc,char * fmt,...)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
smb_mbc_poke(mbuf_chain_t * mbc,int offset,char * fmt,...)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  * Copy data from the src mbuf chain to the dst mbuf chain,
757  * at the given offset in the src and current offset in dst,
758  * for copy_len bytes.  Does NOT update src->chain_offset.
759  */
760 int
smb_mbc_copy(mbuf_chain_t * dst_mbc,const mbuf_chain_t * src_mbc,int copy_offset,int copy_len)761 smb_mbc_copy(mbuf_chain_t *dst_mbc, const mbuf_chain_t *src_mbc,
762 	int copy_offset, int copy_len)
763 {
764 	mbuf_t	*src_m;
765 	int offset, len;
766 	int rc;
767 
768 	if (copy_len <= 0)
769 		return (0);
770 	if (copy_offset < 0)
771 		return (EINVAL);
772 	if ((copy_offset + copy_len) > src_mbc->max_bytes)
773 		return (EMSGSIZE);
774 
775 	/*
776 	 * Advance to the src mbuf where we start copying.
777 	 */
778 	offset = copy_offset;
779 	src_m = src_mbc->chain;
780 	while (src_m && offset >= src_m->m_len) {
781 		offset -= src_m->m_len;
782 		src_m = src_m->m_next;
783 	}
784 	if (src_m == NULL)
785 		return (EFAULT);
786 
787 	/*
788 	 * Copy the first part, which may start somewhere past
789 	 * the beginning of the current mbuf.
790 	 */
791 	len = src_m->m_len - offset;
792 	if (len > copy_len)
793 		len = copy_len;
794 	rc = smb_mbc_put_mem(dst_mbc, src_m->m_data + offset, len);
795 	if (rc != 0)
796 		return (rc);
797 	copy_len -= len;
798 
799 	/*
800 	 * Copy remaining mbufs...
801 	 */
802 	while (copy_len > 0) {
803 		src_m = src_m->m_next;
804 		if (src_m == NULL)
805 			break;
806 		len = src_m->m_len;
807 		if (len > copy_len)
808 			len = copy_len;
809 		rc = smb_mbc_put_mem(dst_mbc, src_m->m_data, len);
810 		copy_len -= len;
811 	}
812 
813 	return (0);
814 }
815 
816 /*
817  * Copy data from the passed memory buffer into the mbuf chain
818  * at the current offset.
819  */
820 int
smb_mbc_put_mem(mbuf_chain_t * mbc,void * vmem,int mem_len)821 smb_mbc_put_mem(mbuf_chain_t *mbc, void *vmem, int mem_len)
822 {
823 	caddr_t mem = vmem;
824 	mbuf_t	*m;
825 	int32_t	offset, tlen;
826 	int rc;
827 
828 	if (mem_len <= 0)
829 		return (0);
830 
831 	if ((rc = mbc_marshal_make_room(mbc, mem_len)) != 0)
832 		return (rc);
833 
834 	/*
835 	 * Advance to the dst mbuf where we start copying.
836 	 * Allocations were done by _make_room().
837 	 */
838 	offset = mbc->chain_offset;
839 	m = mbc->chain;
840 	while (offset >= m->m_len) {
841 		ASSERT(m->m_len > 0);
842 		offset -= m->m_len;
843 		m = m->m_next;
844 	}
845 
846 	/*
847 	 * Copy the first part, which may start somewhere past
848 	 * the beginning of the current mbuf.
849 	 */
850 	tlen = m->m_len - offset;
851 	if (tlen > mem_len)
852 		tlen = mem_len;
853 	bcopy(mem, m->m_data + offset, tlen);
854 	mbc->chain_offset += tlen;
855 	mem += tlen;
856 	mem_len -= tlen;
857 
858 	/*
859 	 * Copy remaining mem into mbufs.  These all start
860 	 * at the beginning of each mbuf, and the last may
861 	 * end somewhere short of m_len.
862 	 */
863 	while (mem_len > 0) {
864 		m = m->m_next;
865 		tlen = m->m_len;
866 		if (tlen > mem_len)
867 			tlen = mem_len;
868 		bcopy(mem, m->m_data, tlen);
869 		mbc->chain_offset += tlen;
870 		mem += tlen;
871 		mem_len -= tlen;
872 	}
873 
874 	return (0);
875 }
876 
877 /*
878  * Put data into mbuf chain allocating as needed.
879  * Adds room to end of mbuf chain if needed.
880  */
881 static int
mbc_marshal_make_room(mbuf_chain_t * mbc,int32_t bytes_needed)882 mbc_marshal_make_room(mbuf_chain_t *mbc, int32_t bytes_needed)
883 {
884 	mbuf_t	*m;
885 	mbuf_t	*l;
886 	int32_t	bytes_available;
887 
888 	bytes_needed += mbc->chain_offset;
889 	if (bytes_needed > mbc->max_bytes)
890 		return (EMSGSIZE);
891 
892 	if ((m = mbc->chain) == 0) {
893 		MGET(m, M_WAIT, MT_DATA);
894 		m->m_len = 0;
895 		if (mbc->max_bytes > MLEN)
896 			MCLGET(m, M_WAIT);
897 		mbc->chain = m;
898 		/* xxxx */
899 		/* ^    */
900 	}
901 
902 	/* ---- ----- --xx ---xxx */
903 	/* ^			  */
904 
905 	l = 0;
906 	while ((m != 0) && (bytes_needed >= m->m_len)) {
907 		l = m;
908 		bytes_needed -= m->m_len;
909 		m = m->m_next;
910 	}
911 
912 	if ((bytes_needed == 0) || (m != 0)) {
913 		/* We have enough room already */
914 		return (0);
915 	}
916 
917 	/* ---- ----- --xx ---xxx */
918 	/*			 ^ */
919 	/* Back up to start of last mbuf */
920 	m = l;
921 	bytes_needed += m->m_len;
922 
923 	/* ---- ----- --xx ---xxx */
924 	/*		   ^	  */
925 
926 	bytes_available = (m->m_flags & M_EXT) ?
927 	    m->m_ext.ext_size : MLEN;
928 
929 	/* ---- ----- --xx ---xxx */
930 	/*		   ^	  */
931 	while ((bytes_needed != 0) && (bytes_needed > bytes_available)) {
932 		m->m_len = bytes_available;
933 		bytes_needed -= m->m_len;
934 		/* ---- ----- --xx ------ */
935 		/*		   ^	  */
936 
937 		MGET(m->m_next, M_WAIT, MT_DATA);
938 		m = m->m_next;
939 		m->m_len = 0;
940 		if (bytes_needed > MLEN)
941 			MCLGET(m, M_WAIT);
942 
943 		bytes_available = (m->m_flags & M_EXT) ?
944 		    m->m_ext.ext_size : MLEN;
945 
946 		/* ---- ----- --xx ------ xxxx */
947 		/*			  ^    */
948 	}
949 
950 	/* ---- ----- --xx ------ xxxx */
951 	/*			  ^    */
952 	/* Expand last tail as needed */
953 	if (m->m_len <= bytes_needed) {
954 		m->m_len = bytes_needed;
955 		/* ---- ----- --xx ------ --xx */
956 		/*			   ^   */
957 	}
958 
959 	return (0);
960 }
961 
962 static void
mbc_marshal_store_byte(mbuf_chain_t * mbc,uint8_t data)963 mbc_marshal_store_byte(mbuf_chain_t *mbc, uint8_t data)
964 {
965 	mbuf_t	*m = mbc->chain;
966 	int32_t	cur_offset = mbc->chain_offset;
967 
968 	/*
969 	 * Scan forward looking for the last data currently in chain.
970 	 */
971 	while (cur_offset >= m->m_len) {
972 		cur_offset -= m->m_len;
973 		m = m->m_next;
974 	}
975 	((char *)m->m_data)[cur_offset] = data;
976 	mbc->chain_offset++;
977 }
978 
979 static int
mbc_marshal_put_char(mbuf_chain_t * mbc,uint8_t data)980 mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t data)
981 {
982 	if (mbc_marshal_make_room(mbc, sizeof (char)) != 0)
983 		return (DECODE_NO_MORE_DATA);
984 	mbc_marshal_store_byte(mbc, data);
985 	return (0);
986 }
987 
988 static int
mbc_marshal_put_short(mbuf_chain_t * mbc,uint16_t data)989 mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t data)
990 {
991 	if (mbc_marshal_make_room(mbc, sizeof (short)))
992 		return (DECODE_NO_MORE_DATA);
993 	mbc_marshal_store_byte(mbc, data);
994 	mbc_marshal_store_byte(mbc, data >> 8);
995 	return (0);
996 }
997 
998 static int
mbc_marshal_put_long(mbuf_chain_t * mbc,uint32_t data)999 mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t data)
1000 {
1001 	if (mbc_marshal_make_room(mbc, sizeof (int32_t)))
1002 		return (DECODE_NO_MORE_DATA);
1003 	mbc_marshal_store_byte(mbc, data);
1004 	mbc_marshal_store_byte(mbc, data >> 8);
1005 	mbc_marshal_store_byte(mbc, data >> 16);
1006 	mbc_marshal_store_byte(mbc, data >> 24);
1007 	return (0);
1008 }
1009 
1010 static int
mbc_marshal_put_long_long(mbuf_chain_t * mbc,uint64_t data)1011 mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t data)
1012 {
1013 	if (mbc_marshal_make_room(mbc, sizeof (int64_t)))
1014 		return (DECODE_NO_MORE_DATA);
1015 
1016 	mbc_marshal_store_byte(mbc, data);
1017 	mbc_marshal_store_byte(mbc, data >> 8);
1018 	mbc_marshal_store_byte(mbc, data >> 16);
1019 	mbc_marshal_store_byte(mbc, data >> 24);
1020 	mbc_marshal_store_byte(mbc, data >> 32);
1021 	mbc_marshal_store_byte(mbc, data >> 40);
1022 	mbc_marshal_store_byte(mbc, data >> 48);
1023 	mbc_marshal_store_byte(mbc, data >> 56);
1024 	return (0);
1025 }
1026 
1027 /*
1028  * When need to convert from UTF-8 (internal format) to a single
1029  * byte string (external format ) when marshalling a string.
1030  */
1031 static int
mbc_marshal_put_ascii_string(mbuf_chain_t * mbc,char * mbs,int repc)1032 mbc_marshal_put_ascii_string(mbuf_chain_t *mbc, char *mbs, int repc)
1033 {
1034 	smb_wchar_t	wide_char;
1035 	int		nbytes;
1036 	int		length;
1037 
1038 	if ((length = smb_sbequiv_strlen(mbs)) == -1)
1039 		return (DECODE_NO_MORE_DATA);
1040 
1041 	length += sizeof (char);
1042 
1043 	if ((repc > 1) && (repc < length))
1044 		length = repc;
1045 	if (mbc_marshal_make_room(mbc, length))
1046 		return (DECODE_NO_MORE_DATA);
1047 
1048 	while (*mbs) {
1049 		/*
1050 		 * We should restore oem chars here.
1051 		 */
1052 		nbytes = smb_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX);
1053 		if (nbytes == -1)
1054 			return (DECODE_NO_MORE_DATA);
1055 
1056 		mbc_marshal_store_byte(mbc, (uint8_t)wide_char);
1057 
1058 		if (wide_char & 0xFF00)
1059 			mbc_marshal_store_byte(mbc, wide_char >> 8);
1060 
1061 		mbs += nbytes;
1062 	}
1063 
1064 	mbc_marshal_store_byte(mbc, 0);
1065 	return (0);
1066 }
1067 
1068 static int
mbc_marshal_put_unicode_string(mbuf_chain_t * mbc,char * ascii,int repc)1069 mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *ascii, int repc)
1070 {
1071 	smb_wchar_t	wchar;
1072 	int		consumed;
1073 	int		length;
1074 
1075 	if ((length = smb_wcequiv_strlen(ascii)) == -1)
1076 		return (DECODE_NO_MORE_DATA);
1077 
1078 	length += sizeof (smb_wchar_t);
1079 
1080 	if ((repc > 1) && (repc < length))
1081 		length = repc;
1082 
1083 	if (mbc_marshal_make_room(mbc, length))
1084 		return (DECODE_NO_MORE_DATA);
1085 	while (length > 0) {
1086 		consumed = smb_mbtowc(&wchar, ascii, MTS_MB_CHAR_MAX);
1087 		if (consumed == -1)
1088 			break;	/* Invalid sequence */
1089 		/*
1090 		 * Note that consumed will be 0 when the null terminator
1091 		 * is encountered and ascii will not be advanced beyond
1092 		 * that point. Length will continue to be decremented so
1093 		 * we won't get stuck here.
1094 		 */
1095 		ascii += consumed;
1096 		mbc_marshal_store_byte(mbc, wchar);
1097 		mbc_marshal_store_byte(mbc, wchar >> 8);
1098 		length -= sizeof (smb_wchar_t);
1099 	}
1100 	return (0);
1101 }
1102 
1103 static int
mbc_marshal_put_uio(mbuf_chain_t * mbc,struct uio * uio)1104 mbc_marshal_put_uio(mbuf_chain_t *mbc, struct uio *uio)
1105 {
1106 	mbuf_t		**t;
1107 	mbuf_t		*m = NULL;
1108 	struct iovec	*iov = uio->uio_iov;
1109 	int32_t		i, iov_cnt = uio->uio_iovcnt;
1110 
1111 	iov = uio->uio_iov;
1112 	t = &mbc->chain;
1113 	for (i = 0; i < iov_cnt; i++) {
1114 		MGET(m, M_WAIT, MT_DATA);
1115 		m->m_ext.ext_buf = iov->iov_base;
1116 		m->m_ext.ext_ref = mclrefnoop;
1117 		m->m_data = m->m_ext.ext_buf;
1118 		m->m_flags |= M_EXT;
1119 		m->m_len = m->m_ext.ext_size = iov->iov_len;
1120 		mbc->max_bytes += m->m_len;
1121 		m->m_next = 0;
1122 		*t = m;
1123 		t = &m->m_next;
1124 		iov++;
1125 	}
1126 	return (0);
1127 }
1128 
1129 static int
mbc_marshal_put_mbufs(mbuf_chain_t * mbc,mbuf_t * m)1130 mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m)
1131 {
1132 	mbuf_t	*mt;
1133 	mbuf_t	**t;
1134 	int	bytes;
1135 
1136 	if (m != NULL) {
1137 		mt = m;
1138 		bytes = mt->m_len;
1139 		while (mt->m_next != 0) {
1140 			mt = mt->m_next;
1141 			bytes += mt->m_len;
1142 		}
1143 		if (bytes != 0) {
1144 			t = &mbc->chain;
1145 			while (*t != 0) {
1146 				bytes += (*t)->m_len;
1147 				t = &(*t)->m_next;
1148 			}
1149 			*t = m;
1150 			mbc->chain_offset = bytes;
1151 		} else {
1152 			m_freem(m);
1153 		}
1154 	}
1155 	return (0);
1156 }
1157 
1158 static int
mbc_marshal_put_mbuf_chain(mbuf_chain_t * mbc,mbuf_chain_t * nmbc)1159 mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc)
1160 {
1161 	if (nmbc->chain != 0) {
1162 		if (mbc_marshal_put_mbufs(mbc, nmbc->chain))
1163 			return (DECODE_NO_MORE_DATA);
1164 		MBC_SETUP(nmbc, nmbc->max_bytes);
1165 	}
1166 	return (0);
1167 }
1168 
1169 static uint8_t
mbc_marshal_fetch_byte(mbuf_chain_t * mbc)1170 mbc_marshal_fetch_byte(mbuf_chain_t *mbc)
1171 {
1172 	uint8_t	data;
1173 	mbuf_t	*m = mbc->chain;
1174 	int32_t	offset = mbc->chain_offset;
1175 
1176 	while (offset >= m->m_len) {
1177 		offset -= m->m_len;
1178 		m = m->m_next;
1179 	}
1180 	data = ((uint8_t *)m->m_data)[offset];
1181 	mbc->chain_offset++;
1182 	return (data);
1183 }
1184 
1185 static int
mbc_marshal_get_char(mbuf_chain_t * mbc,uint8_t * data)1186 mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data)
1187 {
1188 	if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
1189 		/* Data will never be available */
1190 		return (DECODE_NO_MORE_DATA);
1191 	}
1192 	*data = mbc_marshal_fetch_byte(mbc);
1193 	return (0);
1194 }
1195 
1196 static int
mbc_marshal_get_short(mbuf_chain_t * mbc,uint16_t * data)1197 mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data)
1198 {
1199 	uint16_t	tmp;
1200 	mbuf_t		*m = mbc->chain;
1201 	int32_t		offset = mbc->chain_offset;
1202 
1203 	if (MBC_ROOM_FOR(mbc, sizeof (short)) == 0) {
1204 		/* Data will never be available */
1205 		return (DECODE_NO_MORE_DATA);
1206 	}
1207 
1208 	while (offset >= m->m_len) {
1209 		offset -= m->m_len;
1210 		m = m->m_next;
1211 	}
1212 	if ((m->m_len - offset) >= sizeof (short)) {
1213 		*data = LE_IN16(m->m_data + offset);
1214 		mbc->chain_offset += sizeof (short);
1215 	} else {
1216 		tmp = (uint16_t)mbc_marshal_fetch_byte(mbc);
1217 		tmp |= ((uint16_t)mbc_marshal_fetch_byte(mbc)) << 8;
1218 		*data = tmp;
1219 	}
1220 	return (0);
1221 }
1222 
1223 static int
mbc_marshal_get_long(mbuf_chain_t * mbc,uint32_t * data)1224 mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data)
1225 {
1226 	uint32_t	tmp;
1227 	mbuf_t		*m = mbc->chain;
1228 	int32_t		offset = mbc->chain_offset;
1229 
1230 	if (MBC_ROOM_FOR(mbc, sizeof (int32_t)) == 0) {
1231 		/* Data will never be available */
1232 		return (DECODE_NO_MORE_DATA);
1233 	}
1234 	while (offset >= m->m_len) {
1235 		offset -= m->m_len;
1236 		m = m->m_next;
1237 	}
1238 	if ((m->m_len - offset) >= sizeof (int32_t)) {
1239 		*data = LE_IN32(m->m_data + offset);
1240 		mbc->chain_offset += sizeof (int32_t);
1241 	} else {
1242 		tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
1243 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 8;
1244 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 16;
1245 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 24;
1246 		*data = tmp;
1247 	}
1248 	return (0);
1249 }
1250 
1251 static uint64_t
qswap(uint64_t ll)1252 qswap(uint64_t ll)
1253 {
1254 	uint64_t v;
1255 
1256 	v = ll >> 32;
1257 	v |= ll << 32;
1258 
1259 	return (v);
1260 }
1261 
1262 static int
mbc_marshal_get_odd_long_long(mbuf_chain_t * mbc,uint64_t * data)1263 mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data)
1264 {
1265 	uint64_t	tmp;
1266 	mbuf_t		*m = mbc->chain;
1267 	int32_t		offset = mbc->chain_offset;
1268 
1269 	if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
1270 		/* Data will never be available */
1271 		return (DECODE_NO_MORE_DATA);
1272 	}
1273 	while (offset >= m->m_len) {
1274 		offset -= m->m_len;
1275 		m = m->m_next;
1276 	}
1277 
1278 	if ((m->m_len - offset) >= sizeof (int64_t)) {
1279 		*data = qswap(LE_IN64(m->m_data + offset));
1280 		mbc->chain_offset += sizeof (int64_t);
1281 	} else {
1282 		tmp = (uint64_t)mbc_marshal_fetch_byte(mbc) << 32;
1283 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 40;
1284 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 48;
1285 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 56;
1286 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc);
1287 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 8;
1288 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 16;
1289 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 24;
1290 
1291 		*(uint64_t *)data = tmp;
1292 	}
1293 	return (0);
1294 }
1295 
1296 static int
mbc_marshal_get_long_long(mbuf_chain_t * mbc,uint64_t * data)1297 mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data)
1298 {
1299 	uint64_t	tmp;
1300 	mbuf_t		*m = mbc->chain;
1301 	int32_t		offset = mbc->chain_offset;
1302 
1303 	if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
1304 		/* Data will never be available */
1305 		return (DECODE_NO_MORE_DATA);
1306 	}
1307 	while (offset >= m->m_len) {
1308 		offset -= m->m_len;
1309 		m = m->m_next;
1310 	}
1311 	if ((m->m_len - offset) >= sizeof (int64_t)) {
1312 		*data = LE_IN64(m->m_data + offset);
1313 		mbc->chain_offset += sizeof (int64_t);
1314 	} else {
1315 		tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
1316 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 8;
1317 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 16;
1318 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 24;
1319 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32;
1320 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40;
1321 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48;
1322 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56;
1323 		*(uint64_t *)data = tmp;
1324 	}
1325 	return (0);
1326 }
1327 
1328 /*
1329  * mbc_marshal_get_ascii_string
1330  *
1331  * The ascii string in smb includes oem chars. Since the
1332  * system needs utf8 encodes unicode char, conversion is
1333  * required to convert the oem char to unicode and then
1334  * to encode the converted wchars to utf8 format.
1335  * Therefore, the **ascii returned will be in such format
1336  * instead of the real ASCII format.
1337  */
1338 static int
mbc_marshal_get_ascii_string(smb_request_t * sr,mbuf_chain_t * mbc,uint8_t ** ascii,int max_ascii)1339 mbc_marshal_get_ascii_string(
1340     smb_request_t	*sr,
1341     mbuf_chain_t	*mbc,
1342     uint8_t		**ascii,
1343     int			max_ascii)
1344 {
1345 	char		*rcvbuf;
1346 	char		*ch;
1347 	int		max;
1348 	int		length = 0;
1349 
1350 	max = MALLOC_QUANTUM;
1351 	rcvbuf = smb_srm_zalloc(sr, max);
1352 
1353 	if (max_ascii == 0)
1354 		max_ascii = 0xffff;
1355 
1356 	ch = rcvbuf;
1357 	for (;;) {
1358 		while (length < max) {
1359 			if (max_ascii-- <= 0) {
1360 				*ch++ = 0;
1361 				goto multibyte_encode;
1362 			}
1363 			if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
1364 				/* Data will never be available */
1365 				return (DECODE_NO_MORE_DATA);
1366 			}
1367 			if ((*ch++ = mbc_marshal_fetch_byte(mbc)) == 0)
1368 				goto multibyte_encode;
1369 			length++;
1370 		}
1371 		max += MALLOC_QUANTUM;
1372 		rcvbuf = smb_srm_rezalloc(sr, rcvbuf, max);
1373 		ch = rcvbuf + length;
1374 	}
1375 
1376 multibyte_encode:
1377 	/*
1378 	 * UTF-8 encode the string for internal system use.
1379 	 */
1380 	length = strlen(rcvbuf) + 1;
1381 	*ascii = smb_srm_zalloc(sr, length * MTS_MB_CHAR_MAX);
1382 	return (mbc_marshal_cstou8("CP850", (char *)*ascii,
1383 	    (size_t)length * MTS_MB_CHAR_MAX, rcvbuf, (size_t)length));
1384 }
1385 
1386 static int
mbc_marshal_get_unicode_string(smb_request_t * sr,mbuf_chain_t * mbc,uint8_t ** ascii,int max_unicode)1387 mbc_marshal_get_unicode_string(smb_request_t *sr,
1388     mbuf_chain_t *mbc, uint8_t **ascii, int max_unicode)
1389 {
1390 	int		max;
1391 	uint16_t	wchar;
1392 	char		*ch;
1393 	int		emitted;
1394 	int		length = 0;
1395 
1396 	if (max_unicode == 0)
1397 		max_unicode = 0xffff;
1398 
1399 	max = MALLOC_QUANTUM;
1400 	*ascii = smb_srm_zalloc(sr, max);
1401 
1402 	ch = (char *)*ascii;
1403 	for (;;) {
1404 		while ((length + MTS_MB_CHAR_MAX) < max) {
1405 			if (max_unicode <= 0)
1406 				goto done;
1407 			max_unicode -= 2;
1408 
1409 			if (mbc_marshal_get_short(mbc, &wchar) != 0)
1410 				return (DECODE_NO_MORE_DATA);
1411 
1412 			if (wchar == 0)	goto done;
1413 
1414 			emitted = smb_wctomb(ch, wchar);
1415 			length += emitted;
1416 			ch += emitted;
1417 		}
1418 		max += MALLOC_QUANTUM;
1419 		*ascii = smb_srm_rezalloc(sr, *ascii, max);
1420 		ch = (char *)*ascii + length;
1421 	}
1422 done:	*ch = 0;
1423 	return (0);
1424 }
1425 
1426 static int /*ARGSUSED*/
mbc_marshal_get_mbufs(mbuf_chain_t * mbc,int32_t bytes,mbuf_t ** m)1427 mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m)
1428 {
1429 	*m = NULL;
1430 	if (MBC_ROOM_FOR(mbc, bytes) == 0) {
1431 		/* Data will never be available */
1432 		return (DECODE_NO_MORE_DATA);
1433 	}
1434 	/* not yet implemented */
1435 	return (-1);
1436 }
1437 
1438 static int
mbc_marshal_get_mbuf_chain(mbuf_chain_t * mbc,int32_t bytes,mbuf_chain_t * nmbc)1439 mbc_marshal_get_mbuf_chain(mbuf_chain_t *mbc, int32_t bytes, mbuf_chain_t *nmbc)
1440 {
1441 	int	rc;
1442 	mbuf_t	*m;
1443 
1444 	if (bytes == 0) {
1445 		/* Get all the rest */
1446 		bytes = mbc->max_bytes - mbc->chain_offset;
1447 	}
1448 
1449 	MBC_SETUP(nmbc, mbc->max_bytes);
1450 	if ((rc = mbc_marshal_get_mbufs(mbc, bytes, &m)) != 0) {
1451 		if (m)
1452 			m_freem(m);
1453 		return (rc);
1454 	}
1455 	nmbc->chain = m;
1456 	while (m != 0) {
1457 		bytes += m->m_len;
1458 		m = m->m_next;
1459 	}
1460 	nmbc->max_bytes = bytes;
1461 	return (0);
1462 }
1463 
1464 static int
mbc_marshal_get_uio(mbuf_chain_t * mbc,struct uio * uio)1465 mbc_marshal_get_uio(mbuf_chain_t *mbc, struct uio *uio)
1466 {
1467 	int		i, offset;
1468 	int32_t		bytes = uio->uio_resid;
1469 	int32_t		remainder;
1470 	struct iovec	*iov;
1471 	mbuf_t		*m;
1472 
1473 	/*
1474 	 * The residual count is tested because in the case of write requests
1475 	 * with no data (smbtorture RAW-WRITE test will generate that type of
1476 	 * request) this function is called with a residual count of zero
1477 	 * bytes.
1478 	 */
1479 	if (bytes != 0) {
1480 		iov = uio->uio_iov;
1481 		uio->uio_segflg = UIO_SYSSPACE;
1482 		uio->uio_extflg = UIO_COPY_DEFAULT;
1483 
1484 		if (MBC_ROOM_FOR(mbc, bytes) == 0) {
1485 			/* Data will never be available */
1486 			return (DECODE_NO_MORE_DATA);
1487 		}
1488 
1489 		m = mbc->chain;
1490 		offset = mbc->chain_offset;
1491 		while (offset >= m->m_len) {
1492 			offset -= m->m_len;
1493 			m = m->m_next;
1494 			ASSERT((offset == 0) || (offset && m));
1495 		}
1496 
1497 		for (i = 0; (bytes > 0) && (i < uio->uio_iovcnt); i++) {
1498 			iov[i].iov_base = &m->m_data[offset];
1499 			remainder = m->m_len - offset;
1500 			if (remainder >= bytes) {
1501 				iov[i].iov_len = bytes;
1502 				mbc->chain_offset += bytes;
1503 				uio->uio_iovcnt = i + 1;
1504 				return (0);
1505 			}
1506 			iov[i].iov_len = remainder;
1507 			mbc->chain_offset += remainder;
1508 			bytes -= remainder;
1509 			m = m->m_next;
1510 			offset = 0;
1511 		}
1512 		return (DECODE_NO_MORE_DATA);
1513 	}
1514 	return (0);
1515 }
1516 
1517 static int
mbc_marshal_get_skip(mbuf_chain_t * mbc,uint_t skip)1518 mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip)
1519 {
1520 	if (MBC_ROOM_FOR(mbc, skip) == 0)
1521 		return (DECODE_NO_MORE_DATA);
1522 	mbc->chain_offset += skip;
1523 	return (0);
1524 }
1525 
1526 /*
1527  * Converts oem string to UTF-8 string with an output string of max
1528  * maxconv bytes.  The string may be truncated or not null-terminated if
1529  * there is not enough room.
1530  *
1531  * returns -1, cnt (partial conversion)  or 0 (success)
1532  */
1533 
1534 static int
mbc_marshal_cstou8(char * cs,char * outbuf,size_t maxconv,char * inbuf,size_t srcbytes)1535 mbc_marshal_cstou8(char *cs, char *outbuf, size_t maxconv,
1536     char *inbuf, size_t srcbytes)
1537 {
1538 	kiconv_t	t2u;
1539 	size_t		inlen = srcbytes;
1540 	size_t		outlen = maxconv;
1541 	int		err = 0;
1542 	size_t		rc;
1543 
1544 	if ((t2u = kiconv_open("UTF-8", cs)) == (kiconv_t)-1)
1545 		return (-1);
1546 
1547 	rc = kiconv(t2u, &inbuf, &inlen, &outbuf, &outlen, &err);
1548 	(void) kiconv_close(t2u);
1549 	return ((int)rc);
1550 }
1551