1*da6c28aaSamw /* 2*da6c28aaSamw * CDDL HEADER START 3*da6c28aaSamw * 4*da6c28aaSamw * The contents of this file are subject to the terms of the 5*da6c28aaSamw * Common Development and Distribution License (the "License"). 6*da6c28aaSamw * You may not use this file except in compliance with the License. 7*da6c28aaSamw * 8*da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10*da6c28aaSamw * See the License for the specific language governing permissions 11*da6c28aaSamw * and limitations under the License. 12*da6c28aaSamw * 13*da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14*da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16*da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17*da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18*da6c28aaSamw * 19*da6c28aaSamw * CDDL HEADER END 20*da6c28aaSamw */ 21*da6c28aaSamw /* 22*da6c28aaSamw * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*da6c28aaSamw * Use is subject to license terms. 24*da6c28aaSamw */ 25*da6c28aaSamw 26*da6c28aaSamw #pragma ident "%Z%%M% %I% %E% SMI" 27*da6c28aaSamw 28*da6c28aaSamw /* 29*da6c28aaSamw * Msgbuf buffer management implementation. The smb_msgbuf interface is 30*da6c28aaSamw * typically used to encode or decode SMB data using sprintf/scanf 31*da6c28aaSamw * style operations. It contains special handling for the SMB header. 32*da6c28aaSamw * It can also be used for general purpose encoding and decoding. 33*da6c28aaSamw */ 34*da6c28aaSamw 35*da6c28aaSamw #include <sys/types.h> 36*da6c28aaSamw #include <sys/varargs.h> 37*da6c28aaSamw #include <sys/byteorder.h> 38*da6c28aaSamw #ifndef _KERNEL 39*da6c28aaSamw #include <stdlib.h> 40*da6c28aaSamw #include <syslog.h> 41*da6c28aaSamw #include <string.h> 42*da6c28aaSamw #include <strings.h> 43*da6c28aaSamw #else 44*da6c28aaSamw #include <sys/sunddi.h> 45*da6c28aaSamw #include <sys/kmem.h> 46*da6c28aaSamw #endif 47*da6c28aaSamw #include <smbsrv/string.h> 48*da6c28aaSamw #include <smbsrv/msgbuf.h> 49*da6c28aaSamw #include <smbsrv/smb.h> 50*da6c28aaSamw 51*da6c28aaSamw static int buf_decode(smb_msgbuf_t *, char *, va_list ap); 52*da6c28aaSamw static int buf_encode(smb_msgbuf_t *, char *, va_list ap); 53*da6c28aaSamw static void *smb_msgbuf_malloc(smb_msgbuf_t *, size_t); 54*da6c28aaSamw static int smb_msgbuf_chkerc(char *text, int erc); 55*da6c28aaSamw static void buf_decode_wcs(mts_wchar_t *, mts_wchar_t *, int wcstrlen); 56*da6c28aaSamw 57*da6c28aaSamw /* 58*da6c28aaSamw * Returns the offset or number of bytes used within the buffer. 59*da6c28aaSamw */ 60*da6c28aaSamw size_t 61*da6c28aaSamw smb_msgbuf_used(smb_msgbuf_t *mb) 62*da6c28aaSamw { 63*da6c28aaSamw /*LINTED E_PTRDIFF_OVERFLOW*/ 64*da6c28aaSamw return (mb->scan - mb->base); 65*da6c28aaSamw } 66*da6c28aaSamw 67*da6c28aaSamw /* 68*da6c28aaSamw * Returns the actual buffer size. 69*da6c28aaSamw */ 70*da6c28aaSamw size_t 71*da6c28aaSamw smb_msgbuf_size(smb_msgbuf_t *mb) 72*da6c28aaSamw { 73*da6c28aaSamw return (mb->max); 74*da6c28aaSamw } 75*da6c28aaSamw 76*da6c28aaSamw uint8_t * 77*da6c28aaSamw smb_msgbuf_base(smb_msgbuf_t *mb) 78*da6c28aaSamw { 79*da6c28aaSamw return (mb->base); 80*da6c28aaSamw } 81*da6c28aaSamw 82*da6c28aaSamw /* 83*da6c28aaSamw * Ensure that the scan is aligned on a word (16-bit) boundary. 84*da6c28aaSamw */ 85*da6c28aaSamw void 86*da6c28aaSamw smb_msgbuf_word_align(smb_msgbuf_t *mb) 87*da6c28aaSamw { 88*da6c28aaSamw mb->scan = (uint8_t *)((uintptr_t)(mb->scan + 1) & ~1); 89*da6c28aaSamw } 90*da6c28aaSamw 91*da6c28aaSamw /* 92*da6c28aaSamw * Ensure that the scan is aligned on a dword (32-bit) boundary. 93*da6c28aaSamw */ 94*da6c28aaSamw void 95*da6c28aaSamw smb_msgbuf_dword_align(smb_msgbuf_t *mb) 96*da6c28aaSamw { 97*da6c28aaSamw mb->scan = (uint8_t *)((uintptr_t)(mb->scan + 3) & ~3); 98*da6c28aaSamw } 99*da6c28aaSamw 100*da6c28aaSamw /* 101*da6c28aaSamw * Checks whether or not the buffer has space for the amount of data 102*da6c28aaSamw * specified. Returns 1 if there is space, otherwise returns 0. 103*da6c28aaSamw */ 104*da6c28aaSamw int 105*da6c28aaSamw smb_msgbuf_has_space(smb_msgbuf_t *mb, size_t size) 106*da6c28aaSamw { 107*da6c28aaSamw if (size > mb->max || (mb->scan + size) > mb->end) 108*da6c28aaSamw return (0); 109*da6c28aaSamw 110*da6c28aaSamw return (1); 111*da6c28aaSamw } 112*da6c28aaSamw 113*da6c28aaSamw /* 114*da6c28aaSamw * Set flags the smb_msgbuf. 115*da6c28aaSamw */ 116*da6c28aaSamw void 117*da6c28aaSamw smb_msgbuf_fset(smb_msgbuf_t *mb, uint32_t flags) 118*da6c28aaSamw { 119*da6c28aaSamw mb->flags |= flags; 120*da6c28aaSamw } 121*da6c28aaSamw 122*da6c28aaSamw /* 123*da6c28aaSamw * Clear flags the smb_msgbuf. 124*da6c28aaSamw */ 125*da6c28aaSamw void 126*da6c28aaSamw smb_msgbuf_fclear(smb_msgbuf_t *mb, uint32_t flags) 127*da6c28aaSamw { 128*da6c28aaSamw mb->flags &= ~flags; 129*da6c28aaSamw } 130*da6c28aaSamw 131*da6c28aaSamw /* 132*da6c28aaSamw * smb_msgbuf_init 133*da6c28aaSamw * 134*da6c28aaSamw * Initialize a smb_msgbuf_t structure based on the buffer and size 135*da6c28aaSamw * specified. Both scan and base initially point to the beginning 136*da6c28aaSamw * of the buffer and end points to the limit of the buffer. As 137*da6c28aaSamw * data is added scan should be incremented to point to the next 138*da6c28aaSamw * offset at which data will be written. Max and count are set 139*da6c28aaSamw * to the actual buffer size. 140*da6c28aaSamw */ 141*da6c28aaSamw void 142*da6c28aaSamw smb_msgbuf_init(smb_msgbuf_t *mb, uint8_t *buf, size_t size, uint32_t flags) 143*da6c28aaSamw { 144*da6c28aaSamw mb->scan = mb->base = buf; 145*da6c28aaSamw mb->max = mb->count = size; 146*da6c28aaSamw mb->end = &buf[size]; 147*da6c28aaSamw mb->flags = flags; 148*da6c28aaSamw mb->mlist.next = 0; 149*da6c28aaSamw } 150*da6c28aaSamw 151*da6c28aaSamw 152*da6c28aaSamw /* 153*da6c28aaSamw * smb_msgbuf_term 154*da6c28aaSamw * 155*da6c28aaSamw * Destruct a smb_msgbuf_t. Free any memory hanging off the mlist. 156*da6c28aaSamw */ 157*da6c28aaSamw void 158*da6c28aaSamw smb_msgbuf_term(smb_msgbuf_t *mb) 159*da6c28aaSamw { 160*da6c28aaSamw smb_msgbuf_mlist_t *item = mb->mlist.next; 161*da6c28aaSamw smb_msgbuf_mlist_t *tmp; 162*da6c28aaSamw 163*da6c28aaSamw while (item) { 164*da6c28aaSamw tmp = item; 165*da6c28aaSamw item = item->next; 166*da6c28aaSamw #ifndef _KERNEL 167*da6c28aaSamw free(tmp); 168*da6c28aaSamw #else 169*da6c28aaSamw kmem_free(tmp, tmp->size); 170*da6c28aaSamw #endif 171*da6c28aaSamw } 172*da6c28aaSamw } 173*da6c28aaSamw 174*da6c28aaSamw 175*da6c28aaSamw /* 176*da6c28aaSamw * smb_msgbuf_decode 177*da6c28aaSamw * 178*da6c28aaSamw * Decode a smb_msgbuf buffer as indicated by the format string into 179*da6c28aaSamw * the variable arg list. This is similar to a scanf operation. 180*da6c28aaSamw * 181*da6c28aaSamw * On success, returns the number of bytes encoded. Otherwise 182*da6c28aaSamw * returns a -ve error code. 183*da6c28aaSamw */ 184*da6c28aaSamw int 185*da6c28aaSamw smb_msgbuf_decode(smb_msgbuf_t *mb, char *fmt, ...) 186*da6c28aaSamw { 187*da6c28aaSamw int rc; 188*da6c28aaSamw uint8_t *orig_scan; 189*da6c28aaSamw va_list ap; 190*da6c28aaSamw 191*da6c28aaSamw va_start(ap, fmt); 192*da6c28aaSamw orig_scan = mb->scan; 193*da6c28aaSamw rc = buf_decode(mb, fmt, ap); 194*da6c28aaSamw va_end(ap); 195*da6c28aaSamw 196*da6c28aaSamw if (rc != SMB_MSGBUF_SUCCESS) { 197*da6c28aaSamw (void) smb_msgbuf_chkerc("smb_msgbuf_decode", rc); 198*da6c28aaSamw mb->scan = orig_scan; 199*da6c28aaSamw return (rc); 200*da6c28aaSamw } 201*da6c28aaSamw 202*da6c28aaSamw /*LINTED E_PTRDIFF_OVERFLOW*/ 203*da6c28aaSamw return (mb->scan - orig_scan); 204*da6c28aaSamw } 205*da6c28aaSamw 206*da6c28aaSamw 207*da6c28aaSamw /* 208*da6c28aaSamw * buf_decode 209*da6c28aaSamw * 210*da6c28aaSamw * Private decode function, where the real work of decoding the smb_msgbuf 211*da6c28aaSamw * is done. This function should only be called via smb_msgbuf_decode to 212*da6c28aaSamw * ensure correct behaviour and error handling. 213*da6c28aaSamw */ 214*da6c28aaSamw static int 215*da6c28aaSamw buf_decode(smb_msgbuf_t *mb, char *fmt, va_list ap) 216*da6c28aaSamw { 217*da6c28aaSamw uint32_t ival; 218*da6c28aaSamw uint8_t c; 219*da6c28aaSamw uint8_t *cvalp; 220*da6c28aaSamw uint8_t **cvalpp; 221*da6c28aaSamw uint16_t *wvalp; 222*da6c28aaSamw uint32_t *lvalp; 223*da6c28aaSamw uint64_t *llvalp; 224*da6c28aaSamw mts_wchar_t *wcs; 225*da6c28aaSamw int repc; 226*da6c28aaSamw int rc; 227*da6c28aaSamw 228*da6c28aaSamw while ((c = *fmt++) != 0) { 229*da6c28aaSamw repc = 1; 230*da6c28aaSamw 231*da6c28aaSamw if (c == ' ' || c == '\t') 232*da6c28aaSamw continue; 233*da6c28aaSamw 234*da6c28aaSamw if (c == '(') { 235*da6c28aaSamw while (((c = *fmt++) != 0) && c != ')') 236*da6c28aaSamw ; 237*da6c28aaSamw 238*da6c28aaSamw if (!c) 239*da6c28aaSamw return (SMB_MSGBUF_SUCCESS); 240*da6c28aaSamw 241*da6c28aaSamw continue; 242*da6c28aaSamw } 243*da6c28aaSamw 244*da6c28aaSamw if ('0' <= c && c <= '9') { 245*da6c28aaSamw repc = 0; 246*da6c28aaSamw do { 247*da6c28aaSamw repc = repc * 10 + c - '0'; 248*da6c28aaSamw c = *fmt++; 249*da6c28aaSamw } while ('0' <= c && c <= '9'); 250*da6c28aaSamw } else if (c == '#') { 251*da6c28aaSamw repc = va_arg(ap, int); 252*da6c28aaSamw c = *fmt++; 253*da6c28aaSamw } 254*da6c28aaSamw 255*da6c28aaSamw switch (c) { 256*da6c28aaSamw case '.': 257*da6c28aaSamw if (smb_msgbuf_has_space(mb, repc) == 0) 258*da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 259*da6c28aaSamw 260*da6c28aaSamw mb->scan += repc; 261*da6c28aaSamw break; 262*da6c28aaSamw 263*da6c28aaSamw case 'c': 264*da6c28aaSamw if (smb_msgbuf_has_space(mb, repc) == 0) 265*da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 266*da6c28aaSamw 267*da6c28aaSamw cvalp = va_arg(ap, uint8_t *); 268*da6c28aaSamw bcopy(mb->scan, cvalp, repc); 269*da6c28aaSamw mb->scan += repc; 270*da6c28aaSamw break; 271*da6c28aaSamw 272*da6c28aaSamw case 'b': 273*da6c28aaSamw if (smb_msgbuf_has_space(mb, repc) == 0) 274*da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 275*da6c28aaSamw 276*da6c28aaSamw cvalp = va_arg(ap, uint8_t *); 277*da6c28aaSamw while (repc-- > 0) { 278*da6c28aaSamw *cvalp++ = *mb->scan++; 279*da6c28aaSamw } 280*da6c28aaSamw break; 281*da6c28aaSamw 282*da6c28aaSamw case 'w': 283*da6c28aaSamw rc = smb_msgbuf_has_space(mb, repc * sizeof (uint16_t)); 284*da6c28aaSamw if (rc == 0) 285*da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 286*da6c28aaSamw 287*da6c28aaSamw wvalp = va_arg(ap, uint16_t *); 288*da6c28aaSamw while (repc-- > 0) { 289*da6c28aaSamw *wvalp++ = LE_IN16(mb->scan); 290*da6c28aaSamw mb->scan += sizeof (uint16_t); 291*da6c28aaSamw } 292*da6c28aaSamw break; 293*da6c28aaSamw 294*da6c28aaSamw case 'l': 295*da6c28aaSamw rc = smb_msgbuf_has_space(mb, repc * sizeof (int32_t)); 296*da6c28aaSamw if (rc == 0) 297*da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 298*da6c28aaSamw 299*da6c28aaSamw lvalp = va_arg(ap, uint32_t *); 300*da6c28aaSamw while (repc-- > 0) { 301*da6c28aaSamw *lvalp++ = LE_IN32(mb->scan); 302*da6c28aaSamw mb->scan += sizeof (int32_t); 303*da6c28aaSamw } 304*da6c28aaSamw break; 305*da6c28aaSamw 306*da6c28aaSamw case 'q': 307*da6c28aaSamw rc = smb_msgbuf_has_space(mb, repc * sizeof (int64_t)); 308*da6c28aaSamw if (rc == 0) 309*da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 310*da6c28aaSamw 311*da6c28aaSamw llvalp = va_arg(ap, uint64_t *); 312*da6c28aaSamw while (repc-- > 0) { 313*da6c28aaSamw *llvalp++ = LE_IN64(mb->scan); 314*da6c28aaSamw mb->scan += sizeof (int64_t); 315*da6c28aaSamw } 316*da6c28aaSamw break; 317*da6c28aaSamw 318*da6c28aaSamw case 'u': /* Convert from unicode if flags are set */ 319*da6c28aaSamw if (mb->flags & SMB_MSGBUF_UNICODE) 320*da6c28aaSamw goto unicode_translation; 321*da6c28aaSamw /*FALLTHROUGH*/ 322*da6c28aaSamw 323*da6c28aaSamw case 's': 324*da6c28aaSamw ival = strlen((const char *)mb->scan) + 1; 325*da6c28aaSamw if (smb_msgbuf_has_space(mb, ival) == 0) 326*da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 327*da6c28aaSamw 328*da6c28aaSamw if ((cvalp = smb_msgbuf_malloc(mb, ival * 2)) == 0) 329*da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 330*da6c28aaSamw 331*da6c28aaSamw if ((ival = mts_stombs((char *)cvalp, 332*da6c28aaSamw (char *)mb->scan, ival * 2)) == 333*da6c28aaSamw (uint32_t)-1) { 334*da6c28aaSamw return (SMB_MSGBUF_DATA_ERROR); 335*da6c28aaSamw } 336*da6c28aaSamw 337*da6c28aaSamw cvalpp = va_arg(ap, uint8_t **); 338*da6c28aaSamw *cvalpp = cvalp; 339*da6c28aaSamw mb->scan += (ival+1); 340*da6c28aaSamw break; 341*da6c28aaSamw 342*da6c28aaSamw case 'U': /* Convert from unicode */ 343*da6c28aaSamw unicode_translation: 344*da6c28aaSamw /* 345*da6c28aaSamw * Unicode strings are always word aligned. 346*da6c28aaSamw * The malloc'd area is larger than the 347*da6c28aaSamw * original string because the UTF-8 chars 348*da6c28aaSamw * may be longer than the wide-chars. 349*da6c28aaSamw */ 350*da6c28aaSamw smb_msgbuf_word_align(mb); 351*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 352*da6c28aaSamw wcs = (mts_wchar_t *)mb->scan; 353*da6c28aaSamw 354*da6c28aaSamw /* count the null wchar */ 355*da6c28aaSamw repc = sizeof (mts_wchar_t); 356*da6c28aaSamw while (*wcs++) 357*da6c28aaSamw repc += sizeof (mts_wchar_t); 358*da6c28aaSamw 359*da6c28aaSamw if (smb_msgbuf_has_space(mb, repc) == 0) 360*da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 361*da6c28aaSamw 362*da6c28aaSamw /* Decode wchar string into host byte-order */ 363*da6c28aaSamw if ((wcs = smb_msgbuf_malloc(mb, repc)) == 0) 364*da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 365*da6c28aaSamw 366*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 367*da6c28aaSamw buf_decode_wcs(wcs, (mts_wchar_t *)mb->scan, 368*da6c28aaSamw repc / sizeof (mts_wchar_t)); 369*da6c28aaSamw 370*da6c28aaSamw /* Get space for translated string */ 371*da6c28aaSamw if ((cvalp = smb_msgbuf_malloc(mb, repc * 2)) == 0) 372*da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 373*da6c28aaSamw 374*da6c28aaSamw /* Translate string */ 375*da6c28aaSamw (void) mts_wcstombs((char *)cvalp, wcs, repc * 2); 376*da6c28aaSamw 377*da6c28aaSamw cvalpp = va_arg(ap, uint8_t **); 378*da6c28aaSamw *cvalpp = cvalp; 379*da6c28aaSamw mb->scan += repc; 380*da6c28aaSamw break; 381*da6c28aaSamw 382*da6c28aaSamw case 'M': 383*da6c28aaSamw if (smb_msgbuf_has_space(mb, 4) == 0) 384*da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 385*da6c28aaSamw 386*da6c28aaSamw if (mb->scan[0] != 0xFF || 387*da6c28aaSamw mb->scan[1] != 'S' || 388*da6c28aaSamw mb->scan[2] != 'M' || 389*da6c28aaSamw mb->scan[3] != 'B') { 390*da6c28aaSamw return (SMB_MSGBUF_INVALID_HEADER); 391*da6c28aaSamw } 392*da6c28aaSamw mb->scan += 4; 393*da6c28aaSamw break; 394*da6c28aaSamw 395*da6c28aaSamw default: 396*da6c28aaSamw return (SMB_MSGBUF_INVALID_FORMAT); 397*da6c28aaSamw } 398*da6c28aaSamw } 399*da6c28aaSamw 400*da6c28aaSamw return (SMB_MSGBUF_SUCCESS); 401*da6c28aaSamw } 402*da6c28aaSamw 403*da6c28aaSamw 404*da6c28aaSamw /* 405*da6c28aaSamw * smb_msgbuf_encode 406*da6c28aaSamw * 407*da6c28aaSamw * Encode a smb_msgbuf buffer as indicated by the format string using 408*da6c28aaSamw * the variable arg list. This is similar to a sprintf operation. 409*da6c28aaSamw * 410*da6c28aaSamw * On success, returns the number of bytes encoded. Otherwise 411*da6c28aaSamw * returns a -ve error code. 412*da6c28aaSamw */ 413*da6c28aaSamw int 414*da6c28aaSamw smb_msgbuf_encode(smb_msgbuf_t *mb, char *fmt, ...) 415*da6c28aaSamw { 416*da6c28aaSamw int rc; 417*da6c28aaSamw uint8_t *orig_scan; 418*da6c28aaSamw va_list ap; 419*da6c28aaSamw 420*da6c28aaSamw va_start(ap, fmt); 421*da6c28aaSamw orig_scan = mb->scan; 422*da6c28aaSamw rc = buf_encode(mb, fmt, ap); 423*da6c28aaSamw va_end(ap); 424*da6c28aaSamw 425*da6c28aaSamw if (rc != SMB_MSGBUF_SUCCESS) { 426*da6c28aaSamw (void) smb_msgbuf_chkerc("smb_msgbuf_encode", rc); 427*da6c28aaSamw mb->scan = orig_scan; 428*da6c28aaSamw return (rc); 429*da6c28aaSamw } 430*da6c28aaSamw 431*da6c28aaSamw /*LINTED E_PTRDIFF_OVERFLOW*/ 432*da6c28aaSamw return (mb->scan - orig_scan); 433*da6c28aaSamw } 434*da6c28aaSamw 435*da6c28aaSamw 436*da6c28aaSamw /* 437*da6c28aaSamw * buf_encode 438*da6c28aaSamw * 439*da6c28aaSamw * Private encode function, where the real work of encoding the smb_msgbuf 440*da6c28aaSamw * is done. This function should only be called via smb_msgbuf_encode to 441*da6c28aaSamw * ensure correct behaviour and error handling. 442*da6c28aaSamw */ 443*da6c28aaSamw static int 444*da6c28aaSamw buf_encode(smb_msgbuf_t *mb, char *fmt, va_list ap) 445*da6c28aaSamw { 446*da6c28aaSamw uint8_t cval; 447*da6c28aaSamw uint16_t wval; 448*da6c28aaSamw uint32_t lval; 449*da6c28aaSamw uint64_t llval; 450*da6c28aaSamw uint32_t ival; 451*da6c28aaSamw uint8_t *cvalp; 452*da6c28aaSamw uint8_t c; 453*da6c28aaSamw mts_wchar_t wcval; 454*da6c28aaSamw int count; 455*da6c28aaSamw int repc = 1; 456*da6c28aaSamw int rc; 457*da6c28aaSamw 458*da6c28aaSamw while ((c = *fmt++) != 0) { 459*da6c28aaSamw repc = 1; 460*da6c28aaSamw 461*da6c28aaSamw if (c == ' ' || c == '\t') 462*da6c28aaSamw continue; 463*da6c28aaSamw 464*da6c28aaSamw if (c == '(') { 465*da6c28aaSamw while (((c = *fmt++) != 0) && c != ')') 466*da6c28aaSamw ; 467*da6c28aaSamw 468*da6c28aaSamw if (!c) 469*da6c28aaSamw return (SMB_MSGBUF_SUCCESS); 470*da6c28aaSamw 471*da6c28aaSamw continue; 472*da6c28aaSamw } 473*da6c28aaSamw 474*da6c28aaSamw if ('0' <= c && c <= '9') { 475*da6c28aaSamw repc = 0; 476*da6c28aaSamw do { 477*da6c28aaSamw repc = repc * 10 + c - '0'; 478*da6c28aaSamw c = *fmt++; 479*da6c28aaSamw } while ('0' <= c && c <= '9'); 480*da6c28aaSamw } else if (c == '#') { 481*da6c28aaSamw repc = va_arg(ap, int); 482*da6c28aaSamw c = *fmt++; 483*da6c28aaSamw } 484*da6c28aaSamw 485*da6c28aaSamw switch (c) { 486*da6c28aaSamw case '.': 487*da6c28aaSamw if (smb_msgbuf_has_space(mb, repc) == 0) 488*da6c28aaSamw return (SMB_MSGBUF_OVERFLOW); 489*da6c28aaSamw 490*da6c28aaSamw while (repc-- > 0) 491*da6c28aaSamw *mb->scan++ = 0; 492*da6c28aaSamw break; 493*da6c28aaSamw 494*da6c28aaSamw case 'c': 495*da6c28aaSamw if (smb_msgbuf_has_space(mb, repc) == 0) 496*da6c28aaSamw return (SMB_MSGBUF_OVERFLOW); 497*da6c28aaSamw 498*da6c28aaSamw cvalp = va_arg(ap, uint8_t *); 499*da6c28aaSamw bcopy(cvalp, mb->scan, repc); 500*da6c28aaSamw mb->scan += repc; 501*da6c28aaSamw break; 502*da6c28aaSamw 503*da6c28aaSamw case 'b': 504*da6c28aaSamw if (smb_msgbuf_has_space(mb, repc) == 0) 505*da6c28aaSamw return (SMB_MSGBUF_OVERFLOW); 506*da6c28aaSamw 507*da6c28aaSamw while (repc-- > 0) { 508*da6c28aaSamw cval = va_arg(ap, int); 509*da6c28aaSamw *mb->scan++ = cval; 510*da6c28aaSamw } 511*da6c28aaSamw break; 512*da6c28aaSamw 513*da6c28aaSamw case 'w': 514*da6c28aaSamw rc = smb_msgbuf_has_space(mb, repc * sizeof (uint16_t)); 515*da6c28aaSamw if (rc == 0) 516*da6c28aaSamw return (SMB_MSGBUF_OVERFLOW); 517*da6c28aaSamw 518*da6c28aaSamw while (repc-- > 0) { 519*da6c28aaSamw wval = va_arg(ap, int); 520*da6c28aaSamw LE_OUT16(mb->scan, wval); 521*da6c28aaSamw mb->scan += sizeof (uint16_t); 522*da6c28aaSamw } 523*da6c28aaSamw break; 524*da6c28aaSamw 525*da6c28aaSamw case 'l': 526*da6c28aaSamw rc = smb_msgbuf_has_space(mb, repc * sizeof (int32_t)); 527*da6c28aaSamw if (rc == 0) 528*da6c28aaSamw return (SMB_MSGBUF_OVERFLOW); 529*da6c28aaSamw 530*da6c28aaSamw while (repc-- > 0) { 531*da6c28aaSamw lval = va_arg(ap, uint32_t); 532*da6c28aaSamw LE_OUT32(mb->scan, lval); 533*da6c28aaSamw mb->scan += sizeof (int32_t); 534*da6c28aaSamw } 535*da6c28aaSamw break; 536*da6c28aaSamw 537*da6c28aaSamw case 'q': 538*da6c28aaSamw rc = smb_msgbuf_has_space(mb, repc * sizeof (int64_t)); 539*da6c28aaSamw if (rc == 0) 540*da6c28aaSamw return (SMB_MSGBUF_OVERFLOW); 541*da6c28aaSamw 542*da6c28aaSamw while (repc-- > 0) { 543*da6c28aaSamw llval = va_arg(ap, uint64_t); 544*da6c28aaSamw LE_OUT64(mb->scan, llval); 545*da6c28aaSamw mb->scan += sizeof (uint64_t); 546*da6c28aaSamw } 547*da6c28aaSamw break; 548*da6c28aaSamw 549*da6c28aaSamw case 'u': /* conditional unicode */ 550*da6c28aaSamw if (mb->flags & SMB_MSGBUF_UNICODE) 551*da6c28aaSamw goto unicode_translation; 552*da6c28aaSamw /* FALLTHROUGH */ 553*da6c28aaSamw 554*da6c28aaSamw case 's': 555*da6c28aaSamw cvalp = va_arg(ap, uint8_t *); 556*da6c28aaSamw ival = strlen((const char *)cvalp) + 1; 557*da6c28aaSamw 558*da6c28aaSamw if (smb_msgbuf_has_space(mb, ival) == 0) 559*da6c28aaSamw return (SMB_MSGBUF_OVERFLOW); 560*da6c28aaSamw 561*da6c28aaSamw ival = 562*da6c28aaSamw mts_mbstos((char *)mb->scan, (const char *)cvalp); 563*da6c28aaSamw mb->scan += ival + 1; 564*da6c28aaSamw break; 565*da6c28aaSamw 566*da6c28aaSamw case 'U': /* unicode */ 567*da6c28aaSamw unicode_translation: 568*da6c28aaSamw /* 569*da6c28aaSamw * Unicode strings are always word aligned. 570*da6c28aaSamw */ 571*da6c28aaSamw smb_msgbuf_word_align(mb); 572*da6c28aaSamw cvalp = va_arg(ap, uint8_t *); 573*da6c28aaSamw 574*da6c28aaSamw for (;;) { 575*da6c28aaSamw rc = smb_msgbuf_has_space(mb, 576*da6c28aaSamw sizeof (mts_wchar_t)); 577*da6c28aaSamw if (rc == 0) 578*da6c28aaSamw return (SMB_MSGBUF_OVERFLOW); 579*da6c28aaSamw 580*da6c28aaSamw count = mts_mbtowc(&wcval, (const char *)cvalp, 581*da6c28aaSamw MTS_MB_CHAR_MAX); 582*da6c28aaSamw 583*da6c28aaSamw if (count < 0) { 584*da6c28aaSamw return (SMB_MSGBUF_DATA_ERROR); 585*da6c28aaSamw } else if (count == 0) { 586*da6c28aaSamw /* 587*da6c28aaSamw * No longer need to do this now that 588*da6c28aaSamw * mbtowc correctly writes the null 589*da6c28aaSamw * before returning zero but paranoia 590*da6c28aaSamw * wins. 591*da6c28aaSamw */ 592*da6c28aaSamw wcval = 0; 593*da6c28aaSamw count = 1; 594*da6c28aaSamw } 595*da6c28aaSamw 596*da6c28aaSamw /* Write wchar in wire-format */ 597*da6c28aaSamw LE_OUT16(mb->scan, wcval); 598*da6c28aaSamw 599*da6c28aaSamw if (*cvalp == 0) { 600*da6c28aaSamw /* 601*da6c28aaSamw * End of string. Check to see whether 602*da6c28aaSamw * or not to include the null 603*da6c28aaSamw * terminator. 604*da6c28aaSamw */ 605*da6c28aaSamw if ((mb->flags & SMB_MSGBUF_NOTERM) == 606*da6c28aaSamw 0) 607*da6c28aaSamw mb->scan += 608*da6c28aaSamw sizeof (mts_wchar_t); 609*da6c28aaSamw break; 610*da6c28aaSamw } 611*da6c28aaSamw 612*da6c28aaSamw mb->scan += sizeof (mts_wchar_t); 613*da6c28aaSamw cvalp += count; 614*da6c28aaSamw } 615*da6c28aaSamw break; 616*da6c28aaSamw 617*da6c28aaSamw case 'M': 618*da6c28aaSamw if (smb_msgbuf_has_space(mb, 4) == 0) 619*da6c28aaSamw return (SMB_MSGBUF_OVERFLOW); 620*da6c28aaSamw 621*da6c28aaSamw *mb->scan++ = 0xFF; 622*da6c28aaSamw *mb->scan++ = 'S'; 623*da6c28aaSamw *mb->scan++ = 'M'; 624*da6c28aaSamw *mb->scan++ = 'B'; 625*da6c28aaSamw break; 626*da6c28aaSamw 627*da6c28aaSamw default: 628*da6c28aaSamw return (SMB_MSGBUF_INVALID_FORMAT); 629*da6c28aaSamw } 630*da6c28aaSamw } 631*da6c28aaSamw 632*da6c28aaSamw return (SMB_MSGBUF_SUCCESS); 633*da6c28aaSamw } 634*da6c28aaSamw 635*da6c28aaSamw 636*da6c28aaSamw /* 637*da6c28aaSamw * smb_msgbuf_malloc 638*da6c28aaSamw * 639*da6c28aaSamw * Allocate some memory for use with this smb_msgbuf. We increase the 640*da6c28aaSamw * requested size to hold the list pointer and return a pointer 641*da6c28aaSamw * to the area for use by the caller. 642*da6c28aaSamw */ 643*da6c28aaSamw static void * 644*da6c28aaSamw smb_msgbuf_malloc(smb_msgbuf_t *mb, size_t size) 645*da6c28aaSamw { 646*da6c28aaSamw smb_msgbuf_mlist_t *item; 647*da6c28aaSamw 648*da6c28aaSamw size += sizeof (smb_msgbuf_mlist_t); 649*da6c28aaSamw 650*da6c28aaSamw #ifndef _KERNEL 651*da6c28aaSamw if ((item = malloc(size)) == NULL) 652*da6c28aaSamw return (NULL); 653*da6c28aaSamw #else 654*da6c28aaSamw item = kmem_alloc(size, KM_SLEEP); 655*da6c28aaSamw #endif 656*da6c28aaSamw item->next = mb->mlist.next; 657*da6c28aaSamw item->size = size; 658*da6c28aaSamw mb->mlist.next = item; 659*da6c28aaSamw 660*da6c28aaSamw /* 661*da6c28aaSamw * The caller gets a pointer to the address 662*da6c28aaSamw * immediately after the smb_msgbuf_mlist_t. 663*da6c28aaSamw */ 664*da6c28aaSamw return ((void *)(item + 1)); 665*da6c28aaSamw } 666*da6c28aaSamw 667*da6c28aaSamw 668*da6c28aaSamw /* 669*da6c28aaSamw * smb_msgbuf_chkerc 670*da6c28aaSamw * 671*da6c28aaSamw * Diagnostic function to write an appropriate message to the system log. 672*da6c28aaSamw */ 673*da6c28aaSamw static int 674*da6c28aaSamw smb_msgbuf_chkerc(char *text, int erc) 675*da6c28aaSamw { 676*da6c28aaSamw static struct { 677*da6c28aaSamw int erc; 678*da6c28aaSamw char *name; 679*da6c28aaSamw } etable[] = { 680*da6c28aaSamw { SMB_MSGBUF_SUCCESS, "success" }, 681*da6c28aaSamw { SMB_MSGBUF_UNDERFLOW, "overflow/underflow" }, 682*da6c28aaSamw { SMB_MSGBUF_INVALID_FORMAT, "invalid format" }, 683*da6c28aaSamw { SMB_MSGBUF_INVALID_HEADER, "invalid header" }, 684*da6c28aaSamw { SMB_MSGBUF_DATA_ERROR, "data error" } 685*da6c28aaSamw }; 686*da6c28aaSamw 687*da6c28aaSamw int i; 688*da6c28aaSamw 689*da6c28aaSamw for (i = 0; i < sizeof (etable)/sizeof (etable[0]); ++i) { 690*da6c28aaSamw if (etable[i].erc == erc) { 691*da6c28aaSamw if (text == 0) 692*da6c28aaSamw text = "smb_msgbuf_chkerc"; 693*da6c28aaSamw break; 694*da6c28aaSamw } 695*da6c28aaSamw } 696*da6c28aaSamw return (erc); 697*da6c28aaSamw } 698*da6c28aaSamw 699*da6c28aaSamw static void 700*da6c28aaSamw buf_decode_wcs(mts_wchar_t *dst_wcstr, mts_wchar_t *src_wcstr, int wcstrlen) 701*da6c28aaSamw { 702*da6c28aaSamw int i; 703*da6c28aaSamw 704*da6c28aaSamw for (i = 0; i < wcstrlen; i++) { 705*da6c28aaSamw *dst_wcstr = LE_IN16(src_wcstr); 706*da6c28aaSamw dst_wcstr++; 707*da6c28aaSamw src_wcstr++; 708*da6c28aaSamw } 709*da6c28aaSamw } 710