xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c (revision 897907ce12f040adf70d35697d537c9d72b35285)
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  * Copyright 2013-2021 Tintri by DDN, Inc. All rights reserved.
26  */
27 
28 /*
29  * SMB mbuf marshaling encode/decode.
30  */
31 
32 #include <smbsrv/smb_kproto.h>
33 
34 
35 #define	MALLOC_QUANTUM	80
36 
37 #define	DECODE_NO_ERROR		0
38 #define	DECODE_NO_MORE_DATA	1
39 #define	DECODE_ALLOCATION_ERROR	2
40 #define	DECODE_CONVERSION_ERROR	3
41 
42 static int mbc_marshal_make_room(mbuf_chain_t *, int32_t);
43 static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t);
44 static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t);
45 static int mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t);
46 static int mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t);
47 static int mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t);
48 static int mbc_marshal_put_oem_string(mbuf_chain_t *, char *, int);
49 static int mbc_marshal_put_unicode_string(mbuf_chain_t *, char *, int);
50 static int mbc_marshal_put_uio(mbuf_chain_t *, struct uio *);
51 static int mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m);
52 static int mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc);
53 static uint8_t mbc_marshal_fetch_byte(mbuf_chain_t *mbc);
54 static int mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data);
55 static int mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data);
56 static int mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data);
57 static uint64_t qswap(uint64_t ll);
58 static int mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data);
59 static int mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data);
60 static int mbc_marshal_get_oem_string(smb_request_t *, mbuf_chain_t *,
61     char **, int);
62 static int mbc_marshal_get_unicode_string(smb_request_t *, mbuf_chain_t *,
63     char **, int);
64 static int mbc_marshal_get_mbufs(mbuf_chain_t *, int32_t, mbuf_t **);
65 static int mbc_marshal_get_mbuf_chain(mbuf_chain_t *, int32_t, mbuf_chain_t *);
66 static int mbc_marshal_get_uio(mbuf_chain_t *, struct uio *);
67 static int mbc_marshal_get_skip(mbuf_chain_t *, uint_t);
68 
69 /*
70  * smb_mbc_vdecodef
71  *
72  * This function reads the contents of the mbc chain passed in under the list
73  * of arguments passed in.
74  *
75  * The format string provides a description of the parameters passed in as well
76  * as an action to be taken by smb_mbc_vdecodef().
77  *
78  *	%	Pointer to an SMB request structure (smb_request_t *). There
79  *		should be only one of these in the string.
80  *
81  *	C	Pointer to an mbuf chain. Copy to that mbuf chain the number of
82  *		bytes specified (number preceding C).
83  *
84  *	m	Pointer to an mbuf. Copy to that mbuf the number of bytes
85  *		specified (number preceding m).
86  *
87  *	M	Read the 32 bit value at the current location of the mbuf chain
88  *		and check if it matches the signature of an SMB1 request (SMBx).
89  *
90  *	N	Read the 32 bit value at the current location of the mbuf chain
91  *		and check if it matches the signature of an SMB2 request (SMBx).
92  *
93  *	b	Pointer to a buffer. Copy to that buffer the number of bytes
94  *		specified (number preceding b).
95  *
96  *	c	Same as 'b'.
97  *
98  *	w	Pointer to a word (16bit value). Copy the next 16bit value into
99  *		that location.
100  *
101  *	l	Pointer to a long (32bit value). Copy the next 32bit value into
102  *		that location.
103  *
104  *	q	Pointer to a quad (64bit value). Copy the next 64bit value into
105  *		that location.
106  *
107  *	Q	Same as above with a call to qswap().
108  *
109  *	B	Pointer to a vardata_block structure. That structure is used to
110  *		retrieve data from the mbuf chain (an iovec type structure is
111  *		embedded in a vardata_block).
112  *
113  *	D	Pointer to a vardata_block structure. That structure is used to
114  *		retrieve data from the mbuf chain, however, two fields of the
115  *		vardata_block structure (tag and len) are first initialized
116  *		using the mbuf chain itself.
117  *
118  *	V	Same as 'D'.
119  *
120  *	L
121  *
122  *	A
123  *
124  *	P	Same as 'A'
125  *
126  *	S	Same as 'A'
127  *
128  *	u	Pointer to a string pointer. Allocate memory and retrieve the
129  *		string at the current location in the mbuf chain. Store the
130  *		address to the buffer allocated at the address specified by
131  *		the pointer. In addition if an sr was passed and it indicates
132  *		that the string is an unicode string, convert it.
133  *
134  *	s	Same as 'u' without convertion.
135  *
136  *	U	Same as 'u'. The string to retrieve is unicode.
137  *
138  *	y	Pointer to a 32bit value. Read the dos time at the current mbuf
139  *		chain location, convert it to unix time and store it at the
140  *		location indicated by the pointer.
141  *
142  *	Y	Same as 'y' bt the dos time coded in the mbuf chain is inverted.
143  *
144  *	.	Skip the number of bytes indicated by the number preceding '.'.
145  *
146  *	,	Same as '.' but take in account it is an unicode string.
147  */
148 int
smb_mbc_vdecodef(mbuf_chain_t * mbc,const char * fmt,va_list ap)149 smb_mbc_vdecodef(mbuf_chain_t *mbc, const char *fmt, va_list ap)
150 {
151 	uint8_t		c;
152 	uint8_t		cval;
153 	uint8_t		*cvalp;
154 	char		**charpp;
155 	uint16_t	wval;
156 	uint16_t	*wvalp;
157 	uint32_t	*lvalp;
158 	uint64_t	*llvalp;
159 	smb_vdb_t	*vdp;
160 	smb_request_t	*sr = NULL;
161 	uint32_t	lval;
162 	int		unicode = 0;
163 	int		repc;
164 	boolean_t	repc_specified;
165 
166 	while ((c = *fmt++) != 0) {
167 		repc_specified = B_FALSE;
168 		repc = 1;
169 
170 		if ('0' <= c && c <= '9') {
171 			repc = 0;
172 			do {
173 				repc = repc * 10 + c - '0';
174 				c = *fmt++;
175 			} while ('0' <= c && c <= '9');
176 			repc_specified = B_TRUE;
177 		} else if (c == '#') {
178 			repc = va_arg(ap, int);
179 			c = *fmt++;
180 			repc_specified = B_TRUE;
181 		}
182 
183 		switch (c) {
184 		case '%':
185 			sr = va_arg(ap, struct smb_request *);
186 			if (sr->session->dialect >= SMB_VERS_2_BASE) {
187 				unicode = 1;
188 				break;
189 			}
190 			unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
191 			break;
192 
193 		case 'C':	/* Mbuf_chain */
194 			if (mbc_marshal_get_mbuf_chain(mbc, repc,
195 			    va_arg(ap, mbuf_chain_t *)) != 0)
196 				return (-1);
197 			break;
198 
199 		case 'm':	/* struct_mbuf */
200 			if (mbc_marshal_get_mbufs(mbc, repc,
201 			    va_arg(ap, mbuf_t **)) != 0)
202 				return (-1);
203 			break;
204 
205 		case 'M':
206 			if (mbc_marshal_get_long(mbc, &lval) != 0)
207 				return (-1);
208 			if (lval != 0x424D53FF) /* 0xFF S M B */
209 				return (-1);
210 			break;
211 
212 		case 'N':
213 			if (mbc_marshal_get_long(mbc, &lval) != 0)
214 				return (-1);
215 			if (lval != 0x424D53FE) /* 0xFE S M B */
216 				return (-1);
217 			break;
218 
219 		case 'b':
220 		case 'c':
221 			cvalp = va_arg(ap, uint8_t *);
222 			if (MBC_ROOM_FOR(mbc, repc) == 0)
223 				/* Data will never be available */
224 				return (-1);
225 
226 			while (repc-- > 0)
227 				*cvalp++ = mbc_marshal_fetch_byte(mbc);
228 			break;
229 
230 		case 'w':
231 			wvalp = va_arg(ap, uint16_t *);
232 			while (repc-- > 0)
233 				if (mbc_marshal_get_short(mbc, wvalp++) != 0)
234 					return (-1);
235 			break;
236 
237 		case 'l':
238 			lvalp = va_arg(ap, uint32_t *);
239 			while (repc-- > 0)
240 				if (mbc_marshal_get_long(mbc, lvalp++) != 0)
241 					return (-1);
242 			break;
243 
244 		case 'q':
245 			llvalp = va_arg(ap, uint64_t *);
246 			while (repc-- > 0)
247 				if (mbc_marshal_get_long_long(
248 				    mbc, llvalp++) != 0)
249 					return (-1);
250 			break;
251 
252 		case 'Q':
253 			llvalp = va_arg(ap, uint64_t *);
254 			while (repc-- > 0)
255 				if (mbc_marshal_get_odd_long_long(
256 				    mbc, llvalp++) != 0)
257 					return (-1);
258 			break;
259 
260 		case 'B':
261 			vdp = va_arg(ap, struct vardata_block *);
262 			vdp->vdb_tag = 0;
263 			vdp->vdb_len = repc;
264 			vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0];
265 			vdp->vdb_uio.uio_iovcnt = MAX_IOVEC;
266 			vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
267 			vdp->vdb_uio.uio_resid = repc;
268 			if (mbc_marshal_get_uio(mbc, &vdp->vdb_uio) != 0)
269 				return (-1);
270 			break;
271 
272 		case 'D':
273 		case 'V':
274 			vdp = va_arg(ap, struct vardata_block *);
275 			if (mbc_marshal_get_char(mbc, &vdp->vdb_tag) != 0)
276 				return (-1);
277 			if (mbc_marshal_get_short(mbc, &wval) != 0)
278 				return (-1);
279 			vdp->vdb_len = (uint32_t)wval;
280 			vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0];
281 			vdp->vdb_uio.uio_iovcnt = MAX_IOVEC;
282 			vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
283 			vdp->vdb_uio.uio_resid = vdp->vdb_len;
284 			if (vdp->vdb_len != 0) {
285 				if (mbc_marshal_get_uio(mbc,
286 				    &vdp->vdb_uio) != 0)
287 					return (-1);
288 			}
289 			break;
290 
291 		case 'L':
292 			if (mbc_marshal_get_char(mbc, &cval) != 0)
293 				return (-1);
294 			if (cval != 2)
295 				return (-1);
296 			goto oem_conversion;
297 
298 		case 'A':
299 		case 'S':
300 			if (mbc_marshal_get_char(mbc, &cval) != 0)
301 				return (-1);
302 			if (((c == 'A' || c == 'S') && cval != 4) ||
303 			    (c == 'L' && cval != 2))
304 				return (-1);
305 			/* FALLTHROUGH */
306 
307 		case 'u': /* Convert from unicode if flags are set */
308 			if (unicode)
309 				goto unicode_translation;
310 			/* FALLTHROUGH */
311 
312 		case 's':	/* get OEM string */
313 oem_conversion:
314 			ASSERT(sr != NULL);
315 			charpp = va_arg(ap, char **);
316 			if (!repc_specified)
317 				repc = 0;
318 			if (mbc_marshal_get_oem_string(sr,
319 			    mbc, charpp, repc) != 0)
320 				return (-1);
321 			break;
322 
323 		case 'U':	/* get UTF-16 string */
324 unicode_translation:
325 			ASSERT(sr != 0);
326 			charpp = va_arg(ap, char **);
327 			if (!repc_specified)
328 				repc = 0;
329 			if (mbc_marshal_get_unicode_string(sr,
330 			    mbc, charpp, repc) != 0)
331 				return (-1);
332 			break;
333 
334 		case 'Y': /* dos time to unix time tt/dd */
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 *)&t) != 0)
341 					return (-1);
342 				if (mbc_marshal_get_short(mbc,
343 				    (uint16_t *)&d) != 0)
344 					return (-1);
345 				*lvalp++ = smb_time_dos_to_unix(d, t);
346 			}
347 			break;
348 
349 		case 'y': /* dos time to unix time dd/tt */
350 			lvalp = va_arg(ap, uint32_t *);
351 			while (repc-- > 0) {
352 				short	d, t;
353 
354 				if (mbc_marshal_get_short(mbc,
355 				    (uint16_t *)&d) != 0)
356 					return (-1);
357 				if (mbc_marshal_get_short(mbc,
358 				    (uint16_t *)&t) != 0)
359 					return (-1);
360 				*lvalp++ = smb_time_dos_to_unix(d, t);
361 			}
362 			break;
363 
364 		case ',':
365 			if (unicode)
366 				repc *= 2;
367 			/* FALLTHROUGH */
368 
369 		case '.':
370 			if (mbc_marshal_get_skip(mbc, repc) != 0)
371 				return (-1);
372 			break;
373 
374 		default:
375 			ASSERT(0);
376 			return (-1);
377 		}
378 	}
379 	return (0);
380 }
381 
382 /*
383  * smb_mbc_decodef
384  *
385  * This function reads the contents of the mbc chain passed in under the
386  * control of the format fmt.
387  *
388  * (for a description of the format string see smb_mbc_vencodef()).
389  */
390 int
smb_mbc_decodef(mbuf_chain_t * mbc,const char * fmt,...)391 smb_mbc_decodef(mbuf_chain_t *mbc, const char *fmt, ...)
392 {
393 	int	xx;
394 	va_list	ap;
395 
396 	va_start(ap, fmt);
397 	xx = smb_mbc_vdecodef(mbc, fmt, ap);
398 	va_end(ap);
399 	return (xx);
400 }
401 
402 /*
403  * smb_mbc_peek
404  *
405  * This function reads the contents of the mbc passed in at the specified offset
406  * under the control of the format fmt. The offset of the chain passed in is not
407  * modified.
408  *
409  * (for a description of the format string see smb_mbc_vdecodef()).
410  */
411 int
smb_mbc_peek(mbuf_chain_t * mbc,int offset,const char * fmt,...)412 smb_mbc_peek(mbuf_chain_t *mbc, int offset, const char *fmt, ...)
413 {
414 	mbuf_chain_t	tmp;
415 	va_list		ap;
416 	int		xx;
417 
418 	va_start(ap, fmt);
419 
420 	(void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset);
421 	xx = smb_mbc_vdecodef(&tmp, fmt, ap);
422 	va_end(ap);
423 	return (xx);
424 }
425 
426 /*
427  * smb_mbc_vencodef
428  *
429  * This function builds a stream of bytes in the mbc chain passed in under the
430  * control of the list of arguments passed in.
431  *
432  * The format string provides a description of the parameters passed in as well
433  * as an action to be taken by smb_mbc_vencodef().
434  *
435  *	\b	Restore the mbuf chain offset to its initial value.
436  *
437  *	%	Pointer to an SMB request structure (smb_request_t *). There
438  *		should be only one of these in the string. If an sr in present
439  *		it will be used to determine if unicode conversion should be
440  *		applied to the strings.
441  *
442  *	C	Pointer to an mbuf chain. Copy that mbuf chain into the
443  *		destination mbuf chain.
444  *
445  *	D	Pointer to a vardata_block structure. Copy the data described
446  *		by that structure into the mbuf chain. The tag field is hard
447  *		coded to '1'.
448  *
449  *	M	Write the SMB1 request signature ('SMBX') into the mbuf chain.
450  *
451  *	N	Write the SMB2 request signature ('SMBX') into the mbuf chain.
452  *
453  *	T	Pointer to a timestruc_t. Convert the content of the structure
454  *		into NT time and store the result of the conversion in the
455  *		mbuf chain.
456  *
457  *	V	Same as 'D' but the tag field is hard coded to '5'.
458  *
459  *	b	Byte. Store the byte or the nymber of bytes specified into the
460  *		the mbuf chain. A format string like this "2b" would require 2
461  *		bytes to be passed in.
462  *
463  *	m	Pointer to an mbuf. Copy the contents of the mbuf into the mbuf
464  *		chain.
465  *
466  *	c	Pointer to a buffer. Copy the buffer into the mbuf chain. The
467  *		size of the buffer is indicated by the number preceding 'c'.
468  *
469  *	w	Word (16bit value). Store the word or the number of words
470  *              specified into the the mbuf chain. A format string like this
471  *		"2w" would require 2 words to be passed in.
472  *
473  *	l	Long (32bit value). Store the long or the number of longs
474  *		specified into the the mbuf chain. A format string like this
475  *		"2l" would require 2 longs to be passed in.
476  *
477  *	q	Quad (64bit value). Store the quad or the number of quads
478  *		specified into the the mbuf chain. A format string like this
479  *		"2q" would require 2 quads to be passed in.
480  *
481  *	L	Pointer to a string. Store the string passed in into the mbuf
482  *		chain preceded with a tag value of '2'.
483  *
484  *	S	Pointer to a string. Store the string passed in into the mbuf
485  *		chain preceded with a tag value of '4'. Applied a unicode
486  *		conversion is appropriate.
487  *
488  *	A	Same as 'S'
489  *
490  *	P	Pointer to a string. Store the string passed in into the mbuf
491  *		chain preceded with a tag value of '5'. Applied a unicode
492  *		conversion is appropriate.
493  *
494  *	u	Pointer to a string. Store the string passed in into the mbuf
495  *		chain. Applied a unicode conversion is appropriate.
496  *
497  *	s	Pointer to a string. Store the string passed in into the mbuf
498  *		chain.
499  *
500  *	Y	Date/Time.  Store the Date/Time or the number of Date/Time(s)
501  *		specified into the the mbuf chain. A format string like this
502  *		"2Y" would require 2 Date/Time values. The Date/Time is
503  *		converted to DOS before storing.
504  *
505  *	y	Same as 'Y'. The order of Date and Time is reversed.
506  *
507  *	,	Character. Store the character or number of character specified
508  *		into the mbuf chain.  A format string like this "2c" would
509  *		require 2 characters to be passed in. A unicode conversion is
510  *		applied if appropriate.
511  *
512  *	.	Same as '`' without unicode conversion.
513  *
514  *	U	Align the offset of the mbuf chain on a 16bit boundary.
515  */
516 int
smb_mbc_vencodef(mbuf_chain_t * mbc,const char * fmt,va_list ap)517 smb_mbc_vencodef(mbuf_chain_t *mbc, const char *fmt, va_list ap)
518 {
519 	char		*charp;
520 	uint8_t		*cvalp;
521 	timestruc_t	*tvp;
522 	smb_vdb_t	*vdp;
523 	smb_request_t	*sr = NULL;
524 	uint64_t	llval;
525 	int64_t		nt_time;
526 	uint32_t	lval;
527 	uint_t		tag;
528 	int		unicode = 0;
529 	int		repc;
530 	boolean_t	repc_specified;
531 	uint16_t	wval;
532 	uint8_t		cval;
533 	uint8_t		c;
534 
535 	while ((c = *fmt++) != 0) {
536 		repc_specified = B_FALSE;
537 		repc = 1;
538 
539 		if ('0' <= c && c <= '9') {
540 			repc = 0;
541 			do {
542 				repc = repc * 10 + c - '0';
543 				c = *fmt++;
544 			} while ('0' <= c && c <= '9');
545 			repc_specified = B_TRUE;
546 		} else if (c == '#') {
547 			repc = va_arg(ap, int);
548 			c = *fmt++;
549 			repc_specified = B_TRUE;
550 		}
551 
552 		switch (c) {
553 		case '%':
554 			sr = va_arg(ap, struct smb_request *);
555 			if (sr->session->dialect >= SMB_VERS_2_BASE) {
556 				unicode = 1;
557 				break;
558 			}
559 			unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
560 			break;
561 
562 		case 'C':	/* Mbuf_chain */
563 			if (mbc_marshal_put_mbuf_chain(mbc,
564 			    va_arg(ap, mbuf_chain_t *)) != 0)
565 				return (DECODE_NO_MORE_DATA);
566 			break;
567 
568 		case 'D':
569 			vdp = va_arg(ap, struct vardata_block *);
570 
571 			if (mbc_marshal_put_char(mbc, 1) != 0)
572 				return (DECODE_NO_MORE_DATA);
573 			if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0)
574 				return (DECODE_NO_MORE_DATA);
575 			if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0)
576 				return (DECODE_NO_MORE_DATA);
577 			break;
578 
579 		case 'M':
580 			/* 0xFF S M B */
581 			if (mbc_marshal_put_long(mbc, 0x424D53FF))
582 				return (DECODE_NO_MORE_DATA);
583 			break;
584 
585 		case 'N':
586 			/* 0xFE S M B */
587 			if (mbc_marshal_put_long(mbc, 0x424D53FE))
588 				return (DECODE_NO_MORE_DATA);
589 			break;
590 
591 		case 'T':
592 			tvp = va_arg(ap, timestruc_t *);
593 			nt_time = smb_time_unix_to_nt(tvp);
594 			if (mbc_marshal_put_long_long(mbc, nt_time) != 0)
595 				return (DECODE_NO_MORE_DATA);
596 			break;
597 
598 		case 'V':
599 			vdp = va_arg(ap, struct vardata_block *);
600 
601 			if (mbc_marshal_put_char(mbc, 5) != 0)
602 				return (DECODE_NO_MORE_DATA);
603 			if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0)
604 				return (DECODE_NO_MORE_DATA);
605 			if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0)
606 				return (DECODE_NO_MORE_DATA);
607 			break;
608 
609 		case 'b':
610 			while (repc-- > 0) {
611 				cval = va_arg(ap, int);
612 				if (mbc_marshal_put_char(mbc, cval) != 0)
613 					return (DECODE_NO_MORE_DATA);
614 			}
615 			break;
616 
617 		case 'm':	/* struct_mbuf */
618 			if (mbc_marshal_put_mbufs(mbc,
619 			    va_arg(ap, mbuf_t *)) != 0)
620 				return (DECODE_NO_MORE_DATA);
621 			break;
622 
623 		case 'c':
624 			cvalp = va_arg(ap, uint8_t *);
625 			while (repc-- > 0) {
626 				if (mbc_marshal_put_char(mbc,
627 				    *cvalp++) != 0)
628 					return (DECODE_NO_MORE_DATA);
629 			}
630 			break;
631 
632 		case 'w':
633 			while (repc-- > 0) {
634 				wval = va_arg(ap, int);
635 				if (mbc_marshal_put_short(mbc, wval) != 0)
636 					return (DECODE_NO_MORE_DATA);
637 			}
638 			break;
639 
640 		case 'l':
641 			while (repc-- > 0) {
642 				lval = va_arg(ap, uint32_t);
643 				if (mbc_marshal_put_long(mbc, lval) != 0)
644 					return (DECODE_NO_MORE_DATA);
645 			}
646 			break;
647 
648 		case 'q':
649 			while (repc-- > 0) {
650 				llval = va_arg(ap, uint64_t);
651 				if (mbc_marshal_put_long_long(mbc, llval) != 0)
652 					return (DECODE_NO_MORE_DATA);
653 			}
654 			break;
655 
656 
657 		case 'L':
658 			tag = 2;
659 			goto oem_conversion;
660 
661 		case 'S':
662 		case 'A':
663 			tag = 4;
664 			goto tagged_str;
665 
666 		case 'P':
667 			tag = 3;
668 			goto tagged_str;
669 
670 		tagged_str:
671 			if (mbc_marshal_put_char(mbc, tag) != 0)
672 				return (DECODE_NO_MORE_DATA);
673 			/* FALLTHROUGH */
674 
675 		case 'u':	/* Convert from unicode if flags are set */
676 			if (unicode)
677 				goto unicode_translation;
678 			/* FALLTHROUGH */
679 
680 		case 's':	/* put OEM string */
681 oem_conversion:
682 			charp = va_arg(ap, char *);
683 			if (!repc_specified)
684 				repc = 0;
685 			if (mbc_marshal_put_oem_string(mbc,
686 			    charp, repc) != 0)
687 				return (DECODE_NO_MORE_DATA);
688 			break;
689 
690 		case 'U':	/* put UTF-16 string */
691 unicode_translation:
692 			charp = va_arg(ap, char *);
693 			if (!repc_specified)
694 				repc = 0;
695 			if (mbc_marshal_put_unicode_string(mbc,
696 			    charp, repc) != 0)
697 				return (DECODE_NO_MORE_DATA);
698 			break;
699 
700 		case 'Y':		/* int32_t, encode dos date/time */
701 			while (repc-- > 0) {
702 				uint16_t	d, t;
703 
704 				lval = va_arg(ap, uint32_t);
705 				smb_time_unix_to_dos(lval,
706 				    (short *)&d, (short *)&t);
707 				if (mbc_marshal_put_short(mbc, t) != 0)
708 					return (DECODE_NO_MORE_DATA);
709 				if (mbc_marshal_put_short(mbc, d) != 0)
710 					return (DECODE_NO_MORE_DATA);
711 			}
712 			break;
713 
714 		case 'y':		/* int32_t, encode dos date/time */
715 			while (repc-- > 0) {
716 				uint16_t	d, t;
717 
718 				lval = va_arg(ap, uint32_t);
719 				smb_time_unix_to_dos(lval,
720 				    (short *)&d, (short *)&t);
721 				if (mbc_marshal_put_short(mbc, d) != 0)
722 					return (DECODE_NO_MORE_DATA);
723 				if (mbc_marshal_put_short(mbc, t) != 0)
724 					return (DECODE_NO_MORE_DATA);
725 			}
726 			break;
727 
728 		case ',':
729 			if (unicode)
730 				repc *= 2;
731 			/* FALLTHROUGH */
732 
733 		case '.':
734 			while (repc-- > 0)
735 				if (mbc_marshal_put_char(mbc, 0) != 0)
736 					return (DECODE_NO_MORE_DATA);
737 			break;
738 
739 		default:
740 			ASSERT(0);
741 			return (-1);
742 		}
743 	}
744 	return (0);
745 }
746 
747 /*
748  * smb_mbc_encodef
749  *
750  * This function builds a stream of bytes in the mbc chain passed in under the
751  * control of the format fmt.
752  *
753  * (for a description of the format string see smb_mbc_vencodef()).
754  */
755 int
smb_mbc_encodef(mbuf_chain_t * mbc,const char * fmt,...)756 smb_mbc_encodef(mbuf_chain_t *mbc, const char *fmt, ...)
757 {
758 	int	rc;
759 	va_list	ap;
760 
761 	va_start(ap, fmt);
762 	rc = smb_mbc_vencodef(mbc, fmt, ap);
763 	va_end(ap);
764 	return (rc);
765 }
766 
767 /*
768  * smb_mbc_poke
769  *
770  * This function writes a stream of bytes in the mbc passed in at the specified
771  * offset under the control of the format fmt. The offset of the chain passed in
772  * is not modified.
773  *
774  * (for a description of the format string see smb_mbc_vencodef()).
775  */
776 int
smb_mbc_poke(mbuf_chain_t * mbc,int offset,const char * fmt,...)777 smb_mbc_poke(mbuf_chain_t *mbc, int offset, const char *fmt, ...)
778 {
779 	int		len, rc;
780 	mbuf_chain_t	tmp;
781 	va_list		ap;
782 
783 	if ((len = mbc->max_bytes - offset) < 0)
784 		return (DECODE_NO_MORE_DATA);
785 	rc = MBC_SHADOW_CHAIN(&tmp, mbc, offset, len);
786 	if (rc)
787 		return (DECODE_NO_MORE_DATA);
788 
789 	va_start(ap, fmt);
790 	rc = smb_mbc_vencodef(&tmp, fmt, ap);
791 	va_end(ap);
792 
793 	return (rc);
794 }
795 
796 /*
797  * Copy data from the src mbuf chain to the dst mbuf chain,
798  * at the given offset in the src and current offset in dst,
799  * for copy_len bytes.  Does NOT update src->chain_offset.
800  */
801 int
smb_mbc_copy(mbuf_chain_t * dst_mbc,const mbuf_chain_t * src_mbc,int copy_offset,int copy_len)802 smb_mbc_copy(mbuf_chain_t *dst_mbc, const mbuf_chain_t *src_mbc,
803     int copy_offset, int copy_len)
804 {
805 	mbuf_t	*src_m;
806 	int offset, len;
807 	int rc;
808 
809 	if (copy_len <= 0)
810 		return (0);
811 	if (copy_offset < 0)
812 		return (EINVAL);
813 	if ((copy_offset + copy_len) > src_mbc->max_bytes)
814 		return (EMSGSIZE);
815 
816 	/*
817 	 * Advance to the src mbuf where we start copying.
818 	 */
819 	offset = copy_offset;
820 	src_m = src_mbc->chain;
821 	while (src_m && offset >= src_m->m_len) {
822 		offset -= src_m->m_len;
823 		src_m = src_m->m_next;
824 	}
825 	if (src_m == NULL)
826 		return (EFAULT);
827 
828 	/*
829 	 * Copy the first part, which may start somewhere past
830 	 * the beginning of the current mbuf.
831 	 */
832 	len = src_m->m_len - offset;
833 	if (len > copy_len)
834 		len = copy_len;
835 	rc = smb_mbc_put_mem(dst_mbc, src_m->m_data + offset, len);
836 	if (rc != 0)
837 		return (rc);
838 	copy_len -= len;
839 
840 	/*
841 	 * Copy remaining mbufs...
842 	 */
843 	while (copy_len > 0) {
844 		src_m = src_m->m_next;
845 		if (src_m == NULL)
846 			break;
847 		len = src_m->m_len;
848 		if (len > copy_len)
849 			len = copy_len;
850 		rc = smb_mbc_put_mem(dst_mbc, src_m->m_data, len);
851 		copy_len -= len;
852 	}
853 
854 	return (0);
855 }
856 
857 /*
858  * Copy data from the passed memory buffer into the mbuf chain
859  * at the current offset.
860  */
861 int
smb_mbc_put_mem(mbuf_chain_t * mbc,void * vmem,int mem_len)862 smb_mbc_put_mem(mbuf_chain_t *mbc, void *vmem, int mem_len)
863 {
864 	caddr_t mem = vmem;
865 	mbuf_t	*m;
866 	int32_t	offset, tlen;
867 	int rc;
868 
869 	if (mem_len <= 0)
870 		return (0);
871 
872 	if ((rc = mbc_marshal_make_room(mbc, mem_len)) != 0)
873 		return (rc);
874 
875 	/*
876 	 * Advance to the dst mbuf where we start copying.
877 	 * Allocations were done by _make_room().
878 	 */
879 	offset = mbc->chain_offset;
880 	m = mbc->chain;
881 	while (offset >= m->m_len) {
882 		ASSERT(m->m_len > 0);
883 		offset -= m->m_len;
884 		m = m->m_next;
885 	}
886 
887 	/*
888 	 * Copy the first part, which may start somewhere past
889 	 * the beginning of the current mbuf.
890 	 */
891 	tlen = m->m_len - offset;
892 	if (tlen > mem_len)
893 		tlen = mem_len;
894 	bcopy(mem, m->m_data + offset, tlen);
895 	mbc->chain_offset += tlen;
896 	mem += tlen;
897 	mem_len -= tlen;
898 
899 	/*
900 	 * Copy remaining mem into mbufs.  These all start
901 	 * at the beginning of each mbuf, and the last may
902 	 * end somewhere short of m_len.
903 	 */
904 	while (mem_len > 0) {
905 		m = m->m_next;
906 		tlen = m->m_len;
907 		if (tlen > mem_len)
908 			tlen = mem_len;
909 		bcopy(mem, m->m_data, tlen);
910 		mbc->chain_offset += tlen;
911 		mem += tlen;
912 		mem_len -= tlen;
913 	}
914 
915 	return (0);
916 }
917 
918 /*
919  * Put padding sufficient to align to A, where
920  * A is some power of 2 greater than zero.
921  */
922 int
smb_mbc_put_align(mbuf_chain_t * mbc,int align)923 smb_mbc_put_align(mbuf_chain_t *mbc, int align)
924 {
925 	int mask = align - 1;
926 	int padsz;
927 
928 	ASSERT(align > 0 && (align & mask) == 0);
929 	if ((mbc->chain_offset & mask) == 0)
930 		return (0);
931 	padsz = align - (mbc->chain_offset & mask);
932 	return (smb_mbc_encodef(mbc, "#.", padsz));
933 }
934 
935 /*
936  * Put data into mbuf chain allocating as needed.
937  * Adds room to end of mbuf chain if needed.
938  */
939 static int
mbc_marshal_make_room(mbuf_chain_t * mbc,int32_t bytes_needed)940 mbc_marshal_make_room(mbuf_chain_t *mbc, int32_t bytes_needed)
941 {
942 	mbuf_t	*m;
943 	mbuf_t	*last;
944 	int32_t	bytes_available;
945 
946 	bytes_needed += mbc->chain_offset;
947 	if (bytes_needed > mbc->max_bytes)
948 		return (EMSGSIZE);
949 
950 	/*
951 	 * First mbuf in chain should have prepend space.
952 	 * See M_LEADINGSPACE() below.
953 	 */
954 	if ((m = mbc->chain) == NULL) {
955 		MGET(m, M_WAIT, MT_DATA);
956 		m->m_len = 0;
957 		MCLGET(m, M_WAIT);
958 		m->m_data += MH_PREPEND_SPACE;
959 		mbc->chain = m;
960 		/* xxxx */
961 		/* ^    */
962 	}
963 
964 	/* ---- ----- --xx ---xxx */
965 	/* ^			  */
966 
967 	last = NULL;
968 	while ((m != NULL) && (bytes_needed >= m->m_len)) {
969 		last = m;
970 		bytes_needed -= m->m_len;
971 		m = m->m_next;
972 	}
973 
974 	if ((bytes_needed == 0) || (m != NULL)) {
975 		/* We have enough room already */
976 		return (0);
977 	}
978 
979 	/* ---- ----- --xx ---xxx */
980 	/*			 ^ */
981 	/* Back up to start of last mbuf */
982 	m = last;
983 	bytes_needed += m->m_len;
984 
985 	/* ---- ----- --xx ---xxx */
986 	/*		   ^	  */
987 	bytes_available = M_SIZE(m) - M_LEADINGSPACE(m);
988 
989 	/* ---- ----- --xx ---xxx */
990 	/*		   ^	  */
991 	while ((bytes_needed != 0) && (bytes_needed > bytes_available)) {
992 		m->m_len = bytes_available;
993 		bytes_needed -= m->m_len;
994 		/* ---- ----- --xx ------ */
995 		/*		   ^	  */
996 
997 		MGET(m->m_next, M_WAIT, MT_DATA);
998 		m = m->m_next;
999 		m->m_len = 0;
1000 		MCLGET(m, M_WAIT);
1001 
1002 		ASSERT(M_LEADINGSPACE(m) == 0);
1003 		bytes_available = M_SIZE(m);
1004 
1005 		/* ---- ----- --xx ------ xxxx */
1006 		/*			  ^    */
1007 	}
1008 
1009 	/* ---- ----- --xx ------ xxxx */
1010 	/*			  ^    */
1011 	/* Expand last tail as needed */
1012 	if (m->m_len <= bytes_needed) {
1013 		m->m_len = bytes_needed;
1014 		/* ---- ----- --xx ------ --xx */
1015 		/*			   ^   */
1016 	}
1017 
1018 	return (0);
1019 }
1020 
1021 static void
mbc_marshal_store_byte(mbuf_chain_t * mbc,uint8_t data)1022 mbc_marshal_store_byte(mbuf_chain_t *mbc, uint8_t data)
1023 {
1024 	mbuf_t	*m = mbc->chain;
1025 	int32_t	cur_offset = mbc->chain_offset;
1026 
1027 	/*
1028 	 * Scan forward looking for the last data currently in chain.
1029 	 */
1030 	while (cur_offset >= m->m_len) {
1031 		cur_offset -= m->m_len;
1032 		m = m->m_next;
1033 	}
1034 	((char *)m->m_data)[cur_offset] = data;
1035 	mbc->chain_offset++;
1036 }
1037 
1038 static int
mbc_marshal_put_char(mbuf_chain_t * mbc,uint8_t data)1039 mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t data)
1040 {
1041 	if (mbc_marshal_make_room(mbc, sizeof (char)) != 0)
1042 		return (DECODE_NO_MORE_DATA);
1043 	mbc_marshal_store_byte(mbc, data);
1044 	return (0);
1045 }
1046 
1047 static int
mbc_marshal_put_short(mbuf_chain_t * mbc,uint16_t data)1048 mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t data)
1049 {
1050 	if (mbc_marshal_make_room(mbc, sizeof (short)))
1051 		return (DECODE_NO_MORE_DATA);
1052 	mbc_marshal_store_byte(mbc, data);
1053 	mbc_marshal_store_byte(mbc, data >> 8);
1054 	return (0);
1055 }
1056 
1057 static int
mbc_marshal_put_long(mbuf_chain_t * mbc,uint32_t data)1058 mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t data)
1059 {
1060 	if (mbc_marshal_make_room(mbc, sizeof (int32_t)))
1061 		return (DECODE_NO_MORE_DATA);
1062 	mbc_marshal_store_byte(mbc, data);
1063 	mbc_marshal_store_byte(mbc, data >> 8);
1064 	mbc_marshal_store_byte(mbc, data >> 16);
1065 	mbc_marshal_store_byte(mbc, data >> 24);
1066 	return (0);
1067 }
1068 
1069 static int
mbc_marshal_put_long_long(mbuf_chain_t * mbc,uint64_t data)1070 mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t data)
1071 {
1072 	if (mbc_marshal_make_room(mbc, sizeof (int64_t)))
1073 		return (DECODE_NO_MORE_DATA);
1074 
1075 	mbc_marshal_store_byte(mbc, data);
1076 	mbc_marshal_store_byte(mbc, data >> 8);
1077 	mbc_marshal_store_byte(mbc, data >> 16);
1078 	mbc_marshal_store_byte(mbc, data >> 24);
1079 	mbc_marshal_store_byte(mbc, data >> 32);
1080 	mbc_marshal_store_byte(mbc, data >> 40);
1081 	mbc_marshal_store_byte(mbc, data >> 48);
1082 	mbc_marshal_store_byte(mbc, data >> 56);
1083 	return (0);
1084 }
1085 
1086 /*
1087  * Marshal a UTF-8 string (str) into mbc, converting to OEM codeset.
1088  * Also write a null unless the repc count limits the length we put.
1089  * When (repc > 0) the length we marshal must be exactly repc, and
1090  * truncate or pad the mbc data as necessary.
1091  * See also: msgbuf_put_oem_string
1092  */
1093 static int
mbc_marshal_put_oem_string(mbuf_chain_t * mbc,char * mbs,int repc)1094 mbc_marshal_put_oem_string(mbuf_chain_t *mbc, char *mbs, int repc)
1095 {
1096 	uint8_t		*oembuf = NULL;
1097 	uint8_t		*s;
1098 	int		oemlen;
1099 	int		rlen;
1100 	int		rc;
1101 
1102 	/*
1103 	 * Compute length of converted OEM string,
1104 	 * NOT including null terminator
1105 	 */
1106 	if ((oemlen = smb_sbequiv_strlen(mbs)) == -1)
1107 		return (DECODE_NO_MORE_DATA);
1108 
1109 	/*
1110 	 * If repc not specified, put whole string + NULL,
1111 	 * otherwise will truncate or pad as needed.
1112 	 */
1113 	if (repc <= 0)
1114 		repc = oemlen + 1;
1115 
1116 	/*
1117 	 * Convert into a temporary buffer
1118 	 * Free oembuf before return.
1119 	 */
1120 	oembuf = smb_mem_zalloc(oemlen + 1);
1121 	ASSERT(oembuf != NULL);
1122 	rlen = smb_mbstooem(oembuf, mbs, oemlen);
1123 	if (rlen < 0) {
1124 		rc = DECODE_NO_MORE_DATA;
1125 		goto out;
1126 	}
1127 	if (rlen > oemlen)
1128 		rlen = oemlen;
1129 	oembuf[rlen] = '\0';
1130 
1131 	/*
1132 	 * Copy the converted string into the message,
1133 	 * truncated or paded as required.
1134 	 */
1135 	s = oembuf;
1136 	while (repc > 0) {
1137 		if (mbc_marshal_make_room(mbc, 1)) {
1138 			rc = DECODE_NO_MORE_DATA;
1139 			goto out;
1140 		}
1141 		mbc_marshal_store_byte(mbc, *s);
1142 		if (*s != '\0')
1143 			s++;
1144 		repc--;
1145 	}
1146 	rc = 0;
1147 
1148 out:
1149 	if (oembuf != NULL)
1150 		smb_mem_free(oembuf);
1151 	return (rc);
1152 }
1153 
1154 /*
1155  * Marshal a UTF-8 string (str) into mbc, converting to UTF-16.
1156  * Also write a null unless the repc count limits the length.
1157  * When (repc > 0) the length we marshal must be exactly repc,
1158  * and truncate or pad the mbc data as necessary.
1159  * See also: msgbuf_put_unicode_string
1160  */
1161 static int
mbc_marshal_put_unicode_string(mbuf_chain_t * mbc,char * mbs,int repc)1162 mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *mbs, int repc)
1163 {
1164 	smb_wchar_t	*wcsbuf = NULL;
1165 	smb_wchar_t	*wp;
1166 	smb_wchar_t	wchar;
1167 	size_t		wcslen, wcsbytes;
1168 	size_t		rlen;
1169 	int		rc;
1170 
1171 	/* align to word boundary */
1172 	if (mbc->chain_offset & 1) {
1173 		if (mbc_marshal_make_room(mbc, 1))
1174 			return (DECODE_NO_MORE_DATA);
1175 		mbc_marshal_store_byte(mbc, 0);
1176 	}
1177 
1178 	/*
1179 	 * Compute length of converted UTF-16 string,
1180 	 * NOT including null terminator (in bytes).
1181 	 */
1182 	wcsbytes = smb_wcequiv_strlen(mbs);
1183 	if (wcsbytes == (size_t)-1)
1184 		return (DECODE_NO_MORE_DATA);
1185 
1186 	/*
1187 	 * If repc not specified, put whole string + NULL,
1188 	 * otherwise will truncate or pad as needed.
1189 	 */
1190 	if (repc <= 0)
1191 		repc = wcsbytes + 2;
1192 
1193 	/*
1194 	 * Convert into a temporary buffer
1195 	 * Free wcsbuf before return.
1196 	 */
1197 	wcslen = wcsbytes / 2;
1198 	wcsbuf = smb_mem_zalloc(wcsbytes + 2);
1199 	ASSERT(wcsbuf != NULL);
1200 	rlen = smb_mbstowcs(wcsbuf, mbs, wcslen);
1201 	if (rlen == (size_t)-1) {
1202 		rc = DECODE_NO_MORE_DATA;
1203 		goto out;
1204 	}
1205 	if (rlen > wcslen)
1206 		rlen = wcslen;
1207 	wcsbuf[rlen] = 0;
1208 
1209 	/*
1210 	 * Copy the converted string into the message,
1211 	 * truncated or paded as required.  Preserve
1212 	 * little-endian order while copying.
1213 	 */
1214 	wp = wcsbuf;
1215 	while (repc >= sizeof (smb_wchar_t)) {
1216 		if (mbc_marshal_make_room(mbc, sizeof (smb_wchar_t))) {
1217 			rc = DECODE_NO_MORE_DATA;
1218 			goto out;
1219 		}
1220 		wchar = LE_IN16(wp);
1221 		mbc_marshal_store_byte(mbc, wchar);
1222 		mbc_marshal_store_byte(mbc, wchar >> 8);
1223 		if (wchar != 0)
1224 			wp++;
1225 		repc -= sizeof (smb_wchar_t);
1226 	}
1227 	if (repc > 0) {
1228 		if (mbc_marshal_make_room(mbc, 1)) {
1229 			rc = DECODE_NO_MORE_DATA;
1230 			goto out;
1231 		}
1232 		mbc_marshal_store_byte(mbc, 0);
1233 	}
1234 	rc = 0;
1235 
1236 out:
1237 	if (wcsbuf != NULL)
1238 		smb_mem_free(wcsbuf);
1239 	return (rc);
1240 }
1241 
1242 static void /*ARGSUSED*/
uiorefnoop(mbuf_t * m)1243 uiorefnoop(mbuf_t *m)
1244 {
1245 }
1246 
1247 static int
mbc_marshal_put_uio(mbuf_chain_t * mbc,struct uio * uio)1248 mbc_marshal_put_uio(mbuf_chain_t *mbc, struct uio *uio)
1249 {
1250 	mbuf_t		**t;
1251 	mbuf_t		*m = NULL;
1252 	struct iovec	*iov = uio->uio_iov;
1253 	int32_t		i, iov_cnt = uio->uio_iovcnt;
1254 
1255 	iov = uio->uio_iov;
1256 	t = &mbc->chain;
1257 	for (i = 0; i < iov_cnt; i++) {
1258 		MGET(m, M_WAIT, MT_DATA);
1259 		m->m_ext.ext_buf = iov->iov_base;
1260 		m->m_ext.ext_free = uiorefnoop;
1261 		m->m_data = m->m_ext.ext_buf;
1262 		m->m_flags |= M_EXT;
1263 		m->m_len = m->m_ext.ext_size = iov->iov_len;
1264 		mbc->max_bytes += m->m_len;
1265 		m->m_next = 0;
1266 		*t = m;
1267 		t = &m->m_next;
1268 		iov++;
1269 	}
1270 	return (0);
1271 }
1272 
1273 int smb_mbuf_put_copy_threshold = 128;
1274 /*
1275  * Append an mbuf to the chain at chain_offset, with some optimizations:
1276  * If the chain is empty, just set the head (done).
1277  * If m is no larger than the copy threshold, copy.
1278  * Always consumes (or free's) the mbuf passed in.
1279  */
1280 static int
mbc_marshal_put_mbufs(mbuf_chain_t * mbc,mbuf_t * mbuf)1281 mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *mbuf)
1282 {
1283 	mbuf_t	*m;
1284 	int	bytes, rc;
1285 
1286 	/*
1287 	 * Length of mbuf(s) to be appended
1288 	 */
1289 	bytes = 0;
1290 	m = mbuf;
1291 	while (m != NULL) {
1292 		bytes += m->m_len;
1293 		m = m->m_next;
1294 	}
1295 	if (bytes == 0) {
1296 		m_freem(mbuf);
1297 		return (0);
1298 	}
1299 
1300 	/*
1301 	 * Check for space vs max_bytes
1302 	 */
1303 	if (!MBC_ROOM_FOR(mbc, bytes)) {
1304 		m_freem(mbuf);
1305 		return (EMSGSIZE);
1306 	}
1307 
1308 	/*
1309 	 * Empty mbc? (probably rare)
1310 	 */
1311 	if (mbc->chain == NULL) {
1312 		mbc->chain = mbuf;
1313 		mbc->chain_offset = bytes;
1314 		return (0);
1315 	}
1316 
1317 	/*
1318 	 * Copy optimization.  We've already checked that there's room
1319 	 * for the _put_mem operations, and that's the only error case
1320 	 * for that call, so just assert success and continue.
1321 	 */
1322 	if (bytes <= smb_mbuf_put_copy_threshold) {
1323 		m = mbuf;
1324 		while (m != NULL) {
1325 			rc = smb_mbc_put_mem(mbc, m->m_data, m->m_len);
1326 			ASSERT3S(rc, ==, 0);
1327 			m = m_free(m);
1328 		}
1329 		return (0);
1330 	}
1331 
1332 	/*
1333 	 * Trim existing chain and append
1334 	 */
1335 	smb_mbuf_trim(mbc->chain, mbc->chain_offset);
1336 	m = mbc->chain;
1337 	while (m->m_next != NULL)
1338 		m = m->m_next;
1339 	m->m_next = mbuf;
1340 	mbc->chain_offset += bytes;
1341 
1342 	return (0);
1343 }
1344 
1345 /*
1346  * Append a new mbc (nmbc) to the existing chain mbc
1347  * Assumes the new mbc has been "trimmed" to length.
1348  * (This ignores nmbc.chain_offset)
1349  *
1350  * Always consume or dispose of nmbc->chain
1351  */
1352 static int
mbc_marshal_put_mbuf_chain(mbuf_chain_t * mbc,mbuf_chain_t * nmbc)1353 mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc)
1354 {
1355 	int rc = 0;
1356 
1357 	if (nmbc->chain != NULL) {
1358 		rc = mbc_marshal_put_mbufs(mbc, nmbc->chain);
1359 		nmbc->chain = NULL;
1360 	}
1361 	return (rc);
1362 }
1363 
1364 static uint8_t
mbc_marshal_fetch_byte(mbuf_chain_t * mbc)1365 mbc_marshal_fetch_byte(mbuf_chain_t *mbc)
1366 {
1367 	uint8_t	data;
1368 	mbuf_t	*m = mbc->chain;
1369 	int32_t	offset = mbc->chain_offset;
1370 
1371 	while (offset >= m->m_len) {
1372 		offset -= m->m_len;
1373 		m = m->m_next;
1374 	}
1375 	data = ((uint8_t *)m->m_data)[offset];
1376 	mbc->chain_offset++;
1377 	return (data);
1378 }
1379 
1380 static int
mbc_marshal_get_char(mbuf_chain_t * mbc,uint8_t * data)1381 mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data)
1382 {
1383 	if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
1384 		/* Data will never be available */
1385 		return (DECODE_NO_MORE_DATA);
1386 	}
1387 	*data = mbc_marshal_fetch_byte(mbc);
1388 	return (0);
1389 }
1390 
1391 static int
mbc_marshal_get_short(mbuf_chain_t * mbc,uint16_t * data)1392 mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data)
1393 {
1394 	uint16_t	tmp;
1395 	mbuf_t		*m = mbc->chain;
1396 	int32_t		offset = mbc->chain_offset;
1397 
1398 	if (MBC_ROOM_FOR(mbc, sizeof (short)) == 0) {
1399 		/* Data will never be available */
1400 		return (DECODE_NO_MORE_DATA);
1401 	}
1402 
1403 	while (offset >= m->m_len) {
1404 		offset -= m->m_len;
1405 		m = m->m_next;
1406 	}
1407 	if ((m->m_len - offset) >= sizeof (short)) {
1408 		*data = LE_IN16(m->m_data + offset);
1409 		mbc->chain_offset += sizeof (short);
1410 	} else {
1411 		tmp = (uint16_t)mbc_marshal_fetch_byte(mbc);
1412 		tmp |= ((uint16_t)mbc_marshal_fetch_byte(mbc)) << 8;
1413 		*data = tmp;
1414 	}
1415 	return (0);
1416 }
1417 
1418 static int
mbc_marshal_get_long(mbuf_chain_t * mbc,uint32_t * data)1419 mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data)
1420 {
1421 	uint32_t	tmp;
1422 	mbuf_t		*m = mbc->chain;
1423 	int32_t		offset = mbc->chain_offset;
1424 
1425 	if (MBC_ROOM_FOR(mbc, sizeof (int32_t)) == 0) {
1426 		/* Data will never be available */
1427 		return (DECODE_NO_MORE_DATA);
1428 	}
1429 	while (offset >= m->m_len) {
1430 		offset -= m->m_len;
1431 		m = m->m_next;
1432 	}
1433 	if ((m->m_len - offset) >= sizeof (int32_t)) {
1434 		*data = LE_IN32(m->m_data + offset);
1435 		mbc->chain_offset += sizeof (int32_t);
1436 	} else {
1437 		tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
1438 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 8;
1439 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 16;
1440 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 24;
1441 		*data = tmp;
1442 	}
1443 	return (0);
1444 }
1445 
1446 static uint64_t
qswap(uint64_t ll)1447 qswap(uint64_t ll)
1448 {
1449 	uint64_t v;
1450 
1451 	v = ll >> 32;
1452 	v |= ll << 32;
1453 
1454 	return (v);
1455 }
1456 
1457 static int
mbc_marshal_get_odd_long_long(mbuf_chain_t * mbc,uint64_t * data)1458 mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data)
1459 {
1460 	uint64_t	tmp;
1461 	mbuf_t		*m = mbc->chain;
1462 	int32_t		offset = mbc->chain_offset;
1463 
1464 	if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
1465 		/* Data will never be available */
1466 		return (DECODE_NO_MORE_DATA);
1467 	}
1468 	while (offset >= m->m_len) {
1469 		offset -= m->m_len;
1470 		m = m->m_next;
1471 	}
1472 
1473 	if ((m->m_len - offset) >= sizeof (int64_t)) {
1474 		*data = qswap(LE_IN64(m->m_data + offset));
1475 		mbc->chain_offset += sizeof (int64_t);
1476 	} else {
1477 		tmp = (uint64_t)mbc_marshal_fetch_byte(mbc) << 32;
1478 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 40;
1479 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 48;
1480 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 56;
1481 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc);
1482 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 8;
1483 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 16;
1484 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 24;
1485 
1486 		*(uint64_t *)data = tmp;
1487 	}
1488 	return (0);
1489 }
1490 
1491 static int
mbc_marshal_get_long_long(mbuf_chain_t * mbc,uint64_t * data)1492 mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data)
1493 {
1494 	uint64_t	tmp;
1495 	mbuf_t		*m = mbc->chain;
1496 	int32_t		offset = mbc->chain_offset;
1497 
1498 	if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
1499 		/* Data will never be available */
1500 		return (DECODE_NO_MORE_DATA);
1501 	}
1502 	while (offset >= m->m_len) {
1503 		offset -= m->m_len;
1504 		m = m->m_next;
1505 	}
1506 	if ((m->m_len - offset) >= sizeof (int64_t)) {
1507 		*data = LE_IN64(m->m_data + offset);
1508 		mbc->chain_offset += sizeof (int64_t);
1509 	} else {
1510 		tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
1511 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 8;
1512 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 16;
1513 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 24;
1514 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32;
1515 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40;
1516 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48;
1517 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56;
1518 		*(uint64_t *)data = tmp;
1519 	}
1520 	return (0);
1521 }
1522 
1523 /*
1524  * mbc_marshal_get_oem_string
1525  *
1526  * Decode an OEM string, returning its UTF-8 form in strpp,
1527  * allocated using smb_srm_zalloc (automatically freed).
1528  * If max_bytes != 0, consume at most max_bytes of the mbc.
1529  * See also: msgbuf_get_oem_string
1530  */
1531 static int
mbc_marshal_get_oem_string(smb_request_t * sr,mbuf_chain_t * mbc,char ** strpp,int max_bytes)1532 mbc_marshal_get_oem_string(smb_request_t *sr,
1533     mbuf_chain_t *mbc, char **strpp, int max_bytes)
1534 {
1535 	char		*mbs;
1536 	uint8_t		*oembuf = NULL;
1537 	int		oemlen, oemmax;
1538 	int		mbsmax;
1539 	int		rlen;
1540 	int		rc;
1541 
1542 	if (max_bytes == 0)
1543 		max_bytes = 0xffff;
1544 
1545 	/*
1546 	 * Get the OtW data into a temporary buffer.
1547 	 * Free oembuf before return.
1548 	 */
1549 	oemlen = 0;
1550 	oemmax = MALLOC_QUANTUM;
1551 	oembuf = smb_mem_alloc(oemmax);
1552 	for (;;) {
1553 		uint8_t ch;
1554 
1555 		if (oemlen >= max_bytes)
1556 			break;
1557 		if ((oemlen + 2) >= oemmax) {
1558 			oemmax += MALLOC_QUANTUM;
1559 			oembuf = smb_mem_realloc(oembuf, oemmax);
1560 		}
1561 		if (mbc_marshal_get_char(mbc, &ch) != 0) {
1562 			rc = DECODE_NO_MORE_DATA;
1563 			goto out;
1564 		}
1565 		if (ch == 0)
1566 			break;
1567 		oembuf[oemlen++] = ch;
1568 	}
1569 	oembuf[oemlen] = '\0';
1570 
1571 	/*
1572 	 * Get the buffer we'll return and convert to UTF-8.
1573 	 * May take as much as double the space.
1574 	 */
1575 	mbsmax = oemlen * 2;
1576 	mbs = smb_srm_zalloc(sr, mbsmax + 1);
1577 	ASSERT(mbs != NULL);
1578 	rlen = smb_oemtombs(mbs, oembuf, mbsmax);
1579 	if (rlen < 0) {
1580 		rc = DECODE_NO_MORE_DATA;
1581 		goto out;
1582 	}
1583 	if (rlen > mbsmax)
1584 		rlen = mbsmax;
1585 	mbs[rlen] = '\0';
1586 	*strpp = mbs;
1587 	rc = 0;
1588 
1589 out:
1590 	if (oembuf != NULL)
1591 		smb_mem_free(oembuf);
1592 	return (rc);
1593 }
1594 
1595 /*
1596  * mbc_marshal_get_unicode_string
1597  *
1598  * Decode a UTF-16 string, returning its UTF-8 form in strpp,
1599  * allocated using smb_srm_zalloc (automatically freed).
1600  * If max_bytes != 0, consume at most max_bytes of the mbc.
1601  * See also: msgbuf_get_unicode_string
1602  */
1603 static int
mbc_marshal_get_unicode_string(smb_request_t * sr,mbuf_chain_t * mbc,char ** strpp,int max_bytes)1604 mbc_marshal_get_unicode_string(smb_request_t *sr,
1605     mbuf_chain_t *mbc, char **strpp, int max_bytes)
1606 {
1607 	char		*mbs;
1608 	uint16_t	*wcsbuf = NULL;
1609 	int		wcslen;		// wchar count
1610 	int		wcsmax;		// byte count
1611 	size_t		mbsmax;
1612 	size_t		rlen;
1613 	int		rc;
1614 
1615 	if (max_bytes == 0)
1616 		max_bytes = 0xffff;
1617 
1618 	/*
1619 	 * Unicode strings are always word aligned.
1620 	 */
1621 	if (mbc->chain_offset & 1) {
1622 		if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0)
1623 			return (DECODE_NO_MORE_DATA);
1624 		mbc->chain_offset++;
1625 	}
1626 
1627 	/*
1628 	 * Get the OtW data into a temporary buffer.
1629 	 * Free wcsbuf before return.
1630 	 */
1631 	wcslen = 0;
1632 	wcsmax = MALLOC_QUANTUM;
1633 	wcsbuf = smb_mem_alloc(wcsmax);
1634 	for (;;) {
1635 		uint16_t	wchar;
1636 
1637 		if ((wcslen * 2) >= max_bytes)
1638 			break;
1639 		if (((wcslen * 2) + 4) >= wcsmax) {
1640 			wcsmax += MALLOC_QUANTUM;
1641 			wcsbuf = smb_mem_realloc(wcsbuf, wcsmax);
1642 		}
1643 		if (mbc_marshal_get_short(mbc, &wchar) != 0) {
1644 			rc = DECODE_NO_MORE_DATA;
1645 			goto out;
1646 		}
1647 		if (wchar == 0)
1648 			break;
1649 		/* Keep in little-endian form. */
1650 		LE_OUT16(wcsbuf + wcslen, wchar);
1651 		wcslen++;
1652 	}
1653 	wcsbuf[wcslen] = 0;
1654 
1655 	/*
1656 	 * Get the buffer we'll return and convert to UTF-8.
1657 	 * May take as much 4X number of wide chars.
1658 	 */
1659 	mbsmax = wcslen * MTS_MB_CUR_MAX;
1660 	mbs = smb_srm_zalloc(sr, mbsmax + 1);
1661 	ASSERT(mbs != NULL);
1662 	rlen = smb_wcstombs(mbs, wcsbuf, mbsmax);
1663 	if (rlen == (size_t)-1) {
1664 		rc = DECODE_NO_MORE_DATA;
1665 		goto out;
1666 	}
1667 	if (rlen > mbsmax)
1668 		rlen = mbsmax;
1669 	mbs[rlen] = '\0';
1670 	*strpp = mbs;
1671 	rc = 0;
1672 
1673 out:
1674 	if (wcsbuf != NULL)
1675 		smb_mem_free(wcsbuf);
1676 	return (rc);
1677 }
1678 
1679 static int /*ARGSUSED*/
mbc_marshal_get_mbufs(mbuf_chain_t * mbc,int32_t bytes,mbuf_t ** m)1680 mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m)
1681 {
1682 	*m = NULL;
1683 	if (MBC_ROOM_FOR(mbc, bytes) == 0) {
1684 		/* Data will never be available */
1685 		return (DECODE_NO_MORE_DATA);
1686 	}
1687 	/* not yet implemented */
1688 	return (-1);
1689 }
1690 
1691 static int
mbc_marshal_get_mbuf_chain(mbuf_chain_t * mbc,int32_t bytes,mbuf_chain_t * nmbc)1692 mbc_marshal_get_mbuf_chain(mbuf_chain_t *mbc, int32_t bytes, mbuf_chain_t *nmbc)
1693 {
1694 	int	rc;
1695 	mbuf_t	*m;
1696 
1697 	if (bytes == 0) {
1698 		/* Get all the rest */
1699 		bytes = mbc->max_bytes - mbc->chain_offset;
1700 	}
1701 
1702 	MBC_SETUP(nmbc, mbc->max_bytes);
1703 	if ((rc = mbc_marshal_get_mbufs(mbc, bytes, &m)) != 0) {
1704 		if (m)
1705 			m_freem(m);
1706 		return (rc);
1707 	}
1708 	nmbc->chain = m;
1709 	while (m != 0) {
1710 		bytes += m->m_len;
1711 		m = m->m_next;
1712 	}
1713 	nmbc->max_bytes = bytes;
1714 	return (0);
1715 }
1716 
1717 static int
mbc_marshal_get_uio(mbuf_chain_t * mbc,struct uio * uio)1718 mbc_marshal_get_uio(mbuf_chain_t *mbc, struct uio *uio)
1719 {
1720 	int		i, offset;
1721 	int32_t		bytes = uio->uio_resid;
1722 	int32_t		remainder;
1723 	struct iovec	*iov;
1724 	mbuf_t		*m;
1725 
1726 	/*
1727 	 * The residual count is tested because in the case of write requests
1728 	 * with no data (smbtorture RAW-WRITE test will generate that type of
1729 	 * request) this function is called with a residual count of zero
1730 	 * bytes.
1731 	 */
1732 	if (bytes != 0) {
1733 		iov = uio->uio_iov;
1734 		uio->uio_segflg = UIO_SYSSPACE;
1735 		uio->uio_extflg = UIO_COPY_DEFAULT;
1736 
1737 		if (MBC_ROOM_FOR(mbc, bytes) == 0) {
1738 			/* Data will never be available */
1739 			return (DECODE_NO_MORE_DATA);
1740 		}
1741 
1742 		m = mbc->chain;
1743 		offset = mbc->chain_offset;
1744 		while (offset >= m->m_len) {
1745 			offset -= m->m_len;
1746 			m = m->m_next;
1747 			ASSERT((offset == 0) || (offset && m));
1748 		}
1749 
1750 		for (i = 0; (bytes > 0) && (i < uio->uio_iovcnt); i++) {
1751 			iov[i].iov_base = &m->m_data[offset];
1752 			remainder = m->m_len - offset;
1753 			if (remainder >= bytes) {
1754 				iov[i].iov_len = bytes;
1755 				mbc->chain_offset += bytes;
1756 				uio->uio_iovcnt = i + 1;
1757 				return (0);
1758 			}
1759 			iov[i].iov_len = remainder;
1760 			mbc->chain_offset += remainder;
1761 			bytes -= remainder;
1762 			m = m->m_next;
1763 			offset = 0;
1764 		}
1765 		return (DECODE_NO_MORE_DATA);
1766 	}
1767 	return (0);
1768 }
1769 
1770 static int
mbc_marshal_get_skip(mbuf_chain_t * mbc,uint_t skip)1771 mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip)
1772 {
1773 	if (MBC_ROOM_FOR(mbc, skip) == 0)
1774 		return (DECODE_NO_MORE_DATA);
1775 	mbc->chain_offset += skip;
1776 	return (0);
1777 }
1778