1 /* $OpenBSD: misc.c,v 1.64 2006/08/03 03:34:42 deraadt Exp $ */ 2 /* 3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 4 * Copyright (c) 2005,2006 Damien Miller. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "includes.h" 28 29 #include <sys/types.h> 30 #include <sys/ioctl.h> 31 #include <sys/socket.h> 32 #include <sys/param.h> 33 34 #include <stdarg.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <unistd.h> 39 40 #include <netinet/in.h> 41 #include <netinet/tcp.h> 42 43 #include <errno.h> 44 #include <fcntl.h> 45 #ifdef HAVE_PATHS_H 46 # include <paths.h> 47 #include <pwd.h> 48 #endif 49 #ifdef SSH_TUN_OPENBSD 50 #include <net/if.h> 51 #endif 52 53 #include "xmalloc.h" 54 #include "misc.h" 55 #include "log.h" 56 #include "ssh.h" 57 58 /* remove newline at end of string */ 59 char * 60 chop(char *s) 61 { 62 char *t = s; 63 while (*t) { 64 if (*t == '\n' || *t == '\r') { 65 *t = '\0'; 66 return s; 67 } 68 t++; 69 } 70 return s; 71 72 } 73 74 /* set/unset filedescriptor to non-blocking */ 75 int 76 set_nonblock(int fd) 77 { 78 int val; 79 80 val = fcntl(fd, F_GETFL, 0); 81 if (val < 0) { 82 error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); 83 return (-1); 84 } 85 if (val & O_NONBLOCK) { 86 debug3("fd %d is O_NONBLOCK", fd); 87 return (0); 88 } 89 debug2("fd %d setting O_NONBLOCK", fd); 90 val |= O_NONBLOCK; 91 if (fcntl(fd, F_SETFL, val) == -1) { 92 debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd, 93 strerror(errno)); 94 return (-1); 95 } 96 return (0); 97 } 98 99 int 100 unset_nonblock(int fd) 101 { 102 int val; 103 104 val = fcntl(fd, F_GETFL, 0); 105 if (val < 0) { 106 error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); 107 return (-1); 108 } 109 if (!(val & O_NONBLOCK)) { 110 debug3("fd %d is not O_NONBLOCK", fd); 111 return (0); 112 } 113 debug("fd %d clearing O_NONBLOCK", fd); 114 val &= ~O_NONBLOCK; 115 if (fcntl(fd, F_SETFL, val) == -1) { 116 debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s", 117 fd, strerror(errno)); 118 return (-1); 119 } 120 return (0); 121 } 122 123 /* disable nagle on socket */ 124 void 125 set_nodelay(int fd) 126 { 127 int opt; 128 socklen_t optlen; 129 130 optlen = sizeof opt; 131 if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) { 132 debug("getsockopt TCP_NODELAY: %.100s", strerror(errno)); 133 return; 134 } 135 if (opt == 1) { 136 debug2("fd %d is TCP_NODELAY", fd); 137 return; 138 } 139 opt = 1; 140 debug2("fd %d setting TCP_NODELAY", fd); 141 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1) 142 error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); 143 } 144 145 /* Characters considered whitespace in strsep calls. */ 146 #define WHITESPACE " \t\r\n" 147 #define QUOTE "\"" 148 149 /* return next token in configuration line */ 150 char * 151 strdelim(char **s) 152 { 153 char *old; 154 int wspace = 0; 155 156 if (*s == NULL) 157 return NULL; 158 159 old = *s; 160 161 *s = strpbrk(*s, WHITESPACE QUOTE "="); 162 if (*s == NULL) 163 return (old); 164 165 if (*s[0] == '\"') { 166 memmove(*s, *s + 1, strlen(*s)); /* move nul too */ 167 /* Find matching quote */ 168 if ((*s = strpbrk(*s, QUOTE)) == NULL) { 169 return (NULL); /* no matching quote */ 170 } else { 171 *s[0] = '\0'; 172 return (old); 173 } 174 } 175 176 /* Allow only one '=' to be skipped */ 177 if (*s[0] == '=') 178 wspace = 1; 179 *s[0] = '\0'; 180 181 /* Skip any extra whitespace after first token */ 182 *s += strspn(*s + 1, WHITESPACE) + 1; 183 if (*s[0] == '=' && !wspace) 184 *s += strspn(*s + 1, WHITESPACE) + 1; 185 186 return (old); 187 } 188 189 struct passwd * 190 pwcopy(struct passwd *pw) 191 { 192 struct passwd *copy = xcalloc(1, sizeof(*copy)); 193 194 copy->pw_name = xstrdup(pw->pw_name); 195 copy->pw_passwd = xstrdup(pw->pw_passwd); 196 copy->pw_gecos = xstrdup(pw->pw_gecos); 197 copy->pw_uid = pw->pw_uid; 198 copy->pw_gid = pw->pw_gid; 199 #ifdef HAVE_PW_EXPIRE_IN_PASSWD 200 copy->pw_expire = pw->pw_expire; 201 #endif 202 #ifdef HAVE_PW_CHANGE_IN_PASSWD 203 copy->pw_change = pw->pw_change; 204 #endif 205 #ifdef HAVE_PW_CLASS_IN_PASSWD 206 copy->pw_class = xstrdup(pw->pw_class); 207 #endif 208 copy->pw_dir = xstrdup(pw->pw_dir); 209 copy->pw_shell = xstrdup(pw->pw_shell); 210 return copy; 211 } 212 213 /* 214 * Convert ASCII string to TCP/IP port number. 215 * Port must be >0 and <=65535. 216 * Return 0 if invalid. 217 */ 218 int 219 a2port(const char *s) 220 { 221 long port; 222 char *endp; 223 224 errno = 0; 225 port = strtol(s, &endp, 0); 226 if (s == endp || *endp != '\0' || 227 (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) || 228 port <= 0 || port > 65535) 229 return 0; 230 231 return port; 232 } 233 234 int 235 a2tun(const char *s, int *remote) 236 { 237 const char *errstr = NULL; 238 char *sp, *ep; 239 int tun; 240 241 if (remote != NULL) { 242 *remote = SSH_TUNID_ANY; 243 sp = xstrdup(s); 244 if ((ep = strchr(sp, ':')) == NULL) { 245 xfree(sp); 246 return (a2tun(s, NULL)); 247 } 248 ep[0] = '\0'; ep++; 249 *remote = a2tun(ep, NULL); 250 tun = a2tun(sp, NULL); 251 xfree(sp); 252 return (*remote == SSH_TUNID_ERR ? *remote : tun); 253 } 254 255 if (strcasecmp(s, "any") == 0) 256 return (SSH_TUNID_ANY); 257 258 tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr); 259 if (errstr != NULL) 260 return (SSH_TUNID_ERR); 261 262 return (tun); 263 } 264 265 #define SECONDS 1 266 #define MINUTES (SECONDS * 60) 267 #define HOURS (MINUTES * 60) 268 #define DAYS (HOURS * 24) 269 #define WEEKS (DAYS * 7) 270 271 /* 272 * Convert a time string into seconds; format is 273 * a sequence of: 274 * time[qualifier] 275 * 276 * Valid time qualifiers are: 277 * <none> seconds 278 * s|S seconds 279 * m|M minutes 280 * h|H hours 281 * d|D days 282 * w|W weeks 283 * 284 * Examples: 285 * 90m 90 minutes 286 * 1h30m 90 minutes 287 * 2d 2 days 288 * 1w 1 week 289 * 290 * Return -1 if time string is invalid. 291 */ 292 long 293 convtime(const char *s) 294 { 295 long total, secs; 296 const char *p; 297 char *endp; 298 299 errno = 0; 300 total = 0; 301 p = s; 302 303 if (p == NULL || *p == '\0') 304 return -1; 305 306 while (*p) { 307 secs = strtol(p, &endp, 10); 308 if (p == endp || 309 (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) || 310 secs < 0) 311 return -1; 312 313 switch (*endp++) { 314 case '\0': 315 endp--; 316 break; 317 case 's': 318 case 'S': 319 break; 320 case 'm': 321 case 'M': 322 secs *= MINUTES; 323 break; 324 case 'h': 325 case 'H': 326 secs *= HOURS; 327 break; 328 case 'd': 329 case 'D': 330 secs *= DAYS; 331 break; 332 case 'w': 333 case 'W': 334 secs *= WEEKS; 335 break; 336 default: 337 return -1; 338 } 339 total += secs; 340 if (total < 0) 341 return -1; 342 p = endp; 343 } 344 345 return total; 346 } 347 348 /* 349 * Returns a standardized host+port identifier string. 350 * Caller must free returned string. 351 */ 352 char * 353 put_host_port(const char *host, u_short port) 354 { 355 char *hoststr; 356 357 if (port == 0 || port == SSH_DEFAULT_PORT) 358 return(xstrdup(host)); 359 if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0) 360 fatal("put_host_port: asprintf: %s", strerror(errno)); 361 debug3("put_host_port: %s", hoststr); 362 return hoststr; 363 } 364 365 /* 366 * Search for next delimiter between hostnames/addresses and ports. 367 * Argument may be modified (for termination). 368 * Returns *cp if parsing succeeds. 369 * *cp is set to the start of the next delimiter, if one was found. 370 * If this is the last field, *cp is set to NULL. 371 */ 372 char * 373 hpdelim(char **cp) 374 { 375 char *s, *old; 376 377 if (cp == NULL || *cp == NULL) 378 return NULL; 379 380 old = s = *cp; 381 if (*s == '[') { 382 if ((s = strchr(s, ']')) == NULL) 383 return NULL; 384 else 385 s++; 386 } else if ((s = strpbrk(s, ":/")) == NULL) 387 s = *cp + strlen(*cp); /* skip to end (see first case below) */ 388 389 switch (*s) { 390 case '\0': 391 *cp = NULL; /* no more fields*/ 392 break; 393 394 case ':': 395 case '/': 396 *s = '\0'; /* terminate */ 397 *cp = s + 1; 398 break; 399 400 default: 401 return NULL; 402 } 403 404 return old; 405 } 406 407 char * 408 cleanhostname(char *host) 409 { 410 if (*host == '[' && host[strlen(host) - 1] == ']') { 411 host[strlen(host) - 1] = '\0'; 412 return (host + 1); 413 } else 414 return host; 415 } 416 417 char * 418 colon(char *cp) 419 { 420 int flag = 0; 421 422 if (*cp == ':') /* Leading colon is part of file name. */ 423 return (0); 424 if (*cp == '[') 425 flag = 1; 426 427 for (; *cp; ++cp) { 428 if (*cp == '@' && *(cp+1) == '[') 429 flag = 1; 430 if (*cp == ']' && *(cp+1) == ':' && flag) 431 return (cp+1); 432 if (*cp == ':' && !flag) 433 return (cp); 434 if (*cp == '/') 435 return (0); 436 } 437 return (0); 438 } 439 440 /* function to assist building execv() arguments */ 441 void 442 addargs(arglist *args, char *fmt, ...) 443 { 444 va_list ap; 445 char *cp; 446 u_int nalloc; 447 int r; 448 449 va_start(ap, fmt); 450 r = vasprintf(&cp, fmt, ap); 451 va_end(ap); 452 if (r == -1) 453 fatal("addargs: argument too long"); 454 455 nalloc = args->nalloc; 456 if (args->list == NULL) { 457 nalloc = 32; 458 args->num = 0; 459 } else if (args->num+2 >= nalloc) 460 nalloc *= 2; 461 462 args->list = xrealloc(args->list, nalloc, sizeof(char *)); 463 args->nalloc = nalloc; 464 args->list[args->num++] = cp; 465 args->list[args->num] = NULL; 466 } 467 468 void 469 replacearg(arglist *args, u_int which, char *fmt, ...) 470 { 471 va_list ap; 472 char *cp; 473 int r; 474 475 va_start(ap, fmt); 476 r = vasprintf(&cp, fmt, ap); 477 va_end(ap); 478 if (r == -1) 479 fatal("replacearg: argument too long"); 480 481 if (which >= args->num) 482 fatal("replacearg: tried to replace invalid arg %d >= %d", 483 which, args->num); 484 xfree(args->list[which]); 485 args->list[which] = cp; 486 } 487 488 void 489 freeargs(arglist *args) 490 { 491 u_int i; 492 493 if (args->list != NULL) { 494 for (i = 0; i < args->num; i++) 495 xfree(args->list[i]); 496 xfree(args->list); 497 args->nalloc = args->num = 0; 498 args->list = NULL; 499 } 500 } 501 502 /* 503 * Expands tildes in the file name. Returns data allocated by xmalloc. 504 * Warning: this calls getpw*. 505 */ 506 char * 507 tilde_expand_filename(const char *filename, uid_t uid) 508 { 509 const char *path; 510 char user[128], ret[MAXPATHLEN]; 511 struct passwd *pw; 512 u_int len, slash; 513 514 if (*filename != '~') 515 return (xstrdup(filename)); 516 filename++; 517 518 path = strchr(filename, '/'); 519 if (path != NULL && path > filename) { /* ~user/path */ 520 slash = path - filename; 521 if (slash > sizeof(user) - 1) 522 fatal("tilde_expand_filename: ~username too long"); 523 memcpy(user, filename, slash); 524 user[slash] = '\0'; 525 if ((pw = getpwnam(user)) == NULL) 526 fatal("tilde_expand_filename: No such user %s", user); 527 } else if ((pw = getpwuid(uid)) == NULL) /* ~/path */ 528 fatal("tilde_expand_filename: No such uid %d", uid); 529 530 if (strlcpy(ret, pw->pw_dir, sizeof(ret)) >= sizeof(ret)) 531 fatal("tilde_expand_filename: Path too long"); 532 533 /* Make sure directory has a trailing '/' */ 534 len = strlen(pw->pw_dir); 535 if ((len == 0 || pw->pw_dir[len - 1] != '/') && 536 strlcat(ret, "/", sizeof(ret)) >= sizeof(ret)) 537 fatal("tilde_expand_filename: Path too long"); 538 539 /* Skip leading '/' from specified path */ 540 if (path != NULL) 541 filename = path + 1; 542 if (strlcat(ret, filename, sizeof(ret)) >= sizeof(ret)) 543 fatal("tilde_expand_filename: Path too long"); 544 545 return (xstrdup(ret)); 546 } 547 548 /* 549 * Expand a string with a set of %[char] escapes. A number of escapes may be 550 * specified as (char *escape_chars, char *replacement) pairs. The list must 551 * be terminated by a NULL escape_char. Returns replaced string in memory 552 * allocated by xmalloc. 553 */ 554 char * 555 percent_expand(const char *string, ...) 556 { 557 #define EXPAND_MAX_KEYS 16 558 struct { 559 const char *key; 560 const char *repl; 561 } keys[EXPAND_MAX_KEYS]; 562 u_int num_keys, i, j; 563 char buf[4096]; 564 va_list ap; 565 566 /* Gather keys */ 567 va_start(ap, string); 568 for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) { 569 keys[num_keys].key = va_arg(ap, char *); 570 if (keys[num_keys].key == NULL) 571 break; 572 keys[num_keys].repl = va_arg(ap, char *); 573 if (keys[num_keys].repl == NULL) 574 fatal("percent_expand: NULL replacement"); 575 } 576 va_end(ap); 577 578 if (num_keys >= EXPAND_MAX_KEYS) 579 fatal("percent_expand: too many keys"); 580 581 /* Expand string */ 582 *buf = '\0'; 583 for (i = 0; *string != '\0'; string++) { 584 if (*string != '%') { 585 append: 586 buf[i++] = *string; 587 if (i >= sizeof(buf)) 588 fatal("percent_expand: string too long"); 589 buf[i] = '\0'; 590 continue; 591 } 592 string++; 593 if (*string == '%') 594 goto append; 595 for (j = 0; j < num_keys; j++) { 596 if (strchr(keys[j].key, *string) != NULL) { 597 i = strlcat(buf, keys[j].repl, sizeof(buf)); 598 if (i >= sizeof(buf)) 599 fatal("percent_expand: string too long"); 600 break; 601 } 602 } 603 if (j >= num_keys) 604 fatal("percent_expand: unknown key %%%c", *string); 605 } 606 return (xstrdup(buf)); 607 #undef EXPAND_MAX_KEYS 608 } 609 610 /* 611 * Read an entire line from a public key file into a static buffer, discarding 612 * lines that exceed the buffer size. Returns 0 on success, -1 on failure. 613 */ 614 int 615 read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz, 616 u_long *lineno) 617 { 618 while (fgets(buf, bufsz, f) != NULL) { 619 (*lineno)++; 620 if (buf[strlen(buf) - 1] == '\n' || feof(f)) { 621 return 0; 622 } else { 623 debug("%s: %s line %lu exceeds size limit", __func__, 624 filename, *lineno); 625 /* discard remainder of line */ 626 while (fgetc(f) != '\n' && !feof(f)) 627 ; /* nothing */ 628 } 629 } 630 return -1; 631 } 632 633 int 634 tun_open(int tun, int mode) 635 { 636 #if defined(CUSTOM_SYS_TUN_OPEN) 637 return (sys_tun_open(tun, mode)); 638 #elif defined(SSH_TUN_OPENBSD) 639 struct ifreq ifr; 640 char name[100]; 641 int fd = -1, sock; 642 643 /* Open the tunnel device */ 644 if (tun <= SSH_TUNID_MAX) { 645 snprintf(name, sizeof(name), "/dev/tun%d", tun); 646 fd = open(name, O_RDWR); 647 } else if (tun == SSH_TUNID_ANY) { 648 for (tun = 100; tun >= 0; tun--) { 649 snprintf(name, sizeof(name), "/dev/tun%d", tun); 650 if ((fd = open(name, O_RDWR)) >= 0) 651 break; 652 } 653 } else { 654 debug("%s: invalid tunnel %u", __func__, tun); 655 return (-1); 656 } 657 658 if (fd < 0) { 659 debug("%s: %s open failed: %s", __func__, name, strerror(errno)); 660 return (-1); 661 } 662 663 debug("%s: %s mode %d fd %d", __func__, name, mode, fd); 664 665 /* Set the tunnel device operation mode */ 666 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tun%d", tun); 667 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) 668 goto failed; 669 670 if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) 671 goto failed; 672 673 /* Set interface mode */ 674 ifr.ifr_flags &= ~IFF_UP; 675 if (mode == SSH_TUNMODE_ETHERNET) 676 ifr.ifr_flags |= IFF_LINK0; 677 else 678 ifr.ifr_flags &= ~IFF_LINK0; 679 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) 680 goto failed; 681 682 /* Bring interface up */ 683 ifr.ifr_flags |= IFF_UP; 684 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) 685 goto failed; 686 687 close(sock); 688 return (fd); 689 690 failed: 691 if (fd >= 0) 692 close(fd); 693 if (sock >= 0) 694 close(sock); 695 debug("%s: failed to set %s mode %d: %s", __func__, name, 696 mode, strerror(errno)); 697 return (-1); 698 #else 699 error("Tunnel interfaces are not supported on this platform"); 700 return (-1); 701 #endif 702 } 703 704 void 705 sanitise_stdfd(void) 706 { 707 int nullfd, dupfd; 708 709 if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 710 fprintf(stderr, "Couldn't open /dev/null: %s", strerror(errno)); 711 exit(1); 712 } 713 while (++dupfd <= 2) { 714 /* Only clobber closed fds */ 715 if (fcntl(dupfd, F_GETFL, 0) >= 0) 716 continue; 717 if (dup2(nullfd, dupfd) == -1) { 718 fprintf(stderr, "dup2: %s", strerror(errno)); 719 exit(1); 720 } 721 } 722 if (nullfd > 2) 723 close(nullfd); 724 } 725 726 char * 727 tohex(const void *vp, size_t l) 728 { 729 const u_char *p = (const u_char *)vp; 730 char b[3], *r; 731 size_t i, hl; 732 733 if (l > 65536) 734 return xstrdup("tohex: length > 65536"); 735 736 hl = l * 2 + 1; 737 r = xcalloc(1, hl); 738 for (i = 0; i < l; i++) { 739 snprintf(b, sizeof(b), "%02x", p[i]); 740 strlcat(r, b, hl); 741 } 742 return (r); 743 } 744 745 u_int64_t 746 get_u64(const void *vp) 747 { 748 const u_char *p = (const u_char *)vp; 749 u_int64_t v; 750 751 v = (u_int64_t)p[0] << 56; 752 v |= (u_int64_t)p[1] << 48; 753 v |= (u_int64_t)p[2] << 40; 754 v |= (u_int64_t)p[3] << 32; 755 v |= (u_int64_t)p[4] << 24; 756 v |= (u_int64_t)p[5] << 16; 757 v |= (u_int64_t)p[6] << 8; 758 v |= (u_int64_t)p[7]; 759 760 return (v); 761 } 762 763 u_int32_t 764 get_u32(const void *vp) 765 { 766 const u_char *p = (const u_char *)vp; 767 u_int32_t v; 768 769 v = (u_int32_t)p[0] << 24; 770 v |= (u_int32_t)p[1] << 16; 771 v |= (u_int32_t)p[2] << 8; 772 v |= (u_int32_t)p[3]; 773 774 return (v); 775 } 776 777 u_int16_t 778 get_u16(const void *vp) 779 { 780 const u_char *p = (const u_char *)vp; 781 u_int16_t v; 782 783 v = (u_int16_t)p[0] << 8; 784 v |= (u_int16_t)p[1]; 785 786 return (v); 787 } 788 789 void 790 put_u64(void *vp, u_int64_t v) 791 { 792 u_char *p = (u_char *)vp; 793 794 p[0] = (u_char)(v >> 56) & 0xff; 795 p[1] = (u_char)(v >> 48) & 0xff; 796 p[2] = (u_char)(v >> 40) & 0xff; 797 p[3] = (u_char)(v >> 32) & 0xff; 798 p[4] = (u_char)(v >> 24) & 0xff; 799 p[5] = (u_char)(v >> 16) & 0xff; 800 p[6] = (u_char)(v >> 8) & 0xff; 801 p[7] = (u_char)v & 0xff; 802 } 803 804 void 805 put_u32(void *vp, u_int32_t v) 806 { 807 u_char *p = (u_char *)vp; 808 809 p[0] = (u_char)(v >> 24) & 0xff; 810 p[1] = (u_char)(v >> 16) & 0xff; 811 p[2] = (u_char)(v >> 8) & 0xff; 812 p[3] = (u_char)v & 0xff; 813 } 814 815 816 void 817 put_u16(void *vp, u_int16_t v) 818 { 819 u_char *p = (u_char *)vp; 820 821 p[0] = (u_char)(v >> 8) & 0xff; 822 p[1] = (u_char)v & 0xff; 823 } 824