15331Samw /*
25331Samw * CDDL HEADER START
35331Samw *
45331Samw * The contents of this file are subject to the terms of the
55331Samw * Common Development and Distribution License (the "License").
65331Samw * You may not use this file except in compliance with the License.
75331Samw *
85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw * or http://www.opensolaris.org/os/licensing.
105331Samw * See the License for the specific language governing permissions
115331Samw * and limitations under the License.
125331Samw *
135331Samw * When distributing Covered Code, include this CDDL HEADER in each
145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw * If applicable, add the following below this CDDL HEADER, with the
165331Samw * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw *
195331Samw * CDDL HEADER END
205331Samw */
215331Samw /*
22*10966SJordan.Brown@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
235331Samw * Use is subject to license terms.
245331Samw */
255331Samw
265331Samw /*
275331Samw * Msgbuf buffer management implementation. The smb_msgbuf interface is
285331Samw * typically used to encode or decode SMB data using sprintf/scanf
295331Samw * style operations. It contains special handling for the SMB header.
305331Samw * It can also be used for general purpose encoding and decoding.
315331Samw */
325331Samw
335331Samw #include <sys/types.h>
345331Samw #include <sys/varargs.h>
355331Samw #include <sys/byteorder.h>
365331Samw #ifndef _KERNEL
375331Samw #include <stdlib.h>
385331Samw #include <syslog.h>
395331Samw #include <string.h>
405331Samw #include <strings.h>
415331Samw #else
425331Samw #include <sys/sunddi.h>
435331Samw #include <sys/kmem.h>
445331Samw #endif
455331Samw #include <smbsrv/string.h>
465331Samw #include <smbsrv/msgbuf.h>
475331Samw #include <smbsrv/smb.h>
485331Samw
495331Samw static int buf_decode(smb_msgbuf_t *, char *, va_list ap);
505331Samw static int buf_encode(smb_msgbuf_t *, char *, va_list ap);
515331Samw static void *smb_msgbuf_malloc(smb_msgbuf_t *, size_t);
525331Samw static int smb_msgbuf_chkerc(char *text, int erc);
53*10966SJordan.Brown@Sun.COM static void buf_decode_wcs(smb_wchar_t *, smb_wchar_t *, int wcstrlen);
545331Samw
555331Samw /*
565331Samw * Returns the offset or number of bytes used within the buffer.
575331Samw */
585331Samw size_t
smb_msgbuf_used(smb_msgbuf_t * mb)595331Samw smb_msgbuf_used(smb_msgbuf_t *mb)
605331Samw {
615331Samw /*LINTED E_PTRDIFF_OVERFLOW*/
625331Samw return (mb->scan - mb->base);
635331Samw }
645331Samw
655331Samw /*
665331Samw * Returns the actual buffer size.
675331Samw */
685331Samw size_t
smb_msgbuf_size(smb_msgbuf_t * mb)695331Samw smb_msgbuf_size(smb_msgbuf_t *mb)
705331Samw {
715331Samw return (mb->max);
725331Samw }
735331Samw
745331Samw uint8_t *
smb_msgbuf_base(smb_msgbuf_t * mb)755331Samw smb_msgbuf_base(smb_msgbuf_t *mb)
765331Samw {
775331Samw return (mb->base);
785331Samw }
795331Samw
805331Samw /*
815331Samw * Ensure that the scan is aligned on a word (16-bit) boundary.
825331Samw */
835331Samw void
smb_msgbuf_word_align(smb_msgbuf_t * mb)845331Samw smb_msgbuf_word_align(smb_msgbuf_t *mb)
855331Samw {
865331Samw mb->scan = (uint8_t *)((uintptr_t)(mb->scan + 1) & ~1);
875331Samw }
885331Samw
895331Samw /*
905331Samw * Ensure that the scan is aligned on a dword (32-bit) boundary.
915331Samw */
925331Samw void
smb_msgbuf_dword_align(smb_msgbuf_t * mb)935331Samw smb_msgbuf_dword_align(smb_msgbuf_t *mb)
945331Samw {
955331Samw mb->scan = (uint8_t *)((uintptr_t)(mb->scan + 3) & ~3);
965331Samw }
975331Samw
985331Samw /*
995331Samw * Checks whether or not the buffer has space for the amount of data
1005331Samw * specified. Returns 1 if there is space, otherwise returns 0.
1015331Samw */
1025331Samw int
smb_msgbuf_has_space(smb_msgbuf_t * mb,size_t size)1035331Samw smb_msgbuf_has_space(smb_msgbuf_t *mb, size_t size)
1045331Samw {
1055331Samw if (size > mb->max || (mb->scan + size) > mb->end)
1065331Samw return (0);
1075331Samw
1085331Samw return (1);
1095331Samw }
1105331Samw
1115331Samw /*
1125331Samw * Set flags the smb_msgbuf.
1135331Samw */
1145331Samw void
smb_msgbuf_fset(smb_msgbuf_t * mb,uint32_t flags)1155331Samw smb_msgbuf_fset(smb_msgbuf_t *mb, uint32_t flags)
1165331Samw {
1175331Samw mb->flags |= flags;
1185331Samw }
1195331Samw
1205331Samw /*
1215331Samw * Clear flags the smb_msgbuf.
1225331Samw */
1235331Samw void
smb_msgbuf_fclear(smb_msgbuf_t * mb,uint32_t flags)1245331Samw smb_msgbuf_fclear(smb_msgbuf_t *mb, uint32_t flags)
1255331Samw {
1265331Samw mb->flags &= ~flags;
1275331Samw }
1285331Samw
1295331Samw /*
1305331Samw * smb_msgbuf_init
1315331Samw *
1325331Samw * Initialize a smb_msgbuf_t structure based on the buffer and size
1335331Samw * specified. Both scan and base initially point to the beginning
1345331Samw * of the buffer and end points to the limit of the buffer. As
1355331Samw * data is added scan should be incremented to point to the next
1365331Samw * offset at which data will be written. Max and count are set
1375331Samw * to the actual buffer size.
1385331Samw */
1395331Samw void
smb_msgbuf_init(smb_msgbuf_t * mb,uint8_t * buf,size_t size,uint32_t flags)1405331Samw smb_msgbuf_init(smb_msgbuf_t *mb, uint8_t *buf, size_t size, uint32_t flags)
1415331Samw {
1425331Samw mb->scan = mb->base = buf;
1435331Samw mb->max = mb->count = size;
1445331Samw mb->end = &buf[size];
1455331Samw mb->flags = flags;
1465331Samw mb->mlist.next = 0;
1475331Samw }
1485331Samw
1495331Samw
1505331Samw /*
1515331Samw * smb_msgbuf_term
1525331Samw *
1535331Samw * Destruct a smb_msgbuf_t. Free any memory hanging off the mlist.
1545331Samw */
1555331Samw void
smb_msgbuf_term(smb_msgbuf_t * mb)1565331Samw smb_msgbuf_term(smb_msgbuf_t *mb)
1575331Samw {
1585331Samw smb_msgbuf_mlist_t *item = mb->mlist.next;
1595331Samw smb_msgbuf_mlist_t *tmp;
1605331Samw
1615331Samw while (item) {
1625331Samw tmp = item;
1635331Samw item = item->next;
1645331Samw #ifndef _KERNEL
1655331Samw free(tmp);
1665331Samw #else
1675331Samw kmem_free(tmp, tmp->size);
1685331Samw #endif
1695331Samw }
1705331Samw }
1715331Samw
1725331Samw
1735331Samw /*
1745331Samw * smb_msgbuf_decode
1755331Samw *
1765331Samw * Decode a smb_msgbuf buffer as indicated by the format string into
1775331Samw * the variable arg list. This is similar to a scanf operation.
1785331Samw *
1795331Samw * On success, returns the number of bytes encoded. Otherwise
1805331Samw * returns a -ve error code.
1815331Samw */
1825331Samw int
smb_msgbuf_decode(smb_msgbuf_t * mb,char * fmt,...)1835331Samw smb_msgbuf_decode(smb_msgbuf_t *mb, char *fmt, ...)
1845331Samw {
1855331Samw int rc;
1865331Samw uint8_t *orig_scan;
1875331Samw va_list ap;
1885331Samw
1895331Samw va_start(ap, fmt);
1905331Samw orig_scan = mb->scan;
1915331Samw rc = buf_decode(mb, fmt, ap);
1925331Samw va_end(ap);
1935331Samw
1945331Samw if (rc != SMB_MSGBUF_SUCCESS) {
1955331Samw (void) smb_msgbuf_chkerc("smb_msgbuf_decode", rc);
1965331Samw mb->scan = orig_scan;
1975331Samw return (rc);
1985331Samw }
1995331Samw
2005331Samw /*LINTED E_PTRDIFF_OVERFLOW*/
2015331Samw return (mb->scan - orig_scan);
2025331Samw }
2035331Samw
2045331Samw
2055331Samw /*
2065331Samw * buf_decode
2075331Samw *
2085331Samw * Private decode function, where the real work of decoding the smb_msgbuf
2095331Samw * is done. This function should only be called via smb_msgbuf_decode to
2105331Samw * ensure correct behaviour and error handling.
2115331Samw */
2125331Samw static int
buf_decode(smb_msgbuf_t * mb,char * fmt,va_list ap)2135331Samw buf_decode(smb_msgbuf_t *mb, char *fmt, va_list ap)
2145331Samw {
2155331Samw uint32_t ival;
2165331Samw uint8_t c;
2175331Samw uint8_t *cvalp;
2185331Samw uint8_t **cvalpp;
2195331Samw uint16_t *wvalp;
2205331Samw uint32_t *lvalp;
2215331Samw uint64_t *llvalp;
222*10966SJordan.Brown@Sun.COM smb_wchar_t *wcs;
2235331Samw int repc;
2245331Samw int rc;
2255331Samw
2265331Samw while ((c = *fmt++) != 0) {
2275331Samw repc = 1;
2285331Samw
2295331Samw if (c == ' ' || c == '\t')
2305331Samw continue;
2315331Samw
2325331Samw if (c == '(') {
2335331Samw while (((c = *fmt++) != 0) && c != ')')
2345331Samw ;
2355331Samw
2365331Samw if (!c)
2375331Samw return (SMB_MSGBUF_SUCCESS);
2385331Samw
2395331Samw continue;
2405331Samw }
2415331Samw
2425331Samw if ('0' <= c && c <= '9') {
2435331Samw repc = 0;
2445331Samw do {
2455331Samw repc = repc * 10 + c - '0';
2465331Samw c = *fmt++;
2475331Samw } while ('0' <= c && c <= '9');
2485331Samw } else if (c == '#') {
2495331Samw repc = va_arg(ap, int);
2505331Samw c = *fmt++;
2515331Samw }
2525331Samw
2535331Samw switch (c) {
2545331Samw case '.':
2555331Samw if (smb_msgbuf_has_space(mb, repc) == 0)
2565331Samw return (SMB_MSGBUF_UNDERFLOW);
2575331Samw
2585331Samw mb->scan += repc;
2595331Samw break;
2605331Samw
2615331Samw case 'c':
2625331Samw if (smb_msgbuf_has_space(mb, repc) == 0)
2635331Samw return (SMB_MSGBUF_UNDERFLOW);
2645331Samw
2655331Samw cvalp = va_arg(ap, uint8_t *);
2665331Samw bcopy(mb->scan, cvalp, repc);
2675331Samw mb->scan += repc;
2685331Samw break;
2695331Samw
2705331Samw case 'b':
2715331Samw if (smb_msgbuf_has_space(mb, repc) == 0)
2725331Samw return (SMB_MSGBUF_UNDERFLOW);
2735331Samw
2745331Samw cvalp = va_arg(ap, uint8_t *);
2755331Samw while (repc-- > 0) {
2765331Samw *cvalp++ = *mb->scan++;
2775331Samw }
2785331Samw break;
2795331Samw
2805331Samw case 'w':
2815331Samw rc = smb_msgbuf_has_space(mb, repc * sizeof (uint16_t));
2825331Samw if (rc == 0)
2835331Samw return (SMB_MSGBUF_UNDERFLOW);
2845331Samw
2855331Samw wvalp = va_arg(ap, uint16_t *);
2865331Samw while (repc-- > 0) {
2875331Samw *wvalp++ = LE_IN16(mb->scan);
2885331Samw mb->scan += sizeof (uint16_t);
2895331Samw }
2905331Samw break;
2915331Samw
2925331Samw case 'l':
2935331Samw rc = smb_msgbuf_has_space(mb, repc * sizeof (int32_t));
2945331Samw if (rc == 0)
2955331Samw return (SMB_MSGBUF_UNDERFLOW);
2965331Samw
2975331Samw lvalp = va_arg(ap, uint32_t *);
2985331Samw while (repc-- > 0) {
2995331Samw *lvalp++ = LE_IN32(mb->scan);
3005331Samw mb->scan += sizeof (int32_t);
3015331Samw }
3025331Samw break;
3035331Samw
3045331Samw case 'q':
3055331Samw rc = smb_msgbuf_has_space(mb, repc * sizeof (int64_t));
3065331Samw if (rc == 0)
3075331Samw return (SMB_MSGBUF_UNDERFLOW);
3085331Samw
3095331Samw llvalp = va_arg(ap, uint64_t *);
3105331Samw while (repc-- > 0) {
3115331Samw *llvalp++ = LE_IN64(mb->scan);
3125331Samw mb->scan += sizeof (int64_t);
3135331Samw }
3145331Samw break;
3155331Samw
3165331Samw case 'u': /* Convert from unicode if flags are set */
3175331Samw if (mb->flags & SMB_MSGBUF_UNICODE)
3185331Samw goto unicode_translation;
3195331Samw /*FALLTHROUGH*/
3205331Samw
3215331Samw case 's':
3225331Samw ival = strlen((const char *)mb->scan) + 1;
3235331Samw if (smb_msgbuf_has_space(mb, ival) == 0)
3245331Samw return (SMB_MSGBUF_UNDERFLOW);
3255331Samw
3265331Samw if ((cvalp = smb_msgbuf_malloc(mb, ival * 2)) == 0)
3275331Samw return (SMB_MSGBUF_UNDERFLOW);
3285331Samw
329*10966SJordan.Brown@Sun.COM if ((ival = smb_stombs((char *)cvalp,
3305331Samw (char *)mb->scan, ival * 2)) ==
3315331Samw (uint32_t)-1) {
3325331Samw return (SMB_MSGBUF_DATA_ERROR);
3335331Samw }
3345331Samw
3355331Samw cvalpp = va_arg(ap, uint8_t **);
3365331Samw *cvalpp = cvalp;
3375331Samw mb->scan += (ival+1);
3385331Samw break;
3395331Samw
3405331Samw case 'U': /* Convert from unicode */
3415331Samw unicode_translation:
3425331Samw /*
3435331Samw * Unicode strings are always word aligned.
3445331Samw * The malloc'd area is larger than the
3455331Samw * original string because the UTF-8 chars
3465331Samw * may be longer than the wide-chars.
3475331Samw */
3485331Samw smb_msgbuf_word_align(mb);
3495331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/
350*10966SJordan.Brown@Sun.COM wcs = (smb_wchar_t *)mb->scan;
3515331Samw
3525331Samw /* count the null wchar */
353*10966SJordan.Brown@Sun.COM repc = sizeof (smb_wchar_t);
3545331Samw while (*wcs++)
355*10966SJordan.Brown@Sun.COM repc += sizeof (smb_wchar_t);
3565331Samw
3575331Samw if (smb_msgbuf_has_space(mb, repc) == 0)
3585331Samw return (SMB_MSGBUF_UNDERFLOW);
3595331Samw
3605331Samw /* Decode wchar string into host byte-order */
3615331Samw if ((wcs = smb_msgbuf_malloc(mb, repc)) == 0)
3625331Samw return (SMB_MSGBUF_UNDERFLOW);
3635331Samw
3645331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/
365*10966SJordan.Brown@Sun.COM buf_decode_wcs(wcs, (smb_wchar_t *)mb->scan,
366*10966SJordan.Brown@Sun.COM repc / sizeof (smb_wchar_t));
3675331Samw
3685331Samw /* Get space for translated string */
3695331Samw if ((cvalp = smb_msgbuf_malloc(mb, repc * 2)) == 0)
3705331Samw return (SMB_MSGBUF_UNDERFLOW);
3715331Samw
3725331Samw /* Translate string */
373*10966SJordan.Brown@Sun.COM (void) smb_wcstombs((char *)cvalp, wcs, repc * 2);
3745331Samw
3755331Samw cvalpp = va_arg(ap, uint8_t **);
3765331Samw *cvalpp = cvalp;
3775331Samw mb->scan += repc;
3785331Samw break;
3795331Samw
3805331Samw case 'M':
3815331Samw if (smb_msgbuf_has_space(mb, 4) == 0)
3825331Samw return (SMB_MSGBUF_UNDERFLOW);
3835331Samw
3845331Samw if (mb->scan[0] != 0xFF ||
3855331Samw mb->scan[1] != 'S' ||
3865331Samw mb->scan[2] != 'M' ||
3875331Samw mb->scan[3] != 'B') {
3885331Samw return (SMB_MSGBUF_INVALID_HEADER);
3895331Samw }
3905331Samw mb->scan += 4;
3915331Samw break;
3925331Samw
3935331Samw default:
3945331Samw return (SMB_MSGBUF_INVALID_FORMAT);
3955331Samw }
3965331Samw }
3975331Samw
3985331Samw return (SMB_MSGBUF_SUCCESS);
3995331Samw }
4005331Samw
4015331Samw
4025331Samw /*
4035331Samw * smb_msgbuf_encode
4045331Samw *
4055331Samw * Encode a smb_msgbuf buffer as indicated by the format string using
4065331Samw * the variable arg list. This is similar to a sprintf operation.
4075331Samw *
4085331Samw * On success, returns the number of bytes encoded. Otherwise
4095331Samw * returns a -ve error code.
4105331Samw */
4115331Samw int
smb_msgbuf_encode(smb_msgbuf_t * mb,char * fmt,...)4125331Samw smb_msgbuf_encode(smb_msgbuf_t *mb, char *fmt, ...)
4135331Samw {
4145331Samw int rc;
4155331Samw uint8_t *orig_scan;
4165331Samw va_list ap;
4175331Samw
4185331Samw va_start(ap, fmt);
4195331Samw orig_scan = mb->scan;
4205331Samw rc = buf_encode(mb, fmt, ap);
4215331Samw va_end(ap);
4225331Samw
4235331Samw if (rc != SMB_MSGBUF_SUCCESS) {
4245331Samw (void) smb_msgbuf_chkerc("smb_msgbuf_encode", rc);
4255331Samw mb->scan = orig_scan;
4265331Samw return (rc);
4275331Samw }
4285331Samw
4295331Samw /*LINTED E_PTRDIFF_OVERFLOW*/
4305331Samw return (mb->scan - orig_scan);
4315331Samw }
4325331Samw
4335331Samw
4345331Samw /*
4355331Samw * buf_encode
4365331Samw *
4375331Samw * Private encode function, where the real work of encoding the smb_msgbuf
4385331Samw * is done. This function should only be called via smb_msgbuf_encode to
4395331Samw * ensure correct behaviour and error handling.
4405331Samw */
4415331Samw static int
buf_encode(smb_msgbuf_t * mb,char * fmt,va_list ap)4425331Samw buf_encode(smb_msgbuf_t *mb, char *fmt, va_list ap)
4435331Samw {
4445331Samw uint8_t cval;
4455331Samw uint16_t wval;
4465331Samw uint32_t lval;
4475331Samw uint64_t llval;
4485331Samw uint32_t ival;
4495331Samw uint8_t *cvalp;
4505331Samw uint8_t c;
451*10966SJordan.Brown@Sun.COM smb_wchar_t wcval;
4525331Samw int count;
4535331Samw int repc = 1;
4545331Samw int rc;
4555331Samw
4565331Samw while ((c = *fmt++) != 0) {
4575331Samw repc = 1;
4585331Samw
4595331Samw if (c == ' ' || c == '\t')
4605331Samw continue;
4615331Samw
4625331Samw if (c == '(') {
4635331Samw while (((c = *fmt++) != 0) && c != ')')
4645331Samw ;
4655331Samw
4665331Samw if (!c)
4675331Samw return (SMB_MSGBUF_SUCCESS);
4685331Samw
4695331Samw continue;
4705331Samw }
4715331Samw
4725331Samw if ('0' <= c && c <= '9') {
4735331Samw repc = 0;
4745331Samw do {
4755331Samw repc = repc * 10 + c - '0';
4765331Samw c = *fmt++;
4775331Samw } while ('0' <= c && c <= '9');
4785331Samw } else if (c == '#') {
4795331Samw repc = va_arg(ap, int);
4805331Samw c = *fmt++;
4815331Samw }
4825331Samw
4835331Samw switch (c) {
4845331Samw case '.':
4855331Samw if (smb_msgbuf_has_space(mb, repc) == 0)
4865331Samw return (SMB_MSGBUF_OVERFLOW);
4875331Samw
4885331Samw while (repc-- > 0)
4895331Samw *mb->scan++ = 0;
4905331Samw break;
4915331Samw
4925331Samw case 'c':
4935331Samw if (smb_msgbuf_has_space(mb, repc) == 0)
4945331Samw return (SMB_MSGBUF_OVERFLOW);
4955331Samw
4965331Samw cvalp = va_arg(ap, uint8_t *);
4975331Samw bcopy(cvalp, mb->scan, repc);
4985331Samw mb->scan += repc;
4995331Samw break;
5005331Samw
5015331Samw case 'b':
5025331Samw if (smb_msgbuf_has_space(mb, repc) == 0)
5035331Samw return (SMB_MSGBUF_OVERFLOW);
5045331Samw
5055331Samw while (repc-- > 0) {
5065331Samw cval = va_arg(ap, int);
5075331Samw *mb->scan++ = cval;
5085331Samw }
5095331Samw break;
5105331Samw
5115331Samw case 'w':
5125331Samw rc = smb_msgbuf_has_space(mb, repc * sizeof (uint16_t));
5135331Samw if (rc == 0)
5145331Samw return (SMB_MSGBUF_OVERFLOW);
5155331Samw
5165331Samw while (repc-- > 0) {
5175331Samw wval = va_arg(ap, int);
5185331Samw LE_OUT16(mb->scan, wval);
5195331Samw mb->scan += sizeof (uint16_t);
5205331Samw }
5215331Samw break;
5225331Samw
5235331Samw case 'l':
5245331Samw rc = smb_msgbuf_has_space(mb, repc * sizeof (int32_t));
5255331Samw if (rc == 0)
5265331Samw return (SMB_MSGBUF_OVERFLOW);
5275331Samw
5285331Samw while (repc-- > 0) {
5295331Samw lval = va_arg(ap, uint32_t);
5305331Samw LE_OUT32(mb->scan, lval);
5315331Samw mb->scan += sizeof (int32_t);
5325331Samw }
5335331Samw break;
5345331Samw
5355331Samw case 'q':
5365331Samw rc = smb_msgbuf_has_space(mb, repc * sizeof (int64_t));
5375331Samw if (rc == 0)
5385331Samw return (SMB_MSGBUF_OVERFLOW);
5395331Samw
5405331Samw while (repc-- > 0) {
5415331Samw llval = va_arg(ap, uint64_t);
5425331Samw LE_OUT64(mb->scan, llval);
5435331Samw mb->scan += sizeof (uint64_t);
5445331Samw }
5455331Samw break;
5465331Samw
5475331Samw case 'u': /* conditional unicode */
5485331Samw if (mb->flags & SMB_MSGBUF_UNICODE)
5495331Samw goto unicode_translation;
5505331Samw /* FALLTHROUGH */
5515331Samw
5525331Samw case 's':
5535331Samw cvalp = va_arg(ap, uint8_t *);
5545331Samw ival = strlen((const char *)cvalp) + 1;
5555331Samw
5565331Samw if (smb_msgbuf_has_space(mb, ival) == 0)
5575331Samw return (SMB_MSGBUF_OVERFLOW);
5585331Samw
5595331Samw ival =
560*10966SJordan.Brown@Sun.COM smb_mbstos((char *)mb->scan, (const char *)cvalp);
5615331Samw mb->scan += ival + 1;
5625331Samw break;
5635331Samw
5645331Samw case 'U': /* unicode */
5655331Samw unicode_translation:
5665331Samw /*
5675331Samw * Unicode strings are always word aligned.
5685331Samw */
5695331Samw smb_msgbuf_word_align(mb);
5705331Samw cvalp = va_arg(ap, uint8_t *);
5715331Samw
5725331Samw for (;;) {
5735331Samw rc = smb_msgbuf_has_space(mb,
574*10966SJordan.Brown@Sun.COM sizeof (smb_wchar_t));
5755331Samw if (rc == 0)
5765331Samw return (SMB_MSGBUF_OVERFLOW);
5775331Samw
578*10966SJordan.Brown@Sun.COM count = smb_mbtowc(&wcval, (const char *)cvalp,
5795331Samw MTS_MB_CHAR_MAX);
5805331Samw
5815331Samw if (count < 0) {
5825331Samw return (SMB_MSGBUF_DATA_ERROR);
5835331Samw } else if (count == 0) {
5845331Samw /*
5855331Samw * No longer need to do this now that
5865331Samw * mbtowc correctly writes the null
5875331Samw * before returning zero but paranoia
5885331Samw * wins.
5895331Samw */
5905331Samw wcval = 0;
5915331Samw count = 1;
5925331Samw }
5935331Samw
5945331Samw /* Write wchar in wire-format */
5955331Samw LE_OUT16(mb->scan, wcval);
5965331Samw
5975331Samw if (*cvalp == 0) {
5985331Samw /*
5995331Samw * End of string. Check to see whether
6005331Samw * or not to include the null
6015331Samw * terminator.
6025331Samw */
6035331Samw if ((mb->flags & SMB_MSGBUF_NOTERM) ==
6045331Samw 0)
6055331Samw mb->scan +=
606*10966SJordan.Brown@Sun.COM sizeof (smb_wchar_t);
6075331Samw break;
6085331Samw }
6095331Samw
610*10966SJordan.Brown@Sun.COM mb->scan += sizeof (smb_wchar_t);
6115331Samw cvalp += count;
6125331Samw }
6135331Samw break;
6145331Samw
6155331Samw case 'M':
6165331Samw if (smb_msgbuf_has_space(mb, 4) == 0)
6175331Samw return (SMB_MSGBUF_OVERFLOW);
6185331Samw
6195331Samw *mb->scan++ = 0xFF;
6205331Samw *mb->scan++ = 'S';
6215331Samw *mb->scan++ = 'M';
6225331Samw *mb->scan++ = 'B';
6235331Samw break;
6245331Samw
6255331Samw default:
6265331Samw return (SMB_MSGBUF_INVALID_FORMAT);
6275331Samw }
6285331Samw }
6295331Samw
6305331Samw return (SMB_MSGBUF_SUCCESS);
6315331Samw }
6325331Samw
6335331Samw
6345331Samw /*
6355331Samw * smb_msgbuf_malloc
6365331Samw *
6375331Samw * Allocate some memory for use with this smb_msgbuf. We increase the
6385331Samw * requested size to hold the list pointer and return a pointer
6395331Samw * to the area for use by the caller.
6405331Samw */
6415331Samw static void *
smb_msgbuf_malloc(smb_msgbuf_t * mb,size_t size)6425331Samw smb_msgbuf_malloc(smb_msgbuf_t *mb, size_t size)
6435331Samw {
6445331Samw smb_msgbuf_mlist_t *item;
6455331Samw
6465331Samw size += sizeof (smb_msgbuf_mlist_t);
6475331Samw
6485331Samw #ifndef _KERNEL
6495331Samw if ((item = malloc(size)) == NULL)
6505331Samw return (NULL);
6515331Samw #else
6525331Samw item = kmem_alloc(size, KM_SLEEP);
6535331Samw #endif
6545331Samw item->next = mb->mlist.next;
6555331Samw item->size = size;
6565331Samw mb->mlist.next = item;
6575331Samw
6585331Samw /*
6595331Samw * The caller gets a pointer to the address
6605331Samw * immediately after the smb_msgbuf_mlist_t.
6615331Samw */
6625331Samw return ((void *)(item + 1));
6635331Samw }
6645331Samw
6655331Samw
6665331Samw /*
6675331Samw * smb_msgbuf_chkerc
6685331Samw *
6695331Samw * Diagnostic function to write an appropriate message to the system log.
6705331Samw */
6715331Samw static int
smb_msgbuf_chkerc(char * text,int erc)6725331Samw smb_msgbuf_chkerc(char *text, int erc)
6735331Samw {
6745331Samw static struct {
6755331Samw int erc;
6765331Samw char *name;
6775331Samw } etable[] = {
6785331Samw { SMB_MSGBUF_SUCCESS, "success" },
6795331Samw { SMB_MSGBUF_UNDERFLOW, "overflow/underflow" },
6805331Samw { SMB_MSGBUF_INVALID_FORMAT, "invalid format" },
6815331Samw { SMB_MSGBUF_INVALID_HEADER, "invalid header" },
6825331Samw { SMB_MSGBUF_DATA_ERROR, "data error" }
6835331Samw };
6845331Samw
6855331Samw int i;
6865331Samw
6875331Samw for (i = 0; i < sizeof (etable)/sizeof (etable[0]); ++i) {
6885331Samw if (etable[i].erc == erc) {
6895331Samw if (text == 0)
6905331Samw text = "smb_msgbuf_chkerc";
6915331Samw break;
6925331Samw }
6935331Samw }
6945331Samw return (erc);
6955331Samw }
6965331Samw
6975331Samw static void
buf_decode_wcs(smb_wchar_t * dst_wcstr,smb_wchar_t * src_wcstr,int wcstrlen)698*10966SJordan.Brown@Sun.COM buf_decode_wcs(smb_wchar_t *dst_wcstr, smb_wchar_t *src_wcstr, int wcstrlen)
6995331Samw {
7005331Samw int i;
7015331Samw
7025331Samw for (i = 0; i < wcstrlen; i++) {
7035331Samw *dst_wcstr = LE_IN16(src_wcstr);
7045331Samw dst_wcstr++;
7055331Samw src_wcstr++;
7065331Samw }
7075331Samw }
708