1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * SMB mbuf marshaling encode/decode.
28 */
29
30 #include <smbsrv/smb_kproto.h>
31
32
33 #define MALLOC_QUANTUM 80
34
35 #define DECODE_NO_ERROR 0
36 #define DECODE_NO_MORE_DATA 1
37 #define DECODE_ALLOCATION_ERROR 2
38 #define DECODE_CONVERSION_ERROR 3
39
40 static int mbc_marshal_cstou8(char *, char *, size_t, char *, size_t);
41 static int mbc_marshal_make_room(mbuf_chain_t *, int32_t);
42 static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t);
43 static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t);
44 static int mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t);
45 static int mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t);
46 static int mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t);
47 static int mbc_marshal_put_ascii_string(mbuf_chain_t *, char *, int);
48 static int mbc_marshal_put_unicode_string(mbuf_chain_t *, char *, int);
49 static int mbc_marshal_put_uio(mbuf_chain_t *, struct uio *);
50 static int mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m);
51 static int mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc);
52 static uint8_t mbc_marshal_fetch_byte(mbuf_chain_t *mbc);
53 static int mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data);
54 static int mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data);
55 static int mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data);
56 static uint64_t qswap(uint64_t ll);
57 static int mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data);
58 static int mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data);
59 static int mbc_marshal_get_ascii_string(smb_request_t *, mbuf_chain_t *,
60 uint8_t **ascii, int);
61 static int mbc_marshal_get_unicode_string(smb_request_t *, mbuf_chain_t *,
62 uint8_t **, int);
63 static int mbc_marshal_get_mbufs(mbuf_chain_t *, int32_t, mbuf_t **);
64 static int mbc_marshal_get_mbuf_chain(mbuf_chain_t *, int32_t, mbuf_chain_t *);
65 static int mbc_marshal_get_uio(mbuf_chain_t *, struct uio *);
66 static int mbc_marshal_get_skip(mbuf_chain_t *, uint_t);
67
68 /*
69 * smb_mbc_vdecodef
70 *
71 * This function reads the contents of the mbc chain passed in under the list
72 * of arguments passed in.
73 *
74 * The format string provides a description of the parameters passed in as well
75 * as an action to be taken by smb_mbc_vdecodef().
76 *
77 * % Pointer to an SMB request structure (smb_request_t *). There
78 * should be only one of these in the string.
79 *
80 * C Pointer to an mbuf chain. Copy to that mbuf chain the number of
81 * bytes specified (number preceding C).
82 *
83 * m Pointer to an mbuf. Copy to that mbuf the number of bytes
84 * specified (number preceding m).
85 *
86 * M Read the 32 bit value at the current location of the mbuf chain
87 * and check if it matches the signature of an SMB request (SMBX).
88 *
89 * b Pointer to a buffer. Copy to that buffer the number of bytes
90 * specified (number preceding b).
91 *
92 * c Same as 'b'.
93 *
94 * w Pointer to a word (16bit value). Copy the next 16bit value into
95 * that location.
96 *
97 * l Pointer to a long (32bit value). Copy the next 32bit value into
98 * that location.
99 *
100 * q Pointer to a quad (64bit value). Copy the next 64bit value into
101 * that location.
102 *
103 * Q Same as above with a call to qswap().
104 *
105 * B Pointer to a vardata_block structure. That structure is used to
106 * retrieve data from the mbuf chain (an iovec type structure is
107 * embedded in a vardata_block).
108 *
109 * D Pointer to a vardata_block structure. That structure is used to
110 * retrieve data from the mbuf chain, however, two fields of the
111 * vardata_block structure (tag and len) are first initialized
112 * using the mbuf chain itself.
113 *
114 * V Same as 'D'.
115 *
116 * L
117 *
118 * A
119 *
120 * P Same as 'A'
121 *
122 * S Same as 'A'
123 *
124 * u Pointer to a string pointer. Allocate memory and retrieve the
125 * string at the current location in the mbuf chain. Store the
126 * address to the buffer allocated at the address specified by
127 * the pointer. In addition if an sr was passed and it indicates
128 * that the string is an unicode string, convert it.
129 *
130 * s Same as 'u' without convertion.
131 *
132 * U Same as 'u'. The string to retrieve is unicode.
133 *
134 * y Pointer to a 32bit value. Read the dos time at the current mbuf
135 * chain location, convert it to unix time and store it at the
136 * location indicated by the pointer.
137 *
138 * Y Same as 'y' bt the dos time coded in the mbuf chain is inverted.
139 *
140 * . Skip the number of bytes indicated by the number preceding '.'.
141 *
142 * , Same as '.' but take in account it is an unicode string.
143 */
144 int
smb_mbc_vdecodef(mbuf_chain_t * mbc,char * fmt,va_list ap)145 smb_mbc_vdecodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
146 {
147 uint8_t c;
148 uint8_t cval;
149 uint8_t *cvalp;
150 uint8_t **cvalpp;
151 uint16_t wval;
152 uint16_t *wvalp;
153 uint32_t *lvalp;
154 uint64_t *llvalp;
155 smb_vdb_t *vdp;
156 smb_request_t *sr = NULL;
157 uint32_t lval;
158 int unicode = 0;
159 int repc;
160
161 while ((c = *fmt++) != 0) {
162 repc = 1;
163
164 if ('0' <= c && c <= '9') {
165 repc = 0;
166 do {
167 repc = repc * 10 + c - '0';
168 c = *fmt++;
169 } while ('0' <= c && c <= '9');
170 } else if (c == '#') {
171 repc = va_arg(ap, int);
172 c = *fmt++;
173 }
174
175 switch (c) {
176 case '%':
177 sr = va_arg(ap, struct smb_request *);
178 unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
179 break;
180
181 case 'C': /* Mbuf_chain */
182 if (mbc_marshal_get_mbuf_chain(mbc, repc,
183 va_arg(ap, mbuf_chain_t *)) != 0)
184 return (-1);
185 break;
186
187 case 'm': /* struct_mbuf */
188 if (mbc_marshal_get_mbufs(mbc, repc,
189 va_arg(ap, mbuf_t **)) != 0)
190 return (-1);
191 break;
192
193 case 'M':
194 if (mbc_marshal_get_long(mbc, &lval) != 0)
195 /* Data will never be available */
196 return (-1);
197
198 if (lval != 0x424D53FF) /* 0xFF S M B */
199 return (-1);
200 break;
201
202 case 'b':
203 case 'c':
204 cvalp = va_arg(ap, uint8_t *);
205 if (MBC_ROOM_FOR(mbc, repc) == 0)
206 /* Data will never be available */
207 return (-1);
208
209 while (repc-- > 0)
210 *cvalp++ = mbc_marshal_fetch_byte(mbc);
211 break;
212
213 case 'w':
214 wvalp = va_arg(ap, uint16_t *);
215 while (repc-- > 0)
216 if (mbc_marshal_get_short(mbc, wvalp++) != 0)
217 return (-1);
218 break;
219
220 case 'l':
221 lvalp = va_arg(ap, uint32_t *);
222 while (repc-- > 0)
223 if (mbc_marshal_get_long(mbc, lvalp++) != 0)
224 return (-1);
225 break;
226
227 case 'q':
228 llvalp = va_arg(ap, uint64_t *);
229 while (repc-- > 0)
230 if (mbc_marshal_get_long_long(
231 mbc, llvalp++) != 0)
232 return (-1);
233 break;
234
235 case 'Q':
236 llvalp = va_arg(ap, uint64_t *);
237 while (repc-- > 0)
238 if (mbc_marshal_get_odd_long_long(
239 mbc, llvalp++) != 0)
240 return (-1);
241 break;
242
243 case 'B':
244 vdp = va_arg(ap, struct vardata_block *);
245 vdp->vdb_tag = 0;
246 vdp->vdb_len = repc;
247 vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0];
248 vdp->vdb_uio.uio_iovcnt = MAX_IOVEC;
249 vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
250 vdp->vdb_uio.uio_resid = repc;
251 if (mbc_marshal_get_uio(mbc, &vdp->vdb_uio) != 0)
252 return (-1);
253 break;
254
255 case 'D':
256 case 'V':
257 vdp = va_arg(ap, struct vardata_block *);
258 if (mbc_marshal_get_char(mbc, &vdp->vdb_tag) != 0)
259 return (-1);
260 if (mbc_marshal_get_short(mbc, &wval) != 0)
261 return (-1);
262 vdp->vdb_len = (uint32_t)wval;
263 vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0];
264 vdp->vdb_uio.uio_iovcnt = MAX_IOVEC;
265 vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
266 vdp->vdb_uio.uio_resid = vdp->vdb_len;
267 if (vdp->vdb_len != 0) {
268 if (mbc_marshal_get_uio(mbc,
269 &vdp->vdb_uio) != 0)
270 return (-1);
271 }
272 break;
273
274 case 'L':
275 if (mbc_marshal_get_char(mbc, &cval) != 0)
276 return (-1);
277 if (cval != 2)
278 return (-1);
279 goto ascii_conversion;
280
281 case 'A':
282 case 'S':
283 if (mbc_marshal_get_char(mbc, &cval) != 0)
284 return (-1);
285 if (((c == 'A' || c == 'S') && cval != 4) ||
286 (c == 'L' && cval != 2))
287 return (-1);
288 /* FALLTHROUGH */
289
290 case 'u': /* Convert from unicode if flags are set */
291 if (unicode)
292 goto unicode_translation;
293 /* FALLTHROUGH */
294
295 case 's':
296 ascii_conversion:
297 ASSERT(sr != NULL);
298 cvalpp = va_arg(ap, uint8_t **);
299 if (repc <= 1)
300 repc = 0;
301 if (mbc_marshal_get_ascii_string(sr,
302 mbc, cvalpp, repc) != 0)
303 return (-1);
304 break;
305
306 case 'U': /* Convert from unicode */
307 unicode_translation:
308 ASSERT(sr != 0);
309 cvalpp = va_arg(ap, uint8_t **);
310 if (repc <= 1)
311 repc = 0;
312 if (mbc->chain_offset & 1)
313 mbc->chain_offset++;
314 if (mbc_marshal_get_unicode_string(sr,
315 mbc, cvalpp, repc) != 0)
316 return (-1);
317 break;
318
319 case 'Y': /* dos time to unix time tt/dd */
320 lvalp = va_arg(ap, uint32_t *);
321 while (repc-- > 0) {
322 short d, t;
323
324 if (mbc_marshal_get_short(mbc,
325 (uint16_t *)&t) != 0)
326 return (-1);
327 if (mbc_marshal_get_short(mbc,
328 (uint16_t *)&d) != 0)
329 return (-1);
330 *lvalp++ = smb_time_dos_to_unix(d, t);
331 }
332 break;
333
334 case 'y': /* dos time to unix time dd/tt */
335 lvalp = va_arg(ap, uint32_t *);
336 while (repc-- > 0) {
337 short d, t;
338
339 if (mbc_marshal_get_short(mbc,
340 (uint16_t *)&d) != 0)
341 return (-1);
342 if (mbc_marshal_get_short(mbc,
343 (uint16_t *)&t) != 0)
344 return (-1);
345 *lvalp++ = smb_time_dos_to_unix(d, t);
346 }
347 break;
348
349 case ',':
350 if (unicode)
351 repc *= 2;
352 /* FALLTHROUGH */
353
354 case '.':
355 if (mbc_marshal_get_skip(mbc, repc) != 0)
356 return (-1);
357 break;
358
359 default:
360 ASSERT(0);
361 return (-1);
362 }
363 }
364 return (0);
365 }
366
367 /*
368 * smb_mbc_decodef
369 *
370 * This function reads the contents of the mbc chain passed in under the
371 * control of the format fmt.
372 *
373 * (for a description of the format string see smb_mbc_vencodef()).
374 */
375 int
smb_mbc_decodef(mbuf_chain_t * mbc,char * fmt,...)376 smb_mbc_decodef(mbuf_chain_t *mbc, char *fmt, ...)
377 {
378 int xx;
379 va_list ap;
380
381 va_start(ap, fmt);
382 xx = smb_mbc_vdecodef(mbc, fmt, ap);
383 va_end(ap);
384 return (xx);
385 }
386
387 /*
388 * smb_mbc_peek
389 *
390 * This function reads the contents of the mbc passed in at the specified offset
391 * under the control of the format fmt. The offset of the chain passed in is not
392 * modified.
393 *
394 * (for a description of the format string see smb_mbc_vdecodef()).
395 */
396 int
smb_mbc_peek(mbuf_chain_t * mbc,int offset,char * fmt,...)397 smb_mbc_peek(mbuf_chain_t *mbc, int offset, char *fmt, ...)
398 {
399 mbuf_chain_t tmp;
400 va_list ap;
401 int xx;
402
403 va_start(ap, fmt);
404
405 (void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset);
406 xx = smb_mbc_vdecodef(&tmp, fmt, ap);
407 va_end(ap);
408 return (xx);
409 }
410
411 /*
412 * smb_mbc_vencodef
413 *
414 * This function builds a stream of bytes in the mbc chain passed in under the
415 * control of the list of arguments passed in.
416 *
417 * The format string provides a description of the parameters passed in as well
418 * as an action to be taken by smb_mbc_vencodef().
419 *
420 * \b Restore the mbuf chain offset to its initial value.
421 *
422 * % Pointer to an SMB request structure (smb_request_t *). There
423 * should be only one of these in the string. If an sr in present
424 * it will be used to determine if unicode conversion should be
425 * applied to the strings.
426 *
427 * C Pointer to an mbuf chain. Copy that mbuf chain into the
428 * destination mbuf chain.
429 *
430 * D Pointer to a vardata_block structure. Copy the data described
431 * by that structure into the mbuf chain. The tag field is hard
432 * coded to '1'.
433 *
434 * M Write the SMB request signature ('SMBX') into the mbuf chain.
435 *
436 * T Pointer to a timestruc_t. Convert the content of the structure
437 * into NT time and store the result of the conversion in the
438 * mbuf chain.
439 *
440 * V Same as 'D' but the tag field is hard coded to '5'.
441 *
442 * b Byte. Store the byte or the nymber of bytes specified into the
443 * the mbuf chain. A format string like this "2b" would require 2
444 * bytes to be passed in.
445 *
446 * m Pointer to an mbuf. Copy the contents of the mbuf into the mbuf
447 * chain.
448 *
449 * c Pointer to a buffer. Copy the buffer into the mbuf chain. The
450 * size of the buffer is indicated by the number preceding 'c'.
451 *
452 * w Word (16bit value). Store the word or the number of words
453 * specified into the the mbuf chain. A format string like this
454 * "2w" would require 2 words to be passed in.
455 *
456 * l Long (32bit value). Store the long or the number of longs
457 * specified into the the mbuf chain. A format string like this
458 * "2l" would require 2 longs to be passed in.
459 *
460 * q Quad (64bit value). Store the quad or the number of quads
461 * specified into the the mbuf chain. A format string like this
462 * "2q" would require 2 quads to be passed in.
463 *
464 * L Pointer to a string. Store the string passed in into the mbuf
465 * chain preceded with a tag value of '2'.
466 *
467 * S Pointer to a string. Store the string passed in into the mbuf
468 * chain preceded with a tag value of '4'. Applied a unicode
469 * conversion is appropriate.
470 *
471 * A Same as 'S'
472 *
473 * P Pointer to a string. Store the string passed in into the mbuf
474 * chain preceded with a tag value of '5'. Applied a unicode
475 * conversion is appropriate.
476 *
477 * u Pointer to a string. Store the string passed in into the mbuf
478 * chain. Applied a unicode conversion is appropriate.
479 *
480 * s Pointer to a string. Store the string passed in into the mbuf
481 * chain.
482 *
483 * Y Date/Time. Store the Date/Time or the number of Date/Time(s)
484 * specified into the the mbuf chain. A format string like this
485 * "2Y" would require 2 Date/Time values. The Date/Time is
486 * converted to DOS before storing.
487 *
488 * y Same as 'Y'. The order of Date and Time is reversed.
489 *
490 * , Character. Store the character or number of character specified
491 * into the mbuf chain. A format string like this "2c" would
492 * require 2 characters to be passed in. A unicode conversion is
493 * applied if appropriate.
494 *
495 * . Same as '`' without unicode conversion.
496 *
497 * U Align the offset of the mbuf chain on a 16bit boundary.
498 */
499 int
smb_mbc_vencodef(mbuf_chain_t * mbc,char * fmt,va_list ap)500 smb_mbc_vencodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
501 {
502 uint8_t *cvalp;
503 timestruc_t *tvp;
504 smb_vdb_t *vdp;
505 smb_request_t *sr = NULL;
506 uint64_t llval;
507 int64_t nt_time;
508 uint32_t lval;
509 uint_t tag;
510 int unicode = 0;
511 int repc = 1;
512 uint16_t wval;
513 uint8_t cval;
514 uint8_t c;
515
516 while ((c = *fmt++) != 0) {
517 repc = 1;
518
519 if ('0' <= c && c <= '9') {
520 repc = 0;
521 do {
522 repc = repc * 10 + c - '0';
523 c = *fmt++;
524 } while ('0' <= c && c <= '9');
525 } else if (c == '#') {
526 repc = va_arg(ap, int);
527 c = *fmt++;
528 }
529
530 switch (c) {
531 case '%':
532 sr = va_arg(ap, struct smb_request *);
533 unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
534 break;
535
536 case 'C': /* Mbuf_chain */
537 if (mbc_marshal_put_mbuf_chain(mbc,
538 va_arg(ap, mbuf_chain_t *)) != 0)
539 return (DECODE_NO_MORE_DATA);
540 break;
541
542 case 'D':
543 vdp = va_arg(ap, struct vardata_block *);
544
545 if (mbc_marshal_put_char(mbc, 1) != 0)
546 return (DECODE_NO_MORE_DATA);
547 if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0)
548 return (DECODE_NO_MORE_DATA);
549 if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0)
550 return (DECODE_NO_MORE_DATA);
551 break;
552
553 case 'M':
554 /* 0xFF S M B */
555 if (mbc_marshal_put_long(mbc, 0x424D53FF))
556 return (DECODE_NO_MORE_DATA);
557 break;
558
559 case 'T':
560 tvp = va_arg(ap, timestruc_t *);
561 nt_time = smb_time_unix_to_nt(tvp);
562 if (mbc_marshal_put_long_long(mbc, nt_time) != 0)
563 return (DECODE_NO_MORE_DATA);
564 break;
565
566 case 'V':
567 vdp = va_arg(ap, struct vardata_block *);
568
569 if (mbc_marshal_put_char(mbc, 5) != 0)
570 return (DECODE_NO_MORE_DATA);
571 if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0)
572 return (DECODE_NO_MORE_DATA);
573 if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0)
574 return (DECODE_NO_MORE_DATA);
575 break;
576
577 case 'b':
578 while (repc-- > 0) {
579 cval = va_arg(ap, int);
580 if (mbc_marshal_put_char(mbc, cval) != 0)
581 return (DECODE_NO_MORE_DATA);
582 }
583 break;
584
585 case 'm': /* struct_mbuf */
586 if (mbc_marshal_put_mbufs(mbc,
587 va_arg(ap, mbuf_t *)) != 0)
588 return (DECODE_NO_MORE_DATA);
589 break;
590
591 case 'c':
592 cvalp = va_arg(ap, uint8_t *);
593 while (repc-- > 0) {
594 if (mbc_marshal_put_char(mbc,
595 *cvalp++) != 0)
596 return (DECODE_NO_MORE_DATA);
597 }
598 break;
599
600 case 'w':
601 while (repc-- > 0) {
602 wval = va_arg(ap, int);
603 if (mbc_marshal_put_short(mbc, wval) != 0)
604 return (DECODE_NO_MORE_DATA);
605 }
606 break;
607
608 case 'l':
609 while (repc-- > 0) {
610 lval = va_arg(ap, uint32_t);
611 if (mbc_marshal_put_long(mbc, lval) != 0)
612 return (DECODE_NO_MORE_DATA);
613 }
614 break;
615
616 case 'q':
617 while (repc-- > 0) {
618 llval = va_arg(ap, uint64_t);
619 if (mbc_marshal_put_long_long(mbc, llval) != 0)
620 return (DECODE_NO_MORE_DATA);
621 }
622 break;
623
624
625 case 'L':
626 tag = 2;
627 goto ascii_conversion;
628
629 case 'S':
630 case 'A':
631 tag = 4;
632 goto tagged_str;
633
634 case 'P':
635 tag = 3;
636 goto tagged_str;
637
638 tagged_str:
639 if (mbc_marshal_put_char(mbc, tag) != 0)
640 return (DECODE_NO_MORE_DATA);
641 /* FALLTHROUGH */
642
643 case 'u': /* Convert from unicode if flags are set */
644 if (unicode)
645 goto unicode_translation;
646 /* FALLTHROUGH */
647
648 case 's': /* ASCII/multibyte string */
649 ascii_conversion: cvalp = va_arg(ap, uint8_t *);
650 if (mbc_marshal_put_ascii_string(mbc,
651 (char *)cvalp, repc) != 0)
652 return (DECODE_NO_MORE_DATA);
653 break;
654
655 case 'Y': /* int32_t, encode dos date/time */
656 while (repc-- > 0) {
657 uint16_t d, t;
658
659 lval = va_arg(ap, uint32_t);
660 smb_time_unix_to_dos(lval,
661 (short *)&d, (short *)&t);
662 if (mbc_marshal_put_short(mbc, t) != 0)
663 return (DECODE_NO_MORE_DATA);
664 if (mbc_marshal_put_short(mbc, d) != 0)
665 return (DECODE_NO_MORE_DATA);
666 }
667 break;
668
669 case 'y': /* int32_t, encode dos date/time */
670 while (repc-- > 0) {
671 uint16_t d, t;
672
673 lval = va_arg(ap, uint32_t);
674 smb_time_unix_to_dos(lval,
675 (short *)&d, (short *)&t);
676 if (mbc_marshal_put_short(mbc, d) != 0)
677 return (DECODE_NO_MORE_DATA);
678 if (mbc_marshal_put_short(mbc, t) != 0)
679 return (DECODE_NO_MORE_DATA);
680 }
681 break;
682
683 case ',':
684 if (unicode)
685 repc *= 2;
686 /* FALLTHROUGH */
687
688 case '.':
689 while (repc-- > 0)
690 if (mbc_marshal_put_char(mbc, 0) != 0)
691 return (DECODE_NO_MORE_DATA);
692 break;
693
694 case 'U': /* Convert to unicode, align to word boundary */
695 unicode_translation:
696 if (mbc->chain_offset & 1)
697 mbc->chain_offset++;
698 cvalp = va_arg(ap, uint8_t *);
699 if (mbc_marshal_put_unicode_string(mbc,
700 (char *)cvalp, repc) != 0)
701 return (DECODE_NO_MORE_DATA);
702 break;
703
704 default:
705 ASSERT(0);
706 return (-1);
707 }
708 }
709 return (0);
710 }
711
712 /*
713 * smb_mbc_encodef
714 *
715 * This function builds a stream of bytes in the mbc chain passed in under the
716 * control of the format fmt.
717 *
718 * (for a description of the format string see smb_mbc_vencodef()).
719 */
720 int
smb_mbc_encodef(mbuf_chain_t * mbc,char * fmt,...)721 smb_mbc_encodef(mbuf_chain_t *mbc, char *fmt, ...)
722 {
723 int rc;
724 va_list ap;
725
726 va_start(ap, fmt);
727 rc = smb_mbc_vencodef(mbc, fmt, ap);
728 va_end(ap);
729 return (rc);
730 }
731
732 /*
733 * smb_mbc_poke
734 *
735 * This function writes a stream of bytes in the mbc passed in at the specified
736 * offset under the control of the format fmt. The offset of the chain passed in
737 * is not modified.
738 *
739 * (for a description of the format string see smb_mbc_vencodef()).
740 */
741 int
smb_mbc_poke(mbuf_chain_t * mbc,int offset,char * fmt,...)742 smb_mbc_poke(mbuf_chain_t *mbc, int offset, char *fmt, ...)
743 {
744 int xx;
745 mbuf_chain_t tmp;
746 va_list ap;
747
748 (void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset);
749 va_start(ap, fmt);
750 xx = smb_mbc_vencodef(&tmp, fmt, ap);
751 va_end(ap);
752 return (xx);
753 }
754
755 /*
756 * Copy data from the src mbuf chain to the dst mbuf chain,
757 * at the given offset in the src and current offset in dst,
758 * for copy_len bytes. Does NOT update src->chain_offset.
759 */
760 int
smb_mbc_copy(mbuf_chain_t * dst_mbc,const mbuf_chain_t * src_mbc,int copy_offset,int copy_len)761 smb_mbc_copy(mbuf_chain_t *dst_mbc, const mbuf_chain_t *src_mbc,
762 int copy_offset, int copy_len)
763 {
764 mbuf_t *src_m;
765 int offset, len;
766 int rc;
767
768 if (copy_len <= 0)
769 return (0);
770 if (copy_offset < 0)
771 return (EINVAL);
772 if ((copy_offset + copy_len) > src_mbc->max_bytes)
773 return (EMSGSIZE);
774
775 /*
776 * Advance to the src mbuf where we start copying.
777 */
778 offset = copy_offset;
779 src_m = src_mbc->chain;
780 while (src_m && offset >= src_m->m_len) {
781 offset -= src_m->m_len;
782 src_m = src_m->m_next;
783 }
784 if (src_m == NULL)
785 return (EFAULT);
786
787 /*
788 * Copy the first part, which may start somewhere past
789 * the beginning of the current mbuf.
790 */
791 len = src_m->m_len - offset;
792 if (len > copy_len)
793 len = copy_len;
794 rc = smb_mbc_put_mem(dst_mbc, src_m->m_data + offset, len);
795 if (rc != 0)
796 return (rc);
797 copy_len -= len;
798
799 /*
800 * Copy remaining mbufs...
801 */
802 while (copy_len > 0) {
803 src_m = src_m->m_next;
804 if (src_m == NULL)
805 break;
806 len = src_m->m_len;
807 if (len > copy_len)
808 len = copy_len;
809 rc = smb_mbc_put_mem(dst_mbc, src_m->m_data, len);
810 copy_len -= len;
811 }
812
813 return (0);
814 }
815
816 /*
817 * Copy data from the passed memory buffer into the mbuf chain
818 * at the current offset.
819 */
820 int
smb_mbc_put_mem(mbuf_chain_t * mbc,void * vmem,int mem_len)821 smb_mbc_put_mem(mbuf_chain_t *mbc, void *vmem, int mem_len)
822 {
823 caddr_t mem = vmem;
824 mbuf_t *m;
825 int32_t offset, tlen;
826 int rc;
827
828 if (mem_len <= 0)
829 return (0);
830
831 if ((rc = mbc_marshal_make_room(mbc, mem_len)) != 0)
832 return (rc);
833
834 /*
835 * Advance to the dst mbuf where we start copying.
836 * Allocations were done by _make_room().
837 */
838 offset = mbc->chain_offset;
839 m = mbc->chain;
840 while (offset >= m->m_len) {
841 ASSERT(m->m_len > 0);
842 offset -= m->m_len;
843 m = m->m_next;
844 }
845
846 /*
847 * Copy the first part, which may start somewhere past
848 * the beginning of the current mbuf.
849 */
850 tlen = m->m_len - offset;
851 if (tlen > mem_len)
852 tlen = mem_len;
853 bcopy(mem, m->m_data + offset, tlen);
854 mbc->chain_offset += tlen;
855 mem += tlen;
856 mem_len -= tlen;
857
858 /*
859 * Copy remaining mem into mbufs. These all start
860 * at the beginning of each mbuf, and the last may
861 * end somewhere short of m_len.
862 */
863 while (mem_len > 0) {
864 m = m->m_next;
865 tlen = m->m_len;
866 if (tlen > mem_len)
867 tlen = mem_len;
868 bcopy(mem, m->m_data, tlen);
869 mbc->chain_offset += tlen;
870 mem += tlen;
871 mem_len -= tlen;
872 }
873
874 return (0);
875 }
876
877 /*
878 * Put data into mbuf chain allocating as needed.
879 * Adds room to end of mbuf chain if needed.
880 */
881 static int
mbc_marshal_make_room(mbuf_chain_t * mbc,int32_t bytes_needed)882 mbc_marshal_make_room(mbuf_chain_t *mbc, int32_t bytes_needed)
883 {
884 mbuf_t *m;
885 mbuf_t *l;
886 int32_t bytes_available;
887
888 bytes_needed += mbc->chain_offset;
889 if (bytes_needed > mbc->max_bytes)
890 return (EMSGSIZE);
891
892 if ((m = mbc->chain) == 0) {
893 MGET(m, M_WAIT, MT_DATA);
894 m->m_len = 0;
895 if (mbc->max_bytes > MLEN)
896 MCLGET(m, M_WAIT);
897 mbc->chain = m;
898 /* xxxx */
899 /* ^ */
900 }
901
902 /* ---- ----- --xx ---xxx */
903 /* ^ */
904
905 l = 0;
906 while ((m != 0) && (bytes_needed >= m->m_len)) {
907 l = m;
908 bytes_needed -= m->m_len;
909 m = m->m_next;
910 }
911
912 if ((bytes_needed == 0) || (m != 0)) {
913 /* We have enough room already */
914 return (0);
915 }
916
917 /* ---- ----- --xx ---xxx */
918 /* ^ */
919 /* Back up to start of last mbuf */
920 m = l;
921 bytes_needed += m->m_len;
922
923 /* ---- ----- --xx ---xxx */
924 /* ^ */
925
926 bytes_available = (m->m_flags & M_EXT) ?
927 m->m_ext.ext_size : MLEN;
928
929 /* ---- ----- --xx ---xxx */
930 /* ^ */
931 while ((bytes_needed != 0) && (bytes_needed > bytes_available)) {
932 m->m_len = bytes_available;
933 bytes_needed -= m->m_len;
934 /* ---- ----- --xx ------ */
935 /* ^ */
936
937 MGET(m->m_next, M_WAIT, MT_DATA);
938 m = m->m_next;
939 m->m_len = 0;
940 if (bytes_needed > MLEN)
941 MCLGET(m, M_WAIT);
942
943 bytes_available = (m->m_flags & M_EXT) ?
944 m->m_ext.ext_size : MLEN;
945
946 /* ---- ----- --xx ------ xxxx */
947 /* ^ */
948 }
949
950 /* ---- ----- --xx ------ xxxx */
951 /* ^ */
952 /* Expand last tail as needed */
953 if (m->m_len <= bytes_needed) {
954 m->m_len = bytes_needed;
955 /* ---- ----- --xx ------ --xx */
956 /* ^ */
957 }
958
959 return (0);
960 }
961
962 static void
mbc_marshal_store_byte(mbuf_chain_t * mbc,uint8_t data)963 mbc_marshal_store_byte(mbuf_chain_t *mbc, uint8_t data)
964 {
965 mbuf_t *m = mbc->chain;
966 int32_t cur_offset = mbc->chain_offset;
967
968 /*
969 * Scan forward looking for the last data currently in chain.
970 */
971 while (cur_offset >= m->m_len) {
972 cur_offset -= m->m_len;
973 m = m->m_next;
974 }
975 ((char *)m->m_data)[cur_offset] = data;
976 mbc->chain_offset++;
977 }
978
979 static int
mbc_marshal_put_char(mbuf_chain_t * mbc,uint8_t data)980 mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t data)
981 {
982 if (mbc_marshal_make_room(mbc, sizeof (char)) != 0)
983 return (DECODE_NO_MORE_DATA);
984 mbc_marshal_store_byte(mbc, data);
985 return (0);
986 }
987
988 static int
mbc_marshal_put_short(mbuf_chain_t * mbc,uint16_t data)989 mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t data)
990 {
991 if (mbc_marshal_make_room(mbc, sizeof (short)))
992 return (DECODE_NO_MORE_DATA);
993 mbc_marshal_store_byte(mbc, data);
994 mbc_marshal_store_byte(mbc, data >> 8);
995 return (0);
996 }
997
998 static int
mbc_marshal_put_long(mbuf_chain_t * mbc,uint32_t data)999 mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t data)
1000 {
1001 if (mbc_marshal_make_room(mbc, sizeof (int32_t)))
1002 return (DECODE_NO_MORE_DATA);
1003 mbc_marshal_store_byte(mbc, data);
1004 mbc_marshal_store_byte(mbc, data >> 8);
1005 mbc_marshal_store_byte(mbc, data >> 16);
1006 mbc_marshal_store_byte(mbc, data >> 24);
1007 return (0);
1008 }
1009
1010 static int
mbc_marshal_put_long_long(mbuf_chain_t * mbc,uint64_t data)1011 mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t data)
1012 {
1013 if (mbc_marshal_make_room(mbc, sizeof (int64_t)))
1014 return (DECODE_NO_MORE_DATA);
1015
1016 mbc_marshal_store_byte(mbc, data);
1017 mbc_marshal_store_byte(mbc, data >> 8);
1018 mbc_marshal_store_byte(mbc, data >> 16);
1019 mbc_marshal_store_byte(mbc, data >> 24);
1020 mbc_marshal_store_byte(mbc, data >> 32);
1021 mbc_marshal_store_byte(mbc, data >> 40);
1022 mbc_marshal_store_byte(mbc, data >> 48);
1023 mbc_marshal_store_byte(mbc, data >> 56);
1024 return (0);
1025 }
1026
1027 /*
1028 * When need to convert from UTF-8 (internal format) to a single
1029 * byte string (external format ) when marshalling a string.
1030 */
1031 static int
mbc_marshal_put_ascii_string(mbuf_chain_t * mbc,char * mbs,int repc)1032 mbc_marshal_put_ascii_string(mbuf_chain_t *mbc, char *mbs, int repc)
1033 {
1034 smb_wchar_t wide_char;
1035 int nbytes;
1036 int length;
1037
1038 if ((length = smb_sbequiv_strlen(mbs)) == -1)
1039 return (DECODE_NO_MORE_DATA);
1040
1041 length += sizeof (char);
1042
1043 if ((repc > 1) && (repc < length))
1044 length = repc;
1045 if (mbc_marshal_make_room(mbc, length))
1046 return (DECODE_NO_MORE_DATA);
1047
1048 while (*mbs) {
1049 /*
1050 * We should restore oem chars here.
1051 */
1052 nbytes = smb_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX);
1053 if (nbytes == -1)
1054 return (DECODE_NO_MORE_DATA);
1055
1056 mbc_marshal_store_byte(mbc, (uint8_t)wide_char);
1057
1058 if (wide_char & 0xFF00)
1059 mbc_marshal_store_byte(mbc, wide_char >> 8);
1060
1061 mbs += nbytes;
1062 }
1063
1064 mbc_marshal_store_byte(mbc, 0);
1065 return (0);
1066 }
1067
1068 static int
mbc_marshal_put_unicode_string(mbuf_chain_t * mbc,char * ascii,int repc)1069 mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *ascii, int repc)
1070 {
1071 smb_wchar_t wchar;
1072 int consumed;
1073 int length;
1074
1075 if ((length = smb_wcequiv_strlen(ascii)) == -1)
1076 return (DECODE_NO_MORE_DATA);
1077
1078 length += sizeof (smb_wchar_t);
1079
1080 if ((repc > 1) && (repc < length))
1081 length = repc;
1082
1083 if (mbc_marshal_make_room(mbc, length))
1084 return (DECODE_NO_MORE_DATA);
1085 while (length > 0) {
1086 consumed = smb_mbtowc(&wchar, ascii, MTS_MB_CHAR_MAX);
1087 if (consumed == -1)
1088 break; /* Invalid sequence */
1089 /*
1090 * Note that consumed will be 0 when the null terminator
1091 * is encountered and ascii will not be advanced beyond
1092 * that point. Length will continue to be decremented so
1093 * we won't get stuck here.
1094 */
1095 ascii += consumed;
1096 mbc_marshal_store_byte(mbc, wchar);
1097 mbc_marshal_store_byte(mbc, wchar >> 8);
1098 length -= sizeof (smb_wchar_t);
1099 }
1100 return (0);
1101 }
1102
1103 static int
mbc_marshal_put_uio(mbuf_chain_t * mbc,struct uio * uio)1104 mbc_marshal_put_uio(mbuf_chain_t *mbc, struct uio *uio)
1105 {
1106 mbuf_t **t;
1107 mbuf_t *m = NULL;
1108 struct iovec *iov = uio->uio_iov;
1109 int32_t i, iov_cnt = uio->uio_iovcnt;
1110
1111 iov = uio->uio_iov;
1112 t = &mbc->chain;
1113 for (i = 0; i < iov_cnt; i++) {
1114 MGET(m, M_WAIT, MT_DATA);
1115 m->m_ext.ext_buf = iov->iov_base;
1116 m->m_ext.ext_ref = mclrefnoop;
1117 m->m_data = m->m_ext.ext_buf;
1118 m->m_flags |= M_EXT;
1119 m->m_len = m->m_ext.ext_size = iov->iov_len;
1120 mbc->max_bytes += m->m_len;
1121 m->m_next = 0;
1122 *t = m;
1123 t = &m->m_next;
1124 iov++;
1125 }
1126 return (0);
1127 }
1128
1129 static int
mbc_marshal_put_mbufs(mbuf_chain_t * mbc,mbuf_t * m)1130 mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m)
1131 {
1132 mbuf_t *mt;
1133 mbuf_t **t;
1134 int bytes;
1135
1136 if (m != NULL) {
1137 mt = m;
1138 bytes = mt->m_len;
1139 while (mt->m_next != 0) {
1140 mt = mt->m_next;
1141 bytes += mt->m_len;
1142 }
1143 if (bytes != 0) {
1144 t = &mbc->chain;
1145 while (*t != 0) {
1146 bytes += (*t)->m_len;
1147 t = &(*t)->m_next;
1148 }
1149 *t = m;
1150 mbc->chain_offset = bytes;
1151 } else {
1152 m_freem(m);
1153 }
1154 }
1155 return (0);
1156 }
1157
1158 static int
mbc_marshal_put_mbuf_chain(mbuf_chain_t * mbc,mbuf_chain_t * nmbc)1159 mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc)
1160 {
1161 if (nmbc->chain != 0) {
1162 if (mbc_marshal_put_mbufs(mbc, nmbc->chain))
1163 return (DECODE_NO_MORE_DATA);
1164 MBC_SETUP(nmbc, nmbc->max_bytes);
1165 }
1166 return (0);
1167 }
1168
1169 static uint8_t
mbc_marshal_fetch_byte(mbuf_chain_t * mbc)1170 mbc_marshal_fetch_byte(mbuf_chain_t *mbc)
1171 {
1172 uint8_t data;
1173 mbuf_t *m = mbc->chain;
1174 int32_t offset = mbc->chain_offset;
1175
1176 while (offset >= m->m_len) {
1177 offset -= m->m_len;
1178 m = m->m_next;
1179 }
1180 data = ((uint8_t *)m->m_data)[offset];
1181 mbc->chain_offset++;
1182 return (data);
1183 }
1184
1185 static int
mbc_marshal_get_char(mbuf_chain_t * mbc,uint8_t * data)1186 mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data)
1187 {
1188 if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
1189 /* Data will never be available */
1190 return (DECODE_NO_MORE_DATA);
1191 }
1192 *data = mbc_marshal_fetch_byte(mbc);
1193 return (0);
1194 }
1195
1196 static int
mbc_marshal_get_short(mbuf_chain_t * mbc,uint16_t * data)1197 mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data)
1198 {
1199 uint16_t tmp;
1200 mbuf_t *m = mbc->chain;
1201 int32_t offset = mbc->chain_offset;
1202
1203 if (MBC_ROOM_FOR(mbc, sizeof (short)) == 0) {
1204 /* Data will never be available */
1205 return (DECODE_NO_MORE_DATA);
1206 }
1207
1208 while (offset >= m->m_len) {
1209 offset -= m->m_len;
1210 m = m->m_next;
1211 }
1212 if ((m->m_len - offset) >= sizeof (short)) {
1213 *data = LE_IN16(m->m_data + offset);
1214 mbc->chain_offset += sizeof (short);
1215 } else {
1216 tmp = (uint16_t)mbc_marshal_fetch_byte(mbc);
1217 tmp |= ((uint16_t)mbc_marshal_fetch_byte(mbc)) << 8;
1218 *data = tmp;
1219 }
1220 return (0);
1221 }
1222
1223 static int
mbc_marshal_get_long(mbuf_chain_t * mbc,uint32_t * data)1224 mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data)
1225 {
1226 uint32_t tmp;
1227 mbuf_t *m = mbc->chain;
1228 int32_t offset = mbc->chain_offset;
1229
1230 if (MBC_ROOM_FOR(mbc, sizeof (int32_t)) == 0) {
1231 /* Data will never be available */
1232 return (DECODE_NO_MORE_DATA);
1233 }
1234 while (offset >= m->m_len) {
1235 offset -= m->m_len;
1236 m = m->m_next;
1237 }
1238 if ((m->m_len - offset) >= sizeof (int32_t)) {
1239 *data = LE_IN32(m->m_data + offset);
1240 mbc->chain_offset += sizeof (int32_t);
1241 } else {
1242 tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
1243 tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 8;
1244 tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 16;
1245 tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 24;
1246 *data = tmp;
1247 }
1248 return (0);
1249 }
1250
1251 static uint64_t
qswap(uint64_t ll)1252 qswap(uint64_t ll)
1253 {
1254 uint64_t v;
1255
1256 v = ll >> 32;
1257 v |= ll << 32;
1258
1259 return (v);
1260 }
1261
1262 static int
mbc_marshal_get_odd_long_long(mbuf_chain_t * mbc,uint64_t * data)1263 mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data)
1264 {
1265 uint64_t tmp;
1266 mbuf_t *m = mbc->chain;
1267 int32_t offset = mbc->chain_offset;
1268
1269 if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
1270 /* Data will never be available */
1271 return (DECODE_NO_MORE_DATA);
1272 }
1273 while (offset >= m->m_len) {
1274 offset -= m->m_len;
1275 m = m->m_next;
1276 }
1277
1278 if ((m->m_len - offset) >= sizeof (int64_t)) {
1279 *data = qswap(LE_IN64(m->m_data + offset));
1280 mbc->chain_offset += sizeof (int64_t);
1281 } else {
1282 tmp = (uint64_t)mbc_marshal_fetch_byte(mbc) << 32;
1283 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 40;
1284 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 48;
1285 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 56;
1286 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc);
1287 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 8;
1288 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 16;
1289 tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 24;
1290
1291 *(uint64_t *)data = tmp;
1292 }
1293 return (0);
1294 }
1295
1296 static int
mbc_marshal_get_long_long(mbuf_chain_t * mbc,uint64_t * data)1297 mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data)
1298 {
1299 uint64_t tmp;
1300 mbuf_t *m = mbc->chain;
1301 int32_t offset = mbc->chain_offset;
1302
1303 if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
1304 /* Data will never be available */
1305 return (DECODE_NO_MORE_DATA);
1306 }
1307 while (offset >= m->m_len) {
1308 offset -= m->m_len;
1309 m = m->m_next;
1310 }
1311 if ((m->m_len - offset) >= sizeof (int64_t)) {
1312 *data = LE_IN64(m->m_data + offset);
1313 mbc->chain_offset += sizeof (int64_t);
1314 } else {
1315 tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
1316 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 8;
1317 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 16;
1318 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 24;
1319 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32;
1320 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40;
1321 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48;
1322 tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56;
1323 *(uint64_t *)data = tmp;
1324 }
1325 return (0);
1326 }
1327
1328 /*
1329 * mbc_marshal_get_ascii_string
1330 *
1331 * The ascii string in smb includes oem chars. Since the
1332 * system needs utf8 encodes unicode char, conversion is
1333 * required to convert the oem char to unicode and then
1334 * to encode the converted wchars to utf8 format.
1335 * Therefore, the **ascii returned will be in such format
1336 * instead of the real ASCII format.
1337 */
1338 static int
mbc_marshal_get_ascii_string(smb_request_t * sr,mbuf_chain_t * mbc,uint8_t ** ascii,int max_ascii)1339 mbc_marshal_get_ascii_string(
1340 smb_request_t *sr,
1341 mbuf_chain_t *mbc,
1342 uint8_t **ascii,
1343 int max_ascii)
1344 {
1345 char *rcvbuf;
1346 char *ch;
1347 int max;
1348 int length = 0;
1349
1350 max = MALLOC_QUANTUM;
1351 rcvbuf = smb_srm_zalloc(sr, max);
1352
1353 if (max_ascii == 0)
1354 max_ascii = 0xffff;
1355
1356 ch = rcvbuf;
1357 for (;;) {
1358 while (length < max) {
1359 if (max_ascii-- <= 0) {
1360 *ch++ = 0;
1361 goto multibyte_encode;
1362 }
1363 if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
1364 /* Data will never be available */
1365 return (DECODE_NO_MORE_DATA);
1366 }
1367 if ((*ch++ = mbc_marshal_fetch_byte(mbc)) == 0)
1368 goto multibyte_encode;
1369 length++;
1370 }
1371 max += MALLOC_QUANTUM;
1372 rcvbuf = smb_srm_rezalloc(sr, rcvbuf, max);
1373 ch = rcvbuf + length;
1374 }
1375
1376 multibyte_encode:
1377 /*
1378 * UTF-8 encode the string for internal system use.
1379 */
1380 length = strlen(rcvbuf) + 1;
1381 *ascii = smb_srm_zalloc(sr, length * MTS_MB_CHAR_MAX);
1382 return (mbc_marshal_cstou8("CP850", (char *)*ascii,
1383 (size_t)length * MTS_MB_CHAR_MAX, rcvbuf, (size_t)length));
1384 }
1385
1386 static int
mbc_marshal_get_unicode_string(smb_request_t * sr,mbuf_chain_t * mbc,uint8_t ** ascii,int max_unicode)1387 mbc_marshal_get_unicode_string(smb_request_t *sr,
1388 mbuf_chain_t *mbc, uint8_t **ascii, int max_unicode)
1389 {
1390 int max;
1391 uint16_t wchar;
1392 char *ch;
1393 int emitted;
1394 int length = 0;
1395
1396 if (max_unicode == 0)
1397 max_unicode = 0xffff;
1398
1399 max = MALLOC_QUANTUM;
1400 *ascii = smb_srm_zalloc(sr, max);
1401
1402 ch = (char *)*ascii;
1403 for (;;) {
1404 while ((length + MTS_MB_CHAR_MAX) < max) {
1405 if (max_unicode <= 0)
1406 goto done;
1407 max_unicode -= 2;
1408
1409 if (mbc_marshal_get_short(mbc, &wchar) != 0)
1410 return (DECODE_NO_MORE_DATA);
1411
1412 if (wchar == 0) goto done;
1413
1414 emitted = smb_wctomb(ch, wchar);
1415 length += emitted;
1416 ch += emitted;
1417 }
1418 max += MALLOC_QUANTUM;
1419 *ascii = smb_srm_rezalloc(sr, *ascii, max);
1420 ch = (char *)*ascii + length;
1421 }
1422 done: *ch = 0;
1423 return (0);
1424 }
1425
1426 static int /*ARGSUSED*/
mbc_marshal_get_mbufs(mbuf_chain_t * mbc,int32_t bytes,mbuf_t ** m)1427 mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m)
1428 {
1429 *m = NULL;
1430 if (MBC_ROOM_FOR(mbc, bytes) == 0) {
1431 /* Data will never be available */
1432 return (DECODE_NO_MORE_DATA);
1433 }
1434 /* not yet implemented */
1435 return (-1);
1436 }
1437
1438 static int
mbc_marshal_get_mbuf_chain(mbuf_chain_t * mbc,int32_t bytes,mbuf_chain_t * nmbc)1439 mbc_marshal_get_mbuf_chain(mbuf_chain_t *mbc, int32_t bytes, mbuf_chain_t *nmbc)
1440 {
1441 int rc;
1442 mbuf_t *m;
1443
1444 if (bytes == 0) {
1445 /* Get all the rest */
1446 bytes = mbc->max_bytes - mbc->chain_offset;
1447 }
1448
1449 MBC_SETUP(nmbc, mbc->max_bytes);
1450 if ((rc = mbc_marshal_get_mbufs(mbc, bytes, &m)) != 0) {
1451 if (m)
1452 m_freem(m);
1453 return (rc);
1454 }
1455 nmbc->chain = m;
1456 while (m != 0) {
1457 bytes += m->m_len;
1458 m = m->m_next;
1459 }
1460 nmbc->max_bytes = bytes;
1461 return (0);
1462 }
1463
1464 static int
mbc_marshal_get_uio(mbuf_chain_t * mbc,struct uio * uio)1465 mbc_marshal_get_uio(mbuf_chain_t *mbc, struct uio *uio)
1466 {
1467 int i, offset;
1468 int32_t bytes = uio->uio_resid;
1469 int32_t remainder;
1470 struct iovec *iov;
1471 mbuf_t *m;
1472
1473 /*
1474 * The residual count is tested because in the case of write requests
1475 * with no data (smbtorture RAW-WRITE test will generate that type of
1476 * request) this function is called with a residual count of zero
1477 * bytes.
1478 */
1479 if (bytes != 0) {
1480 iov = uio->uio_iov;
1481 uio->uio_segflg = UIO_SYSSPACE;
1482 uio->uio_extflg = UIO_COPY_DEFAULT;
1483
1484 if (MBC_ROOM_FOR(mbc, bytes) == 0) {
1485 /* Data will never be available */
1486 return (DECODE_NO_MORE_DATA);
1487 }
1488
1489 m = mbc->chain;
1490 offset = mbc->chain_offset;
1491 while (offset >= m->m_len) {
1492 offset -= m->m_len;
1493 m = m->m_next;
1494 ASSERT((offset == 0) || (offset && m));
1495 }
1496
1497 for (i = 0; (bytes > 0) && (i < uio->uio_iovcnt); i++) {
1498 iov[i].iov_base = &m->m_data[offset];
1499 remainder = m->m_len - offset;
1500 if (remainder >= bytes) {
1501 iov[i].iov_len = bytes;
1502 mbc->chain_offset += bytes;
1503 uio->uio_iovcnt = i + 1;
1504 return (0);
1505 }
1506 iov[i].iov_len = remainder;
1507 mbc->chain_offset += remainder;
1508 bytes -= remainder;
1509 m = m->m_next;
1510 offset = 0;
1511 }
1512 return (DECODE_NO_MORE_DATA);
1513 }
1514 return (0);
1515 }
1516
1517 static int
mbc_marshal_get_skip(mbuf_chain_t * mbc,uint_t skip)1518 mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip)
1519 {
1520 if (MBC_ROOM_FOR(mbc, skip) == 0)
1521 return (DECODE_NO_MORE_DATA);
1522 mbc->chain_offset += skip;
1523 return (0);
1524 }
1525
1526 /*
1527 * Converts oem string to UTF-8 string with an output string of max
1528 * maxconv bytes. The string may be truncated or not null-terminated if
1529 * there is not enough room.
1530 *
1531 * returns -1, cnt (partial conversion) or 0 (success)
1532 */
1533
1534 static int
mbc_marshal_cstou8(char * cs,char * outbuf,size_t maxconv,char * inbuf,size_t srcbytes)1535 mbc_marshal_cstou8(char *cs, char *outbuf, size_t maxconv,
1536 char *inbuf, size_t srcbytes)
1537 {
1538 kiconv_t t2u;
1539 size_t inlen = srcbytes;
1540 size_t outlen = maxconv;
1541 int err = 0;
1542 size_t rc;
1543
1544 if ((t2u = kiconv_open("UTF-8", cs)) == (kiconv_t)-1)
1545 return (-1);
1546
1547 rc = kiconv(t2u, &inbuf, &inlen, &outbuf, &outlen, &err);
1548 (void) kiconv_close(t2u);
1549 return ((int)rc);
1550 }
1551