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