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*25a9a7aaSGordon Ross * Copyright 2019 Nexenta by DDN, 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
567d1ffc32SGordon Ross static int msgbuf_get_oem_string(smb_msgbuf_t *, char **, int);
577d1ffc32SGordon Ross static int msgbuf_get_unicode_string(smb_msgbuf_t *, char **, int);
587d1ffc32SGordon Ross static int msgbuf_put_oem_string(smb_msgbuf_t *, char *, int);
597d1ffc32SGordon Ross static int msgbuf_put_unicode_string(smb_msgbuf_t *, char *, int);
607d1ffc32SGordon Ross
617d1ffc32SGordon Ross
62da6c28aaSamw /*
63da6c28aaSamw * Returns the offset or number of bytes used within the buffer.
64da6c28aaSamw */
65da6c28aaSamw size_t
smb_msgbuf_used(smb_msgbuf_t * mb)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
smb_msgbuf_size(smb_msgbuf_t * mb)76da6c28aaSamw smb_msgbuf_size(smb_msgbuf_t *mb)
77da6c28aaSamw {
78da6c28aaSamw return (mb->max);
79da6c28aaSamw }
80da6c28aaSamw
81da6c28aaSamw uint8_t *
smb_msgbuf_base(smb_msgbuf_t * mb)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
smb_msgbuf_word_align(smb_msgbuf_t * mb)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
smb_msgbuf_dword_align(smb_msgbuf_t * mb)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
smb_msgbuf_has_space(smb_msgbuf_t * mb,size_t size)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
smb_msgbuf_fset(smb_msgbuf_t * mb,uint32_t flags)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
smb_msgbuf_fclear(smb_msgbuf_t * mb,uint32_t flags)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
smb_msgbuf_init(smb_msgbuf_t * mb,uint8_t * buf,size_t size,uint32_t flags)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
smb_msgbuf_term(smb_msgbuf_t * mb)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 *
1867d1ffc32SGordon Ross * On success, returns the number of bytes decoded. Otherwise
187da6c28aaSamw * returns a -ve error code.
188da6c28aaSamw */
189da6c28aaSamw int
smb_msgbuf_decode(smb_msgbuf_t * mb,char * fmt,...)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
buf_decode(smb_msgbuf_t * mb,char * fmt,va_list ap)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
3307d1ffc32SGordon Ross case 's': /* get OEM string */
33112b65585SGordon Ross cvalpp = va_arg(ap, char **);
3327d1ffc32SGordon Ross if (!repc_specified)
3337d1ffc32SGordon Ross repc = 0;
3347d1ffc32SGordon Ross rc = msgbuf_get_oem_string(mb, cvalpp, repc);
3357d1ffc32SGordon Ross if (rc != 0)
3367d1ffc32SGordon Ross return (rc);
337da6c28aaSamw break;
338da6c28aaSamw
3397d1ffc32SGordon Ross case 'U': /* get UTF-16 string */
340da6c28aaSamw unicode_translation:
34112b65585SGordon Ross cvalpp = va_arg(ap, char **);
3427d1ffc32SGordon Ross if (!repc_specified)
3437d1ffc32SGordon Ross repc = 0;
3447d1ffc32SGordon Ross rc = msgbuf_get_unicode_string(mb, cvalpp, repc);
3457d1ffc32SGordon Ross if (rc != 0)
3467d1ffc32SGordon 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
3707d1ffc32SGordon Ross /*
3717d1ffc32SGordon Ross * msgbuf_get_oem_string
3727d1ffc32SGordon Ross *
3737d1ffc32SGordon Ross * Decode an OEM string, returning its UTF-8 form in strpp,
3747d1ffc32SGordon Ross * allocated using smb_msgbuf_malloc (automatically freed).
3757d1ffc32SGordon Ross * If max_bytes != 0, consume at most max_bytes of the mb.
3767d1ffc32SGordon Ross * See also: mbc_marshal_get_oem_string
3777d1ffc32SGordon Ross */
3787d1ffc32SGordon Ross static int
msgbuf_get_oem_string(smb_msgbuf_t * mb,char ** strpp,int max_bytes)3797d1ffc32SGordon Ross msgbuf_get_oem_string(smb_msgbuf_t *mb, char **strpp, int max_bytes)
3807d1ffc32SGordon Ross {
3817d1ffc32SGordon Ross char *mbs;
3827d1ffc32SGordon Ross uint8_t *oembuf = NULL;
3837d1ffc32SGordon Ross int oemlen; // len of OEM string, w/o null
3847d1ffc32SGordon Ross int datalen; // OtW data len
3857d1ffc32SGordon Ross int mbsmax; // max len of ret str
3867d1ffc32SGordon Ross int rlen;
3877d1ffc32SGordon Ross
3887d1ffc32SGordon Ross if (max_bytes == 0)
3897d1ffc32SGordon Ross max_bytes = 0xffff;
3907d1ffc32SGordon Ross
3917d1ffc32SGordon Ross /*
3927d1ffc32SGordon Ross * Determine the OtW data length and OEM string length
3937d1ffc32SGordon Ross * Note: oemlen is the string length (w/o null) and
3947d1ffc32SGordon Ross * datalen is how much we move mb->scan
3957d1ffc32SGordon Ross */
3967d1ffc32SGordon Ross datalen = 0;
3977d1ffc32SGordon Ross oemlen = 0;
3987d1ffc32SGordon Ross for (;;) {
3997d1ffc32SGordon Ross if (datalen >= max_bytes)
4007d1ffc32SGordon Ross break;
4017d1ffc32SGordon Ross /* in-line smb_msgbuf_has_space */
4027d1ffc32SGordon Ross if ((mb->scan + datalen) >= mb->end)
4037d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW);
4047d1ffc32SGordon Ross datalen++;
4057d1ffc32SGordon Ross if (mb->scan[datalen - 1] == 0)
4067d1ffc32SGordon Ross break;
4077d1ffc32SGordon Ross oemlen++;
4087d1ffc32SGordon Ross }
4097d1ffc32SGordon Ross
4107d1ffc32SGordon Ross /*
4117d1ffc32SGordon Ross * Get datalen bytes into a temp buffer
4127d1ffc32SGordon Ross * sized with room to add a null.
4137d1ffc32SGordon Ross * Free oembuf in smb_msgbuf_term
4147d1ffc32SGordon Ross */
4157d1ffc32SGordon Ross oembuf = smb_msgbuf_malloc(mb, datalen + 1);
4167d1ffc32SGordon Ross if (oembuf == NULL)
4177d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW);
4187d1ffc32SGordon Ross bcopy(mb->scan, oembuf, datalen);
4197d1ffc32SGordon Ross mb->scan += datalen;
4207d1ffc32SGordon Ross oembuf[oemlen] = '\0';
4217d1ffc32SGordon Ross
4227d1ffc32SGordon Ross /*
4237d1ffc32SGordon Ross * Get the buffer we'll return and convert to UTF-8.
4247d1ffc32SGordon Ross * May take as much as double the space.
4257d1ffc32SGordon Ross */
4267d1ffc32SGordon Ross mbsmax = oemlen * 2;
4277d1ffc32SGordon Ross mbs = smb_msgbuf_malloc(mb, mbsmax + 1);
4287d1ffc32SGordon Ross if (mbs == NULL)
4297d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW);
4307d1ffc32SGordon Ross rlen = smb_oemtombs(mbs, oembuf, mbsmax);
4317d1ffc32SGordon Ross if (rlen < 0)
4327d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW);
4337d1ffc32SGordon Ross if (rlen > mbsmax)
4347d1ffc32SGordon Ross rlen = mbsmax;
4357d1ffc32SGordon Ross mbs[rlen] = '\0';
4367d1ffc32SGordon Ross *strpp = mbs;
4377d1ffc32SGordon Ross return (0);
4387d1ffc32SGordon Ross }
4397d1ffc32SGordon Ross
4407d1ffc32SGordon Ross /*
4417d1ffc32SGordon Ross * msgbuf_get_unicode_string
4427d1ffc32SGordon Ross *
4437d1ffc32SGordon Ross * Decode a UTF-16 string, returning its UTF-8 form in strpp,
4447d1ffc32SGordon Ross * allocated using smb_msgbuf_malloc (automatically freed).
4457d1ffc32SGordon Ross * If max_bytes != 0, consume at most max_bytes of the mb.
4467d1ffc32SGordon Ross * See also: mbc_marshal_get_unicode_string
4477d1ffc32SGordon Ross */
4487d1ffc32SGordon Ross static int
msgbuf_get_unicode_string(smb_msgbuf_t * mb,char ** strpp,int max_bytes)4497d1ffc32SGordon Ross msgbuf_get_unicode_string(smb_msgbuf_t *mb, char **strpp, int max_bytes)
4507d1ffc32SGordon Ross {
4517d1ffc32SGordon Ross char *mbs;
4527d1ffc32SGordon Ross uint16_t *wcsbuf = NULL;
4537d1ffc32SGordon Ross int wcslen; // wchar count
4547d1ffc32SGordon Ross int datalen; // OtW data len
4557d1ffc32SGordon Ross size_t mbsmax; // max len of ret str
4567d1ffc32SGordon Ross size_t rlen;
4577d1ffc32SGordon Ross
4587d1ffc32SGordon Ross if (max_bytes == 0)
4597d1ffc32SGordon Ross max_bytes = 0xffff;
4607d1ffc32SGordon Ross
4617d1ffc32SGordon Ross /*
4627d1ffc32SGordon Ross * Unicode strings are always word aligned.
4637d1ffc32SGordon Ross */
4647d1ffc32SGordon Ross smb_msgbuf_word_align(mb);
4657d1ffc32SGordon Ross
4667d1ffc32SGordon Ross /*
4677d1ffc32SGordon Ross * Determine the OtW data length and (WC) string length
4687d1ffc32SGordon Ross * Note: wcslen counts 16-bit wide_chars (w/o null),
4697d1ffc32SGordon Ross * and datalen is how much we move mb->scan
4707d1ffc32SGordon Ross */
4717d1ffc32SGordon Ross datalen = 0;
4727d1ffc32SGordon Ross wcslen = 0;
4737d1ffc32SGordon Ross for (;;) {
4747d1ffc32SGordon Ross if (datalen >= max_bytes)
4757d1ffc32SGordon Ross break;
4767d1ffc32SGordon Ross /* in-line smb_msgbuf_has_space */
4777d1ffc32SGordon Ross if ((mb->scan + datalen) >= mb->end)
4787d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW);
4797d1ffc32SGordon Ross datalen += 2;
4807d1ffc32SGordon Ross if (mb->scan[datalen - 2] == 0 &&
4817d1ffc32SGordon Ross mb->scan[datalen - 1] == 0)
4827d1ffc32SGordon Ross break;
4837d1ffc32SGordon Ross wcslen++;
4847d1ffc32SGordon Ross }
4857d1ffc32SGordon Ross
4867d1ffc32SGordon Ross /*
4877d1ffc32SGordon Ross * Get datalen bytes into a temp buffer
4887d1ffc32SGordon Ross * sized with room to add a (WC) null.
4897d1ffc32SGordon Ross * Note: wcsbuf has little-endian order
4907d1ffc32SGordon Ross */
4917d1ffc32SGordon Ross wcsbuf = smb_msgbuf_malloc(mb, datalen + 2);
4927d1ffc32SGordon Ross if (wcsbuf == NULL)
4937d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW);
4947d1ffc32SGordon Ross bcopy(mb->scan, wcsbuf, datalen);
4957d1ffc32SGordon Ross mb->scan += datalen;
4967d1ffc32SGordon Ross wcsbuf[wcslen] = 0;
4977d1ffc32SGordon Ross
4987d1ffc32SGordon Ross /*
4997d1ffc32SGordon Ross * Get the buffer we'll return and convert to UTF-8.
5007d1ffc32SGordon Ross * May take as much 4X number of wide chars.
5017d1ffc32SGordon Ross */
5027d1ffc32SGordon Ross mbsmax = wcslen * MTS_MB_CUR_MAX;
5037d1ffc32SGordon Ross mbs = smb_msgbuf_malloc(mb, mbsmax + 1);
5047d1ffc32SGordon Ross if (mbs == NULL)
5057d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW);
5067d1ffc32SGordon Ross rlen = smb_wcstombs(mbs, wcsbuf, mbsmax);
5077d1ffc32SGordon Ross if (rlen == (size_t)-1)
5087d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW);
5097d1ffc32SGordon Ross if (rlen > mbsmax)
5107d1ffc32SGordon Ross rlen = mbsmax;
5117d1ffc32SGordon Ross mbs[rlen] = '\0';
5127d1ffc32SGordon Ross *strpp = mbs;
5137d1ffc32SGordon Ross return (0);
5147d1ffc32SGordon 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
smb_msgbuf_encode(smb_msgbuf_t * mb,char * fmt,...)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
buf_encode(smb_msgbuf_t * mb,char * fmt,va_list ap)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
6687d1ffc32SGordon Ross case 's': /* put OEM string */
66912b65585SGordon Ross cvalp = va_arg(ap, char *);
6707d1ffc32SGordon Ross if (!repc_specified)
6717d1ffc32SGordon Ross repc = 0;
6727d1ffc32SGordon Ross rc = msgbuf_put_oem_string(mb, cvalp, repc);
6737d1ffc32SGordon Ross if (rc != 0)
6747d1ffc32SGordon Ross return (rc);
675da6c28aaSamw break;
676da6c28aaSamw
6777d1ffc32SGordon Ross case 'U': /* put UTF-16 string */
678da6c28aaSamw unicode_translation:
67912b65585SGordon Ross cvalp = va_arg(ap, char *);
6807d1ffc32SGordon Ross if (!repc_specified)
6817d1ffc32SGordon Ross repc = 0;
6827d1ffc32SGordon Ross rc = msgbuf_put_unicode_string(mb, cvalp, repc);
6837d1ffc32SGordon Ross if (rc != 0)
6847d1ffc32SGordon 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
7057d1ffc32SGordon Ross /*
7067d1ffc32SGordon Ross * Marshal a UTF-8 string (str) into mbc, converting to OEM codeset.
7077d1ffc32SGordon Ross * Also write a null unless the repc count limits the length we put.
7087d1ffc32SGordon Ross * When (repc > 0) the length we marshal must be exactly repc, and
7097d1ffc32SGordon Ross * truncate or pad the mb data as necessary.
7107d1ffc32SGordon Ross * See also: mbc_marshal_put_oem_string
7117d1ffc32SGordon Ross */
7127d1ffc32SGordon Ross static int
msgbuf_put_oem_string(smb_msgbuf_t * mb,char * mbs,int repc)7137d1ffc32SGordon Ross msgbuf_put_oem_string(smb_msgbuf_t *mb, char *mbs, int repc)
7147d1ffc32SGordon Ross {
7157d1ffc32SGordon Ross uint8_t *oembuf = NULL;
7167d1ffc32SGordon Ross uint8_t *s;
7177d1ffc32SGordon Ross int oemlen;
7187d1ffc32SGordon Ross int rlen;
7197d1ffc32SGordon Ross
7207d1ffc32SGordon Ross /*
7217d1ffc32SGordon Ross * Compute length of converted OEM string,
7227d1ffc32SGordon Ross * NOT including null terminator
7237d1ffc32SGordon Ross */
7247d1ffc32SGordon Ross if ((oemlen = smb_sbequiv_strlen(mbs)) == -1)
7257d1ffc32SGordon Ross return (SMB_MSGBUF_DATA_ERROR);
7267d1ffc32SGordon Ross
7277d1ffc32SGordon Ross /*
7287d1ffc32SGordon Ross * If repc not specified, put whole string + NULL,
7297d1ffc32SGordon Ross * otherwise will truncate or pad as needed.
7307d1ffc32SGordon Ross */
7317d1ffc32SGordon Ross if (repc <= 0) {
7327d1ffc32SGordon Ross repc = oemlen;
7337d1ffc32SGordon Ross if ((mb->flags & SMB_MSGBUF_NOTERM) == 0)
7347d1ffc32SGordon Ross repc += sizeof (char);
7357d1ffc32SGordon Ross }
7367d1ffc32SGordon Ross
7377d1ffc32SGordon Ross /*
7387d1ffc32SGordon Ross * Convert into a temporary buffer
7397d1ffc32SGordon Ross * Free oembuf in smb_msgbuf_term.
7407d1ffc32SGordon Ross */
7417d1ffc32SGordon Ross oembuf = smb_msgbuf_malloc(mb, oemlen + 1);
7427d1ffc32SGordon Ross if (oembuf == NULL)
7437d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW);
7447d1ffc32SGordon Ross rlen = smb_mbstooem(oembuf, mbs, oemlen);
7457d1ffc32SGordon Ross if (rlen < 0)
7467d1ffc32SGordon Ross return (SMB_MSGBUF_DATA_ERROR);
7477d1ffc32SGordon Ross if (rlen > oemlen)
7487d1ffc32SGordon Ross rlen = oemlen;
7497d1ffc32SGordon Ross oembuf[rlen] = '\0';
7507d1ffc32SGordon Ross
7517d1ffc32SGordon Ross /*
7527d1ffc32SGordon Ross * Copy the converted string into the message,
7537d1ffc32SGordon Ross * truncated or paded as required.
7547d1ffc32SGordon Ross */
7557d1ffc32SGordon Ross s = oembuf;
7567d1ffc32SGordon Ross while (repc > 0) {
757*25a9a7aaSGordon Ross if (smb_msgbuf_has_space(mb, 1) == 0)
758*25a9a7aaSGordon Ross return (SMB_MSGBUF_OVERFLOW);
7597d1ffc32SGordon Ross *mb->scan++ = *s;
7607d1ffc32SGordon Ross if (*s != '\0')
7617d1ffc32SGordon Ross s++;
7627d1ffc32SGordon Ross repc--;
7637d1ffc32SGordon Ross }
7647d1ffc32SGordon Ross
7657d1ffc32SGordon Ross return (0);
7667d1ffc32SGordon Ross }
7677d1ffc32SGordon Ross
7687d1ffc32SGordon Ross /*
7697d1ffc32SGordon Ross * Marshal a UTF-8 string (str) into mbc, converting to UTF-16.
7707d1ffc32SGordon Ross * Also write a null unless the repc count limits the length.
7717d1ffc32SGordon Ross * When (repc > 0) the length we marshal must be exactly repc,
7727d1ffc32SGordon Ross * and truncate or pad the mb data as necessary.
7737d1ffc32SGordon Ross * See also: mbc_marshal_put_unicode_string
7747d1ffc32SGordon Ross */
7757d1ffc32SGordon Ross static int
msgbuf_put_unicode_string(smb_msgbuf_t * mb,char * mbs,int repc)7767d1ffc32SGordon Ross msgbuf_put_unicode_string(smb_msgbuf_t *mb, char *mbs, int repc)
7777d1ffc32SGordon Ross {
7787d1ffc32SGordon Ross smb_wchar_t *wcsbuf = NULL;
7797d1ffc32SGordon Ross smb_wchar_t *wp;
780*25a9a7aaSGordon Ross smb_wchar_t wchar;
7817d1ffc32SGordon Ross size_t wcslen, wcsbytes;
7827d1ffc32SGordon Ross size_t rlen;
7837d1ffc32SGordon Ross
7847d1ffc32SGordon Ross /* align to word boundary */
7857d1ffc32SGordon Ross smb_msgbuf_word_align(mb);
7867d1ffc32SGordon Ross
7877d1ffc32SGordon Ross /*
7887d1ffc32SGordon Ross * Compute length of converted UTF-16 string,
7897d1ffc32SGordon Ross * NOT including null terminator (in bytes).
7907d1ffc32SGordon Ross */
7917d1ffc32SGordon Ross wcsbytes = smb_wcequiv_strlen(mbs);
7927d1ffc32SGordon Ross if (wcsbytes == (size_t)-1)
7937d1ffc32SGordon Ross return (SMB_MSGBUF_DATA_ERROR);
7947d1ffc32SGordon Ross
7957d1ffc32SGordon Ross /*
7967d1ffc32SGordon Ross * If repc not specified, put whole string + NULL,
7977d1ffc32SGordon Ross * otherwise will truncate or pad as needed.
7987d1ffc32SGordon Ross */
7997d1ffc32SGordon Ross if (repc <= 0) {
8007d1ffc32SGordon Ross repc = (int)wcsbytes;
8017d1ffc32SGordon Ross if ((mb->flags & SMB_MSGBUF_NOTERM) == 0)
8027d1ffc32SGordon Ross repc += sizeof (smb_wchar_t);
8037d1ffc32SGordon Ross }
8047d1ffc32SGordon Ross
8057d1ffc32SGordon Ross /*
8067d1ffc32SGordon Ross * Convert into a temporary buffer
8077d1ffc32SGordon Ross * Free wcsbuf in smb_msgbuf_term
8087d1ffc32SGordon Ross */
8097d1ffc32SGordon Ross wcslen = wcsbytes / 2;
8107d1ffc32SGordon Ross wcsbuf = smb_msgbuf_malloc(mb, wcsbytes + 2);
8117d1ffc32SGordon Ross if (wcsbuf == NULL)
8127d1ffc32SGordon Ross return (SMB_MSGBUF_UNDERFLOW);
8137d1ffc32SGordon Ross rlen = smb_mbstowcs(wcsbuf, mbs, wcslen);
8147d1ffc32SGordon Ross if (rlen == (size_t)-1)
8157d1ffc32SGordon Ross return (SMB_MSGBUF_DATA_ERROR);
8167d1ffc32SGordon Ross if (rlen > wcslen)
8177d1ffc32SGordon Ross rlen = wcslen;
8187d1ffc32SGordon Ross wcsbuf[rlen] = 0;
8197d1ffc32SGordon Ross
8207d1ffc32SGordon Ross /*
8217d1ffc32SGordon Ross * Copy the converted string into the message,
8227d1ffc32SGordon Ross * truncated or paded as required. Preserve
8237d1ffc32SGordon Ross * little-endian order while copying.
8247d1ffc32SGordon Ross */
8257d1ffc32SGordon Ross wp = wcsbuf;
826*25a9a7aaSGordon Ross while (repc >= sizeof (smb_wchar_t)) {
827*25a9a7aaSGordon Ross if (smb_msgbuf_has_space(mb, sizeof (smb_wchar_t)) == 0)
828*25a9a7aaSGordon Ross return (SMB_MSGBUF_OVERFLOW);
829*25a9a7aaSGordon Ross wchar = LE_IN16(wp);
8307d1ffc32SGordon Ross LE_OUT16(mb->scan, wchar);
8317d1ffc32SGordon Ross mb->scan += 2;
8327d1ffc32SGordon Ross if (wchar != 0)
8337d1ffc32SGordon Ross wp++;
8347d1ffc32SGordon Ross repc -= sizeof (smb_wchar_t);
8357d1ffc32SGordon Ross }
836*25a9a7aaSGordon Ross if (repc > 0) {
837*25a9a7aaSGordon Ross if (smb_msgbuf_has_space(mb, 1) == 0)
838*25a9a7aaSGordon Ross return (SMB_MSGBUF_OVERFLOW);
8397d1ffc32SGordon Ross *mb->scan++ = '\0';
840*25a9a7aaSGordon Ross }
8417d1ffc32SGordon Ross
8427d1ffc32SGordon Ross return (0);
8437d1ffc32SGordon Ross }
844da6c28aaSamw
845da6c28aaSamw /*
846da6c28aaSamw * smb_msgbuf_malloc
847da6c28aaSamw *
848da6c28aaSamw * Allocate some memory for use with this smb_msgbuf. We increase the
849da6c28aaSamw * requested size to hold the list pointer and return a pointer
850da6c28aaSamw * to the area for use by the caller.
851da6c28aaSamw */
852da6c28aaSamw static void *
smb_msgbuf_malloc(smb_msgbuf_t * mb,size_t size)853da6c28aaSamw smb_msgbuf_malloc(smb_msgbuf_t *mb, size_t size)
854da6c28aaSamw {
855da6c28aaSamw smb_msgbuf_mlist_t *item;
856da6c28aaSamw
857da6c28aaSamw size += sizeof (smb_msgbuf_mlist_t);
858da6c28aaSamw
859b819cea2SGordon Ross #if !defined(_KERNEL) && !defined(_FAKE_KERNEL)
860da6c28aaSamw if ((item = malloc(size)) == NULL)
861da6c28aaSamw return (NULL);
862da6c28aaSamw #else
863da6c28aaSamw item = kmem_alloc(size, KM_SLEEP);
864da6c28aaSamw #endif
865da6c28aaSamw item->next = mb->mlist.next;
866da6c28aaSamw item->size = size;
867da6c28aaSamw mb->mlist.next = item;
868da6c28aaSamw
869da6c28aaSamw /*
870da6c28aaSamw * The caller gets a pointer to the address
871da6c28aaSamw * immediately after the smb_msgbuf_mlist_t.
872da6c28aaSamw */
873da6c28aaSamw return ((void *)(item + 1));
874da6c28aaSamw }
875da6c28aaSamw
876da6c28aaSamw
877da6c28aaSamw /*
878da6c28aaSamw * smb_msgbuf_chkerc
879da6c28aaSamw *
880da6c28aaSamw * Diagnostic function to write an appropriate message to the system log.
881da6c28aaSamw */
882da6c28aaSamw static int
smb_msgbuf_chkerc(char * text,int erc)883da6c28aaSamw smb_msgbuf_chkerc(char *text, int erc)
884da6c28aaSamw {
885da6c28aaSamw static struct {
886da6c28aaSamw int erc;
887da6c28aaSamw char *name;
888da6c28aaSamw } etable[] = {
889da6c28aaSamw { SMB_MSGBUF_SUCCESS, "success" },
890da6c28aaSamw { SMB_MSGBUF_UNDERFLOW, "overflow/underflow" },
891da6c28aaSamw { SMB_MSGBUF_INVALID_FORMAT, "invalid format" },
892da6c28aaSamw { SMB_MSGBUF_INVALID_HEADER, "invalid header" },
893da6c28aaSamw { SMB_MSGBUF_DATA_ERROR, "data error" }
894da6c28aaSamw };
895da6c28aaSamw
896da6c28aaSamw int i;
897da6c28aaSamw
898da6c28aaSamw for (i = 0; i < sizeof (etable)/sizeof (etable[0]); ++i) {
899da6c28aaSamw if (etable[i].erc == erc) {
900da6c28aaSamw if (text == 0)
901da6c28aaSamw text = "smb_msgbuf_chkerc";
902da6c28aaSamw break;
903da6c28aaSamw }
904da6c28aaSamw }
905da6c28aaSamw return (erc);
906da6c28aaSamw }
907