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