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. 24b819cea2SGordon Ross * 25*7d1ffc32SGordon Ross * Copyright 2018 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> 38b819cea2SGordon 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); 55da6c28aaSamw 56*7d1ffc32SGordon Ross static int msgbuf_get_oem_string(smb_msgbuf_t *, char **, int); 57*7d1ffc32SGordon Ross static int msgbuf_get_unicode_string(smb_msgbuf_t *, char **, int); 58*7d1ffc32SGordon Ross static int msgbuf_put_oem_string(smb_msgbuf_t *, char *, int); 59*7d1ffc32SGordon Ross static int msgbuf_put_unicode_string(smb_msgbuf_t *, char *, int); 60*7d1ffc32SGordon Ross 61*7d1ffc32SGordon Ross 62da6c28aaSamw /* 63da6c28aaSamw * Returns the offset or number of bytes used within the buffer. 64da6c28aaSamw */ 65da6c28aaSamw size_t 66da6c28aaSamw smb_msgbuf_used(smb_msgbuf_t *mb) 67da6c28aaSamw { 68da6c28aaSamw /*LINTED E_PTRDIFF_OVERFLOW*/ 69da6c28aaSamw return (mb->scan - mb->base); 70da6c28aaSamw } 71da6c28aaSamw 72da6c28aaSamw /* 73da6c28aaSamw * Returns the actual buffer size. 74da6c28aaSamw */ 75da6c28aaSamw size_t 76da6c28aaSamw smb_msgbuf_size(smb_msgbuf_t *mb) 77da6c28aaSamw { 78da6c28aaSamw return (mb->max); 79da6c28aaSamw } 80da6c28aaSamw 81da6c28aaSamw uint8_t * 82da6c28aaSamw smb_msgbuf_base(smb_msgbuf_t *mb) 83da6c28aaSamw { 84da6c28aaSamw return (mb->base); 85da6c28aaSamw } 86da6c28aaSamw 87da6c28aaSamw /* 88da6c28aaSamw * Ensure that the scan is aligned on a word (16-bit) boundary. 89da6c28aaSamw */ 90da6c28aaSamw void 91da6c28aaSamw smb_msgbuf_word_align(smb_msgbuf_t *mb) 92da6c28aaSamw { 93da6c28aaSamw mb->scan = (uint8_t *)((uintptr_t)(mb->scan + 1) & ~1); 94da6c28aaSamw } 95da6c28aaSamw 96da6c28aaSamw /* 97da6c28aaSamw * Ensure that the scan is aligned on a dword (32-bit) boundary. 98da6c28aaSamw */ 99da6c28aaSamw void 100da6c28aaSamw smb_msgbuf_dword_align(smb_msgbuf_t *mb) 101da6c28aaSamw { 102da6c28aaSamw mb->scan = (uint8_t *)((uintptr_t)(mb->scan + 3) & ~3); 103da6c28aaSamw } 104da6c28aaSamw 105da6c28aaSamw /* 106da6c28aaSamw * Checks whether or not the buffer has space for the amount of data 107da6c28aaSamw * specified. Returns 1 if there is space, otherwise returns 0. 108da6c28aaSamw */ 109da6c28aaSamw int 110da6c28aaSamw smb_msgbuf_has_space(smb_msgbuf_t *mb, size_t size) 111da6c28aaSamw { 112da6c28aaSamw if (size > mb->max || (mb->scan + size) > mb->end) 113da6c28aaSamw return (0); 114da6c28aaSamw 115da6c28aaSamw return (1); 116da6c28aaSamw } 117da6c28aaSamw 118da6c28aaSamw /* 119da6c28aaSamw * Set flags the smb_msgbuf. 120da6c28aaSamw */ 121da6c28aaSamw void 122da6c28aaSamw smb_msgbuf_fset(smb_msgbuf_t *mb, uint32_t flags) 123da6c28aaSamw { 124da6c28aaSamw mb->flags |= flags; 125da6c28aaSamw } 126da6c28aaSamw 127da6c28aaSamw /* 128da6c28aaSamw * Clear flags the smb_msgbuf. 129da6c28aaSamw */ 130da6c28aaSamw void 131da6c28aaSamw smb_msgbuf_fclear(smb_msgbuf_t *mb, uint32_t flags) 132da6c28aaSamw { 133da6c28aaSamw mb->flags &= ~flags; 134da6c28aaSamw } 135da6c28aaSamw 136da6c28aaSamw /* 137da6c28aaSamw * smb_msgbuf_init 138da6c28aaSamw * 139da6c28aaSamw * Initialize a smb_msgbuf_t structure based on the buffer and size 140da6c28aaSamw * specified. Both scan and base initially point to the beginning 141da6c28aaSamw * of the buffer and end points to the limit of the buffer. As 142da6c28aaSamw * data is added scan should be incremented to point to the next 143da6c28aaSamw * offset at which data will be written. Max and count are set 144da6c28aaSamw * to the actual buffer size. 145da6c28aaSamw */ 146da6c28aaSamw void 147da6c28aaSamw smb_msgbuf_init(smb_msgbuf_t *mb, uint8_t *buf, size_t size, uint32_t flags) 148da6c28aaSamw { 149da6c28aaSamw mb->scan = mb->base = buf; 150da6c28aaSamw mb->max = mb->count = size; 151da6c28aaSamw mb->end = &buf[size]; 152da6c28aaSamw mb->flags = flags; 153da6c28aaSamw mb->mlist.next = 0; 154da6c28aaSamw } 155da6c28aaSamw 156da6c28aaSamw 157da6c28aaSamw /* 158da6c28aaSamw * smb_msgbuf_term 159da6c28aaSamw * 160da6c28aaSamw * Destruct a smb_msgbuf_t. Free any memory hanging off the mlist. 161da6c28aaSamw */ 162da6c28aaSamw void 163da6c28aaSamw smb_msgbuf_term(smb_msgbuf_t *mb) 164da6c28aaSamw { 165da6c28aaSamw smb_msgbuf_mlist_t *item = mb->mlist.next; 166da6c28aaSamw smb_msgbuf_mlist_t *tmp; 167da6c28aaSamw 168da6c28aaSamw while (item) { 169da6c28aaSamw tmp = item; 170da6c28aaSamw item = item->next; 171b819cea2SGordon Ross #if !defined(_KERNEL) && !defined(_FAKE_KERNEL) 172da6c28aaSamw free(tmp); 173da6c28aaSamw #else 174da6c28aaSamw kmem_free(tmp, tmp->size); 175da6c28aaSamw #endif 176da6c28aaSamw } 177da6c28aaSamw } 178da6c28aaSamw 179da6c28aaSamw 180da6c28aaSamw /* 181da6c28aaSamw * smb_msgbuf_decode 182da6c28aaSamw * 183da6c28aaSamw * Decode a smb_msgbuf buffer as indicated by the format string into 184da6c28aaSamw * the variable arg list. This is similar to a scanf operation. 185da6c28aaSamw * 186*7d1ffc32SGordon Ross * On success, returns the number of bytes decoded. Otherwise 187da6c28aaSamw * returns a -ve error code. 188da6c28aaSamw */ 189da6c28aaSamw int 190da6c28aaSamw smb_msgbuf_decode(smb_msgbuf_t *mb, char *fmt, ...) 191da6c28aaSamw { 192da6c28aaSamw int rc; 193da6c28aaSamw uint8_t *orig_scan; 194da6c28aaSamw va_list ap; 195da6c28aaSamw 196da6c28aaSamw va_start(ap, fmt); 197da6c28aaSamw orig_scan = mb->scan; 198da6c28aaSamw rc = buf_decode(mb, fmt, ap); 199da6c28aaSamw va_end(ap); 200da6c28aaSamw 201da6c28aaSamw if (rc != SMB_MSGBUF_SUCCESS) { 202da6c28aaSamw (void) smb_msgbuf_chkerc("smb_msgbuf_decode", rc); 203da6c28aaSamw mb->scan = orig_scan; 204da6c28aaSamw return (rc); 205da6c28aaSamw } 206da6c28aaSamw 207da6c28aaSamw /*LINTED E_PTRDIFF_OVERFLOW*/ 208da6c28aaSamw return (mb->scan - orig_scan); 209da6c28aaSamw } 210da6c28aaSamw 211da6c28aaSamw 212da6c28aaSamw /* 213da6c28aaSamw * buf_decode 214da6c28aaSamw * 215da6c28aaSamw * Private decode function, where the real work of decoding the smb_msgbuf 216da6c28aaSamw * is done. This function should only be called via smb_msgbuf_decode to 217da6c28aaSamw * ensure correct behaviour and error handling. 218da6c28aaSamw */ 219da6c28aaSamw static int 220da6c28aaSamw buf_decode(smb_msgbuf_t *mb, char *fmt, va_list ap) 221da6c28aaSamw { 222da6c28aaSamw uint8_t c; 22312b65585SGordon Ross uint8_t *bvalp; 224da6c28aaSamw uint16_t *wvalp; 225da6c28aaSamw uint32_t *lvalp; 226da6c28aaSamw uint64_t *llvalp; 22712b65585SGordon Ross char **cvalpp; 22812b65585SGordon Ross boolean_t repc_specified; 229da6c28aaSamw int repc; 230da6c28aaSamw int rc; 231da6c28aaSamw 232da6c28aaSamw while ((c = *fmt++) != 0) { 23312b65585SGordon Ross repc_specified = B_FALSE; 234da6c28aaSamw repc = 1; 235da6c28aaSamw 236da6c28aaSamw if (c == ' ' || c == '\t') 237da6c28aaSamw continue; 238da6c28aaSamw 239da6c28aaSamw if (c == '(') { 240da6c28aaSamw while (((c = *fmt++) != 0) && c != ')') 241da6c28aaSamw ; 242da6c28aaSamw 243da6c28aaSamw if (!c) 244da6c28aaSamw return (SMB_MSGBUF_SUCCESS); 245da6c28aaSamw 246da6c28aaSamw continue; 247da6c28aaSamw } 248da6c28aaSamw 249da6c28aaSamw if ('0' <= c && c <= '9') { 250da6c28aaSamw repc = 0; 251da6c28aaSamw do { 252da6c28aaSamw repc = repc * 10 + c - '0'; 253da6c28aaSamw c = *fmt++; 254da6c28aaSamw } while ('0' <= c && c <= '9'); 25512b65585SGordon Ross repc_specified = B_TRUE; 256da6c28aaSamw } else if (c == '#') { 257da6c28aaSamw repc = va_arg(ap, int); 258da6c28aaSamw c = *fmt++; 25912b65585SGordon Ross repc_specified = B_TRUE; 260da6c28aaSamw } 261da6c28aaSamw 262da6c28aaSamw switch (c) { 263da6c28aaSamw case '.': 264da6c28aaSamw if (smb_msgbuf_has_space(mb, repc) == 0) 265da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 266da6c28aaSamw 267da6c28aaSamw mb->scan += repc; 268da6c28aaSamw break; 269da6c28aaSamw 27012b65585SGordon Ross case 'c': /* get char */ 271da6c28aaSamw if (smb_msgbuf_has_space(mb, repc) == 0) 272da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 273da6c28aaSamw 27412b65585SGordon Ross bvalp = va_arg(ap, uint8_t *); 27512b65585SGordon Ross bcopy(mb->scan, bvalp, repc); 276da6c28aaSamw mb->scan += repc; 277da6c28aaSamw break; 278da6c28aaSamw 27912b65585SGordon Ross case 'b': /* get byte */ 280da6c28aaSamw if (smb_msgbuf_has_space(mb, repc) == 0) 281da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 282da6c28aaSamw 28312b65585SGordon Ross bvalp = va_arg(ap, uint8_t *); 284da6c28aaSamw while (repc-- > 0) { 28512b65585SGordon Ross *bvalp++ = *mb->scan++; 286da6c28aaSamw } 287da6c28aaSamw break; 288da6c28aaSamw 28912b65585SGordon Ross case 'w': /* get word */ 290da6c28aaSamw rc = smb_msgbuf_has_space(mb, repc * sizeof (uint16_t)); 291da6c28aaSamw if (rc == 0) 292da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 293da6c28aaSamw 294da6c28aaSamw wvalp = va_arg(ap, uint16_t *); 295da6c28aaSamw while (repc-- > 0) { 296da6c28aaSamw *wvalp++ = LE_IN16(mb->scan); 297da6c28aaSamw mb->scan += sizeof (uint16_t); 298da6c28aaSamw } 299da6c28aaSamw break; 300da6c28aaSamw 30112b65585SGordon Ross case 'l': /* get long */ 302da6c28aaSamw rc = smb_msgbuf_has_space(mb, repc * sizeof (int32_t)); 303da6c28aaSamw if (rc == 0) 304da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 305da6c28aaSamw 306da6c28aaSamw lvalp = va_arg(ap, uint32_t *); 307da6c28aaSamw while (repc-- > 0) { 308da6c28aaSamw *lvalp++ = LE_IN32(mb->scan); 309da6c28aaSamw mb->scan += sizeof (int32_t); 310da6c28aaSamw } 311da6c28aaSamw break; 312da6c28aaSamw 31312b65585SGordon Ross case 'q': /* get quad */ 314da6c28aaSamw rc = smb_msgbuf_has_space(mb, repc * sizeof (int64_t)); 315da6c28aaSamw if (rc == 0) 316da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 317da6c28aaSamw 318da6c28aaSamw llvalp = va_arg(ap, uint64_t *); 319da6c28aaSamw while (repc-- > 0) { 320da6c28aaSamw *llvalp++ = LE_IN64(mb->scan); 321da6c28aaSamw mb->scan += sizeof (int64_t); 322da6c28aaSamw } 323da6c28aaSamw break; 324da6c28aaSamw 325da6c28aaSamw case 'u': /* Convert from unicode if flags are set */ 326da6c28aaSamw if (mb->flags & SMB_MSGBUF_UNICODE) 327da6c28aaSamw goto unicode_translation; 328da6c28aaSamw /*FALLTHROUGH*/ 329da6c28aaSamw 330*7d1ffc32SGordon Ross case 's': /* get OEM string */ 33112b65585SGordon Ross cvalpp = va_arg(ap, char **); 332*7d1ffc32SGordon Ross if (!repc_specified) 333*7d1ffc32SGordon Ross repc = 0; 334*7d1ffc32SGordon Ross rc = msgbuf_get_oem_string(mb, cvalpp, repc); 335*7d1ffc32SGordon Ross if (rc != 0) 336*7d1ffc32SGordon Ross return (rc); 337da6c28aaSamw break; 338da6c28aaSamw 339*7d1ffc32SGordon Ross case 'U': /* get UTF-16 string */ 340da6c28aaSamw unicode_translation: 34112b65585SGordon Ross cvalpp = va_arg(ap, char **); 342*7d1ffc32SGordon Ross if (!repc_specified) 343*7d1ffc32SGordon Ross repc = 0; 344*7d1ffc32SGordon Ross rc = msgbuf_get_unicode_string(mb, cvalpp, repc); 345*7d1ffc32SGordon Ross if (rc != 0) 346*7d1ffc32SGordon Ross return (rc); 347da6c28aaSamw break; 348da6c28aaSamw 349da6c28aaSamw case 'M': 350da6c28aaSamw if (smb_msgbuf_has_space(mb, 4) == 0) 351da6c28aaSamw return (SMB_MSGBUF_UNDERFLOW); 352da6c28aaSamw 353da6c28aaSamw if (mb->scan[0] != 0xFF || 354da6c28aaSamw mb->scan[1] != 'S' || 355da6c28aaSamw mb->scan[2] != 'M' || 356da6c28aaSamw mb->scan[3] != 'B') { 357da6c28aaSamw return (SMB_MSGBUF_INVALID_HEADER); 358da6c28aaSamw } 359da6c28aaSamw mb->scan += 4; 360da6c28aaSamw break; 361da6c28aaSamw 362da6c28aaSamw default: 363da6c28aaSamw return (SMB_MSGBUF_INVALID_FORMAT); 364da6c28aaSamw } 365da6c28aaSamw } 366da6c28aaSamw 367da6c28aaSamw return (SMB_MSGBUF_SUCCESS); 368da6c28aaSamw } 369da6c28aaSamw 370*7d1ffc32SGordon Ross /* 371*7d1ffc32SGordon Ross * msgbuf_get_oem_string 372*7d1ffc32SGordon Ross * 373*7d1ffc32SGordon Ross * Decode an OEM string, returning its UTF-8 form in strpp, 374*7d1ffc32SGordon Ross * allocated using smb_msgbuf_malloc (automatically freed). 375*7d1ffc32SGordon Ross * If max_bytes != 0, consume at most max_bytes of the mb. 376*7d1ffc32SGordon Ross * See also: mbc_marshal_get_oem_string 377*7d1ffc32SGordon Ross */ 378*7d1ffc32SGordon Ross static int 379*7d1ffc32SGordon Ross msgbuf_get_oem_string(smb_msgbuf_t *mb, char **strpp, int max_bytes) 380*7d1ffc32SGordon Ross { 381*7d1ffc32SGordon Ross char *mbs; 382*7d1ffc32SGordon Ross uint8_t *oembuf = NULL; 383*7d1ffc32SGordon Ross int oemlen; // len of OEM string, w/o null 384*7d1ffc32SGordon Ross int datalen; // OtW data len 385*7d1ffc32SGordon Ross int mbsmax; // max len of ret str 386*7d1ffc32SGordon Ross int rlen; 387*7d1ffc32SGordon Ross 388*7d1ffc32SGordon Ross if (max_bytes == 0) 389*7d1ffc32SGordon Ross max_bytes = 0xffff; 390*7d1ffc32SGordon Ross 391*7d1ffc32SGordon Ross /* 392*7d1ffc32SGordon Ross * Determine the OtW data length and OEM string length 393*7d1ffc32SGordon Ross * Note: oemlen is the string length (w/o null) and 394*7d1ffc32SGordon Ross * datalen is how much we move mb->scan 395*7d1ffc32SGordon Ross */ 396*7d1ffc32SGordon Ross datalen = 0; 397*7d1ffc32SGordon Ross oemlen = 0; 398*7d1ffc32SGordon Ross for (;;) { 399*7d1ffc32SGordon Ross if (datalen >= max_bytes) 400*7d1ffc32SGordon Ross break; 401*7d1ffc32SGordon Ross /* in-line smb_msgbuf_has_space */ 402*7d1ffc32SGordon Ross if ((mb->scan + datalen) >= mb->end) 403*7d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW); 404*7d1ffc32SGordon Ross datalen++; 405*7d1ffc32SGordon Ross if (mb->scan[datalen - 1] == 0) 406*7d1ffc32SGordon Ross break; 407*7d1ffc32SGordon Ross oemlen++; 408*7d1ffc32SGordon Ross } 409*7d1ffc32SGordon Ross 410*7d1ffc32SGordon Ross /* 411*7d1ffc32SGordon Ross * Get datalen bytes into a temp buffer 412*7d1ffc32SGordon Ross * sized with room to add a null. 413*7d1ffc32SGordon Ross * Free oembuf in smb_msgbuf_term 414*7d1ffc32SGordon Ross */ 415*7d1ffc32SGordon Ross oembuf = smb_msgbuf_malloc(mb, datalen + 1); 416*7d1ffc32SGordon Ross if (oembuf == NULL) 417*7d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW); 418*7d1ffc32SGordon Ross bcopy(mb->scan, oembuf, datalen); 419*7d1ffc32SGordon Ross mb->scan += datalen; 420*7d1ffc32SGordon Ross oembuf[oemlen] = '\0'; 421*7d1ffc32SGordon Ross 422*7d1ffc32SGordon Ross /* 423*7d1ffc32SGordon Ross * Get the buffer we'll return and convert to UTF-8. 424*7d1ffc32SGordon Ross * May take as much as double the space. 425*7d1ffc32SGordon Ross */ 426*7d1ffc32SGordon Ross mbsmax = oemlen * 2; 427*7d1ffc32SGordon Ross mbs = smb_msgbuf_malloc(mb, mbsmax + 1); 428*7d1ffc32SGordon Ross if (mbs == NULL) 429*7d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW); 430*7d1ffc32SGordon Ross rlen = smb_oemtombs(mbs, oembuf, mbsmax); 431*7d1ffc32SGordon Ross if (rlen < 0) 432*7d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW); 433*7d1ffc32SGordon Ross if (rlen > mbsmax) 434*7d1ffc32SGordon Ross rlen = mbsmax; 435*7d1ffc32SGordon Ross mbs[rlen] = '\0'; 436*7d1ffc32SGordon Ross *strpp = mbs; 437*7d1ffc32SGordon Ross return (0); 438*7d1ffc32SGordon Ross } 439*7d1ffc32SGordon Ross 440*7d1ffc32SGordon Ross /* 441*7d1ffc32SGordon Ross * msgbuf_get_unicode_string 442*7d1ffc32SGordon Ross * 443*7d1ffc32SGordon Ross * Decode a UTF-16 string, returning its UTF-8 form in strpp, 444*7d1ffc32SGordon Ross * allocated using smb_msgbuf_malloc (automatically freed). 445*7d1ffc32SGordon Ross * If max_bytes != 0, consume at most max_bytes of the mb. 446*7d1ffc32SGordon Ross * See also: mbc_marshal_get_unicode_string 447*7d1ffc32SGordon Ross */ 448*7d1ffc32SGordon Ross static int 449*7d1ffc32SGordon Ross msgbuf_get_unicode_string(smb_msgbuf_t *mb, char **strpp, int max_bytes) 450*7d1ffc32SGordon Ross { 451*7d1ffc32SGordon Ross char *mbs; 452*7d1ffc32SGordon Ross uint16_t *wcsbuf = NULL; 453*7d1ffc32SGordon Ross int wcslen; // wchar count 454*7d1ffc32SGordon Ross int datalen; // OtW data len 455*7d1ffc32SGordon Ross size_t mbsmax; // max len of ret str 456*7d1ffc32SGordon Ross size_t rlen; 457*7d1ffc32SGordon Ross 458*7d1ffc32SGordon Ross if (max_bytes == 0) 459*7d1ffc32SGordon Ross max_bytes = 0xffff; 460*7d1ffc32SGordon Ross 461*7d1ffc32SGordon Ross /* 462*7d1ffc32SGordon Ross * Unicode strings are always word aligned. 463*7d1ffc32SGordon Ross */ 464*7d1ffc32SGordon Ross smb_msgbuf_word_align(mb); 465*7d1ffc32SGordon Ross 466*7d1ffc32SGordon Ross /* 467*7d1ffc32SGordon Ross * Determine the OtW data length and (WC) string length 468*7d1ffc32SGordon Ross * Note: wcslen counts 16-bit wide_chars (w/o null), 469*7d1ffc32SGordon Ross * and datalen is how much we move mb->scan 470*7d1ffc32SGordon Ross */ 471*7d1ffc32SGordon Ross datalen = 0; 472*7d1ffc32SGordon Ross wcslen = 0; 473*7d1ffc32SGordon Ross for (;;) { 474*7d1ffc32SGordon Ross if (datalen >= max_bytes) 475*7d1ffc32SGordon Ross break; 476*7d1ffc32SGordon Ross /* in-line smb_msgbuf_has_space */ 477*7d1ffc32SGordon Ross if ((mb->scan + datalen) >= mb->end) 478*7d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW); 479*7d1ffc32SGordon Ross datalen += 2; 480*7d1ffc32SGordon Ross if (mb->scan[datalen - 2] == 0 && 481*7d1ffc32SGordon Ross mb->scan[datalen - 1] == 0) 482*7d1ffc32SGordon Ross break; 483*7d1ffc32SGordon Ross wcslen++; 484*7d1ffc32SGordon Ross } 485*7d1ffc32SGordon Ross 486*7d1ffc32SGordon Ross /* 487*7d1ffc32SGordon Ross * Get datalen bytes into a temp buffer 488*7d1ffc32SGordon Ross * sized with room to add a (WC) null. 489*7d1ffc32SGordon Ross * Note: wcsbuf has little-endian order 490*7d1ffc32SGordon Ross */ 491*7d1ffc32SGordon Ross wcsbuf = smb_msgbuf_malloc(mb, datalen + 2); 492*7d1ffc32SGordon Ross if (wcsbuf == NULL) 493*7d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW); 494*7d1ffc32SGordon Ross bcopy(mb->scan, wcsbuf, datalen); 495*7d1ffc32SGordon Ross mb->scan += datalen; 496*7d1ffc32SGordon Ross wcsbuf[wcslen] = 0; 497*7d1ffc32SGordon Ross 498*7d1ffc32SGordon Ross /* 499*7d1ffc32SGordon Ross * Get the buffer we'll return and convert to UTF-8. 500*7d1ffc32SGordon Ross * May take as much 4X number of wide chars. 501*7d1ffc32SGordon Ross */ 502*7d1ffc32SGordon Ross mbsmax = wcslen * MTS_MB_CUR_MAX; 503*7d1ffc32SGordon Ross mbs = smb_msgbuf_malloc(mb, mbsmax + 1); 504*7d1ffc32SGordon Ross if (mbs == NULL) 505*7d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW); 506*7d1ffc32SGordon Ross rlen = smb_wcstombs(mbs, wcsbuf, mbsmax); 507*7d1ffc32SGordon Ross if (rlen == (size_t)-1) 508*7d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW); 509*7d1ffc32SGordon Ross if (rlen > mbsmax) 510*7d1ffc32SGordon Ross rlen = mbsmax; 511*7d1ffc32SGordon Ross mbs[rlen] = '\0'; 512*7d1ffc32SGordon Ross *strpp = mbs; 513*7d1ffc32SGordon Ross return (0); 514*7d1ffc32SGordon Ross } 515da6c28aaSamw 516da6c28aaSamw /* 517da6c28aaSamw * smb_msgbuf_encode 518da6c28aaSamw * 519da6c28aaSamw * Encode a smb_msgbuf buffer as indicated by the format string using 520da6c28aaSamw * the variable arg list. This is similar to a sprintf operation. 521da6c28aaSamw * 522da6c28aaSamw * On success, returns the number of bytes encoded. Otherwise 523da6c28aaSamw * returns a -ve error code. 524da6c28aaSamw */ 525da6c28aaSamw int 526da6c28aaSamw smb_msgbuf_encode(smb_msgbuf_t *mb, char *fmt, ...) 527da6c28aaSamw { 528da6c28aaSamw int rc; 529da6c28aaSamw uint8_t *orig_scan; 530da6c28aaSamw va_list ap; 531da6c28aaSamw 532da6c28aaSamw va_start(ap, fmt); 533da6c28aaSamw orig_scan = mb->scan; 534da6c28aaSamw rc = buf_encode(mb, fmt, ap); 535da6c28aaSamw va_end(ap); 536da6c28aaSamw 537da6c28aaSamw if (rc != SMB_MSGBUF_SUCCESS) { 538da6c28aaSamw (void) smb_msgbuf_chkerc("smb_msgbuf_encode", rc); 539da6c28aaSamw mb->scan = orig_scan; 540da6c28aaSamw return (rc); 541da6c28aaSamw } 542da6c28aaSamw 543da6c28aaSamw /*LINTED E_PTRDIFF_OVERFLOW*/ 544da6c28aaSamw return (mb->scan - orig_scan); 545da6c28aaSamw } 546da6c28aaSamw 547da6c28aaSamw 548da6c28aaSamw /* 549da6c28aaSamw * buf_encode 550da6c28aaSamw * 551da6c28aaSamw * Private encode function, where the real work of encoding the smb_msgbuf 552da6c28aaSamw * is done. This function should only be called via smb_msgbuf_encode to 553da6c28aaSamw * ensure correct behaviour and error handling. 554da6c28aaSamw */ 555da6c28aaSamw static int 556da6c28aaSamw buf_encode(smb_msgbuf_t *mb, char *fmt, va_list ap) 557da6c28aaSamw { 558da6c28aaSamw uint8_t cval; 559da6c28aaSamw uint16_t wval; 560da6c28aaSamw uint32_t lval; 561da6c28aaSamw uint64_t llval; 56212b65585SGordon Ross uint8_t *bvalp; 56312b65585SGordon Ross char *cvalp; 564da6c28aaSamw uint8_t c; 56512b65585SGordon Ross boolean_t repc_specified; 56612b65585SGordon Ross int repc; 567da6c28aaSamw int rc; 568da6c28aaSamw 569da6c28aaSamw while ((c = *fmt++) != 0) { 57012b65585SGordon Ross repc_specified = B_FALSE; 571da6c28aaSamw repc = 1; 572da6c28aaSamw 573da6c28aaSamw if (c == ' ' || c == '\t') 574da6c28aaSamw continue; 575da6c28aaSamw 576da6c28aaSamw if (c == '(') { 577da6c28aaSamw while (((c = *fmt++) != 0) && c != ')') 578da6c28aaSamw ; 579da6c28aaSamw 580da6c28aaSamw if (!c) 581da6c28aaSamw return (SMB_MSGBUF_SUCCESS); 582da6c28aaSamw 583da6c28aaSamw continue; 584da6c28aaSamw } 585da6c28aaSamw 586da6c28aaSamw if ('0' <= c && c <= '9') { 587da6c28aaSamw repc = 0; 588da6c28aaSamw do { 589da6c28aaSamw repc = repc * 10 + c - '0'; 590da6c28aaSamw c = *fmt++; 591da6c28aaSamw } while ('0' <= c && c <= '9'); 59212b65585SGordon Ross repc_specified = B_TRUE; 593da6c28aaSamw } else if (c == '#') { 594da6c28aaSamw repc = va_arg(ap, int); 595da6c28aaSamw c = *fmt++; 59612b65585SGordon Ross repc_specified = B_TRUE; 597da6c28aaSamw } 598da6c28aaSamw 599da6c28aaSamw switch (c) { 600da6c28aaSamw case '.': 601da6c28aaSamw if (smb_msgbuf_has_space(mb, repc) == 0) 602da6c28aaSamw return (SMB_MSGBUF_OVERFLOW); 603da6c28aaSamw 604da6c28aaSamw while (repc-- > 0) 605da6c28aaSamw *mb->scan++ = 0; 606da6c28aaSamw break; 607da6c28aaSamw 60812b65585SGordon Ross case 'c': /* put char */ 609da6c28aaSamw if (smb_msgbuf_has_space(mb, repc) == 0) 610da6c28aaSamw return (SMB_MSGBUF_OVERFLOW); 611da6c28aaSamw 61212b65585SGordon Ross bvalp = va_arg(ap, uint8_t *); 61312b65585SGordon Ross bcopy(bvalp, mb->scan, repc); 614da6c28aaSamw mb->scan += repc; 615da6c28aaSamw break; 616da6c28aaSamw 61712b65585SGordon Ross case 'b': /* put byte */ 618da6c28aaSamw if (smb_msgbuf_has_space(mb, repc) == 0) 619da6c28aaSamw return (SMB_MSGBUF_OVERFLOW); 620da6c28aaSamw 621da6c28aaSamw while (repc-- > 0) { 622da6c28aaSamw cval = va_arg(ap, int); 623da6c28aaSamw *mb->scan++ = cval; 624da6c28aaSamw } 625da6c28aaSamw break; 626da6c28aaSamw 62712b65585SGordon Ross case 'w': /* put word */ 628da6c28aaSamw rc = smb_msgbuf_has_space(mb, repc * sizeof (uint16_t)); 629da6c28aaSamw if (rc == 0) 630da6c28aaSamw return (SMB_MSGBUF_OVERFLOW); 631da6c28aaSamw 632da6c28aaSamw while (repc-- > 0) { 633da6c28aaSamw wval = va_arg(ap, int); 634da6c28aaSamw LE_OUT16(mb->scan, wval); 635da6c28aaSamw mb->scan += sizeof (uint16_t); 636da6c28aaSamw } 637da6c28aaSamw break; 638da6c28aaSamw 63912b65585SGordon Ross case 'l': /* put long */ 640da6c28aaSamw rc = smb_msgbuf_has_space(mb, repc * sizeof (int32_t)); 641da6c28aaSamw if (rc == 0) 642da6c28aaSamw return (SMB_MSGBUF_OVERFLOW); 643da6c28aaSamw 644da6c28aaSamw while (repc-- > 0) { 645da6c28aaSamw lval = va_arg(ap, uint32_t); 646da6c28aaSamw LE_OUT32(mb->scan, lval); 647da6c28aaSamw mb->scan += sizeof (int32_t); 648da6c28aaSamw } 649da6c28aaSamw break; 650da6c28aaSamw 65112b65585SGordon Ross case 'q': /* put quad */ 652da6c28aaSamw rc = smb_msgbuf_has_space(mb, repc * sizeof (int64_t)); 653da6c28aaSamw if (rc == 0) 654da6c28aaSamw return (SMB_MSGBUF_OVERFLOW); 655da6c28aaSamw 656da6c28aaSamw while (repc-- > 0) { 657da6c28aaSamw llval = va_arg(ap, uint64_t); 658da6c28aaSamw LE_OUT64(mb->scan, llval); 659da6c28aaSamw mb->scan += sizeof (uint64_t); 660da6c28aaSamw } 661da6c28aaSamw break; 662da6c28aaSamw 663da6c28aaSamw case 'u': /* conditional unicode */ 664da6c28aaSamw if (mb->flags & SMB_MSGBUF_UNICODE) 665da6c28aaSamw goto unicode_translation; 666da6c28aaSamw /* FALLTHROUGH */ 667da6c28aaSamw 668*7d1ffc32SGordon Ross case 's': /* put OEM string */ 66912b65585SGordon Ross cvalp = va_arg(ap, char *); 670*7d1ffc32SGordon Ross if (!repc_specified) 671*7d1ffc32SGordon Ross repc = 0; 672*7d1ffc32SGordon Ross rc = msgbuf_put_oem_string(mb, cvalp, repc); 673*7d1ffc32SGordon Ross if (rc != 0) 674*7d1ffc32SGordon Ross return (rc); 675da6c28aaSamw break; 676da6c28aaSamw 677*7d1ffc32SGordon Ross case 'U': /* put UTF-16 string */ 678da6c28aaSamw unicode_translation: 67912b65585SGordon Ross cvalp = va_arg(ap, char *); 680*7d1ffc32SGordon Ross if (!repc_specified) 681*7d1ffc32SGordon Ross repc = 0; 682*7d1ffc32SGordon Ross rc = msgbuf_put_unicode_string(mb, cvalp, repc); 683*7d1ffc32SGordon Ross if (rc != 0) 684*7d1ffc32SGordon Ross return (rc); 685da6c28aaSamw break; 686da6c28aaSamw 687da6c28aaSamw case 'M': 688da6c28aaSamw if (smb_msgbuf_has_space(mb, 4) == 0) 689da6c28aaSamw return (SMB_MSGBUF_OVERFLOW); 690da6c28aaSamw 691da6c28aaSamw *mb->scan++ = 0xFF; 692da6c28aaSamw *mb->scan++ = 'S'; 693da6c28aaSamw *mb->scan++ = 'M'; 694da6c28aaSamw *mb->scan++ = 'B'; 695da6c28aaSamw break; 696da6c28aaSamw 697da6c28aaSamw default: 698da6c28aaSamw return (SMB_MSGBUF_INVALID_FORMAT); 699da6c28aaSamw } 700da6c28aaSamw } 701da6c28aaSamw 702da6c28aaSamw return (SMB_MSGBUF_SUCCESS); 703da6c28aaSamw } 704da6c28aaSamw 705*7d1ffc32SGordon Ross /* 706*7d1ffc32SGordon Ross * Marshal a UTF-8 string (str) into mbc, converting to OEM codeset. 707*7d1ffc32SGordon Ross * Also write a null unless the repc count limits the length we put. 708*7d1ffc32SGordon Ross * When (repc > 0) the length we marshal must be exactly repc, and 709*7d1ffc32SGordon Ross * truncate or pad the mb data as necessary. 710*7d1ffc32SGordon Ross * See also: mbc_marshal_put_oem_string 711*7d1ffc32SGordon Ross */ 712*7d1ffc32SGordon Ross static int 713*7d1ffc32SGordon Ross msgbuf_put_oem_string(smb_msgbuf_t *mb, char *mbs, int repc) 714*7d1ffc32SGordon Ross { 715*7d1ffc32SGordon Ross uint8_t *oembuf = NULL; 716*7d1ffc32SGordon Ross uint8_t *s; 717*7d1ffc32SGordon Ross int oemlen; 718*7d1ffc32SGordon Ross int rlen; 719*7d1ffc32SGordon Ross 720*7d1ffc32SGordon Ross /* 721*7d1ffc32SGordon Ross * Compute length of converted OEM string, 722*7d1ffc32SGordon Ross * NOT including null terminator 723*7d1ffc32SGordon Ross */ 724*7d1ffc32SGordon Ross if ((oemlen = smb_sbequiv_strlen(mbs)) == -1) 725*7d1ffc32SGordon Ross return (SMB_MSGBUF_DATA_ERROR); 726*7d1ffc32SGordon Ross 727*7d1ffc32SGordon Ross /* 728*7d1ffc32SGordon Ross * If repc not specified, put whole string + NULL, 729*7d1ffc32SGordon Ross * otherwise will truncate or pad as needed. 730*7d1ffc32SGordon Ross */ 731*7d1ffc32SGordon Ross if (repc <= 0) { 732*7d1ffc32SGordon Ross repc = oemlen; 733*7d1ffc32SGordon Ross if ((mb->flags & SMB_MSGBUF_NOTERM) == 0) 734*7d1ffc32SGordon Ross repc += sizeof (char); 735*7d1ffc32SGordon Ross } 736*7d1ffc32SGordon Ross if (smb_msgbuf_has_space(mb, repc) == 0) 737*7d1ffc32SGordon Ross return (SMB_MSGBUF_OVERFLOW); 738*7d1ffc32SGordon Ross 739*7d1ffc32SGordon Ross /* 740*7d1ffc32SGordon Ross * Convert into a temporary buffer 741*7d1ffc32SGordon Ross * Free oembuf in smb_msgbuf_term. 742*7d1ffc32SGordon Ross */ 743*7d1ffc32SGordon Ross oembuf = smb_msgbuf_malloc(mb, oemlen + 1); 744*7d1ffc32SGordon Ross if (oembuf == NULL) 745*7d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW); 746*7d1ffc32SGordon Ross rlen = smb_mbstooem(oembuf, mbs, oemlen); 747*7d1ffc32SGordon Ross if (rlen < 0) 748*7d1ffc32SGordon Ross return (SMB_MSGBUF_DATA_ERROR); 749*7d1ffc32SGordon Ross if (rlen > oemlen) 750*7d1ffc32SGordon Ross rlen = oemlen; 751*7d1ffc32SGordon Ross oembuf[rlen] = '\0'; 752*7d1ffc32SGordon Ross 753*7d1ffc32SGordon Ross /* 754*7d1ffc32SGordon Ross * Copy the converted string into the message, 755*7d1ffc32SGordon Ross * truncated or paded as required. 756*7d1ffc32SGordon Ross */ 757*7d1ffc32SGordon Ross s = oembuf; 758*7d1ffc32SGordon Ross while (repc > 0) { 759*7d1ffc32SGordon Ross *mb->scan++ = *s; 760*7d1ffc32SGordon Ross if (*s != '\0') 761*7d1ffc32SGordon Ross s++; 762*7d1ffc32SGordon Ross repc--; 763*7d1ffc32SGordon Ross } 764*7d1ffc32SGordon Ross 765*7d1ffc32SGordon Ross return (0); 766*7d1ffc32SGordon Ross } 767*7d1ffc32SGordon Ross 768*7d1ffc32SGordon Ross /* 769*7d1ffc32SGordon Ross * Marshal a UTF-8 string (str) into mbc, converting to UTF-16. 770*7d1ffc32SGordon Ross * Also write a null unless the repc count limits the length. 771*7d1ffc32SGordon Ross * When (repc > 0) the length we marshal must be exactly repc, 772*7d1ffc32SGordon Ross * and truncate or pad the mb data as necessary. 773*7d1ffc32SGordon Ross * See also: mbc_marshal_put_unicode_string 774*7d1ffc32SGordon Ross */ 775*7d1ffc32SGordon Ross static int 776*7d1ffc32SGordon Ross msgbuf_put_unicode_string(smb_msgbuf_t *mb, char *mbs, int repc) 777*7d1ffc32SGordon Ross { 778*7d1ffc32SGordon Ross smb_wchar_t *wcsbuf = NULL; 779*7d1ffc32SGordon Ross smb_wchar_t *wp; 780*7d1ffc32SGordon Ross size_t wcslen, wcsbytes; 781*7d1ffc32SGordon Ross size_t rlen; 782*7d1ffc32SGordon Ross 783*7d1ffc32SGordon Ross /* align to word boundary */ 784*7d1ffc32SGordon Ross smb_msgbuf_word_align(mb); 785*7d1ffc32SGordon Ross 786*7d1ffc32SGordon Ross /* 787*7d1ffc32SGordon Ross * Compute length of converted UTF-16 string, 788*7d1ffc32SGordon Ross * NOT including null terminator (in bytes). 789*7d1ffc32SGordon Ross */ 790*7d1ffc32SGordon Ross wcsbytes = smb_wcequiv_strlen(mbs); 791*7d1ffc32SGordon Ross if (wcsbytes == (size_t)-1) 792*7d1ffc32SGordon Ross return (SMB_MSGBUF_DATA_ERROR); 793*7d1ffc32SGordon Ross 794*7d1ffc32SGordon Ross /* 795*7d1ffc32SGordon Ross * If repc not specified, put whole string + NULL, 796*7d1ffc32SGordon Ross * otherwise will truncate or pad as needed. 797*7d1ffc32SGordon Ross */ 798*7d1ffc32SGordon Ross if (repc <= 0) { 799*7d1ffc32SGordon Ross repc = (int)wcsbytes; 800*7d1ffc32SGordon Ross if ((mb->flags & SMB_MSGBUF_NOTERM) == 0) 801*7d1ffc32SGordon Ross repc += sizeof (smb_wchar_t); 802*7d1ffc32SGordon Ross } 803*7d1ffc32SGordon Ross if (smb_msgbuf_has_space(mb, repc) == 0) 804*7d1ffc32SGordon Ross return (SMB_MSGBUF_OVERFLOW); 805*7d1ffc32SGordon Ross 806*7d1ffc32SGordon Ross /* 807*7d1ffc32SGordon Ross * Convert into a temporary buffer 808*7d1ffc32SGordon Ross * Free wcsbuf in smb_msgbuf_term 809*7d1ffc32SGordon Ross */ 810*7d1ffc32SGordon Ross wcslen = wcsbytes / 2; 811*7d1ffc32SGordon Ross wcsbuf = smb_msgbuf_malloc(mb, wcsbytes + 2); 812*7d1ffc32SGordon Ross if (wcsbuf == NULL) 813*7d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW); 814*7d1ffc32SGordon Ross rlen = smb_mbstowcs(wcsbuf, mbs, wcslen); 815*7d1ffc32SGordon Ross if (rlen == (size_t)-1) 816*7d1ffc32SGordon Ross return (SMB_MSGBUF_DATA_ERROR); 817*7d1ffc32SGordon Ross if (rlen > wcslen) 818*7d1ffc32SGordon Ross rlen = wcslen; 819*7d1ffc32SGordon Ross wcsbuf[rlen] = 0; 820*7d1ffc32SGordon Ross 821*7d1ffc32SGordon Ross /* 822*7d1ffc32SGordon Ross * Copy the converted string into the message, 823*7d1ffc32SGordon Ross * truncated or paded as required. Preserve 824*7d1ffc32SGordon Ross * little-endian order while copying. 825*7d1ffc32SGordon Ross */ 826*7d1ffc32SGordon Ross wp = wcsbuf; 827*7d1ffc32SGordon Ross while (repc > 1) { 828*7d1ffc32SGordon Ross smb_wchar_t wchar = LE_IN16(wp); 829*7d1ffc32SGordon Ross LE_OUT16(mb->scan, wchar); 830*7d1ffc32SGordon Ross mb->scan += 2; 831*7d1ffc32SGordon Ross if (wchar != 0) 832*7d1ffc32SGordon Ross wp++; 833*7d1ffc32SGordon Ross repc -= sizeof (smb_wchar_t); 834*7d1ffc32SGordon Ross } 835*7d1ffc32SGordon Ross if (repc > 0) 836*7d1ffc32SGordon Ross *mb->scan++ = '\0'; 837*7d1ffc32SGordon Ross 838*7d1ffc32SGordon Ross return (0); 839*7d1ffc32SGordon Ross } 840da6c28aaSamw 841da6c28aaSamw /* 842da6c28aaSamw * smb_msgbuf_malloc 843da6c28aaSamw * 844da6c28aaSamw * Allocate some memory for use with this smb_msgbuf. We increase the 845da6c28aaSamw * requested size to hold the list pointer and return a pointer 846da6c28aaSamw * to the area for use by the caller. 847da6c28aaSamw */ 848da6c28aaSamw static void * 849da6c28aaSamw smb_msgbuf_malloc(smb_msgbuf_t *mb, size_t size) 850da6c28aaSamw { 851da6c28aaSamw smb_msgbuf_mlist_t *item; 852da6c28aaSamw 853da6c28aaSamw size += sizeof (smb_msgbuf_mlist_t); 854da6c28aaSamw 855b819cea2SGordon Ross #if !defined(_KERNEL) && !defined(_FAKE_KERNEL) 856da6c28aaSamw if ((item = malloc(size)) == NULL) 857da6c28aaSamw return (NULL); 858da6c28aaSamw #else 859da6c28aaSamw item = kmem_alloc(size, KM_SLEEP); 860da6c28aaSamw #endif 861da6c28aaSamw item->next = mb->mlist.next; 862da6c28aaSamw item->size = size; 863da6c28aaSamw mb->mlist.next = item; 864da6c28aaSamw 865da6c28aaSamw /* 866da6c28aaSamw * The caller gets a pointer to the address 867da6c28aaSamw * immediately after the smb_msgbuf_mlist_t. 868da6c28aaSamw */ 869da6c28aaSamw return ((void *)(item + 1)); 870da6c28aaSamw } 871da6c28aaSamw 872da6c28aaSamw 873da6c28aaSamw /* 874da6c28aaSamw * smb_msgbuf_chkerc 875da6c28aaSamw * 876da6c28aaSamw * Diagnostic function to write an appropriate message to the system log. 877da6c28aaSamw */ 878da6c28aaSamw static int 879da6c28aaSamw smb_msgbuf_chkerc(char *text, int erc) 880da6c28aaSamw { 881da6c28aaSamw static struct { 882da6c28aaSamw int erc; 883da6c28aaSamw char *name; 884da6c28aaSamw } etable[] = { 885da6c28aaSamw { SMB_MSGBUF_SUCCESS, "success" }, 886da6c28aaSamw { SMB_MSGBUF_UNDERFLOW, "overflow/underflow" }, 887da6c28aaSamw { SMB_MSGBUF_INVALID_FORMAT, "invalid format" }, 888da6c28aaSamw { SMB_MSGBUF_INVALID_HEADER, "invalid header" }, 889da6c28aaSamw { SMB_MSGBUF_DATA_ERROR, "data error" } 890da6c28aaSamw }; 891da6c28aaSamw 892da6c28aaSamw int i; 893da6c28aaSamw 894da6c28aaSamw for (i = 0; i < sizeof (etable)/sizeof (etable[0]); ++i) { 895da6c28aaSamw if (etable[i].erc == erc) { 896da6c28aaSamw if (text == 0) 897da6c28aaSamw text = "smb_msgbuf_chkerc"; 898da6c28aaSamw break; 899da6c28aaSamw } 900da6c28aaSamw } 901da6c28aaSamw return (erc); 902da6c28aaSamw } 903