1 /* 2 * Copyright (c) 2000, Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Boris Popov. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Id: mbuf.c,v 1.3 2004/12/13 00:25:22 lindak Exp $ 33 */ 34 35 /* 36 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 37 * Use is subject to license terms. 38 */ 39 40 #include <sys/types.h> 41 #include <ctype.h> 42 #include <errno.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <strings.h> 47 #include <libintl.h> 48 #include <assert.h> 49 50 #include <netsmb/smb_lib.h> 51 #include <netsmb/mchain.h> 52 53 #include "private.h" 54 #include "charsets.h" 55 56 static int 57 m_get(size_t len, struct mbuf **mpp) 58 { 59 struct mbuf *m; 60 61 assert(len < 0x100000); /* sanity */ 62 63 len = M_ALIGN(len); 64 if (len < M_MINSIZE) 65 len = M_MINSIZE; 66 m = malloc(M_BASESIZE + len); 67 if (m == NULL) 68 return (ENOMEM); 69 bzero(m, M_BASESIZE + len); 70 m->m_maxlen = len; 71 m->m_data = M_TOP(m); 72 *mpp = m; 73 return (0); 74 } 75 76 static void 77 m_free(struct mbuf *m) 78 { 79 free(m); 80 } 81 82 void 83 m_freem(struct mbuf *m0) 84 { 85 struct mbuf *m; 86 87 while (m0) { 88 m = m0->m_next; 89 m_free(m0); 90 m0 = m; 91 } 92 } 93 94 size_t 95 m_totlen(struct mbuf *m0) 96 { 97 struct mbuf *m = m0; 98 int len = 0; 99 100 while (m) { 101 len += m->m_len; 102 m = m->m_next; 103 } 104 return (len); 105 } 106 107 int 108 m_lineup(struct mbuf *m0, struct mbuf **mpp) 109 { 110 struct mbuf *nm, *m; 111 char *dp; 112 size_t len; 113 int error; 114 115 if (m0->m_next == NULL) { 116 *mpp = m0; 117 return (0); 118 } 119 if ((error = m_get(m_totlen(m0), &nm)) != 0) 120 return (error); 121 dp = mtod(nm, char *); 122 while (m0) { 123 len = m0->m_len; 124 bcopy(m0->m_data, dp, len); 125 dp += len; 126 m = m0->m_next; 127 m_free(m0); 128 m0 = m; 129 } 130 *mpp = nm; 131 return (0); 132 } 133 134 int 135 mb_init(struct mbdata *mbp, size_t size) 136 { 137 struct mbuf *m; 138 int error; 139 140 if ((error = m_get(size, &m)) != 0) 141 return (error); 142 return (mb_initm(mbp, m)); 143 } 144 145 int 146 mb_initm(struct mbdata *mbp, struct mbuf *m) 147 { 148 bzero(mbp, sizeof (*mbp)); 149 mbp->mb_top = mbp->mb_cur = m; 150 mbp->mb_pos = mtod(m, char *); 151 return (0); 152 } 153 154 int 155 mb_done(struct mbdata *mbp) 156 { 157 if (mbp->mb_top) { 158 m_freem(mbp->mb_top); 159 mbp->mb_top = NULL; 160 } 161 return (0); 162 } 163 164 int 165 m_getm(struct mbuf *top, size_t len, struct mbuf **mpp) 166 { 167 struct mbuf *m, *mp; 168 int error, ts; 169 170 for (mp = top; ; mp = mp->m_next) { 171 ts = M_TRAILINGSPACE(mp); 172 if (len <= ts) 173 goto out; 174 len -= ts; 175 if (mp->m_next == NULL) 176 break; 177 178 } 179 if (len > 0) { 180 if ((error = m_get(len, &m)) != 0) 181 return (error); 182 mp->m_next = m; 183 } 184 out: 185 *mpp = top; 186 return (0); 187 } 188 189 /* 190 * Routines to put data in a buffer 191 */ 192 193 /* 194 * Check if object of size 'size' fit to the current position and 195 * allocate new mbuf if not. Advance pointers and increase length of mbuf(s). 196 * Return pointer to the object placeholder or NULL if any error occured. 197 */ 198 int 199 mb_fit(struct mbdata *mbp, size_t size, char **pp) 200 { 201 struct mbuf *m, *mn; 202 int error; 203 204 m = mbp->mb_cur; 205 if (M_TRAILINGSPACE(m) < (int)size) { 206 if ((error = m_get(size, &mn)) != 0) 207 return (error); 208 mbp->mb_pos = mtod(mn, char *); 209 mbp->mb_cur = m->m_next = mn; 210 m = mn; 211 } 212 m->m_len += size; 213 *pp = mbp->mb_pos; 214 mbp->mb_pos += size; 215 mbp->mb_count += size; 216 return (0); 217 } 218 219 int 220 mb_put_uint8(struct mbdata *mbp, uint8_t x) 221 { 222 uint8_t y = x; 223 return (mb_put_mem(mbp, &y, sizeof (y))); 224 } 225 226 int 227 mb_put_uint16be(struct mbdata *mbp, uint16_t x) 228 { 229 uint16_t y = htobes(x); 230 return (mb_put_mem(mbp, &y, sizeof (y))); 231 } 232 233 int 234 mb_put_uint16le(struct mbdata *mbp, uint16_t x) 235 { 236 uint16_t y = htoles(x); 237 return (mb_put_mem(mbp, &y, sizeof (y))); 238 } 239 240 int 241 mb_put_uint32be(struct mbdata *mbp, uint32_t x) 242 { 243 uint32_t y = htobel(x); 244 return (mb_put_mem(mbp, &y, sizeof (y))); 245 } 246 247 int 248 mb_put_uint32le(struct mbdata *mbp, uint32_t x) 249 { 250 uint32_t y = htolel(x); 251 return (mb_put_mem(mbp, &y, sizeof (y))); 252 } 253 254 int 255 mb_put_uint64be(struct mbdata *mbp, uint64_t x) 256 { 257 uint64_t y = htobeq(x); 258 return (mb_put_mem(mbp, &y, sizeof (y))); 259 } 260 261 int 262 mb_put_uint64le(struct mbdata *mbp, uint64_t x) 263 { 264 uint64_t y = htoleq(x); 265 return (mb_put_mem(mbp, &y, sizeof (y))); 266 } 267 268 int 269 mb_put_mem(struct mbdata *mbp, const void *vmem, size_t size) 270 { 271 struct mbuf *m; 272 const char *src; 273 char *dst; 274 size_t cplen; 275 int error; 276 277 if (size == 0) 278 return (0); 279 280 src = vmem; 281 m = mbp->mb_cur; 282 if ((error = m_getm(m, size, &m)) != 0) 283 return (error); 284 while (size > 0) { 285 cplen = M_TRAILINGSPACE(m); 286 if (cplen == 0) { 287 m = m->m_next; 288 continue; 289 } 290 if (cplen > size) 291 cplen = size; 292 dst = mtod(m, char *) + m->m_len; 293 if (src) { 294 bcopy(src, dst, cplen); 295 src += cplen; 296 } else 297 bzero(dst, cplen); 298 size -= cplen; 299 m->m_len += cplen; 300 mbp->mb_count += cplen; 301 } 302 mbp->mb_pos = mtod(m, char *) + m->m_len; 303 mbp->mb_cur = m; 304 return (0); 305 } 306 307 /* 308 * Append another mbuf to the mbuf chain. 309 * If what we're appending is smaller than 310 * the current trailing space, just copy. 311 * This always consumes the passed mbuf. 312 */ 313 int 314 mb_put_mbuf(struct mbdata *mbp, struct mbuf *m) 315 { 316 struct mbuf *cm = mbp->mb_cur; 317 int ts = M_TRAILINGSPACE(cm); 318 319 if (m->m_next == NULL && m->m_len <= ts) { 320 /* just copy */ 321 mb_put_mem(mbp, m->m_data, m->m_len); 322 m_freem(m); 323 return (0); 324 } 325 326 cm->m_next = m; 327 while (m) { 328 mbp->mb_count += m->m_len; 329 if (m->m_next == NULL) 330 break; 331 m = m->m_next; 332 } 333 mbp->mb_pos = mtod(m, char *) + m->m_len; 334 mbp->mb_cur = m; 335 return (0); 336 } 337 338 /* 339 * Convenience function to put an OEM or Unicode string, 340 * null terminated, and aligned if necessary. 341 */ 342 int 343 mb_put_dstring(struct mbdata *mbp, const char *s, int uc) 344 { 345 int err; 346 347 if (uc) { 348 /* Put Unicode. align(2) first. */ 349 if (mbp->mb_count & 1) 350 mb_put_uint8(mbp, 0); 351 err = mb_put_ustring(mbp, s); 352 } else { 353 /* Put ASCII (really OEM) */ 354 err = mb_put_astring(mbp, s); 355 } 356 357 return (err); 358 } 359 360 /* 361 * Put an ASCII string (really OEM), given a UTF-8 string. 362 */ 363 int 364 mb_put_astring(struct mbdata *mbp, const char *s) 365 { 366 char *abuf; 367 int err, len; 368 369 abuf = convert_utf8_to_wincs(s); 370 if (abuf == NULL) 371 return (ENOMEM); 372 len = strlen(abuf) + 1; 373 err = mb_put_mem(mbp, abuf, len); 374 free(abuf); 375 return (err); 376 } 377 378 /* 379 * Put UCS-2LE, given a UTF-8 string. 380 */ 381 int 382 mb_put_ustring(struct mbdata *mbp, const char *s) 383 { 384 uint16_t *ubuf; 385 int err, len; 386 387 ubuf = convert_utf8_to_leunicode(s); 388 if (ubuf == NULL) 389 return (ENOMEM); 390 len = unicode_strlen(ubuf) + 1; 391 err = mb_put_mem(mbp, ubuf, (len << 1)); 392 free(ubuf); 393 return (err); 394 } 395 396 /* 397 * Routines for fetching data from an mbuf chain 398 */ 399 #define mb_left(m, p) (mtod(m, char *) + (m)->m_len - (p)) 400 401 int 402 mb_get_uint8(struct mbdata *mbp, uint8_t *x) 403 { 404 return (mb_get_mem(mbp, x, 1)); 405 } 406 407 int 408 mb_get_uint16(struct mbdata *mbp, uint16_t *x) 409 { 410 return (mb_get_mem(mbp, x, 2)); 411 } 412 413 int 414 mb_get_uint16le(struct mbdata *mbp, uint16_t *x) 415 { 416 uint16_t v; 417 int err; 418 419 if ((err = mb_get_mem(mbp, &v, 2)) != 0) 420 return (err); 421 if (x != NULL) 422 *x = letohs(v); 423 return (0); 424 } 425 426 int 427 mb_get_uint16be(struct mbdata *mbp, uint16_t *x) { 428 uint16_t v; 429 int err; 430 431 if ((err = mb_get_mem(mbp, &v, 2)) != 0) 432 return (err); 433 if (x != NULL) 434 *x = betohs(v); 435 return (0); 436 } 437 438 int 439 mb_get_uint32(struct mbdata *mbp, uint32_t *x) 440 { 441 return (mb_get_mem(mbp, x, 4)); 442 } 443 444 int 445 mb_get_uint32be(struct mbdata *mbp, uint32_t *x) 446 { 447 uint32_t v; 448 int err; 449 450 if ((err = mb_get_mem(mbp, &v, 4)) != 0) 451 return (err); 452 if (x != NULL) 453 *x = betohl(v); 454 return (0); 455 } 456 457 int 458 mb_get_uint32le(struct mbdata *mbp, uint32_t *x) 459 { 460 uint32_t v; 461 int err; 462 463 if ((err = mb_get_mem(mbp, &v, 4)) != 0) 464 return (err); 465 if (x != NULL) 466 *x = letohl(v); 467 return (0); 468 } 469 470 int 471 mb_get_uint64(struct mbdata *mbp, uint64_t *x) 472 { 473 return (mb_get_mem(mbp, x, 8)); 474 } 475 476 int 477 mb_get_uint64be(struct mbdata *mbp, uint64_t *x) 478 { 479 uint64_t v; 480 int err; 481 482 if ((err = mb_get_mem(mbp, &v, 8)) != 0) 483 return (err); 484 if (x != NULL) 485 *x = betohq(v); 486 return (0); 487 } 488 489 int 490 mb_get_uint64le(struct mbdata *mbp, uint64_t *x) 491 { 492 uint64_t v; 493 int err; 494 495 if ((err = mb_get_mem(mbp, &v, 8)) != 0) 496 return (err); 497 if (x != NULL) 498 *x = letohq(v); 499 return (0); 500 } 501 502 int 503 mb_get_mem(struct mbdata *mbp, void *vmem, size_t size) 504 { 505 struct mbuf *m = mbp->mb_cur; 506 char *dst = vmem; 507 uint_t count; 508 509 while (size > 0) { 510 if (m == NULL) { 511 /* DPRINT("incomplete copy"); */ 512 return (EBADRPC); 513 } 514 count = mb_left(m, mbp->mb_pos); 515 if (count == 0) { 516 mbp->mb_cur = m = m->m_next; 517 if (m) 518 mbp->mb_pos = mtod(m, char *); 519 continue; 520 } 521 if (count > size) 522 count = size; 523 size -= count; 524 if (dst) { 525 if (count == 1) { 526 *dst++ = *mbp->mb_pos; 527 } else { 528 bcopy(mbp->mb_pos, dst, count); 529 dst += count; 530 } 531 } 532 mbp->mb_pos += count; 533 } 534 return (0); 535 } 536 537 /* 538 * Get the next SIZE bytes as a separate mblk. 539 * Nothing fancy here - just copy. 540 */ 541 int 542 mb_get_mbuf(struct mbdata *mbp, int size, struct mbuf **ret) 543 { 544 mbuf_t *m; 545 int err; 546 547 err = m_get(size, &m); 548 if (err) 549 return (err); 550 551 err = mb_get_mem(mbp, m->m_data, size); 552 if (err) { 553 m_freem(m); 554 return (err); 555 } 556 m->m_len = size; 557 *ret = m; 558 559 return (0); 560 } 561 562 /* 563 * Get a string from the mbuf chain, 564 * either Unicode or OEM chars. 565 */ 566 int 567 mb_get_string(struct mbdata *mbp, char **str_pp, int uc) 568 { 569 int err; 570 571 if (uc) 572 err = mb_get_ustring(mbp, str_pp); 573 else 574 err = mb_get_astring(mbp, str_pp); 575 return (err); 576 } 577 578 /* 579 * Get an ASCII (really OEM) string from the mbuf chain 580 * and convert it to UTF-8 581 * Similar to mb_get_ustring below. 582 */ 583 int 584 mb_get_astring(struct mbdata *real_mbp, char **str_pp) 585 { 586 struct mbdata tmp_mb, *mbp; 587 char *tstr, *ostr; 588 int err, i, slen; 589 uint8_t ch; 590 591 /* 592 * First, figure out the string length. 593 * Use a copy of the real_mbp so we don't 594 * actually consume it here, then search for 595 * the null (or end of data). 596 */ 597 bcopy(real_mbp, &tmp_mb, sizeof (tmp_mb)); 598 mbp = &tmp_mb; 599 slen = 0; 600 for (;;) { 601 err = mb_get_uint8(mbp, &ch); 602 if (err) 603 break; 604 if (ch == 0) 605 break; 606 slen++; 607 } 608 609 /* 610 * Now read the (OEM) string for real. 611 * No need to re-check errors. 612 */ 613 tstr = malloc(slen + 1); 614 if (tstr == NULL) 615 return (ENOMEM); 616 mbp = real_mbp; 617 for (i = 0; i < slen; i++) { 618 mb_get_uint8(mbp, &ch); 619 tstr[i] = ch; 620 } 621 tstr[i] = 0; 622 mb_get_uint8(mbp, NULL); 623 624 /* 625 * Convert OEM to UTF-8 626 */ 627 ostr = convert_wincs_to_utf8(tstr); 628 free(tstr); 629 if (ostr == NULL) 630 return (ENOMEM); 631 632 *str_pp = ostr; 633 return (0); 634 } 635 636 /* 637 * Get a UCS-2LE string from the mbuf chain, and 638 * convert it to UTF-8. 639 * 640 * Similar to mb_get_astring below. 641 */ 642 int 643 mb_get_ustring(struct mbdata *real_mbp, char **str_pp) 644 { 645 struct mbdata tmp_mb, *mbp; 646 uint16_t *tstr; 647 char *ostr; 648 int err, i, slen; 649 uint16_t ch; 650 651 /* 652 * First, align(2) on the real_mbp 653 */ 654 if (((uintptr_t)real_mbp->mb_pos) & 1) 655 mb_get_uint8(real_mbp, NULL); 656 657 /* 658 * Next, figure out the string length. 659 * Use a copy of the real_mbp so we don't 660 * actually consume it here, then search for 661 * the null (or end of data). 662 */ 663 bcopy(real_mbp, &tmp_mb, sizeof (tmp_mb)); 664 mbp = &tmp_mb; 665 slen = 0; 666 for (;;) { 667 err = mb_get_uint16le(mbp, &ch); 668 if (err) 669 break; 670 if (ch == 0) 671 break; 672 slen++; 673 } 674 675 /* 676 * Now read the (UCS-2) string for real. 677 * No need to re-check errors. Note: 678 * This puts the UCS-2 in NATIVE order! 679 */ 680 tstr = calloc(slen + 1, 2); 681 if (tstr == NULL) 682 return (ENOMEM); 683 mbp = real_mbp; 684 for (i = 0; i < slen; i++) { 685 mb_get_uint16le(mbp, &ch); 686 tstr[i] = ch; 687 } 688 tstr[i] = 0; 689 mb_get_uint16le(mbp, NULL); 690 691 /* 692 * Convert UCS-2 (native!) to UTF-8 693 */ 694 ostr = convert_unicode_to_utf8(tstr); 695 free(tstr); 696 if (ostr == NULL) 697 return (ENOMEM); 698 699 *str_pp = ostr; 700 return (0); 701 } 702