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