1 /* $NetBSD: misc.c,v 1.8 2013/11/08 19:18:25 christos Exp $ */ 2 /* $OpenBSD: misc.c,v 1.91 2013/07/12 00:43:50 djm Exp $ */ 3 /* 4 * Copyright (c) 2000 Markus Friedl. All rights reserved. 5 * Copyright (c) 2005,2006 Damien Miller. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "includes.h" 29 __RCSID("$NetBSD: misc.c,v 1.8 2013/11/08 19:18:25 christos Exp $"); 30 #include <sys/types.h> 31 #include <sys/ioctl.h> 32 #include <sys/socket.h> 33 #include <sys/param.h> 34 35 #include <net/if.h> 36 #include <net/if_tun.h> 37 #include <netinet/in.h> 38 #include <netinet/in_systm.h> 39 #include <netinet/ip.h> 40 #include <netinet/tcp.h> 41 42 #include <errno.h> 43 #include <fcntl.h> 44 #include <netdb.h> 45 #include <paths.h> 46 #include <pwd.h> 47 #include <stdarg.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 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 const char * 124 ssh_gai_strerror(int gaierr) 125 { 126 if (gaierr == EAI_SYSTEM && errno != 0) 127 return strerror(errno); 128 return gai_strerror(gaierr); 129 } 130 131 /* disable nagle on socket */ 132 void 133 set_nodelay(int fd) 134 { 135 int opt; 136 socklen_t optlen; 137 138 optlen = sizeof opt; 139 if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) { 140 debug("getsockopt TCP_NODELAY: %.100s", strerror(errno)); 141 return; 142 } 143 if (opt == 1) { 144 debug2("fd %d is TCP_NODELAY", fd); 145 return; 146 } 147 opt = 1; 148 debug2("fd %d setting TCP_NODELAY", fd); 149 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1) 150 error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); 151 } 152 153 /* Characters considered whitespace in strsep calls. */ 154 #define WHITESPACE " \t\r\n" 155 #define QUOTE "\"" 156 157 /* return next token in configuration line */ 158 char * 159 strdelim(char **s) 160 { 161 char *old; 162 int wspace = 0; 163 164 if (*s == NULL) 165 return NULL; 166 167 old = *s; 168 169 *s = strpbrk(*s, WHITESPACE QUOTE "="); 170 if (*s == NULL) 171 return (old); 172 173 if (*s[0] == '\"') { 174 memmove(*s, *s + 1, strlen(*s)); /* move nul too */ 175 /* Find matching quote */ 176 if ((*s = strpbrk(*s, QUOTE)) == NULL) { 177 return (NULL); /* no matching quote */ 178 } else { 179 *s[0] = '\0'; 180 *s += strspn(*s + 1, WHITESPACE) + 1; 181 return (old); 182 } 183 } 184 185 /* Allow only one '=' to be skipped */ 186 if (*s[0] == '=') 187 wspace = 1; 188 *s[0] = '\0'; 189 190 /* Skip any extra whitespace after first token */ 191 *s += strspn(*s + 1, WHITESPACE) + 1; 192 if (*s[0] == '=' && !wspace) 193 *s += strspn(*s + 1, WHITESPACE) + 1; 194 195 return (old); 196 } 197 198 struct passwd * 199 pwcopy(struct passwd *pw) 200 { 201 struct passwd *copy = xcalloc(1, sizeof(*copy)); 202 203 copy->pw_name = xstrdup(pw->pw_name); 204 copy->pw_passwd = xstrdup(pw->pw_passwd); 205 copy->pw_gecos = xstrdup(pw->pw_gecos); 206 copy->pw_uid = pw->pw_uid; 207 copy->pw_gid = pw->pw_gid; 208 copy->pw_expire = pw->pw_expire; 209 copy->pw_change = pw->pw_change; 210 copy->pw_class = xstrdup(pw->pw_class); 211 copy->pw_dir = xstrdup(pw->pw_dir); 212 copy->pw_shell = xstrdup(pw->pw_shell); 213 return copy; 214 } 215 216 /* 217 * Convert ASCII string to TCP/IP port number. 218 * Port must be >=0 and <=65535. 219 * Return -1 if invalid. 220 */ 221 int 222 a2port(const char *s) 223 { 224 long long port; 225 const char *errstr; 226 227 port = strtonum(s, 0, 65535, &errstr); 228 if (errstr != NULL) 229 return -1; 230 return (int)port; 231 } 232 233 int 234 a2tun(const char *s, int *remote) 235 { 236 const char *errstr = NULL; 237 char *sp, *ep; 238 int tun; 239 240 if (remote != NULL) { 241 *remote = SSH_TUNID_ANY; 242 sp = xstrdup(s); 243 if ((ep = strchr(sp, ':')) == NULL) { 244 free(sp); 245 return (a2tun(s, NULL)); 246 } 247 ep[0] = '\0'; ep++; 248 *remote = a2tun(ep, NULL); 249 tun = a2tun(sp, NULL); 250 free(sp); 251 return (*remote == SSH_TUNID_ERR ? *remote : tun); 252 } 253 254 if (strcasecmp(s, "any") == 0) 255 return (SSH_TUNID_ANY); 256 257 tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr); 258 if (errstr != NULL) 259 return (SSH_TUNID_ERR); 260 261 return (tun); 262 } 263 264 #define SECONDS 1 265 #define MINUTES (SECONDS * 60) 266 #define HOURS (MINUTES * 60) 267 #define DAYS (HOURS * 24) 268 #define WEEKS (DAYS * 7) 269 270 /* 271 * Convert a time string into seconds; format is 272 * a sequence of: 273 * time[qualifier] 274 * 275 * Valid time qualifiers are: 276 * <none> seconds 277 * s|S seconds 278 * m|M minutes 279 * h|H hours 280 * d|D days 281 * w|W weeks 282 * 283 * Examples: 284 * 90m 90 minutes 285 * 1h30m 90 minutes 286 * 2d 2 days 287 * 1w 1 week 288 * 289 * Return -1 if time string is invalid. 290 */ 291 long 292 convtime(const char *s) 293 { 294 long total, secs; 295 const char *p; 296 char *endp; 297 298 errno = 0; 299 total = 0; 300 p = s; 301 302 if (p == NULL || *p == '\0') 303 return -1; 304 305 while (*p) { 306 secs = strtol(p, &endp, 10); 307 if (p == endp || 308 (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) || 309 secs < 0) 310 return -1; 311 312 switch (*endp++) { 313 case '\0': 314 endp--; 315 break; 316 case 's': 317 case 'S': 318 break; 319 case 'm': 320 case 'M': 321 secs *= MINUTES; 322 break; 323 case 'h': 324 case 'H': 325 secs *= HOURS; 326 break; 327 case 'd': 328 case 'D': 329 secs *= DAYS; 330 break; 331 case 'w': 332 case 'W': 333 secs *= WEEKS; 334 break; 335 default: 336 return -1; 337 } 338 total += secs; 339 if (total < 0) 340 return -1; 341 p = endp; 342 } 343 344 return total; 345 } 346 347 /* 348 * Returns a standardized host+port identifier string. 349 * Caller must free returned string. 350 */ 351 char * 352 put_host_port(const char *host, u_short port) 353 { 354 char *hoststr; 355 356 if (port == 0 || port == SSH_DEFAULT_PORT) 357 return(xstrdup(host)); 358 if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0) 359 fatal("put_host_port: asprintf: %s", strerror(errno)); 360 debug3("put_host_port: %s", hoststr); 361 return hoststr; 362 } 363 364 /* 365 * Search for next delimiter between hostnames/addresses and ports. 366 * Argument may be modified (for termination). 367 * Returns *cp if parsing succeeds. 368 * *cp is set to the start of the next delimiter, if one was found. 369 * If this is the last field, *cp is set to NULL. 370 */ 371 char * 372 hpdelim(char **cp) 373 { 374 char *s, *old; 375 376 if (cp == NULL || *cp == NULL) 377 return NULL; 378 379 old = s = *cp; 380 if (*s == '[') { 381 if ((s = strchr(s, ']')) == NULL) 382 return NULL; 383 else 384 s++; 385 } else if ((s = strpbrk(s, ":/")) == NULL) 386 s = *cp + strlen(*cp); /* skip to end (see first case below) */ 387 388 switch (*s) { 389 case '\0': 390 *cp = NULL; /* no more fields*/ 391 break; 392 393 case ':': 394 case '/': 395 *s = '\0'; /* terminate */ 396 *cp = s + 1; 397 break; 398 399 default: 400 return NULL; 401 } 402 403 return old; 404 } 405 406 char * 407 cleanhostname(char *host) 408 { 409 if (*host == '[' && host[strlen(host) - 1] == ']') { 410 host[strlen(host) - 1] = '\0'; 411 return (host + 1); 412 } else 413 return host; 414 } 415 416 char * 417 colon(char *cp) 418 { 419 int flag = 0; 420 421 if (*cp == ':') /* Leading colon is part of file name. */ 422 return NULL; 423 if (*cp == '[') 424 flag = 1; 425 426 for (; *cp; ++cp) { 427 if (*cp == '@' && *(cp+1) == '[') 428 flag = 1; 429 if (*cp == ']' && *(cp+1) == ':' && flag) 430 return (cp+1); 431 if (*cp == ':' && !flag) 432 return (cp); 433 if (*cp == '/') 434 return NULL; 435 } 436 return NULL; 437 } 438 439 /* function to assist building execv() arguments */ 440 void 441 addargs(arglist *args, const char *fmt, ...) 442 { 443 va_list ap; 444 char *cp; 445 u_int nalloc; 446 int r; 447 448 va_start(ap, fmt); 449 r = vasprintf(&cp, fmt, ap); 450 va_end(ap); 451 if (r == -1) 452 fatal("addargs: argument too long"); 453 454 nalloc = args->nalloc; 455 if (args->list == NULL) { 456 nalloc = 32; 457 args->num = 0; 458 } else if (args->num+2 >= nalloc) 459 nalloc *= 2; 460 461 args->list = xrealloc(args->list, nalloc, sizeof(char *)); 462 args->nalloc = nalloc; 463 args->list[args->num++] = cp; 464 args->list[args->num] = NULL; 465 } 466 467 void 468 replacearg(arglist *args, u_int which, const char *fmt, ...) 469 { 470 va_list ap; 471 char *cp; 472 int r; 473 474 va_start(ap, fmt); 475 r = vasprintf(&cp, fmt, ap); 476 va_end(ap); 477 if (r == -1) 478 fatal("replacearg: argument too long"); 479 480 if (which >= args->num) 481 fatal("replacearg: tried to replace invalid arg %d >= %d", 482 which, args->num); 483 free(args->list[which]); 484 args->list[which] = cp; 485 } 486 487 void 488 freeargs(arglist *args) 489 { 490 u_int i; 491 492 if (args->list != NULL) { 493 for (i = 0; i < args->num; i++) 494 free(args->list[i]); 495 free(args->list); 496 args->nalloc = args->num = 0; 497 args->list = NULL; 498 } 499 } 500 501 /* 502 * Expands tildes in the file name. Returns data allocated by xmalloc. 503 * Warning: this calls getpw*. 504 */ 505 char * 506 tilde_expand_filename(const char *filename, uid_t uid) 507 { 508 const char *path, *sep; 509 char user[128], *ret, *homedir; 510 struct passwd *pw; 511 u_int len, slash; 512 513 if (*filename != '~') 514 return (xstrdup(filename)); 515 filename++; 516 517 path = strchr(filename, '/'); 518 if (path != NULL && path > filename) { /* ~user/path */ 519 slash = path - filename; 520 if (slash > sizeof(user) - 1) 521 fatal("tilde_expand_filename: ~username too long"); 522 memcpy(user, filename, slash); 523 user[slash] = '\0'; 524 if ((pw = getpwnam(user)) == NULL) 525 fatal("tilde_expand_filename: No such user %s", user); 526 homedir = pw->pw_dir; 527 } else { 528 if ((pw = getpwuid(uid)) == NULL) /* ~/path */ 529 fatal("tilde_expand_filename: No such uid %ld", 530 (long)uid); 531 homedir = pw->pw_dir; 532 } 533 534 /* Make sure directory has a trailing '/' */ 535 len = strlen(homedir); 536 if (len == 0 || homedir[len - 1] != '/') 537 sep = "/"; 538 else 539 sep = ""; 540 541 /* Skip leading '/' from specified path */ 542 if (path != NULL) 543 filename = path + 1; 544 545 if (xasprintf(&ret, "%s%s%s", homedir, sep, filename) >= MAXPATHLEN) 546 fatal("tilde_expand_filename: Path too long"); 547 548 return (ret); 549 } 550 551 /* 552 * Expand a string with a set of %[char] escapes. A number of escapes may be 553 * specified as (char *escape_chars, char *replacement) pairs. The list must 554 * be terminated by a NULL escape_char. Returns replaced string in memory 555 * allocated by xmalloc. 556 */ 557 char * 558 percent_expand(const char *string, ...) 559 { 560 #define EXPAND_MAX_KEYS 16 561 u_int num_keys, i, j; 562 struct { 563 const char *key; 564 const char *repl; 565 } keys[EXPAND_MAX_KEYS]; 566 char buf[4096]; 567 va_list ap; 568 569 /* Gather keys */ 570 va_start(ap, string); 571 for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) { 572 keys[num_keys].key = va_arg(ap, char *); 573 if (keys[num_keys].key == NULL) 574 break; 575 keys[num_keys].repl = va_arg(ap, char *); 576 if (keys[num_keys].repl == NULL) 577 fatal("%s: NULL replacement", __func__); 578 } 579 if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL) 580 fatal("%s: too many keys", __func__); 581 va_end(ap); 582 583 /* Expand string */ 584 *buf = '\0'; 585 for (i = 0; *string != '\0'; string++) { 586 if (*string != '%') { 587 append: 588 buf[i++] = *string; 589 if (i >= sizeof(buf)) 590 fatal("%s: string too long", __func__); 591 buf[i] = '\0'; 592 continue; 593 } 594 string++; 595 /* %% case */ 596 if (*string == '%') 597 goto append; 598 for (j = 0; j < num_keys; j++) { 599 if (strchr(keys[j].key, *string) != NULL) { 600 i = strlcat(buf, keys[j].repl, sizeof(buf)); 601 if (i >= sizeof(buf)) 602 fatal("%s: string too long", __func__); 603 break; 604 } 605 } 606 if (j >= num_keys) 607 fatal("%s: unknown key %%%c", __func__, *string); 608 } 609 return (xstrdup(buf)); 610 #undef EXPAND_MAX_KEYS 611 } 612 613 /* 614 * Read an entire line from a public key file into a static buffer, discarding 615 * lines that exceed the buffer size. Returns 0 on success, -1 on failure. 616 */ 617 int 618 read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz, 619 u_long *lineno) 620 { 621 while (fgets(buf, bufsz, f) != NULL) { 622 if (buf[0] == '\0') 623 continue; 624 (*lineno)++; 625 if (buf[strlen(buf) - 1] == '\n' || feof(f)) { 626 return 0; 627 } else { 628 debug("%s: %s line %lu exceeds size limit", __func__, 629 filename, *lineno); 630 /* discard remainder of line */ 631 while (fgetc(f) != '\n' && !feof(f)) 632 ; /* nothing */ 633 } 634 } 635 return -1; 636 } 637 638 int 639 tun_open(int tun, int mode) 640 { 641 struct ifreq ifr; 642 int fd = -1, sock, flag; 643 const char *tunbase = mode == SSH_TUNMODE_ETHERNET ? "tap" : "tun"; 644 645 /* Open the tunnel device */ 646 if (tun <= SSH_TUNID_MAX) { 647 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), 648 "/dev/%s%d", tunbase, tun); 649 fd = open(ifr.ifr_name, O_RDWR); 650 } else if (tun == SSH_TUNID_ANY) { 651 for (tun = 100; tun >= 0; tun--) { 652 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), 653 "/dev/%s%d", tunbase, tun); 654 if ((fd = open(ifr.ifr_name, O_RDWR)) >= 0) 655 break; 656 } 657 } else { 658 debug("%s: invalid tunnel %u", __func__, tun); 659 return (-1); 660 } 661 662 if (fd < 0) { 663 debug("%s: %s open failed: %s", __func__, ifr.ifr_name, 664 strerror(errno)); 665 return (-1); 666 } 667 668 669 /* Turn on tunnel headers */ 670 flag = 1; 671 if (mode != SSH_TUNMODE_ETHERNET && 672 ioctl(fd, TUNSIFHEAD, &flag) == -1) { 673 debug("%s: ioctl(%d, TUNSIFHEAD, 1): %s", __func__, fd, 674 strerror(errno)); 675 close(fd); 676 return -1; 677 } 678 679 debug("%s: %s mode %d fd %d", __func__, ifr.ifr_name, mode, fd); 680 /* Set the tunnel device operation mode */ 681 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun); 682 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) 683 goto failed; 684 685 if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) 686 goto failed; 687 688 #if 0 689 /* Set interface mode */ 690 ifr.ifr_flags &= ~IFF_UP; 691 if (mode == SSH_TUNMODE_ETHERNET) 692 ifr.ifr_flags |= IFF_LINK0; 693 else 694 ifr.ifr_flags &= ~IFF_LINK0; 695 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) 696 goto failed; 697 #endif 698 699 /* Bring interface up */ 700 ifr.ifr_flags |= IFF_UP; 701 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) 702 goto failed; 703 704 close(sock); 705 return (fd); 706 707 failed: 708 if (fd >= 0) 709 close(fd); 710 if (sock >= 0) 711 close(sock); 712 debug("%s: failed to set %s mode %d: %s", __func__, ifr.ifr_name, 713 mode, strerror(errno)); 714 return (-1); 715 } 716 717 void 718 sanitise_stdfd(void) 719 { 720 int nullfd, dupfd; 721 722 if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 723 fprintf(stderr, "Couldn't open /dev/null: %s\n", 724 strerror(errno)); 725 exit(1); 726 } 727 while (++dupfd <= 2) { 728 /* Only clobber closed fds */ 729 if (fcntl(dupfd, F_GETFL, 0) >= 0) 730 continue; 731 if (dup2(nullfd, dupfd) == -1) { 732 fprintf(stderr, "dup2: %s\n", strerror(errno)); 733 exit(1); 734 } 735 } 736 if (nullfd > 2) 737 close(nullfd); 738 } 739 740 char * 741 tohex(const void *vp, size_t l) 742 { 743 const u_char *p = (const u_char *)vp; 744 char b[3], *r; 745 size_t i, hl; 746 747 if (l > 65536) 748 return xstrdup("tohex: length > 65536"); 749 750 hl = l * 2 + 1; 751 r = xcalloc(1, hl); 752 for (i = 0; i < l; i++) { 753 snprintf(b, sizeof(b), "%02x", p[i]); 754 strlcat(r, b, hl); 755 } 756 return (r); 757 } 758 759 u_int64_t 760 get_u64(const void *vp) 761 { 762 const u_char *p = (const u_char *)vp; 763 u_int64_t v; 764 765 v = (u_int64_t)p[0] << 56; 766 v |= (u_int64_t)p[1] << 48; 767 v |= (u_int64_t)p[2] << 40; 768 v |= (u_int64_t)p[3] << 32; 769 v |= (u_int64_t)p[4] << 24; 770 v |= (u_int64_t)p[5] << 16; 771 v |= (u_int64_t)p[6] << 8; 772 v |= (u_int64_t)p[7]; 773 774 return (v); 775 } 776 777 u_int32_t 778 get_u32(const void *vp) 779 { 780 const u_char *p = (const u_char *)vp; 781 u_int32_t v; 782 783 v = (u_int32_t)p[0] << 24; 784 v |= (u_int32_t)p[1] << 16; 785 v |= (u_int32_t)p[2] << 8; 786 v |= (u_int32_t)p[3]; 787 788 return (v); 789 } 790 791 u_int16_t 792 get_u16(const void *vp) 793 { 794 const u_char *p = (const u_char *)vp; 795 u_int16_t v; 796 797 v = (u_int16_t)p[0] << 8; 798 v |= (u_int16_t)p[1]; 799 800 return (v); 801 } 802 803 void 804 put_u64(void *vp, u_int64_t v) 805 { 806 u_char *p = (u_char *)vp; 807 808 p[0] = (u_char)(v >> 56) & 0xff; 809 p[1] = (u_char)(v >> 48) & 0xff; 810 p[2] = (u_char)(v >> 40) & 0xff; 811 p[3] = (u_char)(v >> 32) & 0xff; 812 p[4] = (u_char)(v >> 24) & 0xff; 813 p[5] = (u_char)(v >> 16) & 0xff; 814 p[6] = (u_char)(v >> 8) & 0xff; 815 p[7] = (u_char)v & 0xff; 816 } 817 818 void 819 put_u32(void *vp, u_int32_t v) 820 { 821 u_char *p = (u_char *)vp; 822 823 p[0] = (u_char)(v >> 24) & 0xff; 824 p[1] = (u_char)(v >> 16) & 0xff; 825 p[2] = (u_char)(v >> 8) & 0xff; 826 p[3] = (u_char)v & 0xff; 827 } 828 829 830 void 831 put_u16(void *vp, u_int16_t v) 832 { 833 u_char *p = (u_char *)vp; 834 835 p[0] = (u_char)(v >> 8) & 0xff; 836 p[1] = (u_char)v & 0xff; 837 } 838 839 void 840 ms_subtract_diff(struct timeval *start, int *ms) 841 { 842 struct timeval diff, finish; 843 844 gettimeofday(&finish, NULL); 845 timersub(&finish, start, &diff); 846 *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000); 847 } 848 849 void 850 ms_to_timeval(struct timeval *tv, int ms) 851 { 852 if (ms < 0) 853 ms = 0; 854 tv->tv_sec = ms / 1000; 855 tv->tv_usec = (ms % 1000) * 1000; 856 } 857 858 time_t 859 monotime(void) 860 { 861 struct timespec ts; 862 863 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) 864 fatal("clock_gettime: %s", strerror(errno)); 865 866 return (ts.tv_sec); 867 } 868 869 void 870 bandwidth_limit_init(struct bwlimit *bw, u_int64_t kbps, size_t buflen) 871 { 872 bw->buflen = buflen; 873 bw->rate = kbps; 874 bw->thresh = bw->rate; 875 bw->lamt = 0; 876 timerclear(&bw->bwstart); 877 timerclear(&bw->bwend); 878 } 879 880 /* Callback from read/write loop to insert bandwidth-limiting delays */ 881 void 882 bandwidth_limit(struct bwlimit *bw, size_t read_len) 883 { 884 u_int64_t waitlen; 885 struct timespec ts, rm; 886 887 if (!timerisset(&bw->bwstart)) { 888 gettimeofday(&bw->bwstart, NULL); 889 return; 890 } 891 892 bw->lamt += read_len; 893 if (bw->lamt < bw->thresh) 894 return; 895 896 gettimeofday(&bw->bwend, NULL); 897 timersub(&bw->bwend, &bw->bwstart, &bw->bwend); 898 if (!timerisset(&bw->bwend)) 899 return; 900 901 bw->lamt *= 8; 902 waitlen = (double)1000000L * bw->lamt / bw->rate; 903 904 bw->bwstart.tv_sec = waitlen / 1000000L; 905 bw->bwstart.tv_usec = waitlen % 1000000L; 906 907 if (timercmp(&bw->bwstart, &bw->bwend, >)) { 908 timersub(&bw->bwstart, &bw->bwend, &bw->bwend); 909 910 /* Adjust the wait time */ 911 if (bw->bwend.tv_sec) { 912 bw->thresh /= 2; 913 if (bw->thresh < bw->buflen / 4) 914 bw->thresh = bw->buflen / 4; 915 } else if (bw->bwend.tv_usec < 10000) { 916 bw->thresh *= 2; 917 if (bw->thresh > bw->buflen * 8) 918 bw->thresh = bw->buflen * 8; 919 } 920 921 TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts); 922 while (nanosleep(&ts, &rm) == -1) { 923 if (errno != EINTR) 924 break; 925 ts = rm; 926 } 927 } 928 929 bw->lamt = 0; 930 gettimeofday(&bw->bwstart, NULL); 931 } 932 933 /* Make a template filename for mk[sd]temp() */ 934 void 935 mktemp_proto(char *s, size_t len) 936 { 937 const char *tmpdir; 938 int r; 939 940 if ((tmpdir = getenv("TMPDIR")) != NULL) { 941 r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir); 942 if (r > 0 && (size_t)r < len) 943 return; 944 } 945 r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX"); 946 if (r < 0 || (size_t)r >= len) 947 fatal("%s: template string too short", __func__); 948 } 949 950 static const struct { 951 const char *name; 952 int value; 953 } ipqos[] = { 954 { "af11", IPTOS_DSCP_AF11 }, 955 { "af12", IPTOS_DSCP_AF12 }, 956 { "af13", IPTOS_DSCP_AF13 }, 957 { "af21", IPTOS_DSCP_AF21 }, 958 { "af22", IPTOS_DSCP_AF22 }, 959 { "af23", IPTOS_DSCP_AF23 }, 960 { "af31", IPTOS_DSCP_AF31 }, 961 { "af32", IPTOS_DSCP_AF32 }, 962 { "af33", IPTOS_DSCP_AF33 }, 963 { "af41", IPTOS_DSCP_AF41 }, 964 { "af42", IPTOS_DSCP_AF42 }, 965 { "af43", IPTOS_DSCP_AF43 }, 966 { "cs0", IPTOS_DSCP_CS0 }, 967 { "cs1", IPTOS_DSCP_CS1 }, 968 { "cs2", IPTOS_DSCP_CS2 }, 969 { "cs3", IPTOS_DSCP_CS3 }, 970 { "cs4", IPTOS_DSCP_CS4 }, 971 { "cs5", IPTOS_DSCP_CS5 }, 972 { "cs6", IPTOS_DSCP_CS6 }, 973 { "cs7", IPTOS_DSCP_CS7 }, 974 { "ef", IPTOS_DSCP_EF }, 975 { "lowdelay", IPTOS_LOWDELAY }, 976 { "throughput", IPTOS_THROUGHPUT }, 977 { "reliability", IPTOS_RELIABILITY }, 978 { NULL, -1 } 979 }; 980 981 int 982 parse_ipqos(const char *cp) 983 { 984 u_int i; 985 char *ep; 986 long val; 987 988 if (cp == NULL) 989 return -1; 990 for (i = 0; ipqos[i].name != NULL; i++) { 991 if (strcasecmp(cp, ipqos[i].name) == 0) 992 return ipqos[i].value; 993 } 994 /* Try parsing as an integer */ 995 val = strtol(cp, &ep, 0); 996 if (*cp == '\0' || *ep != '\0' || val < 0 || val > 255) 997 return -1; 998 return val; 999 } 1000 1001 const char * 1002 iptos2str(int iptos) 1003 { 1004 int i; 1005 static char iptos_str[sizeof "0xff"]; 1006 1007 for (i = 0; ipqos[i].name != NULL; i++) { 1008 if (ipqos[i].value == iptos) 1009 return ipqos[i].name; 1010 } 1011 snprintf(iptos_str, sizeof iptos_str, "0x%02x", iptos); 1012 return iptos_str; 1013 } 1014 1015 int 1016 timingsafe_bcmp(const void *b1, const void *b2, size_t n) 1017 { 1018 const unsigned char *p1 = b1, *p2 = b2; 1019 int ret = 0; 1020 1021 for (; n > 0; n--) 1022 ret |= *p1++ ^ *p2++; 1023 return (ret != 0); 1024 } 1025