1 /* $OpenBSD: misc.c,v 1.187 2023/08/28 03:31:16 djm Exp $ */ 2 /* 3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 4 * Copyright (c) 2005-2020 Damien Miller. All rights reserved. 5 * Copyright (c) 2004 Henning Brauer <henning@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 21 #include "includes.h" 22 23 #include <sys/types.h> 24 #include <sys/ioctl.h> 25 #include <sys/mman.h> 26 #include <sys/socket.h> 27 #include <sys/stat.h> 28 #include <sys/time.h> 29 #include <sys/wait.h> 30 #include <sys/un.h> 31 32 #include <limits.h> 33 #ifdef HAVE_LIBGEN_H 34 # include <libgen.h> 35 #endif 36 #ifdef HAVE_POLL_H 37 #include <poll.h> 38 #endif 39 #ifdef HAVE_NLIST_H 40 #include <nlist.h> 41 #endif 42 #include <signal.h> 43 #include <stdarg.h> 44 #include <stdio.h> 45 #ifdef HAVE_STDINT_H 46 # include <stdint.h> 47 #endif 48 #include <stdlib.h> 49 #include <string.h> 50 #include <time.h> 51 #include <unistd.h> 52 53 #include <netinet/in.h> 54 #include <netinet/in_systm.h> 55 #include <netinet/ip.h> 56 #include <netinet/tcp.h> 57 #include <arpa/inet.h> 58 59 #include <ctype.h> 60 #include <errno.h> 61 #include <fcntl.h> 62 #include <netdb.h> 63 #ifdef HAVE_PATHS_H 64 # include <paths.h> 65 #include <pwd.h> 66 #include <grp.h> 67 #endif 68 #ifdef SSH_TUN_OPENBSD 69 #include <net/if.h> 70 #endif 71 72 #include "xmalloc.h" 73 #include "misc.h" 74 #include "log.h" 75 #include "ssh.h" 76 #include "sshbuf.h" 77 #include "ssherr.h" 78 #include "platform.h" 79 80 /* remove newline at end of string */ 81 char * 82 chop(char *s) 83 { 84 char *t = s; 85 while (*t) { 86 if (*t == '\n' || *t == '\r') { 87 *t = '\0'; 88 return s; 89 } 90 t++; 91 } 92 return s; 93 94 } 95 96 /* remove whitespace from end of string */ 97 void 98 rtrim(char *s) 99 { 100 size_t i; 101 102 if ((i = strlen(s)) == 0) 103 return; 104 for (i--; i > 0; i--) { 105 if (isspace((unsigned char)s[i])) 106 s[i] = '\0'; 107 } 108 } 109 110 /* set/unset filedescriptor to non-blocking */ 111 int 112 set_nonblock(int fd) 113 { 114 int val; 115 116 val = fcntl(fd, F_GETFL); 117 if (val == -1) { 118 error("fcntl(%d, F_GETFL): %s", fd, strerror(errno)); 119 return (-1); 120 } 121 if (val & O_NONBLOCK) { 122 debug3("fd %d is O_NONBLOCK", fd); 123 return (0); 124 } 125 debug2("fd %d setting O_NONBLOCK", fd); 126 val |= O_NONBLOCK; 127 if (fcntl(fd, F_SETFL, val) == -1) { 128 debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd, 129 strerror(errno)); 130 return (-1); 131 } 132 return (0); 133 } 134 135 int 136 unset_nonblock(int fd) 137 { 138 int val; 139 140 val = fcntl(fd, F_GETFL); 141 if (val == -1) { 142 error("fcntl(%d, F_GETFL): %s", fd, strerror(errno)); 143 return (-1); 144 } 145 if (!(val & O_NONBLOCK)) { 146 debug3("fd %d is not O_NONBLOCK", fd); 147 return (0); 148 } 149 debug("fd %d clearing O_NONBLOCK", fd); 150 val &= ~O_NONBLOCK; 151 if (fcntl(fd, F_SETFL, val) == -1) { 152 debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s", 153 fd, strerror(errno)); 154 return (-1); 155 } 156 return (0); 157 } 158 159 const char * 160 ssh_gai_strerror(int gaierr) 161 { 162 if (gaierr == EAI_SYSTEM && errno != 0) 163 return strerror(errno); 164 return gai_strerror(gaierr); 165 } 166 167 /* disable nagle on socket */ 168 void 169 set_nodelay(int fd) 170 { 171 int opt; 172 socklen_t optlen; 173 174 optlen = sizeof opt; 175 if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) { 176 debug("getsockopt TCP_NODELAY: %.100s", strerror(errno)); 177 return; 178 } 179 if (opt == 1) { 180 debug2("fd %d is TCP_NODELAY", fd); 181 return; 182 } 183 opt = 1; 184 debug2("fd %d setting TCP_NODELAY", fd); 185 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1) 186 error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); 187 } 188 189 /* Allow local port reuse in TIME_WAIT */ 190 int 191 set_reuseaddr(int fd) 192 { 193 int on = 1; 194 195 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { 196 error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno)); 197 return -1; 198 } 199 return 0; 200 } 201 202 /* Get/set routing domain */ 203 char * 204 get_rdomain(int fd) 205 { 206 #if defined(HAVE_SYS_GET_RDOMAIN) 207 return sys_get_rdomain(fd); 208 #elif defined(__OpenBSD__) 209 int rtable; 210 char *ret; 211 socklen_t len = sizeof(rtable); 212 213 if (getsockopt(fd, SOL_SOCKET, SO_RTABLE, &rtable, &len) == -1) { 214 error("Failed to get routing domain for fd %d: %s", 215 fd, strerror(errno)); 216 return NULL; 217 } 218 xasprintf(&ret, "%d", rtable); 219 return ret; 220 #else /* defined(__OpenBSD__) */ 221 return NULL; 222 #endif 223 } 224 225 int 226 set_rdomain(int fd, const char *name) 227 { 228 #if defined(HAVE_SYS_SET_RDOMAIN) 229 return sys_set_rdomain(fd, name); 230 #elif defined(__OpenBSD__) 231 int rtable; 232 const char *errstr; 233 234 if (name == NULL) 235 return 0; /* default table */ 236 237 rtable = (int)strtonum(name, 0, 255, &errstr); 238 if (errstr != NULL) { 239 /* Shouldn't happen */ 240 error("Invalid routing domain \"%s\": %s", name, errstr); 241 return -1; 242 } 243 if (setsockopt(fd, SOL_SOCKET, SO_RTABLE, 244 &rtable, sizeof(rtable)) == -1) { 245 error("Failed to set routing domain %d on fd %d: %s", 246 rtable, fd, strerror(errno)); 247 return -1; 248 } 249 return 0; 250 #else /* defined(__OpenBSD__) */ 251 error("Setting routing domain is not supported on this platform"); 252 return -1; 253 #endif 254 } 255 256 int 257 get_sock_af(int fd) 258 { 259 struct sockaddr_storage to; 260 socklen_t tolen = sizeof(to); 261 262 memset(&to, 0, sizeof(to)); 263 if (getsockname(fd, (struct sockaddr *)&to, &tolen) == -1) 264 return -1; 265 #ifdef IPV4_IN_IPV6 266 if (to.ss_family == AF_INET6 && 267 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&to)->sin6_addr)) 268 return AF_INET; 269 #endif 270 return to.ss_family; 271 } 272 273 void 274 set_sock_tos(int fd, int tos) 275 { 276 #ifndef IP_TOS_IS_BROKEN 277 int af; 278 279 switch ((af = get_sock_af(fd))) { 280 case -1: 281 /* assume not a socket */ 282 break; 283 case AF_INET: 284 # ifdef IP_TOS 285 debug3_f("set socket %d IP_TOS 0x%02x", fd, tos); 286 if (setsockopt(fd, IPPROTO_IP, IP_TOS, 287 &tos, sizeof(tos)) == -1) { 288 error("setsockopt socket %d IP_TOS %d: %s", 289 fd, tos, strerror(errno)); 290 } 291 # endif /* IP_TOS */ 292 break; 293 case AF_INET6: 294 # ifdef IPV6_TCLASS 295 debug3_f("set socket %d IPV6_TCLASS 0x%02x", fd, tos); 296 if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, 297 &tos, sizeof(tos)) == -1) { 298 error("setsockopt socket %d IPV6_TCLASS %d: %s", 299 fd, tos, strerror(errno)); 300 } 301 # endif /* IPV6_TCLASS */ 302 break; 303 default: 304 debug2_f("unsupported socket family %d", af); 305 break; 306 } 307 #endif /* IP_TOS_IS_BROKEN */ 308 } 309 310 /* 311 * Wait up to *timeoutp milliseconds for events on fd. Updates 312 * *timeoutp with time remaining. 313 * Returns 0 if fd ready or -1 on timeout or error (see errno). 314 */ 315 static int 316 waitfd(int fd, int *timeoutp, short events, volatile sig_atomic_t *stop) 317 { 318 struct pollfd pfd; 319 struct timespec timeout; 320 int oerrno, r; 321 sigset_t nsigset, osigset; 322 323 if (timeoutp && *timeoutp == -1) 324 timeoutp = NULL; 325 pfd.fd = fd; 326 pfd.events = events; 327 ptimeout_init(&timeout); 328 if (timeoutp != NULL) 329 ptimeout_deadline_ms(&timeout, *timeoutp); 330 if (stop != NULL) 331 sigfillset(&nsigset); 332 for (; timeoutp == NULL || *timeoutp >= 0;) { 333 if (stop != NULL) { 334 sigprocmask(SIG_BLOCK, &nsigset, &osigset); 335 if (*stop) { 336 sigprocmask(SIG_SETMASK, &osigset, NULL); 337 errno = EINTR; 338 return -1; 339 } 340 } 341 r = ppoll(&pfd, 1, ptimeout_get_tsp(&timeout), 342 stop != NULL ? &osigset : NULL); 343 oerrno = errno; 344 if (stop != NULL) 345 sigprocmask(SIG_SETMASK, &osigset, NULL); 346 if (timeoutp) 347 *timeoutp = ptimeout_get_ms(&timeout); 348 errno = oerrno; 349 if (r > 0) 350 return 0; 351 else if (r == -1 && errno != EAGAIN && errno != EINTR) 352 return -1; 353 else if (r == 0) 354 break; 355 } 356 /* timeout */ 357 errno = ETIMEDOUT; 358 return -1; 359 } 360 361 /* 362 * Wait up to *timeoutp milliseconds for fd to be readable. Updates 363 * *timeoutp with time remaining. 364 * Returns 0 if fd ready or -1 on timeout or error (see errno). 365 */ 366 int 367 waitrfd(int fd, int *timeoutp, volatile sig_atomic_t *stop) { 368 return waitfd(fd, timeoutp, POLLIN, stop); 369 } 370 371 /* 372 * Attempt a non-blocking connect(2) to the specified address, waiting up to 373 * *timeoutp milliseconds for the connection to complete. If the timeout is 374 * <=0, then wait indefinitely. 375 * 376 * Returns 0 on success or -1 on failure. 377 */ 378 int 379 timeout_connect(int sockfd, const struct sockaddr *serv_addr, 380 socklen_t addrlen, int *timeoutp) 381 { 382 int optval = 0; 383 socklen_t optlen = sizeof(optval); 384 385 /* No timeout: just do a blocking connect() */ 386 if (timeoutp == NULL || *timeoutp <= 0) 387 return connect(sockfd, serv_addr, addrlen); 388 389 set_nonblock(sockfd); 390 for (;;) { 391 if (connect(sockfd, serv_addr, addrlen) == 0) { 392 /* Succeeded already? */ 393 unset_nonblock(sockfd); 394 return 0; 395 } else if (errno == EINTR) 396 continue; 397 else if (errno != EINPROGRESS) 398 return -1; 399 break; 400 } 401 402 if (waitfd(sockfd, timeoutp, POLLIN | POLLOUT, NULL) == -1) 403 return -1; 404 405 /* Completed or failed */ 406 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1) { 407 debug("getsockopt: %s", strerror(errno)); 408 return -1; 409 } 410 if (optval != 0) { 411 errno = optval; 412 return -1; 413 } 414 unset_nonblock(sockfd); 415 return 0; 416 } 417 418 /* Characters considered whitespace in strsep calls. */ 419 #define WHITESPACE " \t\r\n" 420 #define QUOTE "\"" 421 422 /* return next token in configuration line */ 423 static char * 424 strdelim_internal(char **s, int split_equals) 425 { 426 char *old; 427 int wspace = 0; 428 429 if (*s == NULL) 430 return NULL; 431 432 old = *s; 433 434 *s = strpbrk(*s, 435 split_equals ? WHITESPACE QUOTE "=" : WHITESPACE QUOTE); 436 if (*s == NULL) 437 return (old); 438 439 if (*s[0] == '\"') { 440 memmove(*s, *s + 1, strlen(*s)); /* move nul too */ 441 /* Find matching quote */ 442 if ((*s = strpbrk(*s, QUOTE)) == NULL) { 443 return (NULL); /* no matching quote */ 444 } else { 445 *s[0] = '\0'; 446 *s += strspn(*s + 1, WHITESPACE) + 1; 447 return (old); 448 } 449 } 450 451 /* Allow only one '=' to be skipped */ 452 if (split_equals && *s[0] == '=') 453 wspace = 1; 454 *s[0] = '\0'; 455 456 /* Skip any extra whitespace after first token */ 457 *s += strspn(*s + 1, WHITESPACE) + 1; 458 if (split_equals && *s[0] == '=' && !wspace) 459 *s += strspn(*s + 1, WHITESPACE) + 1; 460 461 return (old); 462 } 463 464 /* 465 * Return next token in configuration line; splts on whitespace or a 466 * single '=' character. 467 */ 468 char * 469 strdelim(char **s) 470 { 471 return strdelim_internal(s, 1); 472 } 473 474 /* 475 * Return next token in configuration line; splts on whitespace only. 476 */ 477 char * 478 strdelimw(char **s) 479 { 480 return strdelim_internal(s, 0); 481 } 482 483 struct passwd * 484 pwcopy(struct passwd *pw) 485 { 486 struct passwd *copy = xcalloc(1, sizeof(*copy)); 487 488 copy->pw_name = xstrdup(pw->pw_name); 489 copy->pw_passwd = xstrdup(pw->pw_passwd == NULL ? "*" : pw->pw_passwd); 490 #ifdef HAVE_STRUCT_PASSWD_PW_GECOS 491 copy->pw_gecos = xstrdup(pw->pw_gecos); 492 #endif 493 copy->pw_uid = pw->pw_uid; 494 copy->pw_gid = pw->pw_gid; 495 #ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE 496 copy->pw_expire = pw->pw_expire; 497 #endif 498 #ifdef HAVE_STRUCT_PASSWD_PW_CHANGE 499 copy->pw_change = pw->pw_change; 500 #endif 501 #ifdef HAVE_STRUCT_PASSWD_PW_CLASS 502 copy->pw_class = xstrdup(pw->pw_class); 503 #endif 504 copy->pw_dir = xstrdup(pw->pw_dir); 505 copy->pw_shell = xstrdup(pw->pw_shell); 506 return copy; 507 } 508 509 /* 510 * Convert ASCII string to TCP/IP port number. 511 * Port must be >=0 and <=65535. 512 * Return -1 if invalid. 513 */ 514 int 515 a2port(const char *s) 516 { 517 struct servent *se; 518 long long port; 519 const char *errstr; 520 521 port = strtonum(s, 0, 65535, &errstr); 522 if (errstr == NULL) 523 return (int)port; 524 if ((se = getservbyname(s, "tcp")) != NULL) 525 return ntohs(se->s_port); 526 return -1; 527 } 528 529 int 530 a2tun(const char *s, int *remote) 531 { 532 const char *errstr = NULL; 533 char *sp, *ep; 534 int tun; 535 536 if (remote != NULL) { 537 *remote = SSH_TUNID_ANY; 538 sp = xstrdup(s); 539 if ((ep = strchr(sp, ':')) == NULL) { 540 free(sp); 541 return (a2tun(s, NULL)); 542 } 543 ep[0] = '\0'; ep++; 544 *remote = a2tun(ep, NULL); 545 tun = a2tun(sp, NULL); 546 free(sp); 547 return (*remote == SSH_TUNID_ERR ? *remote : tun); 548 } 549 550 if (strcasecmp(s, "any") == 0) 551 return (SSH_TUNID_ANY); 552 553 tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr); 554 if (errstr != NULL) 555 return (SSH_TUNID_ERR); 556 557 return (tun); 558 } 559 560 #define SECONDS 1 561 #define MINUTES (SECONDS * 60) 562 #define HOURS (MINUTES * 60) 563 #define DAYS (HOURS * 24) 564 #define WEEKS (DAYS * 7) 565 566 /* 567 * Convert a time string into seconds; format is 568 * a sequence of: 569 * time[qualifier] 570 * 571 * Valid time qualifiers are: 572 * <none> seconds 573 * s|S seconds 574 * m|M minutes 575 * h|H hours 576 * d|D days 577 * w|W weeks 578 * 579 * Examples: 580 * 90m 90 minutes 581 * 1h30m 90 minutes 582 * 2d 2 days 583 * 1w 1 week 584 * 585 * Return -1 if time string is invalid. 586 */ 587 int 588 convtime(const char *s) 589 { 590 long total, secs, multiplier; 591 const char *p; 592 char *endp; 593 594 errno = 0; 595 total = 0; 596 p = s; 597 598 if (p == NULL || *p == '\0') 599 return -1; 600 601 while (*p) { 602 secs = strtol(p, &endp, 10); 603 if (p == endp || 604 (errno == ERANGE && (secs == INT_MIN || secs == INT_MAX)) || 605 secs < 0) 606 return -1; 607 608 multiplier = 1; 609 switch (*endp++) { 610 case '\0': 611 endp--; 612 break; 613 case 's': 614 case 'S': 615 break; 616 case 'm': 617 case 'M': 618 multiplier = MINUTES; 619 break; 620 case 'h': 621 case 'H': 622 multiplier = HOURS; 623 break; 624 case 'd': 625 case 'D': 626 multiplier = DAYS; 627 break; 628 case 'w': 629 case 'W': 630 multiplier = WEEKS; 631 break; 632 default: 633 return -1; 634 } 635 if (secs > INT_MAX / multiplier) 636 return -1; 637 secs *= multiplier; 638 if (total > INT_MAX - secs) 639 return -1; 640 total += secs; 641 if (total < 0) 642 return -1; 643 p = endp; 644 } 645 646 return total; 647 } 648 649 #define TF_BUFS 8 650 #define TF_LEN 9 651 652 const char * 653 fmt_timeframe(time_t t) 654 { 655 char *buf; 656 static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */ 657 static int idx = 0; 658 unsigned int sec, min, hrs, day; 659 unsigned long long week; 660 661 buf = tfbuf[idx++]; 662 if (idx == TF_BUFS) 663 idx = 0; 664 665 week = t; 666 667 sec = week % 60; 668 week /= 60; 669 min = week % 60; 670 week /= 60; 671 hrs = week % 24; 672 week /= 24; 673 day = week % 7; 674 week /= 7; 675 676 if (week > 0) 677 snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs); 678 else if (day > 0) 679 snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min); 680 else 681 snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec); 682 683 return (buf); 684 } 685 686 /* 687 * Returns a standardized host+port identifier string. 688 * Caller must free returned string. 689 */ 690 char * 691 put_host_port(const char *host, u_short port) 692 { 693 char *hoststr; 694 695 if (port == 0 || port == SSH_DEFAULT_PORT) 696 return(xstrdup(host)); 697 if (asprintf(&hoststr, "[%s]:%d", host, (int)port) == -1) 698 fatal("put_host_port: asprintf: %s", strerror(errno)); 699 debug3("put_host_port: %s", hoststr); 700 return hoststr; 701 } 702 703 /* 704 * Search for next delimiter between hostnames/addresses and ports. 705 * Argument may be modified (for termination). 706 * Returns *cp if parsing succeeds. 707 * *cp is set to the start of the next field, if one was found. 708 * The delimiter char, if present, is stored in delim. 709 * If this is the last field, *cp is set to NULL. 710 */ 711 char * 712 hpdelim2(char **cp, char *delim) 713 { 714 char *s, *old; 715 716 if (cp == NULL || *cp == NULL) 717 return NULL; 718 719 old = s = *cp; 720 if (*s == '[') { 721 if ((s = strchr(s, ']')) == NULL) 722 return NULL; 723 else 724 s++; 725 } else if ((s = strpbrk(s, ":/")) == NULL) 726 s = *cp + strlen(*cp); /* skip to end (see first case below) */ 727 728 switch (*s) { 729 case '\0': 730 *cp = NULL; /* no more fields*/ 731 break; 732 733 case ':': 734 case '/': 735 if (delim != NULL) 736 *delim = *s; 737 *s = '\0'; /* terminate */ 738 *cp = s + 1; 739 break; 740 741 default: 742 return NULL; 743 } 744 745 return old; 746 } 747 748 /* The common case: only accept colon as delimiter. */ 749 char * 750 hpdelim(char **cp) 751 { 752 char *r, delim = '\0'; 753 754 r = hpdelim2(cp, &delim); 755 if (delim == '/') 756 return NULL; 757 return r; 758 } 759 760 char * 761 cleanhostname(char *host) 762 { 763 if (*host == '[' && host[strlen(host) - 1] == ']') { 764 host[strlen(host) - 1] = '\0'; 765 return (host + 1); 766 } else 767 return host; 768 } 769 770 char * 771 colon(char *cp) 772 { 773 int flag = 0; 774 775 if (*cp == ':') /* Leading colon is part of file name. */ 776 return NULL; 777 if (*cp == '[') 778 flag = 1; 779 780 for (; *cp; ++cp) { 781 if (*cp == '@' && *(cp+1) == '[') 782 flag = 1; 783 if (*cp == ']' && *(cp+1) == ':' && flag) 784 return (cp+1); 785 if (*cp == ':' && !flag) 786 return (cp); 787 if (*cp == '/') 788 return NULL; 789 } 790 return NULL; 791 } 792 793 /* 794 * Parse a [user@]host:[path] string. 795 * Caller must free returned user, host and path. 796 * Any of the pointer return arguments may be NULL (useful for syntax checking). 797 * If user was not specified then *userp will be set to NULL. 798 * If host was not specified then *hostp will be set to NULL. 799 * If path was not specified then *pathp will be set to ".". 800 * Returns 0 on success, -1 on failure. 801 */ 802 int 803 parse_user_host_path(const char *s, char **userp, char **hostp, char **pathp) 804 { 805 char *user = NULL, *host = NULL, *path = NULL; 806 char *sdup, *tmp; 807 int ret = -1; 808 809 if (userp != NULL) 810 *userp = NULL; 811 if (hostp != NULL) 812 *hostp = NULL; 813 if (pathp != NULL) 814 *pathp = NULL; 815 816 sdup = xstrdup(s); 817 818 /* Check for remote syntax: [user@]host:[path] */ 819 if ((tmp = colon(sdup)) == NULL) 820 goto out; 821 822 /* Extract optional path */ 823 *tmp++ = '\0'; 824 if (*tmp == '\0') 825 tmp = "."; 826 path = xstrdup(tmp); 827 828 /* Extract optional user and mandatory host */ 829 tmp = strrchr(sdup, '@'); 830 if (tmp != NULL) { 831 *tmp++ = '\0'; 832 host = xstrdup(cleanhostname(tmp)); 833 if (*sdup != '\0') 834 user = xstrdup(sdup); 835 } else { 836 host = xstrdup(cleanhostname(sdup)); 837 user = NULL; 838 } 839 840 /* Success */ 841 if (userp != NULL) { 842 *userp = user; 843 user = NULL; 844 } 845 if (hostp != NULL) { 846 *hostp = host; 847 host = NULL; 848 } 849 if (pathp != NULL) { 850 *pathp = path; 851 path = NULL; 852 } 853 ret = 0; 854 out: 855 free(sdup); 856 free(user); 857 free(host); 858 free(path); 859 return ret; 860 } 861 862 /* 863 * Parse a [user@]host[:port] string. 864 * Caller must free returned user and host. 865 * Any of the pointer return arguments may be NULL (useful for syntax checking). 866 * If user was not specified then *userp will be set to NULL. 867 * If port was not specified then *portp will be -1. 868 * Returns 0 on success, -1 on failure. 869 */ 870 int 871 parse_user_host_port(const char *s, char **userp, char **hostp, int *portp) 872 { 873 char *sdup, *cp, *tmp; 874 char *user = NULL, *host = NULL; 875 int port = -1, ret = -1; 876 877 if (userp != NULL) 878 *userp = NULL; 879 if (hostp != NULL) 880 *hostp = NULL; 881 if (portp != NULL) 882 *portp = -1; 883 884 if ((sdup = tmp = strdup(s)) == NULL) 885 return -1; 886 /* Extract optional username */ 887 if ((cp = strrchr(tmp, '@')) != NULL) { 888 *cp = '\0'; 889 if (*tmp == '\0') 890 goto out; 891 if ((user = strdup(tmp)) == NULL) 892 goto out; 893 tmp = cp + 1; 894 } 895 /* Extract mandatory hostname */ 896 if ((cp = hpdelim(&tmp)) == NULL || *cp == '\0') 897 goto out; 898 host = xstrdup(cleanhostname(cp)); 899 /* Convert and verify optional port */ 900 if (tmp != NULL && *tmp != '\0') { 901 if ((port = a2port(tmp)) <= 0) 902 goto out; 903 } 904 /* Success */ 905 if (userp != NULL) { 906 *userp = user; 907 user = NULL; 908 } 909 if (hostp != NULL) { 910 *hostp = host; 911 host = NULL; 912 } 913 if (portp != NULL) 914 *portp = port; 915 ret = 0; 916 out: 917 free(sdup); 918 free(user); 919 free(host); 920 return ret; 921 } 922 923 /* 924 * Converts a two-byte hex string to decimal. 925 * Returns the decimal value or -1 for invalid input. 926 */ 927 static int 928 hexchar(const char *s) 929 { 930 unsigned char result[2]; 931 int i; 932 933 for (i = 0; i < 2; i++) { 934 if (s[i] >= '0' && s[i] <= '9') 935 result[i] = (unsigned char)(s[i] - '0'); 936 else if (s[i] >= 'a' && s[i] <= 'f') 937 result[i] = (unsigned char)(s[i] - 'a') + 10; 938 else if (s[i] >= 'A' && s[i] <= 'F') 939 result[i] = (unsigned char)(s[i] - 'A') + 10; 940 else 941 return -1; 942 } 943 return (result[0] << 4) | result[1]; 944 } 945 946 /* 947 * Decode an url-encoded string. 948 * Returns a newly allocated string on success or NULL on failure. 949 */ 950 static char * 951 urldecode(const char *src) 952 { 953 char *ret, *dst; 954 int ch; 955 size_t srclen; 956 957 if ((srclen = strlen(src)) >= SIZE_MAX) 958 fatal_f("input too large"); 959 ret = xmalloc(srclen + 1); 960 for (dst = ret; *src != '\0'; src++) { 961 switch (*src) { 962 case '+': 963 *dst++ = ' '; 964 break; 965 case '%': 966 if (!isxdigit((unsigned char)src[1]) || 967 !isxdigit((unsigned char)src[2]) || 968 (ch = hexchar(src + 1)) == -1) { 969 free(ret); 970 return NULL; 971 } 972 *dst++ = ch; 973 src += 2; 974 break; 975 default: 976 *dst++ = *src; 977 break; 978 } 979 } 980 *dst = '\0'; 981 982 return ret; 983 } 984 985 /* 986 * Parse an (scp|ssh|sftp)://[user@]host[:port][/path] URI. 987 * See https://tools.ietf.org/html/draft-ietf-secsh-scp-sftp-ssh-uri-04 988 * Either user or path may be url-encoded (but not host or port). 989 * Caller must free returned user, host and path. 990 * Any of the pointer return arguments may be NULL (useful for syntax checking) 991 * but the scheme must always be specified. 992 * If user was not specified then *userp will be set to NULL. 993 * If port was not specified then *portp will be -1. 994 * If path was not specified then *pathp will be set to NULL. 995 * Returns 0 on success, 1 if non-uri/wrong scheme, -1 on error/invalid uri. 996 */ 997 int 998 parse_uri(const char *scheme, const char *uri, char **userp, char **hostp, 999 int *portp, char **pathp) 1000 { 1001 char *uridup, *cp, *tmp, ch; 1002 char *user = NULL, *host = NULL, *path = NULL; 1003 int port = -1, ret = -1; 1004 size_t len; 1005 1006 len = strlen(scheme); 1007 if (strncmp(uri, scheme, len) != 0 || strncmp(uri + len, "://", 3) != 0) 1008 return 1; 1009 uri += len + 3; 1010 1011 if (userp != NULL) 1012 *userp = NULL; 1013 if (hostp != NULL) 1014 *hostp = NULL; 1015 if (portp != NULL) 1016 *portp = -1; 1017 if (pathp != NULL) 1018 *pathp = NULL; 1019 1020 uridup = tmp = xstrdup(uri); 1021 1022 /* Extract optional ssh-info (username + connection params) */ 1023 if ((cp = strchr(tmp, '@')) != NULL) { 1024 char *delim; 1025 1026 *cp = '\0'; 1027 /* Extract username and connection params */ 1028 if ((delim = strchr(tmp, ';')) != NULL) { 1029 /* Just ignore connection params for now */ 1030 *delim = '\0'; 1031 } 1032 if (*tmp == '\0') { 1033 /* Empty username */ 1034 goto out; 1035 } 1036 if ((user = urldecode(tmp)) == NULL) 1037 goto out; 1038 tmp = cp + 1; 1039 } 1040 1041 /* Extract mandatory hostname */ 1042 if ((cp = hpdelim2(&tmp, &ch)) == NULL || *cp == '\0') 1043 goto out; 1044 host = xstrdup(cleanhostname(cp)); 1045 if (!valid_domain(host, 0, NULL)) 1046 goto out; 1047 1048 if (tmp != NULL && *tmp != '\0') { 1049 if (ch == ':') { 1050 /* Convert and verify port. */ 1051 if ((cp = strchr(tmp, '/')) != NULL) 1052 *cp = '\0'; 1053 if ((port = a2port(tmp)) <= 0) 1054 goto out; 1055 tmp = cp ? cp + 1 : NULL; 1056 } 1057 if (tmp != NULL && *tmp != '\0') { 1058 /* Extract optional path */ 1059 if ((path = urldecode(tmp)) == NULL) 1060 goto out; 1061 } 1062 } 1063 1064 /* Success */ 1065 if (userp != NULL) { 1066 *userp = user; 1067 user = NULL; 1068 } 1069 if (hostp != NULL) { 1070 *hostp = host; 1071 host = NULL; 1072 } 1073 if (portp != NULL) 1074 *portp = port; 1075 if (pathp != NULL) { 1076 *pathp = path; 1077 path = NULL; 1078 } 1079 ret = 0; 1080 out: 1081 free(uridup); 1082 free(user); 1083 free(host); 1084 free(path); 1085 return ret; 1086 } 1087 1088 /* function to assist building execv() arguments */ 1089 void 1090 addargs(arglist *args, char *fmt, ...) 1091 { 1092 va_list ap; 1093 char *cp; 1094 u_int nalloc; 1095 int r; 1096 1097 va_start(ap, fmt); 1098 r = vasprintf(&cp, fmt, ap); 1099 va_end(ap); 1100 if (r == -1) 1101 fatal_f("argument too long"); 1102 1103 nalloc = args->nalloc; 1104 if (args->list == NULL) { 1105 nalloc = 32; 1106 args->num = 0; 1107 } else if (args->num > (256 * 1024)) 1108 fatal_f("too many arguments"); 1109 else if (args->num >= args->nalloc) 1110 fatal_f("arglist corrupt"); 1111 else if (args->num+2 >= nalloc) 1112 nalloc *= 2; 1113 1114 args->list = xrecallocarray(args->list, args->nalloc, 1115 nalloc, sizeof(char *)); 1116 args->nalloc = nalloc; 1117 args->list[args->num++] = cp; 1118 args->list[args->num] = NULL; 1119 } 1120 1121 void 1122 replacearg(arglist *args, u_int which, char *fmt, ...) 1123 { 1124 va_list ap; 1125 char *cp; 1126 int r; 1127 1128 va_start(ap, fmt); 1129 r = vasprintf(&cp, fmt, ap); 1130 va_end(ap); 1131 if (r == -1) 1132 fatal_f("argument too long"); 1133 if (args->list == NULL || args->num >= args->nalloc) 1134 fatal_f("arglist corrupt"); 1135 1136 if (which >= args->num) 1137 fatal_f("tried to replace invalid arg %d >= %d", 1138 which, args->num); 1139 free(args->list[which]); 1140 args->list[which] = cp; 1141 } 1142 1143 void 1144 freeargs(arglist *args) 1145 { 1146 u_int i; 1147 1148 if (args == NULL) 1149 return; 1150 if (args->list != NULL && args->num < args->nalloc) { 1151 for (i = 0; i < args->num; i++) 1152 free(args->list[i]); 1153 free(args->list); 1154 } 1155 args->nalloc = args->num = 0; 1156 args->list = NULL; 1157 } 1158 1159 /* 1160 * Expands tildes in the file name. Returns data allocated by xmalloc. 1161 * Warning: this calls getpw*. 1162 */ 1163 int 1164 tilde_expand(const char *filename, uid_t uid, char **retp) 1165 { 1166 char *ocopy = NULL, *copy, *s = NULL; 1167 const char *path = NULL, *user = NULL; 1168 struct passwd *pw; 1169 size_t len; 1170 int ret = -1, r, slash; 1171 1172 *retp = NULL; 1173 if (*filename != '~') { 1174 *retp = xstrdup(filename); 1175 return 0; 1176 } 1177 ocopy = copy = xstrdup(filename + 1); 1178 1179 if (*copy == '\0') /* ~ */ 1180 path = NULL; 1181 else if (*copy == '/') { 1182 copy += strspn(copy, "/"); 1183 if (*copy == '\0') 1184 path = NULL; /* ~/ */ 1185 else 1186 path = copy; /* ~/path */ 1187 } else { 1188 user = copy; 1189 if ((path = strchr(copy, '/')) != NULL) { 1190 copy[path - copy] = '\0'; 1191 path++; 1192 path += strspn(path, "/"); 1193 if (*path == '\0') /* ~user/ */ 1194 path = NULL; 1195 /* else ~user/path */ 1196 } 1197 /* else ~user */ 1198 } 1199 if (user != NULL) { 1200 if ((pw = getpwnam(user)) == NULL) { 1201 error_f("No such user %s", user); 1202 goto out; 1203 } 1204 } else if ((pw = getpwuid(uid)) == NULL) { 1205 error_f("No such uid %ld", (long)uid); 1206 goto out; 1207 } 1208 1209 /* Make sure directory has a trailing '/' */ 1210 slash = (len = strlen(pw->pw_dir)) == 0 || pw->pw_dir[len - 1] != '/'; 1211 1212 if ((r = xasprintf(&s, "%s%s%s", pw->pw_dir, 1213 slash ? "/" : "", path != NULL ? path : "")) <= 0) { 1214 error_f("xasprintf failed"); 1215 goto out; 1216 } 1217 if (r >= PATH_MAX) { 1218 error_f("Path too long"); 1219 goto out; 1220 } 1221 /* success */ 1222 ret = 0; 1223 *retp = s; 1224 s = NULL; 1225 out: 1226 free(s); 1227 free(ocopy); 1228 return ret; 1229 } 1230 1231 char * 1232 tilde_expand_filename(const char *filename, uid_t uid) 1233 { 1234 char *ret; 1235 1236 if (tilde_expand(filename, uid, &ret) != 0) 1237 cleanup_exit(255); 1238 return ret; 1239 } 1240 1241 /* 1242 * Expand a string with a set of %[char] escapes and/or ${ENVIRONMENT} 1243 * substitutions. A number of escapes may be specified as 1244 * (char *escape_chars, char *replacement) pairs. The list must be terminated 1245 * by a NULL escape_char. Returns replaced string in memory allocated by 1246 * xmalloc which the caller must free. 1247 */ 1248 static char * 1249 vdollar_percent_expand(int *parseerror, int dollar, int percent, 1250 const char *string, va_list ap) 1251 { 1252 #define EXPAND_MAX_KEYS 16 1253 u_int num_keys = 0, i; 1254 struct { 1255 const char *key; 1256 const char *repl; 1257 } keys[EXPAND_MAX_KEYS]; 1258 struct sshbuf *buf; 1259 int r, missingvar = 0; 1260 char *ret = NULL, *var, *varend, *val; 1261 size_t len; 1262 1263 if ((buf = sshbuf_new()) == NULL) 1264 fatal_f("sshbuf_new failed"); 1265 if (parseerror == NULL) 1266 fatal_f("null parseerror arg"); 1267 *parseerror = 1; 1268 1269 /* Gather keys if we're doing percent expansion. */ 1270 if (percent) { 1271 for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) { 1272 keys[num_keys].key = va_arg(ap, char *); 1273 if (keys[num_keys].key == NULL) 1274 break; 1275 keys[num_keys].repl = va_arg(ap, char *); 1276 if (keys[num_keys].repl == NULL) { 1277 fatal_f("NULL replacement for token %s", 1278 keys[num_keys].key); 1279 } 1280 } 1281 if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL) 1282 fatal_f("too many keys"); 1283 if (num_keys == 0) 1284 fatal_f("percent expansion without token list"); 1285 } 1286 1287 /* Expand string */ 1288 for (i = 0; *string != '\0'; string++) { 1289 /* Optionally process ${ENVIRONMENT} expansions. */ 1290 if (dollar && string[0] == '$' && string[1] == '{') { 1291 string += 2; /* skip over '${' */ 1292 if ((varend = strchr(string, '}')) == NULL) { 1293 error_f("environment variable '%s' missing " 1294 "closing '}'", string); 1295 goto out; 1296 } 1297 len = varend - string; 1298 if (len == 0) { 1299 error_f("zero-length environment variable"); 1300 goto out; 1301 } 1302 var = xmalloc(len + 1); 1303 (void)strlcpy(var, string, len + 1); 1304 if ((val = getenv(var)) == NULL) { 1305 error_f("env var ${%s} has no value", var); 1306 missingvar = 1; 1307 } else { 1308 debug3_f("expand ${%s} -> '%s'", var, val); 1309 if ((r = sshbuf_put(buf, val, strlen(val))) !=0) 1310 fatal_fr(r, "sshbuf_put ${}"); 1311 } 1312 free(var); 1313 string += len; 1314 continue; 1315 } 1316 1317 /* 1318 * Process percent expansions if we have a list of TOKENs. 1319 * If we're not doing percent expansion everything just gets 1320 * appended here. 1321 */ 1322 if (*string != '%' || !percent) { 1323 append: 1324 if ((r = sshbuf_put_u8(buf, *string)) != 0) 1325 fatal_fr(r, "sshbuf_put_u8 %%"); 1326 continue; 1327 } 1328 string++; 1329 /* %% case */ 1330 if (*string == '%') 1331 goto append; 1332 if (*string == '\0') { 1333 error_f("invalid format"); 1334 goto out; 1335 } 1336 for (i = 0; i < num_keys; i++) { 1337 if (strchr(keys[i].key, *string) != NULL) { 1338 if ((r = sshbuf_put(buf, keys[i].repl, 1339 strlen(keys[i].repl))) != 0) 1340 fatal_fr(r, "sshbuf_put %%-repl"); 1341 break; 1342 } 1343 } 1344 if (i >= num_keys) { 1345 error_f("unknown key %%%c", *string); 1346 goto out; 1347 } 1348 } 1349 if (!missingvar && (ret = sshbuf_dup_string(buf)) == NULL) 1350 fatal_f("sshbuf_dup_string failed"); 1351 *parseerror = 0; 1352 out: 1353 sshbuf_free(buf); 1354 return *parseerror ? NULL : ret; 1355 #undef EXPAND_MAX_KEYS 1356 } 1357 1358 /* 1359 * Expand only environment variables. 1360 * Note that although this function is variadic like the other similar 1361 * functions, any such arguments will be unused. 1362 */ 1363 1364 char * 1365 dollar_expand(int *parseerr, const char *string, ...) 1366 { 1367 char *ret; 1368 int err; 1369 va_list ap; 1370 1371 va_start(ap, string); 1372 ret = vdollar_percent_expand(&err, 1, 0, string, ap); 1373 va_end(ap); 1374 if (parseerr != NULL) 1375 *parseerr = err; 1376 return ret; 1377 } 1378 1379 /* 1380 * Returns expanded string or NULL if a specified environment variable is 1381 * not defined, or calls fatal if the string is invalid. 1382 */ 1383 char * 1384 percent_expand(const char *string, ...) 1385 { 1386 char *ret; 1387 int err; 1388 va_list ap; 1389 1390 va_start(ap, string); 1391 ret = vdollar_percent_expand(&err, 0, 1, string, ap); 1392 va_end(ap); 1393 if (err) 1394 fatal_f("failed"); 1395 return ret; 1396 } 1397 1398 /* 1399 * Returns expanded string or NULL if a specified environment variable is 1400 * not defined, or calls fatal if the string is invalid. 1401 */ 1402 char * 1403 percent_dollar_expand(const char *string, ...) 1404 { 1405 char *ret; 1406 int err; 1407 va_list ap; 1408 1409 va_start(ap, string); 1410 ret = vdollar_percent_expand(&err, 1, 1, string, ap); 1411 va_end(ap); 1412 if (err) 1413 fatal_f("failed"); 1414 return ret; 1415 } 1416 1417 int 1418 tun_open(int tun, int mode, char **ifname) 1419 { 1420 #if defined(CUSTOM_SYS_TUN_OPEN) 1421 return (sys_tun_open(tun, mode, ifname)); 1422 #elif defined(SSH_TUN_OPENBSD) 1423 struct ifreq ifr; 1424 char name[100]; 1425 int fd = -1, sock; 1426 const char *tunbase = "tun"; 1427 1428 if (ifname != NULL) 1429 *ifname = NULL; 1430 1431 if (mode == SSH_TUNMODE_ETHERNET) 1432 tunbase = "tap"; 1433 1434 /* Open the tunnel device */ 1435 if (tun <= SSH_TUNID_MAX) { 1436 snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun); 1437 fd = open(name, O_RDWR); 1438 } else if (tun == SSH_TUNID_ANY) { 1439 for (tun = 100; tun >= 0; tun--) { 1440 snprintf(name, sizeof(name), "/dev/%s%d", 1441 tunbase, tun); 1442 if ((fd = open(name, O_RDWR)) >= 0) 1443 break; 1444 } 1445 } else { 1446 debug_f("invalid tunnel %u", tun); 1447 return -1; 1448 } 1449 1450 if (fd == -1) { 1451 debug_f("%s open: %s", name, strerror(errno)); 1452 return -1; 1453 } 1454 1455 debug_f("%s mode %d fd %d", name, mode, fd); 1456 1457 /* Bring interface up if it is not already */ 1458 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun); 1459 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) 1460 goto failed; 1461 1462 if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) { 1463 debug_f("get interface %s flags: %s", ifr.ifr_name, 1464 strerror(errno)); 1465 goto failed; 1466 } 1467 1468 if (!(ifr.ifr_flags & IFF_UP)) { 1469 ifr.ifr_flags |= IFF_UP; 1470 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) { 1471 debug_f("activate interface %s: %s", ifr.ifr_name, 1472 strerror(errno)); 1473 goto failed; 1474 } 1475 } 1476 1477 if (ifname != NULL) 1478 *ifname = xstrdup(ifr.ifr_name); 1479 1480 close(sock); 1481 return fd; 1482 1483 failed: 1484 if (fd >= 0) 1485 close(fd); 1486 if (sock >= 0) 1487 close(sock); 1488 return -1; 1489 #else 1490 error("Tunnel interfaces are not supported on this platform"); 1491 return (-1); 1492 #endif 1493 } 1494 1495 void 1496 sanitise_stdfd(void) 1497 { 1498 int nullfd, dupfd; 1499 1500 if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 1501 fprintf(stderr, "Couldn't open /dev/null: %s\n", 1502 strerror(errno)); 1503 exit(1); 1504 } 1505 while (++dupfd <= STDERR_FILENO) { 1506 /* Only populate closed fds. */ 1507 if (fcntl(dupfd, F_GETFL) == -1 && errno == EBADF) { 1508 if (dup2(nullfd, dupfd) == -1) { 1509 fprintf(stderr, "dup2: %s\n", strerror(errno)); 1510 exit(1); 1511 } 1512 } 1513 } 1514 if (nullfd > STDERR_FILENO) 1515 close(nullfd); 1516 } 1517 1518 char * 1519 tohex(const void *vp, size_t l) 1520 { 1521 const u_char *p = (const u_char *)vp; 1522 char b[3], *r; 1523 size_t i, hl; 1524 1525 if (l > 65536) 1526 return xstrdup("tohex: length > 65536"); 1527 1528 hl = l * 2 + 1; 1529 r = xcalloc(1, hl); 1530 for (i = 0; i < l; i++) { 1531 snprintf(b, sizeof(b), "%02x", p[i]); 1532 strlcat(r, b, hl); 1533 } 1534 return (r); 1535 } 1536 1537 /* 1538 * Extend string *sp by the specified format. If *sp is not NULL (or empty), 1539 * then the separator 'sep' will be prepended before the formatted arguments. 1540 * Extended strings are heap allocated. 1541 */ 1542 void 1543 xextendf(char **sp, const char *sep, const char *fmt, ...) 1544 { 1545 va_list ap; 1546 char *tmp1, *tmp2; 1547 1548 va_start(ap, fmt); 1549 xvasprintf(&tmp1, fmt, ap); 1550 va_end(ap); 1551 1552 if (*sp == NULL || **sp == '\0') { 1553 free(*sp); 1554 *sp = tmp1; 1555 return; 1556 } 1557 xasprintf(&tmp2, "%s%s%s", *sp, sep == NULL ? "" : sep, tmp1); 1558 free(tmp1); 1559 free(*sp); 1560 *sp = tmp2; 1561 } 1562 1563 1564 u_int64_t 1565 get_u64(const void *vp) 1566 { 1567 const u_char *p = (const u_char *)vp; 1568 u_int64_t v; 1569 1570 v = (u_int64_t)p[0] << 56; 1571 v |= (u_int64_t)p[1] << 48; 1572 v |= (u_int64_t)p[2] << 40; 1573 v |= (u_int64_t)p[3] << 32; 1574 v |= (u_int64_t)p[4] << 24; 1575 v |= (u_int64_t)p[5] << 16; 1576 v |= (u_int64_t)p[6] << 8; 1577 v |= (u_int64_t)p[7]; 1578 1579 return (v); 1580 } 1581 1582 u_int32_t 1583 get_u32(const void *vp) 1584 { 1585 const u_char *p = (const u_char *)vp; 1586 u_int32_t v; 1587 1588 v = (u_int32_t)p[0] << 24; 1589 v |= (u_int32_t)p[1] << 16; 1590 v |= (u_int32_t)p[2] << 8; 1591 v |= (u_int32_t)p[3]; 1592 1593 return (v); 1594 } 1595 1596 u_int32_t 1597 get_u32_le(const void *vp) 1598 { 1599 const u_char *p = (const u_char *)vp; 1600 u_int32_t v; 1601 1602 v = (u_int32_t)p[0]; 1603 v |= (u_int32_t)p[1] << 8; 1604 v |= (u_int32_t)p[2] << 16; 1605 v |= (u_int32_t)p[3] << 24; 1606 1607 return (v); 1608 } 1609 1610 u_int16_t 1611 get_u16(const void *vp) 1612 { 1613 const u_char *p = (const u_char *)vp; 1614 u_int16_t v; 1615 1616 v = (u_int16_t)p[0] << 8; 1617 v |= (u_int16_t)p[1]; 1618 1619 return (v); 1620 } 1621 1622 void 1623 put_u64(void *vp, u_int64_t v) 1624 { 1625 u_char *p = (u_char *)vp; 1626 1627 p[0] = (u_char)(v >> 56) & 0xff; 1628 p[1] = (u_char)(v >> 48) & 0xff; 1629 p[2] = (u_char)(v >> 40) & 0xff; 1630 p[3] = (u_char)(v >> 32) & 0xff; 1631 p[4] = (u_char)(v >> 24) & 0xff; 1632 p[5] = (u_char)(v >> 16) & 0xff; 1633 p[6] = (u_char)(v >> 8) & 0xff; 1634 p[7] = (u_char)v & 0xff; 1635 } 1636 1637 void 1638 put_u32(void *vp, u_int32_t v) 1639 { 1640 u_char *p = (u_char *)vp; 1641 1642 p[0] = (u_char)(v >> 24) & 0xff; 1643 p[1] = (u_char)(v >> 16) & 0xff; 1644 p[2] = (u_char)(v >> 8) & 0xff; 1645 p[3] = (u_char)v & 0xff; 1646 } 1647 1648 void 1649 put_u32_le(void *vp, u_int32_t v) 1650 { 1651 u_char *p = (u_char *)vp; 1652 1653 p[0] = (u_char)v & 0xff; 1654 p[1] = (u_char)(v >> 8) & 0xff; 1655 p[2] = (u_char)(v >> 16) & 0xff; 1656 p[3] = (u_char)(v >> 24) & 0xff; 1657 } 1658 1659 void 1660 put_u16(void *vp, u_int16_t v) 1661 { 1662 u_char *p = (u_char *)vp; 1663 1664 p[0] = (u_char)(v >> 8) & 0xff; 1665 p[1] = (u_char)v & 0xff; 1666 } 1667 1668 void 1669 ms_subtract_diff(struct timeval *start, int *ms) 1670 { 1671 struct timeval diff, finish; 1672 1673 monotime_tv(&finish); 1674 timersub(&finish, start, &diff); 1675 *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000); 1676 } 1677 1678 void 1679 ms_to_timespec(struct timespec *ts, int ms) 1680 { 1681 if (ms < 0) 1682 ms = 0; 1683 ts->tv_sec = ms / 1000; 1684 ts->tv_nsec = (ms % 1000) * 1000 * 1000; 1685 } 1686 1687 void 1688 monotime_ts(struct timespec *ts) 1689 { 1690 struct timeval tv; 1691 #if defined(HAVE_CLOCK_GETTIME) && (defined(CLOCK_BOOTTIME) || \ 1692 defined(CLOCK_MONOTONIC) || defined(CLOCK_REALTIME)) 1693 static int gettime_failed = 0; 1694 1695 if (!gettime_failed) { 1696 # ifdef CLOCK_BOOTTIME 1697 if (clock_gettime(CLOCK_BOOTTIME, ts) == 0) 1698 return; 1699 # endif /* CLOCK_BOOTTIME */ 1700 # ifdef CLOCK_MONOTONIC 1701 if (clock_gettime(CLOCK_MONOTONIC, ts) == 0) 1702 return; 1703 # endif /* CLOCK_MONOTONIC */ 1704 # ifdef CLOCK_REALTIME 1705 /* Not monotonic, but we're almost out of options here. */ 1706 if (clock_gettime(CLOCK_REALTIME, ts) == 0) 1707 return; 1708 # endif /* CLOCK_REALTIME */ 1709 debug3("clock_gettime: %s", strerror(errno)); 1710 gettime_failed = 1; 1711 } 1712 #endif /* HAVE_CLOCK_GETTIME && (BOOTTIME || MONOTONIC || REALTIME) */ 1713 gettimeofday(&tv, NULL); 1714 ts->tv_sec = tv.tv_sec; 1715 ts->tv_nsec = (long)tv.tv_usec * 1000; 1716 } 1717 1718 void 1719 monotime_tv(struct timeval *tv) 1720 { 1721 struct timespec ts; 1722 1723 monotime_ts(&ts); 1724 tv->tv_sec = ts.tv_sec; 1725 tv->tv_usec = ts.tv_nsec / 1000; 1726 } 1727 1728 time_t 1729 monotime(void) 1730 { 1731 struct timespec ts; 1732 1733 monotime_ts(&ts); 1734 return ts.tv_sec; 1735 } 1736 1737 double 1738 monotime_double(void) 1739 { 1740 struct timespec ts; 1741 1742 monotime_ts(&ts); 1743 return ts.tv_sec + ((double)ts.tv_nsec / 1000000000); 1744 } 1745 1746 void 1747 bandwidth_limit_init(struct bwlimit *bw, u_int64_t kbps, size_t buflen) 1748 { 1749 bw->buflen = buflen; 1750 bw->rate = kbps; 1751 bw->thresh = buflen; 1752 bw->lamt = 0; 1753 timerclear(&bw->bwstart); 1754 timerclear(&bw->bwend); 1755 } 1756 1757 /* Callback from read/write loop to insert bandwidth-limiting delays */ 1758 void 1759 bandwidth_limit(struct bwlimit *bw, size_t read_len) 1760 { 1761 u_int64_t waitlen; 1762 struct timespec ts, rm; 1763 1764 bw->lamt += read_len; 1765 if (!timerisset(&bw->bwstart)) { 1766 monotime_tv(&bw->bwstart); 1767 return; 1768 } 1769 if (bw->lamt < bw->thresh) 1770 return; 1771 1772 monotime_tv(&bw->bwend); 1773 timersub(&bw->bwend, &bw->bwstart, &bw->bwend); 1774 if (!timerisset(&bw->bwend)) 1775 return; 1776 1777 bw->lamt *= 8; 1778 waitlen = (double)1000000L * bw->lamt / bw->rate; 1779 1780 bw->bwstart.tv_sec = waitlen / 1000000L; 1781 bw->bwstart.tv_usec = waitlen % 1000000L; 1782 1783 if (timercmp(&bw->bwstart, &bw->bwend, >)) { 1784 timersub(&bw->bwstart, &bw->bwend, &bw->bwend); 1785 1786 /* Adjust the wait time */ 1787 if (bw->bwend.tv_sec) { 1788 bw->thresh /= 2; 1789 if (bw->thresh < bw->buflen / 4) 1790 bw->thresh = bw->buflen / 4; 1791 } else if (bw->bwend.tv_usec < 10000) { 1792 bw->thresh *= 2; 1793 if (bw->thresh > bw->buflen * 8) 1794 bw->thresh = bw->buflen * 8; 1795 } 1796 1797 TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts); 1798 while (nanosleep(&ts, &rm) == -1) { 1799 if (errno != EINTR) 1800 break; 1801 ts = rm; 1802 } 1803 } 1804 1805 bw->lamt = 0; 1806 monotime_tv(&bw->bwstart); 1807 } 1808 1809 /* Make a template filename for mk[sd]temp() */ 1810 void 1811 mktemp_proto(char *s, size_t len) 1812 { 1813 const char *tmpdir; 1814 int r; 1815 1816 if ((tmpdir = getenv("TMPDIR")) != NULL) { 1817 r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir); 1818 if (r > 0 && (size_t)r < len) 1819 return; 1820 } 1821 r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX"); 1822 if (r < 0 || (size_t)r >= len) 1823 fatal_f("template string too short"); 1824 } 1825 1826 static const struct { 1827 const char *name; 1828 int value; 1829 } ipqos[] = { 1830 { "none", INT_MAX }, /* can't use 0 here; that's CS0 */ 1831 { "af11", IPTOS_DSCP_AF11 }, 1832 { "af12", IPTOS_DSCP_AF12 }, 1833 { "af13", IPTOS_DSCP_AF13 }, 1834 { "af21", IPTOS_DSCP_AF21 }, 1835 { "af22", IPTOS_DSCP_AF22 }, 1836 { "af23", IPTOS_DSCP_AF23 }, 1837 { "af31", IPTOS_DSCP_AF31 }, 1838 { "af32", IPTOS_DSCP_AF32 }, 1839 { "af33", IPTOS_DSCP_AF33 }, 1840 { "af41", IPTOS_DSCP_AF41 }, 1841 { "af42", IPTOS_DSCP_AF42 }, 1842 { "af43", IPTOS_DSCP_AF43 }, 1843 { "cs0", IPTOS_DSCP_CS0 }, 1844 { "cs1", IPTOS_DSCP_CS1 }, 1845 { "cs2", IPTOS_DSCP_CS2 }, 1846 { "cs3", IPTOS_DSCP_CS3 }, 1847 { "cs4", IPTOS_DSCP_CS4 }, 1848 { "cs5", IPTOS_DSCP_CS5 }, 1849 { "cs6", IPTOS_DSCP_CS6 }, 1850 { "cs7", IPTOS_DSCP_CS7 }, 1851 { "ef", IPTOS_DSCP_EF }, 1852 { "le", IPTOS_DSCP_LE }, 1853 { "lowdelay", IPTOS_LOWDELAY }, 1854 { "throughput", IPTOS_THROUGHPUT }, 1855 { "reliability", IPTOS_RELIABILITY }, 1856 { NULL, -1 } 1857 }; 1858 1859 int 1860 parse_ipqos(const char *cp) 1861 { 1862 u_int i; 1863 char *ep; 1864 long val; 1865 1866 if (cp == NULL) 1867 return -1; 1868 for (i = 0; ipqos[i].name != NULL; i++) { 1869 if (strcasecmp(cp, ipqos[i].name) == 0) 1870 return ipqos[i].value; 1871 } 1872 /* Try parsing as an integer */ 1873 val = strtol(cp, &ep, 0); 1874 if (*cp == '\0' || *ep != '\0' || val < 0 || val > 255) 1875 return -1; 1876 return val; 1877 } 1878 1879 const char * 1880 iptos2str(int iptos) 1881 { 1882 int i; 1883 static char iptos_str[sizeof "0xff"]; 1884 1885 for (i = 0; ipqos[i].name != NULL; i++) { 1886 if (ipqos[i].value == iptos) 1887 return ipqos[i].name; 1888 } 1889 snprintf(iptos_str, sizeof iptos_str, "0x%02x", iptos); 1890 return iptos_str; 1891 } 1892 1893 void 1894 lowercase(char *s) 1895 { 1896 for (; *s; s++) 1897 *s = tolower((u_char)*s); 1898 } 1899 1900 int 1901 unix_listener(const char *path, int backlog, int unlink_first) 1902 { 1903 struct sockaddr_un sunaddr; 1904 int saved_errno, sock; 1905 1906 memset(&sunaddr, 0, sizeof(sunaddr)); 1907 sunaddr.sun_family = AF_UNIX; 1908 if (strlcpy(sunaddr.sun_path, path, 1909 sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) { 1910 error_f("path \"%s\" too long for Unix domain socket", path); 1911 errno = ENAMETOOLONG; 1912 return -1; 1913 } 1914 1915 sock = socket(PF_UNIX, SOCK_STREAM, 0); 1916 if (sock == -1) { 1917 saved_errno = errno; 1918 error_f("socket: %.100s", strerror(errno)); 1919 errno = saved_errno; 1920 return -1; 1921 } 1922 if (unlink_first == 1) { 1923 if (unlink(path) != 0 && errno != ENOENT) 1924 error("unlink(%s): %.100s", path, strerror(errno)); 1925 } 1926 if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) { 1927 saved_errno = errno; 1928 error_f("cannot bind to path %s: %s", path, strerror(errno)); 1929 close(sock); 1930 errno = saved_errno; 1931 return -1; 1932 } 1933 if (listen(sock, backlog) == -1) { 1934 saved_errno = errno; 1935 error_f("cannot listen on path %s: %s", path, strerror(errno)); 1936 close(sock); 1937 unlink(path); 1938 errno = saved_errno; 1939 return -1; 1940 } 1941 return sock; 1942 } 1943 1944 void 1945 sock_set_v6only(int s) 1946 { 1947 #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__) 1948 int on = 1; 1949 1950 debug3("%s: set socket %d IPV6_V6ONLY", __func__, s); 1951 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1) 1952 error("setsockopt IPV6_V6ONLY: %s", strerror(errno)); 1953 #endif 1954 } 1955 1956 /* 1957 * Compares two strings that maybe be NULL. Returns non-zero if strings 1958 * are both NULL or are identical, returns zero otherwise. 1959 */ 1960 static int 1961 strcmp_maybe_null(const char *a, const char *b) 1962 { 1963 if ((a == NULL && b != NULL) || (a != NULL && b == NULL)) 1964 return 0; 1965 if (a != NULL && strcmp(a, b) != 0) 1966 return 0; 1967 return 1; 1968 } 1969 1970 /* 1971 * Compare two forwards, returning non-zero if they are identical or 1972 * zero otherwise. 1973 */ 1974 int 1975 forward_equals(const struct Forward *a, const struct Forward *b) 1976 { 1977 if (strcmp_maybe_null(a->listen_host, b->listen_host) == 0) 1978 return 0; 1979 if (a->listen_port != b->listen_port) 1980 return 0; 1981 if (strcmp_maybe_null(a->listen_path, b->listen_path) == 0) 1982 return 0; 1983 if (strcmp_maybe_null(a->connect_host, b->connect_host) == 0) 1984 return 0; 1985 if (a->connect_port != b->connect_port) 1986 return 0; 1987 if (strcmp_maybe_null(a->connect_path, b->connect_path) == 0) 1988 return 0; 1989 /* allocated_port and handle are not checked */ 1990 return 1; 1991 } 1992 1993 /* returns 1 if process is already daemonized, 0 otherwise */ 1994 int 1995 daemonized(void) 1996 { 1997 int fd; 1998 1999 if ((fd = open(_PATH_TTY, O_RDONLY | O_NOCTTY)) >= 0) { 2000 close(fd); 2001 return 0; /* have controlling terminal */ 2002 } 2003 if (getppid() != 1) 2004 return 0; /* parent is not init */ 2005 if (getsid(0) != getpid()) 2006 return 0; /* not session leader */ 2007 debug3("already daemonized"); 2008 return 1; 2009 } 2010 2011 /* 2012 * Splits 's' into an argument vector. Handles quoted string and basic 2013 * escape characters (\\, \", \'). Caller must free the argument vector 2014 * and its members. 2015 */ 2016 int 2017 argv_split(const char *s, int *argcp, char ***argvp, int terminate_on_comment) 2018 { 2019 int r = SSH_ERR_INTERNAL_ERROR; 2020 int argc = 0, quote, i, j; 2021 char *arg, **argv = xcalloc(1, sizeof(*argv)); 2022 2023 *argvp = NULL; 2024 *argcp = 0; 2025 2026 for (i = 0; s[i] != '\0'; i++) { 2027 /* Skip leading whitespace */ 2028 if (s[i] == ' ' || s[i] == '\t') 2029 continue; 2030 if (terminate_on_comment && s[i] == '#') 2031 break; 2032 /* Start of a token */ 2033 quote = 0; 2034 2035 argv = xreallocarray(argv, (argc + 2), sizeof(*argv)); 2036 arg = argv[argc++] = xcalloc(1, strlen(s + i) + 1); 2037 argv[argc] = NULL; 2038 2039 /* Copy the token in, removing escapes */ 2040 for (j = 0; s[i] != '\0'; i++) { 2041 if (s[i] == '\\') { 2042 if (s[i + 1] == '\'' || 2043 s[i + 1] == '\"' || 2044 s[i + 1] == '\\' || 2045 (quote == 0 && s[i + 1] == ' ')) { 2046 i++; /* Skip '\' */ 2047 arg[j++] = s[i]; 2048 } else { 2049 /* Unrecognised escape */ 2050 arg[j++] = s[i]; 2051 } 2052 } else if (quote == 0 && (s[i] == ' ' || s[i] == '\t')) 2053 break; /* done */ 2054 else if (quote == 0 && (s[i] == '\"' || s[i] == '\'')) 2055 quote = s[i]; /* quote start */ 2056 else if (quote != 0 && s[i] == quote) 2057 quote = 0; /* quote end */ 2058 else 2059 arg[j++] = s[i]; 2060 } 2061 if (s[i] == '\0') { 2062 if (quote != 0) { 2063 /* Ran out of string looking for close quote */ 2064 r = SSH_ERR_INVALID_FORMAT; 2065 goto out; 2066 } 2067 break; 2068 } 2069 } 2070 /* Success */ 2071 *argcp = argc; 2072 *argvp = argv; 2073 argc = 0; 2074 argv = NULL; 2075 r = 0; 2076 out: 2077 if (argc != 0 && argv != NULL) { 2078 for (i = 0; i < argc; i++) 2079 free(argv[i]); 2080 free(argv); 2081 } 2082 return r; 2083 } 2084 2085 /* 2086 * Reassemble an argument vector into a string, quoting and escaping as 2087 * necessary. Caller must free returned string. 2088 */ 2089 char * 2090 argv_assemble(int argc, char **argv) 2091 { 2092 int i, j, ws, r; 2093 char c, *ret; 2094 struct sshbuf *buf, *arg; 2095 2096 if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL) 2097 fatal_f("sshbuf_new failed"); 2098 2099 for (i = 0; i < argc; i++) { 2100 ws = 0; 2101 sshbuf_reset(arg); 2102 for (j = 0; argv[i][j] != '\0'; j++) { 2103 r = 0; 2104 c = argv[i][j]; 2105 switch (c) { 2106 case ' ': 2107 case '\t': 2108 ws = 1; 2109 r = sshbuf_put_u8(arg, c); 2110 break; 2111 case '\\': 2112 case '\'': 2113 case '"': 2114 if ((r = sshbuf_put_u8(arg, '\\')) != 0) 2115 break; 2116 /* FALLTHROUGH */ 2117 default: 2118 r = sshbuf_put_u8(arg, c); 2119 break; 2120 } 2121 if (r != 0) 2122 fatal_fr(r, "sshbuf_put_u8"); 2123 } 2124 if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) || 2125 (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) || 2126 (r = sshbuf_putb(buf, arg)) != 0 || 2127 (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0)) 2128 fatal_fr(r, "assemble"); 2129 } 2130 if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL) 2131 fatal_f("malloc failed"); 2132 memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf)); 2133 ret[sshbuf_len(buf)] = '\0'; 2134 sshbuf_free(buf); 2135 sshbuf_free(arg); 2136 return ret; 2137 } 2138 2139 char * 2140 argv_next(int *argcp, char ***argvp) 2141 { 2142 char *ret = (*argvp)[0]; 2143 2144 if (*argcp > 0 && ret != NULL) { 2145 (*argcp)--; 2146 (*argvp)++; 2147 } 2148 return ret; 2149 } 2150 2151 void 2152 argv_consume(int *argcp) 2153 { 2154 *argcp = 0; 2155 } 2156 2157 void 2158 argv_free(char **av, int ac) 2159 { 2160 int i; 2161 2162 if (av == NULL) 2163 return; 2164 for (i = 0; i < ac; i++) 2165 free(av[i]); 2166 free(av); 2167 } 2168 2169 /* Returns 0 if pid exited cleanly, non-zero otherwise */ 2170 int 2171 exited_cleanly(pid_t pid, const char *tag, const char *cmd, int quiet) 2172 { 2173 int status; 2174 2175 while (waitpid(pid, &status, 0) == -1) { 2176 if (errno != EINTR) { 2177 error("%s waitpid: %s", tag, strerror(errno)); 2178 return -1; 2179 } 2180 } 2181 if (WIFSIGNALED(status)) { 2182 error("%s %s exited on signal %d", tag, cmd, WTERMSIG(status)); 2183 return -1; 2184 } else if (WEXITSTATUS(status) != 0) { 2185 do_log2(quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO, 2186 "%s %s failed, status %d", tag, cmd, WEXITSTATUS(status)); 2187 return -1; 2188 } 2189 return 0; 2190 } 2191 2192 /* 2193 * Check a given path for security. This is defined as all components 2194 * of the path to the file must be owned by either the owner of 2195 * of the file or root and no directories must be group or world writable. 2196 * 2197 * XXX Should any specific check be done for sym links ? 2198 * 2199 * Takes a file name, its stat information (preferably from fstat() to 2200 * avoid races), the uid of the expected owner, their home directory and an 2201 * error buffer plus max size as arguments. 2202 * 2203 * Returns 0 on success and -1 on failure 2204 */ 2205 int 2206 safe_path(const char *name, struct stat *stp, const char *pw_dir, 2207 uid_t uid, char *err, size_t errlen) 2208 { 2209 char buf[PATH_MAX], homedir[PATH_MAX]; 2210 char *cp; 2211 int comparehome = 0; 2212 struct stat st; 2213 2214 if (realpath(name, buf) == NULL) { 2215 snprintf(err, errlen, "realpath %s failed: %s", name, 2216 strerror(errno)); 2217 return -1; 2218 } 2219 if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL) 2220 comparehome = 1; 2221 2222 if (!S_ISREG(stp->st_mode)) { 2223 snprintf(err, errlen, "%s is not a regular file", buf); 2224 return -1; 2225 } 2226 if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) || 2227 (stp->st_mode & 022) != 0) { 2228 snprintf(err, errlen, "bad ownership or modes for file %s", 2229 buf); 2230 return -1; 2231 } 2232 2233 /* for each component of the canonical path, walking upwards */ 2234 for (;;) { 2235 if ((cp = dirname(buf)) == NULL) { 2236 snprintf(err, errlen, "dirname() failed"); 2237 return -1; 2238 } 2239 strlcpy(buf, cp, sizeof(buf)); 2240 2241 if (stat(buf, &st) == -1 || 2242 (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) || 2243 (st.st_mode & 022) != 0) { 2244 snprintf(err, errlen, 2245 "bad ownership or modes for directory %s", buf); 2246 return -1; 2247 } 2248 2249 /* If are past the homedir then we can stop */ 2250 if (comparehome && strcmp(homedir, buf) == 0) 2251 break; 2252 2253 /* 2254 * dirname should always complete with a "/" path, 2255 * but we can be paranoid and check for "." too 2256 */ 2257 if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0)) 2258 break; 2259 } 2260 return 0; 2261 } 2262 2263 /* 2264 * Version of safe_path() that accepts an open file descriptor to 2265 * avoid races. 2266 * 2267 * Returns 0 on success and -1 on failure 2268 */ 2269 int 2270 safe_path_fd(int fd, const char *file, struct passwd *pw, 2271 char *err, size_t errlen) 2272 { 2273 struct stat st; 2274 2275 /* check the open file to avoid races */ 2276 if (fstat(fd, &st) == -1) { 2277 snprintf(err, errlen, "cannot stat file %s: %s", 2278 file, strerror(errno)); 2279 return -1; 2280 } 2281 return safe_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen); 2282 } 2283 2284 /* 2285 * Sets the value of the given variable in the environment. If the variable 2286 * already exists, its value is overridden. 2287 */ 2288 void 2289 child_set_env(char ***envp, u_int *envsizep, const char *name, 2290 const char *value) 2291 { 2292 char **env; 2293 u_int envsize; 2294 u_int i, namelen; 2295 2296 if (strchr(name, '=') != NULL) { 2297 error("Invalid environment variable \"%.100s\"", name); 2298 return; 2299 } 2300 2301 /* 2302 * If we're passed an uninitialized list, allocate a single null 2303 * entry before continuing. 2304 */ 2305 if ((*envp == NULL) != (*envsizep == 0)) 2306 fatal_f("environment size mismatch"); 2307 if (*envp == NULL && *envsizep == 0) { 2308 *envp = xmalloc(sizeof(char *)); 2309 *envp[0] = NULL; 2310 *envsizep = 1; 2311 } 2312 2313 /* 2314 * Find the slot where the value should be stored. If the variable 2315 * already exists, we reuse the slot; otherwise we append a new slot 2316 * at the end of the array, expanding if necessary. 2317 */ 2318 env = *envp; 2319 namelen = strlen(name); 2320 for (i = 0; env[i]; i++) 2321 if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=') 2322 break; 2323 if (env[i]) { 2324 /* Reuse the slot. */ 2325 free(env[i]); 2326 } else { 2327 /* New variable. Expand if necessary. */ 2328 envsize = *envsizep; 2329 if (i >= envsize - 1) { 2330 if (envsize >= 1000) 2331 fatal("child_set_env: too many env vars"); 2332 envsize += 50; 2333 env = (*envp) = xreallocarray(env, envsize, sizeof(char *)); 2334 *envsizep = envsize; 2335 } 2336 /* Need to set the NULL pointer at end of array beyond the new slot. */ 2337 env[i + 1] = NULL; 2338 } 2339 2340 /* Allocate space and format the variable in the appropriate slot. */ 2341 /* XXX xasprintf */ 2342 env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1); 2343 snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value); 2344 } 2345 2346 /* 2347 * Check and optionally lowercase a domain name, also removes trailing '.' 2348 * Returns 1 on success and 0 on failure, storing an error message in errstr. 2349 */ 2350 int 2351 valid_domain(char *name, int makelower, const char **errstr) 2352 { 2353 size_t i, l = strlen(name); 2354 u_char c, last = '\0'; 2355 static char errbuf[256]; 2356 2357 if (l == 0) { 2358 strlcpy(errbuf, "empty domain name", sizeof(errbuf)); 2359 goto bad; 2360 } 2361 if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0])) { 2362 snprintf(errbuf, sizeof(errbuf), "domain name \"%.100s\" " 2363 "starts with invalid character", name); 2364 goto bad; 2365 } 2366 for (i = 0; i < l; i++) { 2367 c = tolower((u_char)name[i]); 2368 if (makelower) 2369 name[i] = (char)c; 2370 if (last == '.' && c == '.') { 2371 snprintf(errbuf, sizeof(errbuf), "domain name " 2372 "\"%.100s\" contains consecutive separators", name); 2373 goto bad; 2374 } 2375 if (c != '.' && c != '-' && !isalnum(c) && 2376 c != '_') /* technically invalid, but common */ { 2377 snprintf(errbuf, sizeof(errbuf), "domain name " 2378 "\"%.100s\" contains invalid characters", name); 2379 goto bad; 2380 } 2381 last = c; 2382 } 2383 if (name[l - 1] == '.') 2384 name[l - 1] = '\0'; 2385 if (errstr != NULL) 2386 *errstr = NULL; 2387 return 1; 2388 bad: 2389 if (errstr != NULL) 2390 *errstr = errbuf; 2391 return 0; 2392 } 2393 2394 /* 2395 * Verify that a environment variable name (not including initial '$') is 2396 * valid; consisting of one or more alphanumeric or underscore characters only. 2397 * Returns 1 on valid, 0 otherwise. 2398 */ 2399 int 2400 valid_env_name(const char *name) 2401 { 2402 const char *cp; 2403 2404 if (name[0] == '\0') 2405 return 0; 2406 for (cp = name; *cp != '\0'; cp++) { 2407 if (!isalnum((u_char)*cp) && *cp != '_') 2408 return 0; 2409 } 2410 return 1; 2411 } 2412 2413 const char * 2414 atoi_err(const char *nptr, int *val) 2415 { 2416 const char *errstr = NULL; 2417 long long num; 2418 2419 if (nptr == NULL || *nptr == '\0') 2420 return "missing"; 2421 num = strtonum(nptr, 0, INT_MAX, &errstr); 2422 if (errstr == NULL) 2423 *val = (int)num; 2424 return errstr; 2425 } 2426 2427 int 2428 parse_absolute_time(const char *s, uint64_t *tp) 2429 { 2430 struct tm tm; 2431 time_t tt; 2432 char buf[32], *fmt; 2433 const char *cp; 2434 size_t l; 2435 int is_utc = 0; 2436 2437 *tp = 0; 2438 2439 l = strlen(s); 2440 if (l > 1 && strcasecmp(s + l - 1, "Z") == 0) { 2441 is_utc = 1; 2442 l--; 2443 } else if (l > 3 && strcasecmp(s + l - 3, "UTC") == 0) { 2444 is_utc = 1; 2445 l -= 3; 2446 } 2447 /* 2448 * POSIX strptime says "The application shall ensure that there 2449 * is white-space or other non-alphanumeric characters between 2450 * any two conversion specifications" so arrange things this way. 2451 */ 2452 switch (l) { 2453 case 8: /* YYYYMMDD */ 2454 fmt = "%Y-%m-%d"; 2455 snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2s", s, s + 4, s + 6); 2456 break; 2457 case 12: /* YYYYMMDDHHMM */ 2458 fmt = "%Y-%m-%dT%H:%M"; 2459 snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s", 2460 s, s + 4, s + 6, s + 8, s + 10); 2461 break; 2462 case 14: /* YYYYMMDDHHMMSS */ 2463 fmt = "%Y-%m-%dT%H:%M:%S"; 2464 snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s:%.2s", 2465 s, s + 4, s + 6, s + 8, s + 10, s + 12); 2466 break; 2467 default: 2468 return SSH_ERR_INVALID_FORMAT; 2469 } 2470 2471 memset(&tm, 0, sizeof(tm)); 2472 if ((cp = strptime(buf, fmt, &tm)) == NULL || *cp != '\0') 2473 return SSH_ERR_INVALID_FORMAT; 2474 if (is_utc) { 2475 if ((tt = timegm(&tm)) < 0) 2476 return SSH_ERR_INVALID_FORMAT; 2477 } else { 2478 if ((tt = mktime(&tm)) < 0) 2479 return SSH_ERR_INVALID_FORMAT; 2480 } 2481 /* success */ 2482 *tp = (uint64_t)tt; 2483 return 0; 2484 } 2485 2486 void 2487 format_absolute_time(uint64_t t, char *buf, size_t len) 2488 { 2489 time_t tt = t > SSH_TIME_T_MAX ? SSH_TIME_T_MAX : t; 2490 struct tm tm; 2491 2492 localtime_r(&tt, &tm); 2493 strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm); 2494 } 2495 2496 /* check if path is absolute */ 2497 int 2498 path_absolute(const char *path) 2499 { 2500 return (*path == '/') ? 1 : 0; 2501 } 2502 2503 void 2504 skip_space(char **cpp) 2505 { 2506 char *cp; 2507 2508 for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++) 2509 ; 2510 *cpp = cp; 2511 } 2512 2513 /* authorized_key-style options parsing helpers */ 2514 2515 /* 2516 * Match flag 'opt' in *optsp, and if allow_negate is set then also match 2517 * 'no-opt'. Returns -1 if option not matched, 1 if option matches or 0 2518 * if negated option matches. 2519 * If the option or negated option matches, then *optsp is updated to 2520 * point to the first character after the option. 2521 */ 2522 int 2523 opt_flag(const char *opt, int allow_negate, const char **optsp) 2524 { 2525 size_t opt_len = strlen(opt); 2526 const char *opts = *optsp; 2527 int negate = 0; 2528 2529 if (allow_negate && strncasecmp(opts, "no-", 3) == 0) { 2530 opts += 3; 2531 negate = 1; 2532 } 2533 if (strncasecmp(opts, opt, opt_len) == 0) { 2534 *optsp = opts + opt_len; 2535 return negate ? 0 : 1; 2536 } 2537 return -1; 2538 } 2539 2540 char * 2541 opt_dequote(const char **sp, const char **errstrp) 2542 { 2543 const char *s = *sp; 2544 char *ret; 2545 size_t i; 2546 2547 *errstrp = NULL; 2548 if (*s != '"') { 2549 *errstrp = "missing start quote"; 2550 return NULL; 2551 } 2552 s++; 2553 if ((ret = malloc(strlen((s)) + 1)) == NULL) { 2554 *errstrp = "memory allocation failed"; 2555 return NULL; 2556 } 2557 for (i = 0; *s != '\0' && *s != '"';) { 2558 if (s[0] == '\\' && s[1] == '"') 2559 s++; 2560 ret[i++] = *s++; 2561 } 2562 if (*s == '\0') { 2563 *errstrp = "missing end quote"; 2564 free(ret); 2565 return NULL; 2566 } 2567 ret[i] = '\0'; 2568 s++; 2569 *sp = s; 2570 return ret; 2571 } 2572 2573 int 2574 opt_match(const char **opts, const char *term) 2575 { 2576 if (strncasecmp((*opts), term, strlen(term)) == 0 && 2577 (*opts)[strlen(term)] == '=') { 2578 *opts += strlen(term) + 1; 2579 return 1; 2580 } 2581 return 0; 2582 } 2583 2584 void 2585 opt_array_append2(const char *file, const int line, const char *directive, 2586 char ***array, int **iarray, u_int *lp, const char *s, int i) 2587 { 2588 2589 if (*lp >= INT_MAX) 2590 fatal("%s line %d: Too many %s entries", file, line, directive); 2591 2592 if (iarray != NULL) { 2593 *iarray = xrecallocarray(*iarray, *lp, *lp + 1, 2594 sizeof(**iarray)); 2595 (*iarray)[*lp] = i; 2596 } 2597 2598 *array = xrecallocarray(*array, *lp, *lp + 1, sizeof(**array)); 2599 (*array)[*lp] = xstrdup(s); 2600 (*lp)++; 2601 } 2602 2603 void 2604 opt_array_append(const char *file, const int line, const char *directive, 2605 char ***array, u_int *lp, const char *s) 2606 { 2607 opt_array_append2(file, line, directive, array, NULL, lp, s, 0); 2608 } 2609 2610 sshsig_t 2611 ssh_signal(int signum, sshsig_t handler) 2612 { 2613 struct sigaction sa, osa; 2614 2615 /* mask all other signals while in handler */ 2616 memset(&sa, 0, sizeof(sa)); 2617 sa.sa_handler = handler; 2618 sigfillset(&sa.sa_mask); 2619 #if defined(SA_RESTART) && !defined(NO_SA_RESTART) 2620 if (signum != SIGALRM) 2621 sa.sa_flags = SA_RESTART; 2622 #endif 2623 if (sigaction(signum, &sa, &osa) == -1) { 2624 debug3("sigaction(%s): %s", strsignal(signum), strerror(errno)); 2625 return SIG_ERR; 2626 } 2627 return osa.sa_handler; 2628 } 2629 2630 int 2631 stdfd_devnull(int do_stdin, int do_stdout, int do_stderr) 2632 { 2633 int devnull, ret = 0; 2634 2635 if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { 2636 error_f("open %s: %s", _PATH_DEVNULL, 2637 strerror(errno)); 2638 return -1; 2639 } 2640 if ((do_stdin && dup2(devnull, STDIN_FILENO) == -1) || 2641 (do_stdout && dup2(devnull, STDOUT_FILENO) == -1) || 2642 (do_stderr && dup2(devnull, STDERR_FILENO) == -1)) { 2643 error_f("dup2: %s", strerror(errno)); 2644 ret = -1; 2645 } 2646 if (devnull > STDERR_FILENO) 2647 close(devnull); 2648 return ret; 2649 } 2650 2651 /* 2652 * Runs command in a subprocess with a minimal environment. 2653 * Returns pid on success, 0 on failure. 2654 * The child stdout and stderr maybe captured, left attached or sent to 2655 * /dev/null depending on the contents of flags. 2656 * "tag" is prepended to log messages. 2657 * NB. "command" is only used for logging; the actual command executed is 2658 * av[0]. 2659 */ 2660 pid_t 2661 subprocess(const char *tag, const char *command, 2662 int ac, char **av, FILE **child, u_int flags, 2663 struct passwd *pw, privdrop_fn *drop_privs, privrestore_fn *restore_privs) 2664 { 2665 FILE *f = NULL; 2666 struct stat st; 2667 int fd, devnull, p[2], i; 2668 pid_t pid; 2669 char *cp, errmsg[512]; 2670 u_int nenv = 0; 2671 char **env = NULL; 2672 2673 /* If dropping privs, then must specify user and restore function */ 2674 if (drop_privs != NULL && (pw == NULL || restore_privs == NULL)) { 2675 error("%s: inconsistent arguments", tag); /* XXX fatal? */ 2676 return 0; 2677 } 2678 if (pw == NULL && (pw = getpwuid(getuid())) == NULL) { 2679 error("%s: no user for current uid", tag); 2680 return 0; 2681 } 2682 if (child != NULL) 2683 *child = NULL; 2684 2685 debug3_f("%s command \"%s\" running as %s (flags 0x%x)", 2686 tag, command, pw->pw_name, flags); 2687 2688 /* Check consistency */ 2689 if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 && 2690 (flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) { 2691 error_f("inconsistent flags"); 2692 return 0; 2693 } 2694 if (((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) != (child == NULL)) { 2695 error_f("inconsistent flags/output"); 2696 return 0; 2697 } 2698 2699 /* 2700 * If executing an explicit binary, then verify the it exists 2701 * and appears safe-ish to execute 2702 */ 2703 if (!path_absolute(av[0])) { 2704 error("%s path is not absolute", tag); 2705 return 0; 2706 } 2707 if (drop_privs != NULL) 2708 drop_privs(pw); 2709 if (stat(av[0], &st) == -1) { 2710 error("Could not stat %s \"%s\": %s", tag, 2711 av[0], strerror(errno)); 2712 goto restore_return; 2713 } 2714 if ((flags & SSH_SUBPROCESS_UNSAFE_PATH) == 0 && 2715 safe_path(av[0], &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) { 2716 error("Unsafe %s \"%s\": %s", tag, av[0], errmsg); 2717 goto restore_return; 2718 } 2719 /* Prepare to keep the child's stdout if requested */ 2720 if (pipe(p) == -1) { 2721 error("%s: pipe: %s", tag, strerror(errno)); 2722 restore_return: 2723 if (restore_privs != NULL) 2724 restore_privs(); 2725 return 0; 2726 } 2727 if (restore_privs != NULL) 2728 restore_privs(); 2729 2730 switch ((pid = fork())) { 2731 case -1: /* error */ 2732 error("%s: fork: %s", tag, strerror(errno)); 2733 close(p[0]); 2734 close(p[1]); 2735 return 0; 2736 case 0: /* child */ 2737 /* Prepare a minimal environment for the child. */ 2738 if ((flags & SSH_SUBPROCESS_PRESERVE_ENV) == 0) { 2739 nenv = 5; 2740 env = xcalloc(sizeof(*env), nenv); 2741 child_set_env(&env, &nenv, "PATH", _PATH_STDPATH); 2742 child_set_env(&env, &nenv, "USER", pw->pw_name); 2743 child_set_env(&env, &nenv, "LOGNAME", pw->pw_name); 2744 child_set_env(&env, &nenv, "HOME", pw->pw_dir); 2745 if ((cp = getenv("LANG")) != NULL) 2746 child_set_env(&env, &nenv, "LANG", cp); 2747 } 2748 2749 for (i = 1; i < NSIG; i++) 2750 ssh_signal(i, SIG_DFL); 2751 2752 if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { 2753 error("%s: open %s: %s", tag, _PATH_DEVNULL, 2754 strerror(errno)); 2755 _exit(1); 2756 } 2757 if (dup2(devnull, STDIN_FILENO) == -1) { 2758 error("%s: dup2: %s", tag, strerror(errno)); 2759 _exit(1); 2760 } 2761 2762 /* Set up stdout as requested; leave stderr in place for now. */ 2763 fd = -1; 2764 if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) 2765 fd = p[1]; 2766 else if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0) 2767 fd = devnull; 2768 if (fd != -1 && dup2(fd, STDOUT_FILENO) == -1) { 2769 error("%s: dup2: %s", tag, strerror(errno)); 2770 _exit(1); 2771 } 2772 closefrom(STDERR_FILENO + 1); 2773 2774 if (geteuid() == 0 && 2775 initgroups(pw->pw_name, pw->pw_gid) == -1) { 2776 error("%s: initgroups(%s, %u): %s", tag, 2777 pw->pw_name, (u_int)pw->pw_gid, strerror(errno)); 2778 _exit(1); 2779 } 2780 if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1) { 2781 error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid, 2782 strerror(errno)); 2783 _exit(1); 2784 } 2785 if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) { 2786 error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid, 2787 strerror(errno)); 2788 _exit(1); 2789 } 2790 /* stdin is pointed to /dev/null at this point */ 2791 if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 && 2792 dup2(STDIN_FILENO, STDERR_FILENO) == -1) { 2793 error("%s: dup2: %s", tag, strerror(errno)); 2794 _exit(1); 2795 } 2796 if (env != NULL) 2797 execve(av[0], av, env); 2798 else 2799 execv(av[0], av); 2800 error("%s %s \"%s\": %s", tag, env == NULL ? "execv" : "execve", 2801 command, strerror(errno)); 2802 _exit(127); 2803 default: /* parent */ 2804 break; 2805 } 2806 2807 close(p[1]); 2808 if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) 2809 close(p[0]); 2810 else if ((f = fdopen(p[0], "r")) == NULL) { 2811 error("%s: fdopen: %s", tag, strerror(errno)); 2812 close(p[0]); 2813 /* Don't leave zombie child */ 2814 kill(pid, SIGTERM); 2815 while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) 2816 ; 2817 return 0; 2818 } 2819 /* Success */ 2820 debug3_f("%s pid %ld", tag, (long)pid); 2821 if (child != NULL) 2822 *child = f; 2823 return pid; 2824 } 2825 2826 const char * 2827 lookup_env_in_list(const char *env, char * const *envs, size_t nenvs) 2828 { 2829 size_t i, envlen; 2830 2831 envlen = strlen(env); 2832 for (i = 0; i < nenvs; i++) { 2833 if (strncmp(envs[i], env, envlen) == 0 && 2834 envs[i][envlen] == '=') { 2835 return envs[i] + envlen + 1; 2836 } 2837 } 2838 return NULL; 2839 } 2840 2841 const char * 2842 lookup_setenv_in_list(const char *env, char * const *envs, size_t nenvs) 2843 { 2844 char *name, *cp; 2845 const char *ret; 2846 2847 name = xstrdup(env); 2848 if ((cp = strchr(name, '=')) == NULL) { 2849 free(name); 2850 return NULL; /* not env=val */ 2851 } 2852 *cp = '\0'; 2853 ret = lookup_env_in_list(name, envs, nenvs); 2854 free(name); 2855 return ret; 2856 } 2857 2858 /* 2859 * Helpers for managing poll(2)/ppoll(2) timeouts 2860 * Will remember the earliest deadline and return it for use in poll/ppoll. 2861 */ 2862 2863 /* Initialise a poll/ppoll timeout with an indefinite deadline */ 2864 void 2865 ptimeout_init(struct timespec *pt) 2866 { 2867 /* 2868 * Deliberately invalid for ppoll(2). 2869 * Will be converted to NULL in ptimeout_get_tspec() later. 2870 */ 2871 pt->tv_sec = -1; 2872 pt->tv_nsec = 0; 2873 } 2874 2875 /* Specify a poll/ppoll deadline of at most 'sec' seconds */ 2876 void 2877 ptimeout_deadline_sec(struct timespec *pt, long sec) 2878 { 2879 if (pt->tv_sec == -1 || pt->tv_sec >= sec) { 2880 pt->tv_sec = sec; 2881 pt->tv_nsec = 0; 2882 } 2883 } 2884 2885 /* Specify a poll/ppoll deadline of at most 'p' (timespec) */ 2886 static void 2887 ptimeout_deadline_tsp(struct timespec *pt, struct timespec *p) 2888 { 2889 if (pt->tv_sec == -1 || timespeccmp(pt, p, >=)) 2890 *pt = *p; 2891 } 2892 2893 /* Specify a poll/ppoll deadline of at most 'ms' milliseconds */ 2894 void 2895 ptimeout_deadline_ms(struct timespec *pt, long ms) 2896 { 2897 struct timespec p; 2898 2899 p.tv_sec = ms / 1000; 2900 p.tv_nsec = (ms % 1000) * 1000000; 2901 ptimeout_deadline_tsp(pt, &p); 2902 } 2903 2904 /* Specify a poll/ppoll deadline at wall clock monotime 'when' (timespec) */ 2905 void 2906 ptimeout_deadline_monotime_tsp(struct timespec *pt, struct timespec *when) 2907 { 2908 struct timespec now, t; 2909 2910 monotime_ts(&now); 2911 2912 if (timespeccmp(&now, when, >=)) { 2913 /* 'when' is now or in the past. Timeout ASAP */ 2914 pt->tv_sec = 0; 2915 pt->tv_nsec = 0; 2916 } else { 2917 timespecsub(when, &now, &t); 2918 ptimeout_deadline_tsp(pt, &t); 2919 } 2920 } 2921 2922 /* Specify a poll/ppoll deadline at wall clock monotime 'when' */ 2923 void 2924 ptimeout_deadline_monotime(struct timespec *pt, time_t when) 2925 { 2926 struct timespec t; 2927 2928 t.tv_sec = when; 2929 t.tv_nsec = 0; 2930 ptimeout_deadline_monotime_tsp(pt, &t); 2931 } 2932 2933 /* Get a poll(2) timeout value in milliseconds */ 2934 int 2935 ptimeout_get_ms(struct timespec *pt) 2936 { 2937 if (pt->tv_sec == -1) 2938 return -1; 2939 if (pt->tv_sec >= (INT_MAX - (pt->tv_nsec / 1000000)) / 1000) 2940 return INT_MAX; 2941 return (pt->tv_sec * 1000) + (pt->tv_nsec / 1000000); 2942 } 2943 2944 /* Get a ppoll(2) timeout value as a timespec pointer */ 2945 struct timespec * 2946 ptimeout_get_tsp(struct timespec *pt) 2947 { 2948 return pt->tv_sec == -1 ? NULL : pt; 2949 } 2950 2951 /* Returns non-zero if a timeout has been set (i.e. is not indefinite) */ 2952 int 2953 ptimeout_isset(struct timespec *pt) 2954 { 2955 return pt->tv_sec != -1; 2956 } 2957 2958 /* 2959 * Returns zero if the library at 'path' contains symbol 's', nonzero 2960 * otherwise. 2961 */ 2962 int 2963 lib_contains_symbol(const char *path, const char *s) 2964 { 2965 #ifdef HAVE_NLIST_H 2966 struct nlist nl[2]; 2967 int ret = -1, r; 2968 2969 memset(nl, 0, sizeof(nl)); 2970 nl[0].n_name = xstrdup(s); 2971 nl[1].n_name = NULL; 2972 if ((r = nlist(path, nl)) == -1) { 2973 error_f("nlist failed for %s", path); 2974 goto out; 2975 } 2976 if (r != 0 || nl[0].n_value == 0 || nl[0].n_type == 0) { 2977 error_f("library %s does not contain symbol %s", path, s); 2978 goto out; 2979 } 2980 /* success */ 2981 ret = 0; 2982 out: 2983 free(nl[0].n_name); 2984 return ret; 2985 #else /* HAVE_NLIST_H */ 2986 int fd, ret = -1; 2987 struct stat st; 2988 void *m = NULL; 2989 size_t sz = 0; 2990 2991 memset(&st, 0, sizeof(st)); 2992 if ((fd = open(path, O_RDONLY)) < 0) { 2993 error_f("open %s: %s", path, strerror(errno)); 2994 return -1; 2995 } 2996 if (fstat(fd, &st) != 0) { 2997 error_f("fstat %s: %s", path, strerror(errno)); 2998 goto out; 2999 } 3000 if (!S_ISREG(st.st_mode)) { 3001 error_f("%s is not a regular file", path); 3002 goto out; 3003 } 3004 if (st.st_size < 0 || 3005 (size_t)st.st_size < strlen(s) || 3006 st.st_size >= INT_MAX/2) { 3007 error_f("%s bad size %lld", path, (long long)st.st_size); 3008 goto out; 3009 } 3010 sz = (size_t)st.st_size; 3011 if ((m = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED || 3012 m == NULL) { 3013 error_f("mmap %s: %s", path, strerror(errno)); 3014 goto out; 3015 } 3016 if (memmem(m, sz, s, strlen(s)) == NULL) { 3017 error_f("%s does not contain expected string %s", path, s); 3018 goto out; 3019 } 3020 /* success */ 3021 ret = 0; 3022 out: 3023 if (m != NULL && m != MAP_FAILED) 3024 munmap(m, sz); 3025 close(fd); 3026 return ret; 3027 #endif /* HAVE_NLIST_H */ 3028 } 3029