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 2015 Nexenta Systems, 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_cstou8(char *, char *, size_t, char *, size_t);
43 static int mbc_marshal_make_room(mbuf_chain_t *, int32_t);
44 static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t);
45 static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t);
46 static int mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t);
47 static int mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t);
48 static int mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t);
49 static int mbc_marshal_put_ascii_string(mbuf_chain_t *, char *, int);
50 static int mbc_marshal_put_unicode_string(mbuf_chain_t *, char *, int);
51 static int mbc_marshal_put_uio(mbuf_chain_t *, struct uio *);
52 static int mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m);
53 static int mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc);
54 static uint8_t mbc_marshal_fetch_byte(mbuf_chain_t *mbc);
55 static int mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data);
56 static int mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data);
57 static int mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data);
58 static uint64_t qswap(uint64_t ll);
59 static int mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data);
60 static int mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data);
61 static int mbc_marshal_get_ascii_string(smb_request_t *, mbuf_chain_t *,
62 uint8_t **ascii, int);
63 static int mbc_marshal_get_unicode_string(smb_request_t *, mbuf_chain_t *,
64 uint8_t **, int);
65 static int mbc_marshal_get_mbufs(mbuf_chain_t *, int32_t, mbuf_t **);
66 static int mbc_marshal_get_mbuf_chain(mbuf_chain_t *, int32_t, mbuf_chain_t *);
67 static int mbc_marshal_get_uio(mbuf_chain_t *, struct uio *);
68 static int mbc_marshal_get_skip(mbuf_chain_t *, uint_t);
69
70 /*
71 * smb_mbc_vdecodef
72 *
73 * This function reads the contents of the mbc chain passed in under the list
74 * of arguments passed in.
75 *
76 * The format string provides a description of the parameters passed in as well
77 * as an action to be taken by smb_mbc_vdecodef().
78 *
79 * % Pointer to an SMB request structure (smb_request_t *). There
80 * should be only one of these in the string.
81 *
82 * C Pointer to an mbuf chain. Copy to that mbuf chain the number of
83 * bytes specified (number preceding C).
84 *
135 * s Same as 'u' without convertion.
136 *
137 * U Same as 'u'. The string to retrieve is unicode.
138 *
139 * y Pointer to a 32bit value. Read the dos time at the current mbuf
140 * chain location, convert it to unix time and store it at the
141 * location indicated by the pointer.
142 *
143 * Y Same as 'y' bt the dos time coded in the mbuf chain is inverted.
144 *
145 * . Skip the number of bytes indicated by the number preceding '.'.
146 *
147 * , Same as '.' but take in account it is an unicode string.
148 */
149 int
150 smb_mbc_vdecodef(mbuf_chain_t *mbc, const char *fmt, va_list ap)
151 {
152 uint8_t c;
153 uint8_t cval;
154 uint8_t *cvalp;
155 uint8_t **cvalpp;
156 uint16_t wval;
157 uint16_t *wvalp;
158 uint32_t *lvalp;
159 uint64_t *llvalp;
160 smb_vdb_t *vdp;
161 smb_request_t *sr = NULL;
162 uint32_t lval;
163 int unicode = 0;
164 int repc;
165 boolean_t repc_specified;
166
167 while ((c = *fmt++) != 0) {
168 repc_specified = B_FALSE;
169 repc = 1;
170
171 if ('0' <= c && c <= '9') {
172 repc = 0;
173 do {
174 repc = repc * 10 + c - '0';
175 c = *fmt++;
277 return (-1);
278 if (mbc_marshal_get_short(mbc, &wval) != 0)
279 return (-1);
280 vdp->vdb_len = (uint32_t)wval;
281 vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0];
282 vdp->vdb_uio.uio_iovcnt = MAX_IOVEC;
283 vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
284 vdp->vdb_uio.uio_resid = vdp->vdb_len;
285 if (vdp->vdb_len != 0) {
286 if (mbc_marshal_get_uio(mbc,
287 &vdp->vdb_uio) != 0)
288 return (-1);
289 }
290 break;
291
292 case 'L':
293 if (mbc_marshal_get_char(mbc, &cval) != 0)
294 return (-1);
295 if (cval != 2)
296 return (-1);
297 goto ascii_conversion;
298
299 case 'A':
300 case 'S':
301 if (mbc_marshal_get_char(mbc, &cval) != 0)
302 return (-1);
303 if (((c == 'A' || c == 'S') && cval != 4) ||
304 (c == 'L' && cval != 2))
305 return (-1);
306 /* FALLTHROUGH */
307
308 case 'u': /* Convert from unicode if flags are set */
309 if (unicode)
310 goto unicode_translation;
311 /* FALLTHROUGH */
312
313 case 's':
314 ascii_conversion:
315 ASSERT(sr != NULL);
316 cvalpp = va_arg(ap, uint8_t **);
317 if (!repc_specified)
318 repc = 0;
319 if (mbc_marshal_get_ascii_string(sr,
320 mbc, cvalpp, repc) != 0)
321 return (-1);
322 break;
323
324 case 'U': /* Convert from unicode */
325 unicode_translation:
326 ASSERT(sr != 0);
327 cvalpp = va_arg(ap, uint8_t **);
328 if (!repc_specified)
329 repc = 0;
330 if (mbc->chain_offset & 1)
331 mbc->chain_offset++;
332 if (mbc_marshal_get_unicode_string(sr,
333 mbc, cvalpp, repc) != 0)
334 return (-1);
335 break;
336
337 case 'Y': /* dos time to unix time tt/dd */
338 lvalp = va_arg(ap, uint32_t *);
339 while (repc-- > 0) {
340 short d, t;
341
342 if (mbc_marshal_get_short(mbc,
343 (uint16_t *)&t) != 0)
344 return (-1);
345 if (mbc_marshal_get_short(mbc,
346 (uint16_t *)&d) != 0)
347 return (-1);
348 *lvalp++ = smb_time_dos_to_unix(d, t);
349 }
350 break;
351
352 case 'y': /* dos time to unix time dd/tt */
353 lvalp = va_arg(ap, uint32_t *);
502 *
503 * Y Date/Time. Store the Date/Time or the number of Date/Time(s)
504 * specified into the the mbuf chain. A format string like this
505 * "2Y" would require 2 Date/Time values. The Date/Time is
506 * converted to DOS before storing.
507 *
508 * y Same as 'Y'. The order of Date and Time is reversed.
509 *
510 * , Character. Store the character or number of character specified
511 * into the mbuf chain. A format string like this "2c" would
512 * require 2 characters to be passed in. A unicode conversion is
513 * applied if appropriate.
514 *
515 * . Same as '`' without unicode conversion.
516 *
517 * U Align the offset of the mbuf chain on a 16bit boundary.
518 */
519 int
520 smb_mbc_vencodef(mbuf_chain_t *mbc, const char *fmt, va_list ap)
521 {
522 uint8_t *cvalp;
523 timestruc_t *tvp;
524 smb_vdb_t *vdp;
525 smb_request_t *sr = NULL;
526 uint64_t llval;
527 int64_t nt_time;
528 uint32_t lval;
529 uint_t tag;
530 int unicode = 0;
531 int repc;
532 boolean_t repc_specified;
533 uint16_t wval;
534 uint8_t cval;
535 uint8_t c;
536
537 while ((c = *fmt++) != 0) {
538 repc_specified = B_FALSE;
539 repc = 1;
540
541 if ('0' <= c && c <= '9') {
542 repc = 0;
543 do {
544 repc = repc * 10 + c - '0';
545 c = *fmt++;
546 } while ('0' <= c && c <= '9');
547 repc_specified = B_TRUE;
548 } else if (c == '#') {
549 repc = va_arg(ap, int);
550 c = *fmt++;
551 repc_specified = B_TRUE;
552
553 }
554
555 switch (c) {
556 case '%':
557 sr = va_arg(ap, struct smb_request *);
558 if (sr->session->dialect >= SMB_VERS_2_BASE) {
559 unicode = 1;
560 break;
561 }
562 unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
563 break;
564
565 case 'C': /* Mbuf_chain */
566 if (mbc_marshal_put_mbuf_chain(mbc,
567 va_arg(ap, mbuf_chain_t *)) != 0)
568 return (DECODE_NO_MORE_DATA);
569 break;
570
571 case 'D':
572 vdp = va_arg(ap, struct vardata_block *);
642
643 case 'l':
644 while (repc-- > 0) {
645 lval = va_arg(ap, uint32_t);
646 if (mbc_marshal_put_long(mbc, lval) != 0)
647 return (DECODE_NO_MORE_DATA);
648 }
649 break;
650
651 case 'q':
652 while (repc-- > 0) {
653 llval = va_arg(ap, uint64_t);
654 if (mbc_marshal_put_long_long(mbc, llval) != 0)
655 return (DECODE_NO_MORE_DATA);
656 }
657 break;
658
659
660 case 'L':
661 tag = 2;
662 goto ascii_conversion;
663
664 case 'S':
665 case 'A':
666 tag = 4;
667 goto tagged_str;
668
669 case 'P':
670 tag = 3;
671 goto tagged_str;
672
673 tagged_str:
674 if (mbc_marshal_put_char(mbc, tag) != 0)
675 return (DECODE_NO_MORE_DATA);
676 /* FALLTHROUGH */
677
678 case 'u': /* Convert from unicode if flags are set */
679 if (unicode)
680 goto unicode_translation;
681 /* FALLTHROUGH */
682
683 case 's': /* ASCII/multibyte string */
684 ascii_conversion: cvalp = va_arg(ap, uint8_t *);
685 if (!repc_specified)
686 repc = 0;
687 if (mbc_marshal_put_ascii_string(mbc,
688 (char *)cvalp, repc) != 0)
689 return (DECODE_NO_MORE_DATA);
690 break;
691
692 case 'Y': /* int32_t, encode dos date/time */
693 while (repc-- > 0) {
694 uint16_t d, t;
695
696 lval = va_arg(ap, uint32_t);
697 smb_time_unix_to_dos(lval,
698 (short *)&d, (short *)&t);
699 if (mbc_marshal_put_short(mbc, t) != 0)
700 return (DECODE_NO_MORE_DATA);
701 if (mbc_marshal_put_short(mbc, d) != 0)
702 return (DECODE_NO_MORE_DATA);
703 }
704 break;
705
706 case 'y': /* int32_t, encode dos date/time */
707 while (repc-- > 0) {
708 uint16_t d, t;
709
710 lval = va_arg(ap, uint32_t);
711 smb_time_unix_to_dos(lval,
712 (short *)&d, (short *)&t);
713 if (mbc_marshal_put_short(mbc, d) != 0)
714 return (DECODE_NO_MORE_DATA);
715 if (mbc_marshal_put_short(mbc, t) != 0)
716 return (DECODE_NO_MORE_DATA);
717 }
718 break;
719
720 case ',':
721 if (unicode)
722 repc *= 2;
723 /* FALLTHROUGH */
724
725 case '.':
726 while (repc-- > 0)
727 if (mbc_marshal_put_char(mbc, 0) != 0)
728 return (DECODE_NO_MORE_DATA);
729 break;
730
731 case 'U': /* Convert to unicode, align to word boundary */
732 unicode_translation:
733 if (mbc->chain_offset & 1)
734 mbc->chain_offset++;
735 cvalp = va_arg(ap, uint8_t *);
736 if (!repc_specified)
737 repc = 0;
738 if (mbc_marshal_put_unicode_string(mbc,
739 (char *)cvalp, repc) != 0)
740 return (DECODE_NO_MORE_DATA);
741 break;
742
743 default:
744 ASSERT(0);
745 return (-1);
746 }
747 }
748 return (0);
749 }
750
751 /*
752 * smb_mbc_encodef
753 *
754 * This function builds a stream of bytes in the mbc chain passed in under the
755 * control of the format fmt.
756 *
757 * (for a description of the format string see smb_mbc_vencodef()).
758 */
759 int
760 smb_mbc_encodef(mbuf_chain_t *mbc, const char *fmt, ...)
761 {
762 int rc;
903 /*
904 * Copy remaining mem into mbufs. These all start
905 * at the beginning of each mbuf, and the last may
906 * end somewhere short of m_len.
907 */
908 while (mem_len > 0) {
909 m = m->m_next;
910 tlen = m->m_len;
911 if (tlen > mem_len)
912 tlen = mem_len;
913 bcopy(mem, m->m_data, tlen);
914 mbc->chain_offset += tlen;
915 mem += tlen;
916 mem_len -= tlen;
917 }
918
919 return (0);
920 }
921
922 /*
923 * Put data into mbuf chain allocating as needed.
924 * Adds room to end of mbuf chain if needed.
925 */
926 static int
927 mbc_marshal_make_room(mbuf_chain_t *mbc, int32_t bytes_needed)
928 {
929 mbuf_t *m;
930 mbuf_t *l;
931 int32_t bytes_available;
932
933 bytes_needed += mbc->chain_offset;
934 if (bytes_needed > mbc->max_bytes)
935 return (EMSGSIZE);
936
937 if ((m = mbc->chain) == 0) {
938 MGET(m, M_WAIT, MT_DATA);
939 m->m_len = 0;
940 MCLGET(m, M_WAIT);
941 mbc->chain = m;
942 /* xxxx */
1051 }
1052
1053 static int
1054 mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t data)
1055 {
1056 if (mbc_marshal_make_room(mbc, sizeof (int64_t)))
1057 return (DECODE_NO_MORE_DATA);
1058
1059 mbc_marshal_store_byte(mbc, data);
1060 mbc_marshal_store_byte(mbc, data >> 8);
1061 mbc_marshal_store_byte(mbc, data >> 16);
1062 mbc_marshal_store_byte(mbc, data >> 24);
1063 mbc_marshal_store_byte(mbc, data >> 32);
1064 mbc_marshal_store_byte(mbc, data >> 40);
1065 mbc_marshal_store_byte(mbc, data >> 48);
1066 mbc_marshal_store_byte(mbc, data >> 56);
1067 return (0);
1068 }
1069
1070 /*
1071 * When need to convert from UTF-8 (internal format) to a single
1072 * byte string (external format ) when marshalling a string.
1073 */
1074 static int
1075 mbc_marshal_put_ascii_string(mbuf_chain_t *mbc, char *mbs, int repc)
1076 {
1077 smb_wchar_t wide_char;
1078 int nbytes;
1079 int length;
1080
1081 if ((length = smb_sbequiv_strlen(mbs)) == -1)
1082 return (DECODE_NO_MORE_DATA);
1083
1084 length += sizeof (char);
1085
1086 if ((repc > 0) && (repc < length))
1087 length = repc;
1088 if (mbc_marshal_make_room(mbc, length))
1089 return (DECODE_NO_MORE_DATA);
1090
1091 while (*mbs) {
1092 /*
1093 * We should restore oem chars here.
1094 */
1095 nbytes = smb_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX);
1096 if (nbytes == -1)
1097 return (DECODE_NO_MORE_DATA);
1098
1099 mbc_marshal_store_byte(mbc, (uint8_t)wide_char);
1100
1101 if (wide_char & 0xFF00)
1102 mbc_marshal_store_byte(mbc, wide_char >> 8);
1103
1104 mbs += nbytes;
1105 }
1106
1107 mbc_marshal_store_byte(mbc, 0);
1108 return (0);
1109 }
1110
1111 static int
1112 mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *ascii, int repc)
1113 {
1114 smb_wchar_t wchar;
1115 int consumed;
1116 int length;
1117
1118 if ((length = smb_wcequiv_strlen(ascii)) == -1)
1119 return (DECODE_NO_MORE_DATA);
1120
1121 length += sizeof (smb_wchar_t);
1122
1123 if ((repc > 0) && (repc < length))
1124 length = repc;
1125
1126 if (mbc_marshal_make_room(mbc, length))
1127 return (DECODE_NO_MORE_DATA);
1128 while (length > 0) {
1129 consumed = smb_mbtowc(&wchar, ascii, MTS_MB_CHAR_MAX);
1130 if (consumed == -1)
1131 break; /* Invalid sequence */
1132 /*
1133 * Note that consumed will be 0 when the null terminator
1134 * is encountered and ascii will not be advanced beyond
1135 * that point. Length will continue to be decremented so
1136 * we won't get stuck here.
1137 */
1138 ascii += consumed;
1139 mbc_marshal_store_byte(mbc, wchar);
1140 mbc_marshal_store_byte(mbc, wchar >> 8);
1141 length -= sizeof (smb_wchar_t);
1142 }
1143 return (0);
1144 }
1145
1146 static int /*ARGSUSED*/
1147 uiorefnoop(caddr_t p, int size, int adj)
1148 {
1149 return (0);
1150 }
1151
1152 static int
1153 mbc_marshal_put_uio(mbuf_chain_t *mbc, struct uio *uio)
1154 {
1155 mbuf_t **t;
1156 mbuf_t *m = NULL;
1157 struct iovec *iov = uio->uio_iov;
1158 int32_t i, iov_cnt = uio->uio_iovcnt;
1159
1160 iov = uio->uio_iov;
1161 t = &mbc->chain;
1162 for (i = 0; i < iov_cnt; i++) {
1163 MGET(m, M_WAIT, MT_DATA);
1358 m = m->m_next;
1359 }
1360 if ((m->m_len - offset) >= sizeof (int64_t)) {
1361 *data = LE_IN64(m->m_data + offset);
1362 mbc->chain_offset += sizeof (int64_t);
1363 } else {
1364 tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
1365 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 8;
1366 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 16;
1367 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 24;
1368 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32;
1369 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40;
1370 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48;
1371 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56;
1372 *(uint64_t *)data = tmp;
1373 }
1374 return (0);
1375 }
1376
1377 /*
1378 * mbc_marshal_get_ascii_string
1379 *
1380 * The ascii string in smb includes oem chars. Since the
1381 * system needs utf8 encodes unicode char, conversion is
1382 * required to convert the oem char to unicode and then
1383 * to encode the converted wchars to utf8 format.
1384 * Therefore, the **ascii returned will be in such format
1385 * instead of the real ASCII format.
1386 */
1387 static int
1388 mbc_marshal_get_ascii_string(
1389 smb_request_t *sr,
1390 mbuf_chain_t *mbc,
1391 uint8_t **ascii,
1392 int max_ascii)
1393 {
1394 char *rcvbuf;
1395 char *ch;
1396 int max;
1397 int length = 0;
1398
1399 max = MALLOC_QUANTUM;
1400 rcvbuf = smb_srm_zalloc(sr, max);
1401
1402 if (max_ascii == 0)
1403 max_ascii = 0xffff;
1404
1405 ch = rcvbuf;
1406 for (;;) {
1407 while (length < max) {
1408 if (max_ascii-- <= 0) {
1409 *ch++ = 0;
1410 goto multibyte_encode;
1411 }
1412 if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
1413 /* Data will never be available */
1414 return (DECODE_NO_MORE_DATA);
1415 }
1416 if ((*ch++ = mbc_marshal_fetch_byte(mbc)) == 0)
1417 goto multibyte_encode;
1418 length++;
1419 }
1420 max += MALLOC_QUANTUM;
1421 rcvbuf = smb_srm_rezalloc(sr, rcvbuf, max);
1422 ch = rcvbuf + length;
1423 }
1424
1425 multibyte_encode:
1426 /*
1427 * UTF-8 encode the string for internal system use.
1428 */
1429 length = strlen(rcvbuf) + 1;
1430 *ascii = smb_srm_zalloc(sr, length * MTS_MB_CHAR_MAX);
1431 return (mbc_marshal_cstou8("CP850", (char *)*ascii,
1432 (size_t)length * MTS_MB_CHAR_MAX, rcvbuf, (size_t)length));
1433 }
1434
1435 static int
1436 mbc_marshal_get_unicode_string(smb_request_t *sr,
1437 mbuf_chain_t *mbc, uint8_t **ascii, int max_unicode)
1438 {
1439 int max;
1440 uint16_t wchar;
1441 char *ch;
1442 int emitted;
1443 int length = 0;
1444
1445 if (max_unicode == 0)
1446 max_unicode = 0xffff;
1447
1448 max = MALLOC_QUANTUM;
1449 *ascii = smb_srm_zalloc(sr, max);
1450
1451 ch = (char *)*ascii;
1452 for (;;) {
1453 while ((length + MTS_MB_CHAR_MAX) < max) {
1454 if (max_unicode <= 0)
1455 goto done;
1456 max_unicode -= 2;
1457
1458 if (mbc_marshal_get_short(mbc, &wchar) != 0)
1459 return (DECODE_NO_MORE_DATA);
1460
1461 if (wchar == 0) goto done;
1462
1463 emitted = smb_wctomb(ch, wchar);
1464 length += emitted;
1465 ch += emitted;
1466 }
1467 max += MALLOC_QUANTUM;
1468 *ascii = smb_srm_rezalloc(sr, *ascii, max);
1469 ch = (char *)*ascii + length;
1470 }
1471 done: *ch = 0;
1472 return (0);
1473 }
1474
1475 static int /*ARGSUSED*/
1476 mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m)
1477 {
1478 *m = NULL;
1479 if (MBC_ROOM_FOR(mbc, bytes) == 0) {
1480 /* Data will never be available */
1481 return (DECODE_NO_MORE_DATA);
1482 }
1483 /* not yet implemented */
1484 return (-1);
1485 }
1486
1487 static int
1488 mbc_marshal_get_mbuf_chain(mbuf_chain_t *mbc, int32_t bytes, mbuf_chain_t *nmbc)
1489 {
1490 int rc;
1491 mbuf_t *m;
1492
1553 return (0);
1554 }
1555 iov[i].iov_len = remainder;
1556 mbc->chain_offset += remainder;
1557 bytes -= remainder;
1558 m = m->m_next;
1559 offset = 0;
1560 }
1561 return (DECODE_NO_MORE_DATA);
1562 }
1563 return (0);
1564 }
1565
1566 static int
1567 mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip)
1568 {
1569 if (MBC_ROOM_FOR(mbc, skip) == 0)
1570 return (DECODE_NO_MORE_DATA);
1571 mbc->chain_offset += skip;
1572 return (0);
1573 }
1574
1575 /*
1576 * Converts oem string to UTF-8 string with an output string of max
1577 * maxconv bytes. The string may be truncated or not null-terminated if
1578 * there is not enough room.
1579 *
1580 * returns -1, cnt (partial conversion) or 0 (success)
1581 */
1582
1583 static int
1584 mbc_marshal_cstou8(char *cs, char *outbuf, size_t maxconv,
1585 char *inbuf, size_t srcbytes)
1586 {
1587 kiconv_t t2u;
1588 size_t inlen = srcbytes;
1589 size_t outlen = maxconv;
1590 int err = 0;
1591 size_t rc;
1592
1593 if ((t2u = kiconv_open("UTF-8", cs)) == (kiconv_t)-1)
1594 return (-1);
1595
1596 rc = kiconv(t2u, &inbuf, &inlen, &outbuf, &outlen, &err);
1597 (void) kiconv_close(t2u);
1598 return ((int)rc);
1599 }
|
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 2018 Nexenta Systems, 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 *
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
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++;
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 *);
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
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 *);
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
756 smb_mbc_encodef(mbuf_chain_t *mbc, const char *fmt, ...)
757 {
758 int rc;
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
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
940 mbc_marshal_make_room(mbuf_chain_t *mbc, int32_t bytes_needed)
941 {
942 mbuf_t *m;
943 mbuf_t *l;
944 int32_t bytes_available;
945
946 bytes_needed += mbc->chain_offset;
947 if (bytes_needed > mbc->max_bytes)
948 return (EMSGSIZE);
949
950 if ((m = mbc->chain) == 0) {
951 MGET(m, M_WAIT, MT_DATA);
952 m->m_len = 0;
953 MCLGET(m, M_WAIT);
954 mbc->chain = m;
955 /* xxxx */
1064 }
1065
1066 static int
1067 mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t data)
1068 {
1069 if (mbc_marshal_make_room(mbc, sizeof (int64_t)))
1070 return (DECODE_NO_MORE_DATA);
1071
1072 mbc_marshal_store_byte(mbc, data);
1073 mbc_marshal_store_byte(mbc, data >> 8);
1074 mbc_marshal_store_byte(mbc, data >> 16);
1075 mbc_marshal_store_byte(mbc, data >> 24);
1076 mbc_marshal_store_byte(mbc, data >> 32);
1077 mbc_marshal_store_byte(mbc, data >> 40);
1078 mbc_marshal_store_byte(mbc, data >> 48);
1079 mbc_marshal_store_byte(mbc, data >> 56);
1080 return (0);
1081 }
1082
1083 /*
1084 * Marshal a UTF-8 string (str) into mbc, converting to OEM codeset.
1085 * Also write a null unless the repc count limits the length we put.
1086 * When (repc > 0) the length we marshal must be exactly repc, and
1087 * truncate or pad the mbc data as necessary.
1088 * See also: msgbuf_put_oem_string
1089 */
1090 static int
1091 mbc_marshal_put_oem_string(mbuf_chain_t *mbc, char *mbs, int repc)
1092 {
1093 uint8_t *oembuf = NULL;
1094 uint8_t *s;
1095 int oemlen;
1096 int rlen;
1097 int rc;
1098
1099 /*
1100 * Compute length of converted OEM string,
1101 * NOT including null terminator
1102 */
1103 if ((oemlen = smb_sbequiv_strlen(mbs)) == -1)
1104 return (DECODE_NO_MORE_DATA);
1105
1106 /*
1107 * If repc not specified, put whole string + NULL,
1108 * otherwise will truncate or pad as needed.
1109 */
1110 if (repc <= 0)
1111 repc = oemlen + 1;
1112 if (mbc_marshal_make_room(mbc, repc))
1113 return (DECODE_NO_MORE_DATA);
1114
1115 /*
1116 * Convert into a temporary buffer
1117 * Free oembuf before return.
1118 */
1119 oembuf = smb_mem_zalloc(oemlen + 1);
1120 ASSERT(oembuf != NULL);
1121 rlen = smb_mbstooem(oembuf, mbs, oemlen);
1122 if (rlen < 0) {
1123 rc = DECODE_NO_MORE_DATA;
1124 goto out;
1125 }
1126 if (rlen > oemlen)
1127 rlen = oemlen;
1128 oembuf[rlen] = '\0';
1129
1130 /*
1131 * Copy the converted string into the message,
1132 * truncated or paded as required.
1133 */
1134 s = oembuf;
1135 while (repc > 0) {
1136 mbc_marshal_store_byte(mbc, *s);
1137 if (*s != '\0')
1138 s++;
1139 repc--;
1140 }
1141 rc = 0;
1142
1143 out:
1144 if (oembuf != NULL)
1145 smb_mem_free(oembuf);
1146 return (rc);
1147 }
1148
1149 /*
1150 * Marshal a UTF-8 string (str) into mbc, converting to UTF-16.
1151 * Also write a null unless the repc count limits the length.
1152 * When (repc > 0) the length we marshal must be exactly repc,
1153 * and truncate or pad the mbc data as necessary.
1154 * See also: msgbuf_put_unicode_string
1155 */
1156 static int
1157 mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *mbs, int repc)
1158 {
1159 smb_wchar_t *wcsbuf = NULL;
1160 smb_wchar_t *wp;
1161 size_t wcslen, wcsbytes;
1162 size_t rlen;
1163 int rc;
1164
1165 /* align to word boundary */
1166 if (mbc->chain_offset & 1) {
1167 if (mbc_marshal_make_room(mbc, 1))
1168 return (DECODE_NO_MORE_DATA);
1169 mbc_marshal_store_byte(mbc, 0);
1170 }
1171
1172 /*
1173 * Compute length of converted UTF-16 string,
1174 * NOT including null terminator (in bytes).
1175 */
1176 wcsbytes = smb_wcequiv_strlen(mbs);
1177 if (wcsbytes == (size_t)-1)
1178 return (DECODE_NO_MORE_DATA);
1179
1180 /*
1181 * If repc not specified, put whole string + NULL,
1182 * otherwise will truncate or pad as needed.
1183 */
1184 if (repc <= 0)
1185 repc = wcsbytes + 2;
1186 if (mbc_marshal_make_room(mbc, repc))
1187 return (DECODE_NO_MORE_DATA);
1188
1189 /*
1190 * Convert into a temporary buffer
1191 * Free wcsbuf before return.
1192 */
1193 wcslen = wcsbytes / 2;
1194 wcsbuf = smb_mem_zalloc(wcsbytes + 2);
1195 ASSERT(wcsbuf != NULL);
1196 rlen = smb_mbstowcs(wcsbuf, mbs, wcslen);
1197 if (rlen == (size_t)-1) {
1198 rc = DECODE_NO_MORE_DATA;
1199 goto out;
1200 }
1201 if (rlen > wcslen)
1202 rlen = wcslen;
1203 wcsbuf[rlen] = 0;
1204
1205 /*
1206 * Copy the converted string into the message,
1207 * truncated or paded as required. Preserve
1208 * little-endian order while copying.
1209 */
1210 wp = wcsbuf;
1211 while (repc > 1) {
1212 smb_wchar_t wchar = LE_IN16(wp);
1213 mbc_marshal_store_byte(mbc, wchar);
1214 mbc_marshal_store_byte(mbc, wchar >> 8);
1215 if (wchar != 0)
1216 wp++;
1217 repc -= sizeof (smb_wchar_t);
1218 }
1219 if (repc > 0)
1220 mbc_marshal_store_byte(mbc, 0);
1221
1222 rc = 0;
1223 out:
1224 if (wcsbuf != NULL)
1225 smb_mem_free(wcsbuf);
1226 return (rc);
1227 }
1228
1229 static int /*ARGSUSED*/
1230 uiorefnoop(caddr_t p, int size, int adj)
1231 {
1232 return (0);
1233 }
1234
1235 static int
1236 mbc_marshal_put_uio(mbuf_chain_t *mbc, struct uio *uio)
1237 {
1238 mbuf_t **t;
1239 mbuf_t *m = NULL;
1240 struct iovec *iov = uio->uio_iov;
1241 int32_t i, iov_cnt = uio->uio_iovcnt;
1242
1243 iov = uio->uio_iov;
1244 t = &mbc->chain;
1245 for (i = 0; i < iov_cnt; i++) {
1246 MGET(m, M_WAIT, MT_DATA);
1441 m = m->m_next;
1442 }
1443 if ((m->m_len - offset) >= sizeof (int64_t)) {
1444 *data = LE_IN64(m->m_data + offset);
1445 mbc->chain_offset += sizeof (int64_t);
1446 } else {
1447 tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
1448 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 8;
1449 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 16;
1450 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 24;
1451 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32;
1452 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40;
1453 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48;
1454 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56;
1455 *(uint64_t *)data = tmp;
1456 }
1457 return (0);
1458 }
1459
1460 /*
1461 * mbc_marshal_get_oem_string
1462 *
1463 * Decode an OEM string, returning its UTF-8 form in strpp,
1464 * allocated using smb_srm_zalloc (automatically freed).
1465 * If max_bytes != 0, consume at most max_bytes of the mbc.
1466 * See also: msgbuf_get_oem_string
1467 */
1468 static int
1469 mbc_marshal_get_oem_string(smb_request_t *sr,
1470 mbuf_chain_t *mbc, char **strpp, int max_bytes)
1471 {
1472 char *mbs;
1473 uint8_t *oembuf = NULL;
1474 int oemlen, oemmax;
1475 int mbsmax;
1476 int rlen;
1477 int rc;
1478
1479 if (max_bytes == 0)
1480 max_bytes = 0xffff;
1481
1482 /*
1483 * Get the OtW data into a temporary buffer.
1484 * Free oembuf before return.
1485 */
1486 oemlen = 0;
1487 oemmax = MALLOC_QUANTUM;
1488 oembuf = smb_mem_alloc(oemmax);
1489 for (;;) {
1490 uint8_t ch;
1491
1492 if (oemlen >= max_bytes)
1493 break;
1494 if ((oemlen + 2) >= oemmax) {
1495 oemmax += MALLOC_QUANTUM;
1496 oembuf = smb_mem_realloc(oembuf, oemmax);
1497 }
1498 if (mbc_marshal_get_char(mbc, &ch) != 0) {
1499 rc = DECODE_NO_MORE_DATA;
1500 goto out;
1501 }
1502 if (ch == 0)
1503 break;
1504 oembuf[oemlen++] = ch;
1505 }
1506 oembuf[oemlen] = '\0';
1507
1508 /*
1509 * Get the buffer we'll return and convert to UTF-8.
1510 * May take as much as double the space.
1511 */
1512 mbsmax = oemlen * 2;
1513 mbs = smb_srm_zalloc(sr, mbsmax + 1);
1514 ASSERT(mbs != NULL);
1515 rlen = smb_oemtombs(mbs, oembuf, mbsmax);
1516 if (rlen < 0) {
1517 rc = DECODE_NO_MORE_DATA;
1518 goto out;
1519 }
1520 if (rlen > mbsmax)
1521 rlen = mbsmax;
1522 mbs[rlen] = '\0';
1523 *strpp = mbs;
1524 rc = 0;
1525
1526 out:
1527 if (oembuf != NULL)
1528 smb_mem_free(oembuf);
1529 return (rc);
1530 }
1531
1532 /*
1533 * mbc_marshal_get_unicode_string
1534 *
1535 * Decode a UTF-16 string, returning its UTF-8 form in strpp,
1536 * allocated using smb_srm_zalloc (automatically freed).
1537 * If max_bytes != 0, consume at most max_bytes of the mbc.
1538 * See also: msgbuf_get_unicode_string
1539 */
1540 static int
1541 mbc_marshal_get_unicode_string(smb_request_t *sr,
1542 mbuf_chain_t *mbc, char **strpp, int max_bytes)
1543 {
1544 char *mbs;
1545 uint16_t *wcsbuf = NULL;
1546 int wcslen; // wchar count
1547 int wcsmax; // byte count
1548 size_t mbsmax;
1549 size_t rlen;
1550 int rc;
1551
1552 if (max_bytes == 0)
1553 max_bytes = 0xffff;
1554
1555 /*
1556 * Unicode strings are always word aligned.
1557 */
1558 if (mbc->chain_offset & 1) {
1559 if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0)
1560 return (DECODE_NO_MORE_DATA);
1561 mbc->chain_offset++;
1562 }
1563
1564 /*
1565 * Get the OtW data into a temporary buffer.
1566 * Free wcsbuf before return.
1567 */
1568 wcslen = 0;
1569 wcsmax = MALLOC_QUANTUM;
1570 wcsbuf = smb_mem_alloc(wcsmax);
1571 for (;;) {
1572 uint16_t wchar;
1573
1574 if ((wcslen * 2) >= max_bytes)
1575 break;
1576 if (((wcslen * 2) + 4) >= wcsmax) {
1577 wcsmax += MALLOC_QUANTUM;
1578 wcsbuf = smb_mem_realloc(wcsbuf, wcsmax);
1579 }
1580 if (mbc_marshal_get_short(mbc, &wchar) != 0) {
1581 rc = DECODE_NO_MORE_DATA;
1582 goto out;
1583 }
1584 if (wchar == 0)
1585 break;
1586 /* Keep in little-endian form. */
1587 LE_OUT16(wcsbuf + wcslen, wchar);
1588 wcslen++;
1589 }
1590 wcsbuf[wcslen] = 0;
1591
1592 /*
1593 * Get the buffer we'll return and convert to UTF-8.
1594 * May take as much 4X number of wide chars.
1595 */
1596 mbsmax = wcslen * MTS_MB_CUR_MAX;
1597 mbs = smb_srm_zalloc(sr, mbsmax + 1);
1598 ASSERT(mbs != NULL);
1599 rlen = smb_wcstombs(mbs, wcsbuf, mbsmax);
1600 if (rlen == (size_t)-1) {
1601 rc = DECODE_NO_MORE_DATA;
1602 goto out;
1603 }
1604 if (rlen > mbsmax)
1605 rlen = mbsmax;
1606 mbs[rlen] = '\0';
1607 *strpp = mbs;
1608 rc = 0;
1609
1610 out:
1611 if (wcsbuf != NULL)
1612 smb_mem_free(wcsbuf);
1613 return (rc);
1614 }
1615
1616 static int /*ARGSUSED*/
1617 mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m)
1618 {
1619 *m = NULL;
1620 if (MBC_ROOM_FOR(mbc, bytes) == 0) {
1621 /* Data will never be available */
1622 return (DECODE_NO_MORE_DATA);
1623 }
1624 /* not yet implemented */
1625 return (-1);
1626 }
1627
1628 static int
1629 mbc_marshal_get_mbuf_chain(mbuf_chain_t *mbc, int32_t bytes, mbuf_chain_t *nmbc)
1630 {
1631 int rc;
1632 mbuf_t *m;
1633
1694 return (0);
1695 }
1696 iov[i].iov_len = remainder;
1697 mbc->chain_offset += remainder;
1698 bytes -= remainder;
1699 m = m->m_next;
1700 offset = 0;
1701 }
1702 return (DECODE_NO_MORE_DATA);
1703 }
1704 return (0);
1705 }
1706
1707 static int
1708 mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip)
1709 {
1710 if (MBC_ROOM_FOR(mbc, skip) == 0)
1711 return (DECODE_NO_MORE_DATA);
1712 mbc->chain_offset += skip;
1713 return (0);
1714 }
|