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 }
 |