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